Commit e3c92d0532

LemonBoy <thatlemon@gmail.com>
2020-03-19 11:52:15
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.
1 parent 7a36175
Changed files (4)
src
test
stage1
behavior
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<ZigValue>(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);
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);
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) {
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{};