Commit af4d4c882a

Andrew Kelley <superjoe30@gmail.com>
2016-11-15 03:01:48
IR: implement compile time array access
1 parent 2edc6c1
Changed files (1)
src
src/ir.cpp
@@ -2180,7 +2180,9 @@ static ConstExprValue *ir_build_const_from(IrAnalyze *ira, IrInstruction *old_in
     } else if (old_instruction->id == IrInstructionIdFieldPtr) {
         zig_panic("TODO");
     } else if (old_instruction->id == IrInstructionIdElemPtr) {
-        zig_panic("TODO");
+        IrInstructionElemPtr *elem_ptr_instruction = ir_create_instruction<IrInstructionElemPtr>(ira->new_irb.exec,
+                old_instruction->source_node);
+        new_instruction = &elem_ptr_instruction->base;
     } else {
         IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec,
                 old_instruction->source_node);
@@ -2577,7 +2579,7 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
     IrInstructionReturn *return_instruction)
 {
     IrInstruction *value = return_instruction->value->other;
-    if (value == ira->codegen->invalid_instruction)
+    if (value->type_entry->id == TypeTableEntryIdInvalid)
         return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
     ira->implicit_return_type_list.append(value);
 
@@ -3512,7 +3514,12 @@ static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstruct
 
 static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) {
     IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->other;
+    if (array_ptr->type_entry->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
+
     IrInstruction *elem_index = elem_ptr_instruction->elem_index->other;
+    if (elem_index->type_entry->id == TypeTableEntryIdInvalid)
+        return ira->codegen->builtin_types.entry_invalid;
 
     TypeTableEntry *array_type = array_ptr->type_entry;
     TypeTableEntry *return_type;
@@ -3522,7 +3529,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
     } else if (array_type->id == TypeTableEntryIdArray) {
         if (array_type->data.array.len == 0) {
             add_node_error(ira->codegen, elem_ptr_instruction->base.source_node,
-                    buf_sprintf("out of bounds array access"));
+                    buf_sprintf("index 0 outside array of size 0"));
         }
         TypeTableEntry *child_type = array_type->data.array.child_type;
         return_type = get_pointer_to_type(ira->codegen, child_type, false);
@@ -3541,12 +3548,57 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
     if (casted_elem_index == ira->codegen->invalid_instruction)
         return ira->codegen->builtin_types.entry_invalid;
 
-    if (array_ptr->static_value.ok && casted_elem_index->static_value.ok) {
-        zig_panic("TODO compile time array access");
+    if (casted_elem_index->static_value.ok) {
+        uint64_t index = casted_elem_index->static_value.data.x_bignum.data.x_uint;
+        if (array_type->id == TypeTableEntryIdArray) {
+            uint64_t array_len = array_type->data.array.len;
+            if (index >= array_len) {
+                add_node_error(ira->codegen, elem_ptr_instruction->base.source_node,
+                    buf_sprintf("index %" PRIu64 " outside array of size %" PRIu64,
+                            index, array_len));
+                return ira->codegen->builtin_types.entry_invalid;
+            }
+        }
+
+        if (array_ptr->static_value.ok) {
+            bool depends_on_compile_var = array_ptr->static_value.depends_on_compile_var ||
+                casted_elem_index->static_value.depends_on_compile_var;
+            ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base, depends_on_compile_var);
+            out_val->data.x_ptr.len = 1;
+            out_val->data.x_ptr.is_c_str = false;
+            out_val->data.x_ptr.ptr = allocate<ConstExprValue *>(1);
+            if (array_type->id == TypeTableEntryIdPointer) {
+                uint64_t pointer_len = array_ptr->static_value.data.x_ptr.len;
+                if (index >= pointer_len) {
+                    add_node_error(ira->codegen, elem_ptr_instruction->base.source_node,
+                        buf_sprintf("index %" PRIu64 " outside pointer of size %" PRIu64,
+                            index, pointer_len));
+                    return ira->codegen->builtin_types.entry_invalid;
+                }
+                out_val->data.x_ptr.ptr[0] = array_ptr->static_value.data.x_ptr.ptr[index];
+            } else if (is_slice(array_type)) {
+                ConstExprValue *ptr_field = array_ptr->static_value.data.x_struct.fields[0];
+                ConstExprValue *len_field = array_ptr->static_value.data.x_struct.fields[1];
+                uint64_t slice_len = len_field->data.x_bignum.data.x_uint;
+                if (index >= slice_len) {
+                    add_node_error(ira->codegen, elem_ptr_instruction->base.source_node,
+                        buf_sprintf("index %" PRIu64 " outside slice of size %" PRIu64,
+                            index, slice_len));
+                    return ira->codegen->builtin_types.entry_invalid;
+                }
+                assert(index < ptr_field->data.x_ptr.len);
+                out_val->data.x_ptr.ptr[0] = ptr_field->data.x_ptr.ptr[index];
+            } else if (array_type->id == TypeTableEntryIdArray) {
+                out_val->data.x_ptr.ptr[0] = array_ptr->static_value.data.x_array.fields[index];
+            } else {
+                zig_unreachable();
+            }
+            return return_type;
+        }
+
     }
 
     ir_build_elem_ptr_from(&ira->new_irb, &elem_ptr_instruction->base, array_ptr, casted_elem_index);
-
     return return_type;
 }