From e3c92d05328d7b40927bed66e7c2500a7853cdc8 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 19 Mar 2020 11:52:15 +0100 Subject: [PATCH] ir: More changes to sentinel-terminated const arrays * Don't add an extra slot for the sentinel. Most of the code keeps using the constant value from the type descriptor, let's harmonize all the code dealing with sentinels. * Properly write out sentinel values when reinterpreting pointers at comptime. * Allow the reading of the 0th element in a `[0:S]T` type. --- src/analyze.cpp | 7 +----- src/codegen.cpp | 39 +++++++++++++++++++--------------- src/ir.cpp | 8 +++---- test/stage1/behavior/array.zig | 18 ++++++++++++++++ 4 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index fbd7d85ac1..9ba247012d 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5806,18 +5806,13 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { // The elements array cannot be left unpopulated ZigType *array_type = result->type; ZigType *elem_type = array_type->data.array.child_type; - ZigValue *sentinel_value = array_type->data.array.sentinel; - const size_t elem_count = array_type->data.array.len + (sentinel_value != nullptr); + const size_t elem_count = array_type->data.array.len; result->data.x_array.data.s_none.elements = g->pass1_arena->allocate(elem_count); for (size_t i = 0; i < elem_count; i += 1) { ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i]; copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type)); } - if (sentinel_value != nullptr) { - ZigValue *last_elem_val = &result->data.x_array.data.s_none.elements[elem_count - 1]; - copy_const_val(g, last_elem_val, sentinel_value); - } } else if (result->type->id == ZigTypeIdPointer) { result->data.x_ptr.special = ConstPtrSpecialRef; result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type); diff --git a/src/codegen.cpp b/src/codegen.cpp index 75f3223250..3343807691 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3584,9 +3584,7 @@ static bool value_is_all_undef(CodeGen *g, ZigValue *const_val) { } return true; } else if (const_val->type->id == ZigTypeIdArray) { - const size_t full_len = const_val->type->data.array.len + - (const_val->type->data.array.sentinel != nullptr); - return value_is_all_undef_array(g, const_val, full_len); + return value_is_all_undef_array(g, const_val, const_val->type->data.array.len); } else if (const_val->type->id == ZigTypeIdVector) { return value_is_all_undef_array(g, const_val, const_val->type->data.vector.len); } else { @@ -6792,6 +6790,22 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Zig used_bits += packed_bits_size; } } + + if (type_entry->data.array.sentinel != nullptr) { + ZigValue *elem_val = type_entry->data.array.sentinel; + LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, elem_val); + + if (is_big_endian) { + LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false); + val = LLVMConstShl(val, shift_amt); + val = LLVMConstOr(val, child_val); + } else { + LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); + LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); + val = LLVMConstOr(val, child_val_shifted); + used_bits += packed_bits_size; + } + } return val; } case ZigTypeIdVector: @@ -6858,20 +6872,11 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; assert(array_const_val->type->id == ZigTypeIdArray); if (!type_has_bits(g, array_const_val->type)) { - if (array_const_val->type->data.array.sentinel != nullptr) { - ZigValue *pointee = array_const_val->type->data.array.sentinel; - render_const_val(g, pointee, ""); - render_const_val_global(g, pointee, ""); - const_val->llvm_value = LLVMConstBitCast(pointee->llvm_global, - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } else { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } + // make this a null pointer + ZigType *usize = g->builtin_types.entry_usize; + const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), + get_llvm_type(g, const_val->type)); + return const_val->llvm_value; } size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index); diff --git a/src/ir.cpp b/src/ir.cpp index b9875a7efe..ef75744576 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20578,11 +20578,6 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP } if (array_type->id == ZigTypeIdArray) { - if (array_type->data.array.len == 0) { - ir_add_error_node(ira, elem_ptr_instruction->base.base.source_node, - buf_sprintf("index 0 outside array of size 0")); - return ira->codegen->invalid_inst_gen; - } ZigType *child_type = array_type->data.array.child_type; if (ptr_type->data.pointer.host_int_bytes == 0) { return_type = get_pointer_to_type_extra(ira->codegen, child_type, @@ -27657,6 +27652,9 @@ static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ZigValue buf_write_value_bytes(codegen, &buf[buf_i], elem); buf_i += type_size(codegen, elem->type); } + if (val->type->id == ZigTypeIdArray && val->type->data.array.sentinel != nullptr) { + buf_write_value_bytes(codegen, &buf[buf_i], val->type->data.array.sentinel); + } } static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val) { diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig index 1f2d4a2f6b..792c0e70d1 100644 --- a/test/stage1/behavior/array.zig +++ b/test/stage1/behavior/array.zig @@ -28,6 +28,24 @@ fn getArrayLen(a: []const u32) usize { return a.len; } +test "array with sentinels" { + const S = struct { + fn doTheTest(is_ct: bool) void { + var zero_sized: [0:0xde]u8 = [_:0xde]u8{}; + expectEqual(@as(u8, 0xde), zero_sized[0]); + // Disabled at runtime because of + // https://github.com/ziglang/zig/issues/4372 + if (is_ct) { + var reinterpreted = @ptrCast(*[1]u8, &zero_sized); + expectEqual(@as(u8, 0xde), reinterpreted[0]); + } + } + }; + + S.doTheTest(false); + comptime S.doTheTest(true); +} + test "void arrays" { var array: [4]void = undefined; array[0] = void{};