Commit 4cbeb87e83

Andrew Kelley <superjoe30@gmail.com>
2017-01-16 18:42:46
fix handling of const values for 2d arrays
1 parent c759173
Changed files (4)
src/all_types.hpp
@@ -81,6 +81,11 @@ struct ConstArrayValue {
     // This will be the same as `len` from the type, but we duplicate the information
     // in the constant value so that pointers pointing to arrays can see this size.
     size_t size;
+    // If the data for this array is supposed to be contained in a different constant
+    // value, we link to the parent here. This way getting a pointer to this constant
+    // value can return a pointer into the parent data structure.
+    ConstExprValue *parent_array;
+    size_t parent_array_index;
 };
 
 enum ConstPtrSpecial {
src/codegen.cpp
@@ -2412,6 +2412,25 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
     }
 }
 
+static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index) {
+    ConstExprValue *parent_array = array_const_val->data.x_array.parent_array;
+    LLVMValueRef base_ptr;
+    if (parent_array) {
+        size_t parent_array_index = array_const_val->data.x_array.parent_array_index;
+        base_ptr = gen_const_ptr_array_recursive(g, parent_array, parent_array_index);
+    } else {
+        render_const_val(g, array_const_val);
+        render_const_val_global(g, array_const_val);
+        base_ptr = array_const_val->llvm_global;
+    }
+    TypeTableEntry *usize = g->builtin_types.entry_usize;
+    LLVMValueRef indices[] = {
+        LLVMConstNull(usize->type_ref),
+        LLVMConstInt(usize->type_ref, index, false),
+    };
+    return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
 static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
     TypeTableEntry *canon_type = get_underlying_type(const_val->type);
     assert(!canon_type->zero_bits);
@@ -2554,7 +2573,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                 render_const_val_global(g, const_val);
                 size_t index = const_val->data.x_ptr.index;
                 ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr;
-                TypeTableEntry *usize = g->builtin_types.entry_usize;
                 if (base_ptr) {
                     if (index == SIZE_MAX) {
                         render_const_val(g, base_ptr);
@@ -2568,25 +2586,20 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                         assert(array_const_val->type->id == TypeTableEntryIdArray);
                         if (array_const_val->type->zero_bits) {
                             // make this a null pointer
-                            TypeTableEntry *usize_type = g->builtin_types.entry_usize;
-                            const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize_type->type_ref),
+                            TypeTableEntry *usize = g->builtin_types.entry_usize;
+                            const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
                                     const_val->type->type_ref);
                             render_const_val_global(g, const_val);
                             return const_val->llvm_value;
                         }
-                        render_const_val(g, array_const_val);
-                        render_const_val_global(g, array_const_val);
-                        LLVMValueRef indices[] = {
-                            LLVMConstNull(usize->type_ref),
-                            LLVMConstInt(usize->type_ref, index, false),
-                        };
-                        LLVMValueRef uncasted_ptr_val = LLVMConstInBoundsGEP(array_const_val->llvm_global, indices, 2);
+                        LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, index);
                         LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
                         const_val->llvm_value = ptr_val;
                         render_const_val_global(g, const_val);
                         return ptr_val;
                     }
                 } else {
+                    TypeTableEntry *usize = g->builtin_types.entry_usize;
                     const_val->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, index, false), const_val->type->type_ref);
                     render_const_val_global(g, const_val);
                     return const_val->llvm_value;
src/ir.cpp
@@ -8314,7 +8314,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
         return ira->codegen->builtin_types.entry_invalid;
 
     bool safety_check_on = elem_ptr_instruction->safety_check_on;
-    if (casted_elem_index->value.special != ConstValSpecialRuntime) {
+    if (instr_is_comptime(casted_elem_index)) {
         uint64_t index = casted_elem_index->value.data.x_bignum.data.x_uint;
         if (array_type->id == TypeTableEntryIdArray) {
             uint64_t array_len = array_type->data.array.len;
@@ -9923,6 +9923,13 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
             if (const_val.special == ConstValSpecialStatic) {
                 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, const_val.depends_on_compile_var);
                 *out_val = const_val;
+                for (size_t i = 0; i < elem_count; i += 1) {
+                    ConstExprValue *elem_val = &out_val->data.x_array.elements[i];
+                    if (elem_val->type->id == TypeTableEntryIdArray) {
+                        elem_val->data.x_array.parent_array = out_val;
+                        elem_val->data.x_array.parent_array_index = i;
+                    }
+                }
                 return fixed_size_array_type;
             }
 
test/cases/misc.zig
@@ -500,3 +500,20 @@ fn nonConstPtrToAliasedType() {
     const int = i32;
     assert(?&int == ?&i32);
 }
+
+
+
+fn array2DConstDoublePtr() {
+    @setFnTest(this);
+
+    const rect_2d_vertexes = [][1]f32 {
+        []f32{1.0},
+        []f32{2.0},
+    };
+    testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
+}
+
+fn testArray2DConstDoublePtr(ptr: &const f32) {
+    assert(ptr[0] == 1.0);
+    assert(ptr[1] == 2.0);
+}