Commit 9a324ecb42

Andrew Kelley <andrew@ziglang.org>
2019-06-11 01:11:34
result loc semantics for loading packed struct pointer to packed struct
```zig export fn entry() void { var x = foo(); var ptr = &x.b; var y = ptr.*; } const Foo = packed struct { a: u24 = 1, b: Bar = Bar{}, }; const Bar = packed struct { a: u4 = 2, b: u4 = 3, }; ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %x = alloca %Foo, align 1 %ptr = alloca i32*, align 8 %y = alloca %Bar, align 1 call fastcc void @foo(%Foo* sret %x), !dbg !55 call void @llvm.dbg.declare(metadata %Foo* %x, metadata !39, metadata !DIExpression()), !dbg !56 %0 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0, !dbg !57 store i32* %0, i32** %ptr, align 8, !dbg !57 call void @llvm.dbg.declare(metadata i32** %ptr, metadata !51, metadata !DIExpression()), !dbg !58 %1 = load i32*, i32** %ptr, align 8, !dbg !59 %2 = load i32, i32* %1, align 1, !dbg !60 %3 = lshr i32 %2, 24, !dbg !60 %4 = trunc i32 %3 to i8, !dbg !60 %5 = bitcast %Bar* %y to i8*, !dbg !60 store i8 %4, i8* %5, !dbg !60 call void @llvm.dbg.declare(metadata %Bar* %y, metadata !54, metadata !DIExpression()), !dbg !61 ret void, !dbg !62 } ```
1 parent 65f6ea6
src/all_types.hpp
@@ -2449,8 +2449,9 @@ struct IrInstructionUnOp {
     IrInstruction base;
 
     IrUnOp op_id;
-    IrInstruction *value;
     LVal lval;
+    IrInstruction *value;
+    ResultLoc *result_loc;
 };
 
 enum IrBinOp {
@@ -2507,7 +2508,7 @@ struct IrInstructionLoadPtrGen {
     IrInstruction base;
 
     IrInstruction *ptr;
-    LLVMValueRef tmp_ptr;
+    IrInstruction *result_loc;
 };
 
 struct IrInstructionStorePtr {
src/codegen.cpp
@@ -3376,13 +3376,13 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
     LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
 
     if (handle_is_ptr(child_type)) {
-        assert(instruction->tmp_ptr != nullptr);
+        LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);
         LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);
         LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, "");
-        LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr,
+        LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, result_loc,
                                                       LLVMPointerType(same_size_int, 0), "");
         LLVMBuildStore(g->builder, truncated_int, bitcasted_ptr);
-        return instruction->tmp_ptr;
+        return result_loc;
     }
 
     if (child_type->id == ZigTypeIdFloat) {
@@ -6838,9 +6838,6 @@ static void do_code_gen(CodeGen *g) {
                 slot = &ref_instruction->tmp_ptr;
                 assert(instruction->value.type->id == ZigTypeIdPointer);
                 slot_type = instruction->value.type->data.pointer.child_type;
-            } else if (instruction->id == IrInstructionIdLoadPtrGen) {
-                IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction;
-                slot = &load_ptr_inst->tmp_ptr;
             } else if (instruction->id == IrInstructionIdVectorToArray) {
                 IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction;
                 alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type);
src/ir.cpp
@@ -161,7 +161,8 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
 static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,
         ResultLoc *result_loc);
 static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type);
-static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr);
+static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr,
+        ResultLoc *result_loc);
 static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg);
 static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,
     IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing);
@@ -1467,12 +1468,13 @@ static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *s
 }
 
 static IrInstruction *ir_build_un_op_lval(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id,
-        IrInstruction *value, LVal lval)
+        IrInstruction *value, LVal lval, ResultLoc *result_loc)
 {
     IrInstructionUnOp *instruction = ir_build_instruction<IrInstructionUnOp>(irb, scope, source_node);
     instruction->op_id = op_id;
     instruction->value = value;
     instruction->lval = lval;
+    instruction->result_loc = result_loc;
 
     ir_ref_instruction(value, irb->current_basic_block);
 
@@ -1482,7 +1484,7 @@ static IrInstruction *ir_build_un_op_lval(IrBuilder *irb, Scope *scope, AstNode
 static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id,
         IrInstruction *value)
 {
-    return ir_build_un_op_lval(irb, scope, source_node, op_id, value, LValNone);
+    return ir_build_un_op_lval(irb, scope, source_node, op_id, value, LValNone, nullptr);
 }
 
 static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, AstNode *source_node,
@@ -2471,14 +2473,16 @@ static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *sourc
 }
 
 static IrInstruction *ir_build_load_ptr_gen(IrAnalyze *ira, IrInstruction *source_instruction,
-        IrInstruction *ptr, ZigType *ty)
+        IrInstruction *ptr, ZigType *ty, IrInstruction *result_loc)
 {
     IrInstructionLoadPtrGen *instruction = ir_build_instruction<IrInstructionLoadPtrGen>(
             &ira->new_irb, source_instruction->scope, source_instruction->source_node);
     instruction->base.value.type = ty;
     instruction->ptr = ptr;
+    instruction->result_loc = result_loc;
 
     ir_ref_instruction(ptr, ira->new_irb.current_basic_block);
+    if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
 
     return &instruction->base;
 }
@@ -8028,7 +8032,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
             // We essentially just converted any lvalue from &(x.*) to (&x).*;
             // this inhibits checking that x is a pointer later, so we directly
             // record whether the pointer check is needed
-            return ir_build_un_op_lval(irb, scope, node, IrUnOpDereference, value, lval);
+            IrInstruction *un_op = ir_build_un_op_lval(irb, scope, node, IrUnOpDereference, value, lval, result_loc);
+            return ir_expr_wrap(irb, scope, un_op, result_loc);
         }
         case NodeTypeUnwrapOptional: {
             AstNode *expr_node = node->data.unwrap_optional.expr;
@@ -11312,7 +11317,7 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
     IrInstruction *array_ptr = nullptr;
     IrInstruction *array;
     if (array_arg->value.type->id == ZigTypeIdPointer) {
-        array = ir_get_deref(ira, source_instr, array_arg);
+        array = ir_get_deref(ira, source_instr, array_arg, nullptr);
         array_ptr = array_arg;
     } else {
         array = array_arg;
@@ -12512,60 +12517,71 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Zig
     return ir_implicit_cast_with_result(ira, value, expected_type, nullptr);
 }
 
-static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
+static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr,
+        ResultLoc *result_loc)
+{
     Error err;
     ZigType *type_entry = ptr->value.type;
-    if (type_is_invalid(type_entry)) {
+    if (type_is_invalid(type_entry))
         return ira->codegen->invalid_instruction;
-    } else if (type_entry->id == ZigTypeIdPointer) {
-        ZigType *child_type = type_entry->data.pointer.child_type;
-        // if the child type has one possible value, the deref is comptime
-        switch (type_has_one_possible_value(ira->codegen, child_type)) {
-            case OnePossibleValueInvalid:
-                return ira->codegen->invalid_instruction;
-            case OnePossibleValueYes:
-                return ir_const(ira, source_instruction, child_type);
-            case OnePossibleValueNo:
-                break;
+
+    if (type_entry->id != ZigTypeIdPointer) {
+        ir_add_error_node(ira, source_instruction->source_node,
+            buf_sprintf("attempt to dereference non-pointer type '%s'",
+                buf_ptr(&type_entry->name)));
+        return ira->codegen->invalid_instruction;
+    }
+
+    ZigType *child_type = type_entry->data.pointer.child_type;
+    // if the child type has one possible value, the deref is comptime
+    switch (type_has_one_possible_value(ira->codegen, child_type)) {
+        case OnePossibleValueInvalid:
+            return ira->codegen->invalid_instruction;
+        case OnePossibleValueYes:
+            return ir_const(ira, source_instruction, child_type);
+        case OnePossibleValueNo:
+            break;
+    }
+    if (instr_is_comptime(ptr)) {
+        if (ptr->value.special == ConstValSpecialUndef) {
+            ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value"));
+            return ira->codegen->invalid_instruction;
         }
-        if (instr_is_comptime(ptr)) {
-            if (ptr->value.special == ConstValSpecialUndef) {
-                ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value"));
-                return ira->codegen->invalid_instruction;
-            }
-            if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst ||
-                ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
-            {
-                ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
-                if (pointee->special != ConstValSpecialRuntime) {
-                    IrInstruction *result = ir_const(ira, source_instruction, child_type);
+        if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst ||
+            ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
+        {
+            ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
+            if (pointee->special != ConstValSpecialRuntime) {
+                IrInstruction *result = ir_const(ira, source_instruction, child_type);
 
-                    if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value,
-                                    &ptr->value)))
-                    {
-                        return ira->codegen->invalid_instruction;
-                    }
-                    result->value.type = child_type;
-                    return result;
+                if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value,
+                                &ptr->value)))
+                {
+                    return ira->codegen->invalid_instruction;
                 }
+                result->value.type = child_type;
+                return result;
             }
         }
-        // if the instruction is a const ref instruction we can skip it
-        if (ptr->id == IrInstructionIdRef) {
-            IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr);
-            return ref_inst->value;
-        }
-        IrInstruction *result = ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type);
-        if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) {
-            ir_add_alloca(ira, result, child_type);
+    }
+    // if the instruction is a const ref instruction we can skip it
+    if (ptr->id == IrInstructionIdRef) {
+        IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr);
+        return ref_inst->value;
+    }
+
+    IrInstruction *result_loc_inst;
+    if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) {
+        if (result_loc == nullptr) result_loc = no_result_loc();
+        result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr);
+        if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
+            return result_loc_inst;
         }
-        return result;
     } else {
-        ir_add_error_node(ira, source_instruction->source_node,
-            buf_sprintf("attempt to dereference non-pointer type '%s'",
-                buf_ptr(&type_entry->name)));
-        return ira->codegen->invalid_instruction;
+        result_loc_inst = nullptr;
     }
+
+    return ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type, result_loc_inst);
 }
 
 static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) {
@@ -14585,7 +14601,7 @@ IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_i
                 ZigVar *coro_allocator_var = ira->old_irb.exec->coro_allocator_var;
                 assert(coro_allocator_var != nullptr);
                 IrInstruction *var_ptr_inst = ir_get_var_ptr(ira, source_instr, coro_allocator_var);
-                IrInstruction *result = ir_get_deref(ira, source_instr, var_ptr_inst);
+                IrInstruction *result = ir_get_deref(ira, source_instr, var_ptr_inst, nullptr);
                 assert(result->value.type != nullptr);
                 return result;
             }
@@ -15313,7 +15329,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
             if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
                 first_arg = first_arg_ptr;
             } else {
-                first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
+                first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr, nullptr);
                 if (type_is_invalid(first_arg->value.type))
                     return ira->codegen->invalid_instruction;
             }
@@ -15472,7 +15488,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
             if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
                 first_arg = first_arg_ptr;
             } else {
-                first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
+                first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr, nullptr);
                 if (type_is_invalid(first_arg->value.type))
                     return ira->codegen->invalid_instruction;
             }
@@ -15516,7 +15532,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
                     if (type_is_invalid(arg_var_ptr_inst->value.type))
                         return ira->codegen->invalid_instruction;
 
-                    IrInstruction *arg_tuple_arg = ir_get_deref(ira, arg, arg_var_ptr_inst);
+                    IrInstruction *arg_tuple_arg = ir_get_deref(ira, arg, arg_var_ptr_inst, nullptr);
                     if (type_is_invalid(arg_tuple_arg->value.type))
                         return ira->codegen->invalid_instruction;
 
@@ -15702,7 +15718,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
         {
             first_arg = first_arg_ptr;
         } else {
-            first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
+            first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr, nullptr);
             if (type_is_invalid(first_arg->value.type))
                 return ira->codegen->invalid_instruction;
         }
@@ -16113,7 +16129,7 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction
                 return ira->codegen->invalid_instruction;
             }
 
-            IrInstruction *result = ir_get_deref(ira, &instruction->base, ptr);
+            IrInstruction *result = ir_get_deref(ira, &instruction->base, ptr, instruction->result_loc);
             if (result == ira->codegen->invalid_instruction)
                 return ira->codegen->invalid_instruction;
 
@@ -16994,7 +17010,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
         assert(container_ptr->value.type->id == ZigTypeIdPointer);
         if (container_type->id == ZigTypeIdPointer) {
             ZigType *bare_type = container_ref_type(container_type);
-            IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr);
+            IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr, nullptr);
             IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_child, bare_type, field_ptr_instruction->initializing);
             return result;
         } else {
@@ -17339,7 +17355,7 @@ static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruct
     IrInstruction *ptr = instruction->ptr->child;
     if (type_is_invalid(ptr->value.type))
         return ira->codegen->invalid_instruction;
-    return ir_get_deref(ira, &instruction->base, ptr);
+    return ir_get_deref(ira, &instruction->base, ptr, nullptr);
 }
 
 static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) {
@@ -17807,7 +17823,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr
         }
         if (!safety_check_on)
             return base_ptr;
-        IrInstruction *c_ptr_val = ir_get_deref(ira, source_instr, base_ptr);
+        IrInstruction *c_ptr_val = ir_get_deref(ira, source_instr, base_ptr, nullptr);
         ir_build_assert_non_null(ira, source_instr, c_ptr_val);
         return base_ptr;
     }
@@ -18162,7 +18178,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
                 return result;
             }
 
-            IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
+            IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr, nullptr);
             result->value.type = target_type;
             return result;
         }
@@ -18192,7 +18208,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
                 return result;
             }
 
-            IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
+            IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr, nullptr);
             union_value->value.type = target_type;
 
             IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope,
@@ -18216,7 +18232,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
                 return result;
             }
 
-            IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
+            IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr, nullptr);
             enum_value->value.type = target_type;
             return enum_value;
         }
@@ -23105,7 +23121,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
             if (lval == LValPtr) {
                 return var_ptr;
             } else {
-                return ir_get_deref(ira, &instruction->base, var_ptr);
+                return ir_get_deref(ira, &instruction->base, var_ptr, nullptr);
             }
         }
         case TldIdFn: {
@@ -23640,7 +23656,7 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr
     }
 
     if (instr_is_comptime(casted_ptr)) {
-        IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr);
+        IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr, nullptr);
         ir_assert(result->value.type != nullptr, &instruction->base);
         return result;
     }
@@ -24474,7 +24490,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdUnOp:
         case IrInstructionIdBinOp:
         case IrInstructionIdLoadPtr:
-        case IrInstructionIdLoadPtrGen:
         case IrInstructionIdConst:
         case IrInstructionIdCast:
         case IrInstructionIdContainerInitList:
@@ -24585,6 +24600,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
             return reinterpret_cast<IrInstructionErrWrapPayload *>(instruction)->result_loc != nullptr;
         case IrInstructionIdErrWrapCode:
             return reinterpret_cast<IrInstructionErrWrapCode *>(instruction)->result_loc != nullptr;
+        case IrInstructionIdLoadPtrGen:
+            return reinterpret_cast<IrInstructionLoadPtrGen *>(instruction)->result_loc != nullptr;
     }
     zig_unreachable();
 }
src/ir_print.cpp
@@ -397,8 +397,10 @@ static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
 }
 
 static void ir_print_load_ptr_gen(IrPrint *irp, IrInstructionLoadPtrGen *instruction) {
+    fprintf(irp->f, "loadptr(");
     ir_print_other_instruction(irp, instruction->ptr);
-    fprintf(irp->f, ".*");
+    fprintf(irp->f, ")result=");
+    ir_print_other_instruction(irp, instruction->result_loc);
 }
 
 static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {