diff --git a/src/all_types.hpp b/src/all_types.hpp index a14401394780..56da5198372e 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -40,6 +40,7 @@ struct ZigWindowsSDK; struct Tld; struct TldExport; struct IrAnalyze; +struct IrResultLocationAlloca; enum X64CABIClass { X64CABIClass_Unknown, @@ -614,7 +615,6 @@ enum CastOp { CastOpNumLitToConcrete, CastOpErrSet, CastOpBitCast, - CastOpPtrOfArrayToSlice, }; struct AstNodeFnCallExpr { @@ -1320,7 +1320,7 @@ struct ZigFn { AstNode *fn_no_inline_set_node; AstNode *fn_static_eval_set_node; - ZigList alloca_list; + ZigList result_loc_alloca_list; ZigList variable_list; Buf *section_name; @@ -2029,6 +2029,66 @@ struct IrBasicBlock { IrInstruction *must_be_comptime_source_instr; }; +enum IrResultLocationId { + IrResultLocationIdVar, + IrResultLocationIdAlloca, + IrResultLocationIdLVal, + IrResultLocationIdRet, + + IrResultLocationIdOptionalUnwrap, + IrResultLocationIdErrorUnionPayload, + IrResultLocationIdErrorUnionCode, + IrResultLocationIdArrayToSlice, +}; + +struct IrResultLocation { + IrResultLocation *child; + IrResultLocation *parent; + IrResultLocationId id; + bool from_call; +}; + +struct IrResultLocationVar { + IrResultLocation base; + ZigVar *var; +}; + +struct IrResultLocationAlloca { + IrResultLocation base; + LLVMValueRef alloca; + ZigType *ty; +}; + +struct IrResultLocationLVal { + IrResultLocation base; + IrInstruction *parent_instruction; +}; + +struct IrResultLocationRet { + IrResultLocation base; +}; + +struct IrResultLocationOptionalUnwrap { + IrResultLocation base; + LLVMValueRef result; +}; + +struct IrResultLocationErrorUnionPayload { + IrResultLocation base; + LLVMValueRef result; +}; + +struct IrResultLocationErrorUnionCode { + IrResultLocation base; + LLVMValueRef result; +}; + +struct IrResultLocationArrayToSlice { + IrResultLocation base; + LLVMValueRef result; + uint64_t len; +}; + enum IrInstructionId { IrInstructionIdInvalid, IrInstructionIdBr, @@ -2173,10 +2233,11 @@ enum IrInstructionId { IrInstructionIdToBytes, IrInstructionIdFromBytes, IrInstructionIdCheckRuntimeScope, + IrInstructionIdResultLoc, + IrInstructionIdPtrOfArrayToSlice, }; struct IrInstruction { - IrInstructionId id; Scope *scope; AstNode *source_node; ConstExprValue value; @@ -2190,6 +2251,8 @@ struct IrInstruction { // with this child field. IrInstruction *child; IrBasicBlock *owner_bb; + + IrInstructionId id; // true if this instruction was generated by zig and not from user code bool is_gen; }; @@ -2320,6 +2383,7 @@ struct IrInstructionLoadPtr { IrInstruction base; IrInstruction *ptr; + IrResultLocation *result_location; }; struct IrInstructionStorePtr { @@ -2369,6 +2433,7 @@ struct IrInstructionVarPtr { ZigVar *var; ScopeFnDef *crossed_fndef_scope; + IrResultLocation *result_location; }; struct IrInstructionCall { @@ -2379,9 +2444,9 @@ struct IrInstructionCall { size_t arg_count; IrInstruction **args; bool is_comptime; - LLVMValueRef tmp_ptr; FnInline fn_inline; bool is_async; + IrResultLocation *result_location; IrInstruction *async_allocator; IrInstruction *new_stack; @@ -2407,7 +2472,7 @@ struct IrInstructionCast { IrInstruction *value; ZigType *dest_type; CastOp cast_op; - LLVMValueRef tmp_ptr; + IrResultLocation *result_location; }; struct IrInstructionContainerInitList { @@ -2416,7 +2481,7 @@ struct IrInstructionContainerInitList { IrInstruction *container_type; size_t item_count; IrInstruction **items; - LLVMValueRef tmp_ptr; + IrResultLocation *result_location; }; struct IrInstructionContainerInitFieldsField { @@ -2445,7 +2510,7 @@ struct IrInstructionStructInit { ZigType *struct_type; size_t field_count; IrInstructionStructInitField *fields; - LLVMValueRef tmp_ptr; + IrResultLocation *result_location; }; struct IrInstructionUnionInit { @@ -2454,7 +2519,7 @@ struct IrInstructionUnionInit { ZigType *union_type; TypeUnionField *field; IrInstruction *init_value; - LLVMValueRef tmp_ptr; + IrResultLocation *result_location; }; struct IrInstructionUnreachable { @@ -2604,9 +2669,9 @@ struct IrInstructionRef { IrInstruction base; IrInstruction *value; - LLVMValueRef tmp_ptr; bool is_const; bool is_volatile; + IrResultLocation *result_location; }; struct IrInstructionMinValue { @@ -2678,6 +2743,7 @@ struct IrInstructionCmpxchg { IrInstruction *new_value; IrInstruction *success_order_value; IrInstruction *failure_order_value; + IrResultLocation *result_location; // if this instruction gets to runtime then we know these values: ZigType *type; @@ -2685,8 +2751,6 @@ struct IrInstructionCmpxchg { AtomicOrder failure_order; bool is_weak; - - LLVMValueRef tmp_ptr; }; struct IrInstructionFence { @@ -2794,8 +2858,8 @@ struct IrInstructionSlice { IrInstruction *ptr; IrInstruction *start; IrInstruction *end; + IrResultLocation *result_location; bool safety_check_on; - LLVMValueRef tmp_ptr; }; struct IrInstructionMemberCount { @@ -2883,21 +2947,21 @@ struct IrInstructionOptionalWrap { IrInstruction base; IrInstruction *value; - LLVMValueRef tmp_ptr; + IrResultLocation *result_location; }; struct IrInstructionErrWrapPayload { IrInstruction base; IrInstruction *value; - LLVMValueRef tmp_ptr; + IrResultLocation *result_location; }; struct IrInstructionErrWrapCode { IrInstruction base; IrInstruction *value; - LLVMValueRef tmp_ptr; + IrResultLocation *result_location; }; struct IrInstructionFnProto { @@ -3280,6 +3344,20 @@ struct IrInstructionCheckRuntimeScope { IrInstruction *is_comptime; }; +struct IrInstructionResultLoc { + IrInstruction base; + + IrInstruction *value; + IrResultLocation *result_location; +}; + +struct IrInstructionPtrOfArrayToSlice { + IrInstruction base; + + IrInstruction *value; + IrResultLocation *result_location; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/codegen.cpp b/src/codegen.cpp index a3061b24d216..677291f31f71 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1794,6 +1794,8 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty return nullptr; if (handle_is_ptr(child_type)) { + if (ptr == value) + return nullptr; assert(LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMPointerTypeKind); assert(LLVMGetTypeKind(LLVMTypeOf(ptr)) == LLVMPointerTypeKind); @@ -1876,6 +1878,19 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { return instruction->llvm_value; } +static LLVMValueRef gen_assign(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type, + IrInstruction *value) +{ + IrResultLocation *result_location = ir_get_result_location(value); + bool elide_copy = value->id == IrInstructionIdResultLoc || + (result_location != nullptr && result_location->from_call); + + if (elide_copy) + return nullptr; + + return gen_assign_raw(g, ptr, ptr_type, ir_llvm_value(g, value)); +} + ATTRIBUTE_NORETURN static void report_errors_and_exit(CodeGen *g) { assert(g->errors.length != 0); @@ -2243,7 +2258,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) { assert(g->cur_ret_ptr); - gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); + gen_assign(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), return_instruction->value); LLVMBuildRetVoid(g->builder); } else if (handle_is_ptr(return_type)) { LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, ""); @@ -2802,6 +2817,110 @@ static void add_error_range_check(CodeGen *g, ZigType *err_set_type, ZigType *in } } +static LLVMValueRef gen_result_location_recur(CodeGen *g, IrResultLocation *base, LLVMValueRef prev) { + switch (base->id) { + case IrResultLocationIdAlloca: { + IrResultLocationAlloca *loc = reinterpret_cast(base); + assert(prev == nullptr); + LLVMValueRef result = loc->alloca; + if (base->child != nullptr) { + return gen_result_location_recur(g, base->child, result); + } + return result; + } + case IrResultLocationIdVar: { + IrResultLocationVar *loc = reinterpret_cast(base); + assert(prev == nullptr); + LLVMValueRef result = loc->var->value_ref; + if (base->child != nullptr) { + return gen_result_location_recur(g, base->child, result); + } + return result; + } + case IrResultLocationIdLVal: { + IrResultLocationLVal *lval_loc = reinterpret_cast(base); + assert(prev == nullptr); + IrInstruction *ptr = lval_loc->parent_instruction->child; + LLVMValueRef result = ir_llvm_value(g, ptr); + if (base->child != nullptr) { + return gen_result_location_recur(g, base->child, result); + } + return result; + } + case IrResultLocationIdRet: { + //IrResultLocationRet *ret_loc = reinterpret_cast(base); + assert(prev == nullptr); + LLVMValueRef result = g->cur_ret_ptr; + if (base->child != nullptr) { + return gen_result_location_recur(g, base->child, result); + } + return result; + } + + case IrResultLocationIdOptionalUnwrap: { + IrResultLocationOptionalUnwrap *loc = reinterpret_cast(base); + if (loc->result != nullptr) + return loc->result; + assert(prev != nullptr); + if (base->child != nullptr) { + prev = gen_result_location_recur(g, base->child, prev); + } + LLVMValueRef nonnull_ptr = LLVMBuildStructGEP(g->builder, prev, maybe_null_index, ""); + gen_store_untyped(g, LLVMConstInt(LLVMInt1Type(), 1, false), nonnull_ptr, 0, false); + loc->result = LLVMBuildStructGEP(g->builder, prev, maybe_child_index, ""); + return loc->result; + } + case IrResultLocationIdErrorUnionPayload: { + IrResultLocationErrorUnionPayload *loc = reinterpret_cast(base); + if (loc->result != nullptr) + return loc->result; + assert(prev != nullptr); + if (base->child != nullptr) { + prev = gen_result_location_recur(g, base->child, prev); + } + LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, prev, err_union_err_index, ""); + LLVMTypeRef err_type_ref = g->builtin_types.entry_global_error_set->type_ref; + gen_store_untyped(g, LLVMConstInt(err_type_ref, 0, false), err_val_ptr, 0, false); + loc->result = LLVMBuildStructGEP(g->builder, prev, err_union_payload_index, ""); + return loc->result; + } + case IrResultLocationIdErrorUnionCode: { + IrResultLocationErrorUnionCode *loc = reinterpret_cast(base); + if (loc->result != nullptr) + return loc->result; + assert(prev != nullptr); + if (base->child != nullptr) { + prev = gen_result_location_recur(g, base->child, prev); + } + // TODO write 0xaa in debug mode to the undefined payload + loc->result = LLVMBuildStructGEP(g->builder, prev, err_union_err_index, ""); + return loc->result; + } + case IrResultLocationIdArrayToSlice: { + IrResultLocationArrayToSlice *loc = reinterpret_cast(base); + if (loc->result != nullptr) + return loc->result; + assert(prev != nullptr); + if (base->child != nullptr) { + prev = gen_result_location_recur(g, base->child, prev); + } + + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, prev, slice_len_index, ""); + LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref, loc->len, false); + gen_store_untyped(g, len_value, len_field_ptr, 0, false); + + loc->result = LLVMBuildStructGEP(g->builder, prev, slice_ptr_index, ""); + return loc->result; + } + } + zig_unreachable(); +} + +static LLVMValueRef gen_result_location(CodeGen *g, IrResultLocation *base) { + assert(base != nullptr); + return gen_result_location_recur(g, base, nullptr); +} + static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, IrInstructionCast *cast_instruction) { @@ -2818,12 +2937,13 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, return expr_val; case CastOpResizeSlice: { - assert(cast_instruction->tmp_ptr); assert(wanted_type->id == ZigTypeIdStruct); assert(wanted_type->data.structure.is_slice); assert(actual_type->id == ZigTypeIdStruct); assert(actual_type->data.structure.is_slice); + LLVMValueRef result_loc = gen_result_location(g, cast_instruction->result_location); + ZigType *actual_pointer_type = actual_type->data.structure.fields[0].type_entry; ZigType *actual_child_type = actual_pointer_type->data.pointer.child_type; ZigType *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry; @@ -2839,7 +2959,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, ""); LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, wanted_type->data.structure.fields[0].type_entry->type_ref, ""); - LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, + LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, result_loc, (unsigned)wanted_ptr_index, ""); gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false); @@ -2872,38 +2992,39 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, zig_unreachable(); } - LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, + LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, result_loc, (unsigned)wanted_len_index, ""); gen_store_untyped(g, new_len, dest_len_ptr, 0, false); - return cast_instruction->tmp_ptr; + return result_loc; } case CastOpBytesToSlice: { - assert(cast_instruction->tmp_ptr); assert(wanted_type->id == ZigTypeIdStruct); assert(wanted_type->data.structure.is_slice); assert(actual_type->id == ZigTypeIdArray); + LLVMValueRef result_loc = gen_result_location(g, cast_instruction->result_location); + ZigType *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; ZigType *wanted_child_type = wanted_pointer_type->data.pointer.child_type; size_t wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index; - LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, + LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, result_loc, (unsigned)wanted_ptr_index, ""); LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, expr_val, wanted_pointer_type->type_ref, ""); gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false); size_t wanted_len_index = wanted_type->data.structure.fields[1].gen_index; - LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, + LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, result_loc, (unsigned)wanted_len_index, ""); LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, actual_type->data.array.len / type_size(g, wanted_child_type), false); gen_store_untyped(g, len_val, len_ptr, 0, false); - return cast_instruction->tmp_ptr; + return result_loc; } case CastOpIntToFloat: assert(actual_type->id == ZigTypeIdInt); @@ -2958,33 +3079,41 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, return expr_val; case CastOpBitCast: return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, ""); - case CastOpPtrOfArrayToSlice: { - assert(cast_instruction->tmp_ptr); - assert(actual_type->id == ZigTypeIdPointer); - ZigType *array_type = actual_type->data.pointer.child_type; - assert(array_type->id == ZigTypeIdArray); - - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, - slice_ptr_index, ""); - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->type_ref), - LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false), - }; - LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, ""); - gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); - - LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, - slice_len_index, ""); - LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref, - array_type->data.array.len, false); - gen_store_untyped(g, len_value, len_field_ptr, 0, false); - - return cast_instruction->tmp_ptr; - } } zig_unreachable(); } +static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, IrExecutable *executable, + IrInstructionPtrOfArrayToSlice *instruction) +{ + ZigType *actual_type = instruction->value->value.type; + LLVMValueRef expr_val = ir_llvm_value(g, instruction->value); + assert(expr_val); + + LLVMValueRef result_loc = gen_result_location(g, instruction->result_location); + + assert(actual_type->id == ZigTypeIdPointer); + ZigType *array_type = actual_type->data.pointer.child_type; + assert(array_type->id == ZigTypeIdArray); + + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, + slice_ptr_index, ""); + LLVMValueRef indices[] = { + LLVMConstNull(g->builtin_types.entry_usize->type_ref), + LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false), + }; + LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, ""); + gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); + + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, + slice_len_index, ""); + LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref, + array_type->data.array.len, false); + gen_store_untyped(g, len_value, len_field_ptr, 0, false); + + return result_loc; +} + static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, IrInstructionPtrCast *instruction) { @@ -3173,6 +3302,40 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, ""); } +static bool value_is_all_undef(ConstExprValue *const_val) { + switch (const_val->special) { + case ConstValSpecialRuntime: + return false; + case ConstValSpecialUndef: + return true; + case ConstValSpecialStatic: + if (const_val->type->id == ZigTypeIdStruct) { + for (size_t i = 0; i < const_val->type->data.structure.src_field_count; i += 1) { + if (!value_is_all_undef(&const_val->data.x_struct.fields[i])) + return false; + } + return true; + } else { + return false; + } + } + zig_unreachable(); +} + +static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) { + ZigType *usize = g->builtin_types.entry_usize; + uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, value_type->type_ref); + assert(size_bytes > 0); + assert(ptr_align_bytes > 0); + + // memset uninitialized memory to 0xaa + LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); + LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); + LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, ""); + LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false); + ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false); +} + static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstructionDeclVar *decl_var_instruction) { @@ -3186,34 +3349,16 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstruction *init_value = decl_var_instruction->init_value; - bool have_init_expr = false; - ConstExprValue *const_val = &init_value->value; - if (const_val->special == ConstValSpecialRuntime || const_val->special == ConstValSpecialStatic) - have_init_expr = true; + bool have_init_expr = !value_is_all_undef(const_val); if (have_init_expr) { assert(var->value->type == init_value->value.type); ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false, PtrLenSingle, var->align_bytes, 0, 0); - LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value); - gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val); - } else { - bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base); - if (want_safe) { - ZigType *usize = g->builtin_types.entry_usize; - uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value->type->type_ref); - assert(size_bytes > 0); - - assert(var->align_bytes > 0); - - // memset uninitialized memory to 0xa - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); - LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, var->value_ref, ptr_u8, ""); - LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false); - ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, var->align_bytes, false); - } + gen_assign(g, var->value_ref, var_ptr_type, init_value); + } else if (ir_want_runtime_safety(g, &decl_var_instruction->base)) { + gen_undef_init(g, var->align_bytes, var->value->type, var->value_ref); } gen_var_debug_decl(g, var); @@ -3251,14 +3396,23 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI } static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) { - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - LLVMValueRef value = ir_llvm_value(g, instruction->value); + bool have_init_expr = !value_is_all_undef(&instruction->value->value); + if (have_init_expr) { + LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - assert(instruction->ptr->value.type->id == ZigTypeIdPointer); - ZigType *ptr_type = instruction->ptr->value.type; + assert(instruction->ptr->value.type->id == ZigTypeIdPointer); + ZigType *ptr_type = instruction->ptr->value.type; - gen_assign_raw(g, ptr, ptr_type, value); + gen_assign(g, ptr, ptr_type, instruction->value); + return nullptr; + } + if (ir_want_runtime_safety(g, &instruction->base)) { + gen_undef_init(g, + get_ptr_align(g, instruction->ptr->value.type), + instruction->value->value.type, + ir_llvm_value(g, instruction->ptr)); + } return nullptr; } @@ -3443,9 +3597,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr bool first_arg_ret = ret_has_bits && want_first_arg_sret(g, fn_type_id); bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id); bool is_var_args = fn_type_id->is_var_args; + + LLVMValueRef tmp_ptr = gen_result_location(g, instruction->result_location); + ZigList gen_param_values = {}; if (first_arg_ret) { - gen_param_values.append(instruction->tmp_ptr); + gen_param_values.append(tmp_ptr); } if (prefix_arg_err_ret_stack) { gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope)); @@ -3453,7 +3610,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr if (instruction->is_async) { gen_param_values.append(ir_llvm_value(g, instruction->async_allocator)); - LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); + LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, tmp_ptr, err_union_err_index, ""); gen_param_values.append(err_val_ptr); } FnWalk fn_walk = {}; @@ -3496,9 +3653,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr if (instruction->is_async) { - LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, ""); + LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, tmp_ptr, err_union_payload_index, ""); LLVMBuildStore(g->builder, result, payload_ptr); - return instruction->tmp_ptr; + return tmp_ptr; } if (src_return_type->id == ZigTypeIdUnreachable) { @@ -3507,11 +3664,11 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr return nullptr; } else if (first_arg_ret) { set_call_instr_sret(g, result); - return instruction->tmp_ptr; - } else if (handle_is_ptr(src_return_type)) { - auto store_instr = LLVMBuildStore(g->builder, result, instruction->tmp_ptr); - LLVMSetAlignment(store_instr, LLVMGetAlignment(instruction->tmp_ptr)); - return instruction->tmp_ptr; + return tmp_ptr; + } else if (tmp_ptr != nullptr) { + auto store_instr = LLVMBuildStore(g->builder, result, tmp_ptr); + LLVMSetAlignment(store_instr, LLVMGetAlignment(tmp_ptr)); + return tmp_ptr; } else { return result; } @@ -3883,9 +4040,9 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru if (handle_is_ptr(instruction->value->value.type)) { return value; } else { - assert(instruction->tmp_ptr); - gen_store_untyped(g, value, instruction->tmp_ptr, 0, false); - return instruction->tmp_ptr; + LLVMValueRef result_loc = gen_result_location(g, instruction->result_location); + gen_store_untyped(g, value, result_loc, 0, false); + return result_loc; } } @@ -4187,18 +4344,18 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, ""); } - assert(instruction->tmp_ptr != nullptr); + LLVMValueRef result_loc = gen_result_location(g, instruction->result_location); assert(type_has_bits(instruction->type)); LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); - LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); + LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, ""); gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val); LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, ""); - LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, ""); + LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_null_index, ""); gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false); - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) { @@ -4261,7 +4418,7 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns } static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSlice *instruction) { - assert(instruction->tmp_ptr); + LLVMValueRef tmp_struct_ptr = gen_result_location(g, instruction->result_location); LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr); ZigType *array_ptr_type = instruction->ptr->value.type; @@ -4269,8 +4426,6 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst ZigType *array_type = array_ptr_type->data.pointer.child_type; LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); - LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr; - bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); if (array_type->id == ZigTypeIdArray || @@ -4598,20 +4753,20 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I return LLVMConstInt(LLVMInt1Type(), 1, false); } - LLVMValueRef payload_val = ir_llvm_value(g, instruction->value); if (type_is_codegen_pointer(child_type)) { - return payload_val; + return ir_llvm_value(g, instruction->value); } - assert(instruction->tmp_ptr); - LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); + LLVMValueRef result_loc = gen_result_location(g, instruction->result_location); + + LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, ""); // child_type and instruction->value->value.type may differ by constness - gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val); - LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, ""); + gen_assign(g, val_ptr, get_pointer_to_type(g, child_type, false), instruction->value); + LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_null_index, ""); gen_store_untyped(g, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr, 0, false); - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapCode *instruction) { @@ -4627,12 +4782,12 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable if (!type_has_bits(payload_type) || !type_has_bits(err_set_type)) return err_val; - assert(instruction->tmp_ptr); + LLVMValueRef result_loc = gen_result_location(g, instruction->result_location); - LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); + LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, result_loc, err_union_err_index, ""); gen_store_untyped(g, err_val, err_tag_ptr, 0, false); - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapPayload *instruction) { @@ -4652,17 +4807,15 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa if (!type_has_bits(payload_type)) return ok_err_val; - assert(instruction->tmp_ptr); - - LLVMValueRef payload_val = ir_llvm_value(g, instruction->value); + LLVMValueRef result_loc = gen_result_location(g, instruction->result_location); - LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); + LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, result_loc, err_union_err_index, ""); gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false); - LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, ""); - gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, payload_type, false), payload_val); + LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, result_loc, err_union_payload_index, ""); + gen_assign(g, payload_ptr, get_pointer_to_type(g, payload_type, false), instruction->value); - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, IrInstructionUnionTag *instruction) { @@ -4684,15 +4837,17 @@ static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, Ir } static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, IrInstructionStructInit *instruction) { + LLVMValueRef result_loc = gen_result_location(g, instruction->result_location); + for (size_t i = 0; i < instruction->field_count; i += 1) { IrInstructionStructInitField *field = &instruction->fields[i]; TypeStructField *type_struct_field = field->type_struct_field; if (!type_has_bits(type_struct_field->type_entry)) continue; - LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, + + LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, result_loc, (unsigned)type_struct_field->gen_index, ""); - LLVMValueRef value = ir_llvm_value(g, field->value); uint32_t field_align_bytes = get_abi_alignment(g, type_struct_field->type_entry); uint32_t host_int_bytes = get_host_int_bytes(g, instruction->struct_type, type_struct_field); @@ -4701,9 +4856,9 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, false, false, PtrLenSingle, field_align_bytes, (uint32_t)type_struct_field->bit_offset_in_host, host_int_bytes); - gen_assign_raw(g, field_ptr, ptr_type, value); + gen_assign(g, field_ptr, ptr_type, field->value); } - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) { @@ -4712,6 +4867,8 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I if (!type_has_bits(type_union_field->type_entry)) return nullptr; + LLVMValueRef result_loc = gen_result_location(g, instruction->result_location); + uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry); ZigType *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry, false, false, PtrLenSingle, field_align_bytes, @@ -4722,25 +4879,24 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I // correctly. Otherwise safety code somewhere other than here could fail. ZigType *union_type = instruction->union_type; if (union_type->data.unionation.gen_tag_index != SIZE_MAX) { - LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, + LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, union_type->data.unionation.gen_tag_index, ""); LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref, &type_union_field->enum_field->value); gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); - uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, + uncasted_union_ptr = LLVMBuildStructGEP(g->builder, result_loc, (unsigned)union_type->data.unionation.gen_union_index, ""); } else { - uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, ""); + uncasted_union_ptr = LLVMBuildStructGEP(g->builder, result_loc, (unsigned)0, ""); } LLVMValueRef field_ptr = LLVMBuildBitCast(g->builder, uncasted_union_ptr, ptr_type->type_ref, ""); - LLVMValueRef value = ir_llvm_value(g, instruction->init_value); - gen_assign_raw(g, field_ptr, ptr_type, value); + gen_assign(g, field_ptr, ptr_type, instruction->init_value); - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable, @@ -4748,20 +4904,19 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec { ZigType *array_type = instruction->base.value.type; assert(array_type->id == ZigTypeIdArray); - LLVMValueRef tmp_array_ptr = instruction->tmp_ptr; + LLVMValueRef tmp_array_ptr = gen_result_location(g, instruction->result_location); assert(tmp_array_ptr); size_t field_count = instruction->item_count; ZigType *child_type = array_type->data.array.child_type; for (size_t i = 0; i < field_count; i += 1) { - LLVMValueRef elem_val = ir_llvm_value(g, instruction->items[i]); LLVMValueRef indices[] = { LLVMConstNull(g->builtin_types.entry_usize->type_ref), LLVMConstInt(g->builtin_types.entry_usize->type_ref, i, false), }; LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, tmp_array_ptr, indices, 2, ""); - gen_assign_raw(g, elem_ptr, get_pointer_to_type(g, child_type, false), elem_val); + gen_assign(g, elem_ptr, get_pointer_to_type(g, child_type, false), instruction->items[i]); } return tmp_array_ptr; @@ -5070,6 +5225,30 @@ static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstr return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); } +static LLVMValueRef ir_render_result_loc(CodeGen *g, IrExecutable *executable, + IrInstructionResultLoc *instruction) +{ + // Generate the ancestor so that it caches our result + IrResultLocation *result_loc = instruction->result_location; + while (result_loc->parent != nullptr) { + result_loc = result_loc->parent; + } + LLVMValueRef ancestor_ptr = gen_result_location(g, result_loc); + + LLVMValueRef ptr = gen_result_location(g, instruction->result_location); + if (instruction->result_location->child == nullptr && !instruction->result_location->from_call) { + IrInstructionResultLoc *ancestor = instruction; + while (ancestor->value->id == IrInstructionIdResultLoc) { + ancestor = reinterpret_cast(ancestor->value); + } + + LLVMValueRef val = ir_llvm_value(g, ancestor->value); + LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, LLVMGetElementType(LLVMTypeOf(ancestor_ptr)), ""); + gen_store_untyped(g, bitcasted, ancestor_ptr, 0, false); + } + return ptr; +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5310,6 +5489,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction); case IrInstructionIdSqrt: return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction); + case IrInstructionIdResultLoc: + return ir_render_result_loc(g, executable, (IrInstructionResultLoc *)instruction); + case IrInstructionIdPtrOfArrayToSlice: + return ir_render_ptr_of_array_to_slice(g, executable, (IrInstructionPtrOfArrayToSlice *)instruction); } zig_unreachable(); } @@ -6197,51 +6380,10 @@ static void do_code_gen(CodeGen *g) { } // allocate temporary stack data - for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) { - IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i); - LLVMValueRef *slot; - ZigType *slot_type = instruction->value.type; - if (instruction->id == IrInstructionIdCast) { - IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction; - slot = &cast_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdRef) { - IrInstructionRef *ref_instruction = (IrInstructionRef *)instruction; - slot = &ref_instruction->tmp_ptr; - assert(instruction->value.type->id == ZigTypeIdPointer); - slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdContainerInitList) { - IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction; - slot = &container_init_list_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdStructInit) { - IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction; - slot = &struct_init_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdUnionInit) { - IrInstructionUnionInit *union_init_instruction = (IrInstructionUnionInit *)instruction; - slot = &union_init_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdCall) { - IrInstructionCall *call_instruction = (IrInstructionCall *)instruction; - slot = &call_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdSlice) { - IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction; - slot = &slice_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdOptionalWrap) { - IrInstructionOptionalWrap *maybe_wrap_instruction = (IrInstructionOptionalWrap *)instruction; - slot = &maybe_wrap_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdErrWrapPayload) { - IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction; - slot = &err_wrap_payload_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdErrWrapCode) { - IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; - slot = &err_wrap_code_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdCmpxchg) { - IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction; - slot = &cmpxchg_instruction->tmp_ptr; - } else { - zig_unreachable(); - } - *slot = build_alloca(g, slot_type, "", get_abi_alignment(g, slot_type)); + for (size_t alloca_i = 0; alloca_i < fn_table_entry->result_loc_alloca_list.length; alloca_i += 1) { + IrResultLocationAlloca *alloca_loc = fn_table_entry->result_loc_alloca_list.at(alloca_i); + alloca_loc->alloca = build_alloca(g, alloca_loc->ty, "", get_abi_alignment(g, alloca_loc->ty)); } - ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); unsigned gen_i_init = want_first_arg_sret(g, fn_type_id) ? 1 : 0; diff --git a/src/ir.cpp b/src/ir.cpp index 0c8da5a575b4..0b6ac12f55ca 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -139,7 +139,9 @@ struct ConstCastErrSetMismatch { }; 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); +static IrInstruction *ir_gen_node_lval(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval); +static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, + IrResultLocation *result_location); static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction); static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type); static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr); @@ -863,6 +865,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScop return IrInstructionIdCheckRuntimeScope; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionResultLoc *) { + return IrInstructionIdResultLoc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) { + return IrInstructionIdPtrOfArrayToSlice; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -1085,11 +1095,12 @@ static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *sou } static IrInstruction *ir_build_var_ptr_x(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var, - ScopeFnDef *crossed_fndef_scope) + ScopeFnDef *crossed_fndef_scope, IrResultLocation *result_location) { IrInstructionVarPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->var = var; instruction->crossed_fndef_scope = crossed_fndef_scope; + instruction->result_location = result_location; ir_ref_var(var); @@ -1097,7 +1108,7 @@ static IrInstruction *ir_build_var_ptr_x(IrBuilder *irb, Scope *scope, AstNode * } static IrInstruction *ir_build_var_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var) { - return ir_build_var_ptr_x(irb, scope, source_node, var, nullptr); + return ir_build_var_ptr_x(irb, scope, source_node, var, nullptr, nullptr); } static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr, @@ -1169,7 +1180,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator, - IrInstruction *new_stack) + IrInstruction *new_stack, IrResultLocation *result_location) { IrInstructionCall *call_instruction = ir_build_instruction(irb, scope, source_node); call_instruction->fn_entry = fn_entry; @@ -1181,6 +1192,7 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc call_instruction->is_async = is_async; call_instruction->async_allocator = async_allocator; call_instruction->new_stack = new_stack; + call_instruction->result_location = result_location; if (fn_ref) ir_ref_instruction(fn_ref, irb->current_basic_block); @@ -1385,9 +1397,12 @@ static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *sou return &export_instruction->base; } -static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { +static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr, + IrResultLocation *result_location) +{ IrInstructionLoadPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->ptr = ptr; + instruction->result_location = result_location; ir_ref_instruction(ptr, irb->current_basic_block); @@ -1548,27 +1563,36 @@ static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNod return &instruction->base; } -static IrInstruction *ir_build_maybe_wrap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { +static IrInstruction *ir_build_maybe_wrap(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value, IrResultLocation *result_location) +{ IrInstructionOptionalWrap *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; + instruction->result_location = result_location; ir_ref_instruction(value, irb->current_basic_block); return &instruction->base; } -static IrInstruction *ir_build_err_wrap_payload(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { +static IrInstruction *ir_build_err_wrap_payload(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value, IrResultLocation *result_location) +{ IrInstructionErrWrapPayload *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; + instruction->result_location = result_location; ir_ref_instruction(value, irb->current_basic_block); return &instruction->base; } -static IrInstruction *ir_build_err_wrap_code(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { +static IrInstruction *ir_build_err_wrap_code(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value, IrResultLocation *result_location) +{ IrInstructionErrWrapCode *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; + instruction->result_location = result_location; ir_ref_instruction(value, irb->current_basic_block); @@ -1970,12 +1994,14 @@ static IrInstruction *ir_build_memcpy(IrBuilder *irb, Scope *scope, AstNode *sou } static IrInstruction *ir_build_slice(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on) + IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on, + IrResultLocation *result_location) { IrInstructionSlice *instruction = ir_build_instruction(irb, scope, source_node); instruction->ptr = ptr; instruction->start = start; instruction->end = end; + instruction->result_location = result_location; instruction->safety_check_on = safety_check_on; ir_ref_instruction(ptr, irb->current_basic_block); @@ -2746,6 +2772,30 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, return &instruction->base; } +static IrInstruction *ir_build_result_loc(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrResultLocation *result_location, IrInstruction *value) +{ + IrInstructionResultLoc *instruction = ir_build_instruction(irb, scope, source_node); + instruction->result_location = result_location; + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstruction *ir_build_ptr_of_array_to_slice(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value, IrResultLocation *result_location) +{ + IrInstructionPtrOfArrayToSlice *instruction = ir_build_instruction(irb, scope, source_node); + instruction->value = value; + instruction->result_location = result_location; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -2955,12 +3005,15 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, switch (node->data.return_expr.kind) { case ReturnKindUnconditional: { + IrResultLocationRet *result_loc_ret = allocate(1); + result_loc_ret->base.id = IrResultLocationIdRet; + IrInstruction *return_value; if (expr_node) { // Temporarily set this so that if we return a type it gets the name of the function ZigFn *prev_name_fn = irb->exec->name_fn; irb->exec->name_fn = exec_fn_entry(irb->exec); - return_value = ir_gen_node(irb, expr_node, scope); + return_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, &result_loc_ret->base); irb->exec->name_fn = prev_name_fn; if (return_value == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -3017,10 +3070,10 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, case ReturnKindError: { assert(expr_node); - IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr); + IrInstruction *err_union_ptr = ir_gen_node_lval(irb, expr_node, scope, LValPtr); if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr); + IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr, nullptr); IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_union_val); IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn"); @@ -3048,7 +3101,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, if (lval == LValPtr) return unwrapped_ptr; else - return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); + return ir_build_load_ptr(irb, scope, node, unwrapped_ptr, nullptr); } } zig_unreachable(); @@ -3218,8 +3271,12 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *no } static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) { - IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr); - IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); + IrInstruction *lvalue = ir_gen_node_lval(irb, node->data.bin_op_expr.op1, scope, LValPtr); + IrResultLocationLVal *lval_result_loc = allocate(1); + lval_result_loc->base.id = IrResultLocationIdLVal; + lval_result_loc->parent_instruction = lvalue; + IrInstruction *rvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op2, scope, LValNone, + &lval_result_loc->base); if (lvalue == irb->codegen->invalid_instruction || rvalue == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -3229,10 +3286,10 @@ static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) } static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) { - IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr); + IrInstruction *lvalue = ir_gen_node_lval(irb, node->data.bin_op_expr.op1, scope, LValPtr); if (lvalue == irb->codegen->invalid_instruction) return lvalue; - IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue); + IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue, nullptr); IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); if (op2 == irb->codegen->invalid_instruction) return op2; @@ -3331,11 +3388,11 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As AstNode *op1_node = node->data.bin_op_expr.op1; AstNode *op2_node = node->data.bin_op_expr.op2; - IrInstruction *maybe_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr); + IrInstruction *maybe_ptr = ir_gen_node_lval(irb, op1_node, parent_scope, LValPtr); if (maybe_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr); + IrInstruction *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr, nullptr); IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_val); IrInstruction *is_comptime; @@ -3360,7 +3417,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As ir_set_cursor_at_end_and_append_block(irb, ok_block); IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, parent_scope, node, maybe_ptr, false); - IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); + IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr, nullptr); IrBasicBlock *after_ok_block = irb->current_basic_block; ir_build_br(irb, parent_scope, node, end_block, is_comptime); @@ -3513,7 +3570,9 @@ static IrInstruction *ir_gen_null_literal(IrBuilder *irb, Scope *scope, AstNode return ir_build_const_null(irb, scope, node); } -static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { +static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + IrResultLocation *result_location) +{ assert(node->type == NodeTypeSymbol); Buf *variable_name = node->data.symbol_expr.symbol; @@ -3540,11 +3599,11 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, ScopeFnDef *crossed_fndef_scope; ZigVar *var = find_variable(irb->codegen, scope, variable_name, &crossed_fndef_scope); if (var) { - IrInstruction *var_ptr = ir_build_var_ptr_x(irb, scope, node, var, crossed_fndef_scope); + IrInstruction *var_ptr = ir_build_var_ptr_x(irb, scope, node, var, crossed_fndef_scope, result_location); if (lval == LValPtr) return var_ptr; else - return ir_build_load_ptr(irb, scope, node, var_ptr); + return ir_build_load_ptr(irb, scope, node, var_ptr, result_location); } Tld *tld = find_decl(irb->codegen, scope, variable_name); @@ -3567,7 +3626,7 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode assert(node->type == NodeTypeArrayAccessExpr); AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr; - IrInstruction *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, scope, LValPtr); + IrInstruction *array_ref_instruction = ir_gen_node_lval(irb, array_ref_node, scope, LValPtr); if (array_ref_instruction == irb->codegen->invalid_instruction) return array_ref_instruction; @@ -3581,7 +3640,7 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode if (lval == LValPtr) return ptr_instruction; - return ir_build_load_ptr(irb, scope, node, ptr_instruction); + return ir_build_load_ptr(irb, scope, node, ptr_instruction, nullptr); } static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -3590,7 +3649,7 @@ static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode AstNode *container_ref_node = node->data.field_access_expr.struct_expr; Buf *field_name = node->data.field_access_expr.field_name; - IrInstruction *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, scope, LValPtr); + IrInstruction *container_ref_instruction = ir_gen_node_lval(irb, container_ref_node, scope, LValPtr); if (container_ref_instruction == irb->codegen->invalid_instruction) return container_ref_instruction; @@ -4260,7 +4319,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo case BuiltinFnIdField: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node_extra(irb, arg0_node, scope, LValPtr); + IrInstruction *arg0_value = ir_gen_node_lval(irb, arg0_node, scope, LValPtr); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; @@ -4274,7 +4333,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (lval == LValPtr) return ptr_instruction; - return ir_build_load_ptr(irb, scope, node, ptr_instruction); + return ir_build_load_ptr(irb, scope, node, ptr_instruction, nullptr); } case BuiltinFnIdTypeInfo: { @@ -4490,7 +4549,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever; - IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr); + IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr, nullptr); return ir_lval_wrap(irb, scope, call, lval); } case BuiltinFnIdNewStackCall: @@ -4520,7 +4579,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return args[i]; } - IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, false, nullptr, new_stack); + IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, false, nullptr, new_stack, nullptr); return ir_lval_wrap(irb, scope, call, lval); } case BuiltinFnIdTypeId: @@ -4730,7 +4789,9 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo zig_unreachable(); } -static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { +static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + IrResultLocation *result_location) +{ assert(node->type == NodeTypeFnCallExpr); if (node->data.fn_call_expr.is_builtin) @@ -4760,7 +4821,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node } } - IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr); + IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, + FnInlineAuto, is_async, async_allocator, nullptr, result_location); return ir_lval_wrap(irb, scope, fn_call, lval); } @@ -4825,7 +4887,7 @@ static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, Ast assert(node->type == NodeTypePrefixOpExpr); AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval); + IrInstruction *value = ir_gen_node_lval(irb, expr_node, scope, lval); if (value == irb->codegen->invalid_instruction) return value; @@ -4906,7 +4968,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node, LVal lval) { - IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr); + IrInstruction *err_union_ptr = ir_gen_node_lval(irb, expr_node, scope, LValPtr); if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -4917,7 +4979,7 @@ static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode if (lval == LValPtr) return payload_ptr; - return ir_build_load_ptr(irb, scope, source_node, payload_ptr); + return ir_build_load_ptr(irb, scope, source_node, payload_ptr, nullptr); } static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -4931,7 +4993,9 @@ static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *nod return ir_build_bool_not(irb, scope, node, value); } -static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { +static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + IrResultLocation *result_location) +{ assert(node->type == NodeTypePrefixOpExpr); PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; @@ -4951,7 +5015,7 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval); case PrefixOpAddrOf: { AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr), lval); + return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr, result_location), lval); } } zig_unreachable(); @@ -5050,11 +5114,16 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol))); } + IrResultLocationVar *result_loc = allocate(1); + result_loc->base.id = IrResultLocationIdVar; + result_loc->var = var; + // Temporarily set the name of the IrExecutable to the VariableDeclaration // so that the struct or enum from the init expression inherits the name. Buf *old_exec_name = irb->exec->name; irb->exec->name = variable_declaration->symbol; - IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope); + IrInstruction *init_value = ir_gen_node_extra(irb, variable_declaration->expr, scope, LValNone, + &result_loc->base); irb->exec->name = old_exec_name; if (init_value == irb->codegen->invalid_instruction) @@ -5098,10 +5167,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n } else { payload_scope = subexpr_scope; } - IrInstruction *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, LValPtr); + IrInstruction *err_val_ptr = ir_gen_node_lval(irb, node->data.while_expr.condition, subexpr_scope, LValPtr); if (err_val_ptr == irb->codegen->invalid_instruction) return err_val_ptr; - IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr); + IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr, nullptr); IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val); IrBasicBlock *after_cond_block = irb->current_basic_block; IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); @@ -5115,7 +5184,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node, err_val_ptr, false); IrInstruction *var_value = node->data.while_expr.var_is_ptr ? - var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value); + var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value, nullptr); ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value); } @@ -5185,10 +5254,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ZigVar *payload_var = ir_create_var(irb, symbol_node, subexpr_scope, var_symbol, true, false, false, is_comptime); Scope *child_scope = payload_var->child_scope; - IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, LValPtr); + IrInstruction *maybe_val_ptr = ir_gen_node_lval(irb, node->data.while_expr.condition, subexpr_scope, LValPtr); if (maybe_val_ptr == irb->codegen->invalid_instruction) return maybe_val_ptr; - IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr); + IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr, nullptr); IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val); IrBasicBlock *after_cond_block = irb->current_basic_block; IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); @@ -5200,7 +5269,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_set_cursor_at_end_and_append_block(irb, body_block); IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false); IrInstruction *var_value = node->data.while_expr.var_is_ptr ? - var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value); + var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value, nullptr); ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value); ZigList incoming_values = {0}; @@ -5335,11 +5404,11 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo } assert(elem_node->type == NodeTypeSymbol); - IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LValPtr); + IrInstruction *array_val_ptr = ir_gen_node_lval(irb, array_node, parent_scope, LValPtr); if (array_val_ptr == irb->codegen->invalid_instruction) return array_val_ptr; - IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr); + IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr, nullptr); IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val); IrInstruction *elem_var_type; @@ -5390,7 +5459,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo ir_build_br(irb, child_scope, node, cond_block, is_comptime); ir_set_cursor_at_end_and_append_block(irb, cond_block); - IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_ptr); + IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_ptr, nullptr); IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false); IrBasicBlock *after_cond_block = irb->current_basic_block; IrInstruction *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node)); @@ -5402,7 +5471,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo if (node->data.for_expr.elem_is_ptr) { elem_val = elem_ptr; } else { - elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr); + elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr, nullptr); } ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val)); @@ -5597,11 +5666,11 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no AstNode *else_node = node->data.test_expr.else_node; bool var_is_ptr = node->data.test_expr.var_is_ptr; - IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr); + IrInstruction *maybe_val_ptr = ir_gen_node_lval(irb, expr_node, scope, LValPtr); if (maybe_val_ptr == irb->codegen->invalid_instruction) return maybe_val_ptr; - IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr); + IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr, nullptr); IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_val); IrBasicBlock *then_block = ir_create_basic_block(irb, scope, "OptionalThen"); @@ -5628,7 +5697,7 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no var_symbol, is_const, is_const, is_shadowable, is_comptime); IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false); - IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value); + IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value, nullptr); ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value); var_scope = var->child_scope; } else { @@ -5676,11 +5745,11 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * Buf *var_symbol = node->data.if_err_expr.var_symbol; Buf *err_symbol = node->data.if_err_expr.err_symbol; - IrInstruction *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr); + IrInstruction *err_val_ptr = ir_gen_node_lval(irb, target_node, scope, LValPtr); if (err_val_ptr == irb->codegen->invalid_instruction) return err_val_ptr; - IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); + IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr, nullptr); IrInstruction *is_err = ir_build_test_err(irb, scope, node, err_val); IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk"); @@ -5703,7 +5772,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime); IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false); - IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value); + IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value, nullptr); ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value); var_scope = var->child_scope; } else { @@ -5779,9 +5848,9 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit IrInstruction *var_value; if (prong_value) { IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value); - var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value); + var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value, nullptr); } else { - var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); + var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr, nullptr); } IrInstruction *var_type = nullptr; // infer the type ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, nullptr, var_value); @@ -5803,7 +5872,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * assert(node->type == NodeTypeSwitchExpr); AstNode *target_node = node->data.switch_expr.expr; - IrInstruction *target_value_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr); + IrInstruction *target_value_ptr = ir_gen_node_lval(irb, target_node, scope, LValPtr); if (target_value_ptr == irb->codegen->invalid_instruction) return target_value_ptr; IrInstruction *target_value = ir_build_switch_target(irb, scope, node, target_value_ptr); @@ -5995,7 +6064,7 @@ static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNo assert(node->type == NodeTypeCompTime); Scope *child_scope = create_comptime_scope(irb->codegen, node, parent_scope); - return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval); + return ir_gen_node_lval(irb, node->data.comptime_expr.expr, child_scope, lval); } static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) { @@ -6166,7 +6235,7 @@ static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode return ir_build_const_void(irb, parent_scope, node); } -static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) { +static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, IrResultLocation *result_location) { assert(node->type == NodeTypeSliceExpr); AstNodeSliceExpr *slice_expr = &node->data.slice_expr; @@ -6174,7 +6243,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) AstNode *start_node = slice_expr->start; AstNode *end_node = slice_expr->end; - IrInstruction *ptr_value = ir_gen_node_extra(irb, array_node, scope, LValPtr); + IrInstruction *ptr_value = ir_gen_node_lval(irb, array_node, scope, LValPtr); if (ptr_value == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -6191,7 +6260,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) end_value = nullptr; } - return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true); + return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true, result_location); } static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) { @@ -6212,11 +6281,11 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN } - IrInstruction *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr); + IrInstruction *err_union_ptr = ir_gen_node_lval(irb, op1_node, parent_scope, LValPtr); if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *err_union_val = ir_build_load_ptr(irb, parent_scope, node, err_union_ptr); + IrInstruction *err_union_val = ir_build_load_ptr(irb, parent_scope, node, err_union_ptr, nullptr); IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_val); IrInstruction *is_comptime; @@ -6255,7 +6324,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN ir_set_cursor_at_end_and_append_block(irb, ok_block); IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, parent_scope, node, err_union_ptr, false); - IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); + IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr, nullptr); IrBasicBlock *after_ok_block = irb->current_basic_block; ir_build_br(irb, parent_scope, node, end_block, is_comptime); @@ -6768,7 +6837,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name); // If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to, // because we're about to destroy the memory. So we store it into our result variable. - IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr); + IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr, nullptr); ir_build_store_ptr(irb, scope, node, my_result_var_ptr, no_suspend_result); ir_build_cancel(irb, scope, node, target_inst); ir_build_br(irb, scope, node, merge_block, const_bool_false); @@ -6828,7 +6897,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_build_br(irb, scope, node, merge_block, const_bool_false); ir_set_cursor_at_end_and_append_block(irb, merge_block); - return ir_build_load_ptr(irb, scope, node, my_result_var_ptr); + return ir_build_load_ptr(irb, scope, node, my_result_var_ptr, nullptr); } static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) { @@ -6949,7 +7018,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod } static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, - LVal lval) + LVal lval, IrResultLocation *result_location) { assert(scope); switch (node->type) { @@ -6966,7 +7035,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeBlock: return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval); case NodeTypeGroupedExpr: - return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval); + return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval, result_location); case NodeTypeBinOpExpr: return ir_lval_wrap(irb, scope, ir_gen_bin_op(irb, scope, node), lval); case NodeTypeIntLiteral: @@ -6976,13 +7045,13 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeCharLiteral: return ir_lval_wrap(irb, scope, ir_gen_char_lit(irb, scope, node), lval); case NodeTypeSymbol: - return ir_gen_symbol(irb, scope, node, lval); + return ir_gen_symbol(irb, scope, node, lval, result_location); case NodeTypeFnCallExpr: - return ir_gen_fn_call(irb, scope, node, lval); + return ir_gen_fn_call(irb, scope, node, lval, result_location); case NodeTypeIfBoolExpr: return ir_lval_wrap(irb, scope, ir_gen_if_bool_expr(irb, scope, node), lval); case NodeTypePrefixOpExpr: - return ir_gen_prefix_op_expr(irb, scope, node, lval); + return ir_gen_prefix_op_expr(irb, scope, node, lval, result_location); case NodeTypeContainerInitExpr: return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node), lval); case NodeTypeVariableDeclaration: @@ -7003,11 +7072,11 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop if (lval == LValPtr) return ptr_instruction; - return ir_build_load_ptr(irb, scope, node, ptr_instruction); + return ir_build_load_ptr(irb, scope, node, ptr_instruction, nullptr); } case NodeTypePtrDeref: { AstNode *expr_node = node->data.ptr_deref_expr.target; - IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval); + IrInstruction *value = ir_gen_node_lval(irb, expr_node, scope, lval); if (value == irb->codegen->invalid_instruction) return value; @@ -7016,7 +7085,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeUnwrapOptional: { AstNode *expr_node = node->data.unwrap_optional.expr; - IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr); + IrInstruction *maybe_ptr = ir_gen_node_lval(irb, expr_node, scope, LValPtr); if (maybe_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -7024,7 +7093,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop if (lval == LValPtr) return unwrapped_ptr; - return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); + return ir_build_load_ptr(irb, scope, node, unwrapped_ptr, nullptr); } case NodeTypeBoolLiteral: return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval); @@ -7061,7 +7130,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeDefer: return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval); case NodeTypeSliceExpr: - return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node, result_location), lval); case NodeTypeUnwrapErrorExpr: return ir_lval_wrap(irb, scope, ir_gen_err_ok_or(irb, scope, node), lval); case NodeTypeContainerDecl: @@ -7082,14 +7151,20 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop zig_unreachable(); } -static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval) { - IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval); +static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, + IrResultLocation *result_location) +{ + IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_location); irb->exec->invalid = irb->exec->invalid || (result == irb->codegen->invalid_instruction); return result; } +static IrInstruction *ir_gen_node_lval(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval) { + return ir_gen_node_extra(irb, node, scope, lval, nullptr); +} + static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) { - return ir_gen_node_extra(irb, node, scope, LValNone); + return ir_gen_node_extra(irb, node, scope, LValNone, nullptr); } static void invalidate_exec(IrExecutable *exec) { @@ -7165,7 +7240,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name); - IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr); + IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr, nullptr); IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size); IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr); IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError"); @@ -7208,7 +7283,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses"); IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name); - IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false); + IrResultLocationLVal *addrs_slice_ptr_loc = allocate(1); + addrs_slice_ptr_loc->base.id = IrResultLocationIdLVal; + addrs_slice_ptr_loc->parent_instruction = addrs_slice_ptr; + IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false, &addrs_slice_ptr_loc->base); ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value); } @@ -7219,7 +7297,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec irb->exec->coro_final_cleanup_block = ir_create_basic_block(irb, scope, "FinalCleanup"); } - IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone); + IrInstruction *result = ir_gen_node_lval(irb, node, scope, LValNone); assert(result); if (irb->exec->invalid) return false; @@ -7255,7 +7333,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, 0, 0, 0)); - IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); + IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, nullptr); IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr); IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, irb->exec->coro_result_field_ptr); @@ -7267,7 +7345,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec if (irb->codegen->have_err_ret_tracing) { Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME); IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name); - IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr); + IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, nullptr); ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr); } // Before we destroy the coroutine frame, we need to load the target promise into @@ -7275,7 +7353,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec // otherwise llvm tries to access memory inside the destroyed frame. IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node, irb->exec->await_handle_var_ptr, false); - IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr); + IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr, nullptr); ir_build_br(irb, scope, node, check_free_block, const_bool_false); ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block); @@ -7302,7 +7380,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node, ImplicitAllocatorIdLocalVar); IrInstruction *free_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, free_field_name); - IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr); + IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr, nullptr); IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0); IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle); IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, @@ -7311,13 +7389,13 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe); IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false); IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var); - IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr); - IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false); + IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr, nullptr); + IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false, nullptr); size_t arg_count = 2; IrInstruction **args = allocate(arg_count); args[0] = implicit_allocator_ptr; // self args[1] = mem_slice; // old_mem - ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr, nullptr); + ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr, nullptr, nullptr); IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume"); ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false); @@ -9114,15 +9192,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT } } -static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry) { - if (type_has_bits(type_entry) && handle_is_ptr(type_entry)) { - ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); - if (fn_entry != nullptr) { - fn_entry->alloca_list.append(instruction); - } - } -} - static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs) { ConstGlobalRefs *global_refs = dest->global_refs; *dest = *src; @@ -9148,7 +9217,6 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ zig_unreachable(); case CastOpErrSet: case CastOpBitCast: - case CastOpPtrOfArrayToSlice: zig_panic("TODO"); case CastOpNoop: { @@ -9238,7 +9306,7 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ return true; } static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, - ZigType *wanted_type, CastOp cast_op, bool need_alloca) + ZigType *wanted_type, CastOp cast_op) { if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) && cast_op != CastOpResizeSlice && cast_op != CastOpBytesToSlice) @@ -9254,9 +9322,6 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst } else { IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, cast_op); result->value.type = wanted_type; - if (need_alloca) { - ir_add_alloca(ira, result, wanted_type); - } return result; } } @@ -9299,14 +9364,261 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, return result; } +IrResultLocation *ir_get_result_location(IrInstruction *base) { + switch (base->id) { + case IrInstructionIdInvalid: + zig_unreachable(); + case IrInstructionIdCall: { + IrInstructionCall *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdCast: { + IrInstructionCast *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdContainerInitList: { + IrInstructionContainerInitList *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdStructInit: { + IrInstructionStructInit *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdUnionInit: { + IrInstructionUnionInit *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdRef: { + IrInstructionRef *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdCmpxchg: { + IrInstructionCmpxchg *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdSlice: { + IrInstructionSlice *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdOptionalWrap: { + IrInstructionOptionalWrap *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdErrWrapPayload: { + IrInstructionErrWrapPayload *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdErrWrapCode: { + IrInstructionErrWrapCode *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdResultLoc: { + IrInstructionResultLoc *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdPtrOfArrayToSlice: { + IrInstructionPtrOfArrayToSlice *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdVarPtr: { + IrInstructionVarPtr *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdLoadPtr: { + IrInstructionLoadPtr *inst = reinterpret_cast(base); + return inst->result_location; + } + case IrInstructionIdBr: + case IrInstructionIdCondBr: + case IrInstructionIdSwitchBr: + case IrInstructionIdDeclVar: + case IrInstructionIdStorePtr: + case IrInstructionIdReturn: + case IrInstructionIdUnreachable: + case IrInstructionIdSetCold: + case IrInstructionIdSetRuntimeSafety: + case IrInstructionIdSetFloatMode: + case IrInstructionIdImport: + case IrInstructionIdCompileErr: + case IrInstructionIdCompileLog: + case IrInstructionIdCImport: + case IrInstructionIdCInclude: + case IrInstructionIdCDefine: + case IrInstructionIdCUndef: + case IrInstructionIdFence: + case IrInstructionIdMemset: + case IrInstructionIdMemcpy: + case IrInstructionIdBreakpoint: + case IrInstructionIdOverflowOp: + case IrInstructionIdCheckSwitchProngs: + case IrInstructionIdCheckStatementIsVoid: + case IrInstructionIdCheckRuntimeScope: + case IrInstructionIdPanic: + case IrInstructionIdSetEvalBranchQuota: + case IrInstructionIdPtrType: + case IrInstructionIdSetAlignStack: + case IrInstructionIdExport: + case IrInstructionIdCancel: + case IrInstructionIdCoroId: + case IrInstructionIdCoroBegin: + case IrInstructionIdCoroAllocFail: + case IrInstructionIdCoroEnd: + case IrInstructionIdCoroResume: + case IrInstructionIdCoroSave: + case IrInstructionIdCoroAllocHelper: + case IrInstructionIdAwaitBookkeeping: + case IrInstructionIdSaveErrRetAddr: + case IrInstructionIdAddImplicitReturnType: + case IrInstructionIdMergeErrRetTraces: + case IrInstructionIdMarkErrRetTracePtr: + case IrInstructionIdAtomicRmw: + case IrInstructionIdPhi: + case IrInstructionIdUnOp: + case IrInstructionIdBinOp: + case IrInstructionIdConst: + case IrInstructionIdContainerInitFields: + case IrInstructionIdFieldPtr: + case IrInstructionIdElemPtr: + case IrInstructionIdTypeOf: + case IrInstructionIdToPtrType: + case IrInstructionIdPtrTypeChild: + case IrInstructionIdArrayLen: + case IrInstructionIdStructFieldPtr: + case IrInstructionIdUnionFieldPtr: + case IrInstructionIdArrayType: + case IrInstructionIdPromiseType: + case IrInstructionIdSliceType: + case IrInstructionIdSizeOf: + case IrInstructionIdTestNonNull: + case IrInstructionIdUnwrapOptional: + case IrInstructionIdClz: + case IrInstructionIdCtz: + case IrInstructionIdPopCount: + case IrInstructionIdSwitchVar: + case IrInstructionIdSwitchTarget: + case IrInstructionIdUnionTag: + case IrInstructionIdMinValue: + case IrInstructionIdMaxValue: + case IrInstructionIdEmbedFile: + case IrInstructionIdTruncate: + case IrInstructionIdIntType: + case IrInstructionIdBoolNot: + case IrInstructionIdMemberCount: + case IrInstructionIdMemberType: + case IrInstructionIdMemberName: + case IrInstructionIdAlignOf: + case IrInstructionIdReturnAddress: + case IrInstructionIdFrameAddress: + case IrInstructionIdHandle: + case IrInstructionIdTestErr: + case IrInstructionIdUnwrapErrCode: + case IrInstructionIdFnProto: + case IrInstructionIdTestComptime: + case IrInstructionIdPtrCast: + case IrInstructionIdBitCast: + case IrInstructionIdWidenOrShorten: + case IrInstructionIdPtrToInt: + case IrInstructionIdIntToPtr: + case IrInstructionIdIntToEnum: + case IrInstructionIdIntToErr: + case IrInstructionIdErrToInt: + case IrInstructionIdDeclRef: + case IrInstructionIdErrName: + case IrInstructionIdTypeName: + case IrInstructionIdTagName: + case IrInstructionIdFieldParentPtr: + case IrInstructionIdByteOffsetOf: + case IrInstructionIdBitOffsetOf: + case IrInstructionIdTypeInfo: + case IrInstructionIdTypeId: + case IrInstructionIdAlignCast: + case IrInstructionIdOpaqueType: + case IrInstructionIdArgType: + case IrInstructionIdTagType: + case IrInstructionIdErrorReturnTrace: + case IrInstructionIdErrorUnion: + case IrInstructionIdGetImplicitAllocator: + case IrInstructionIdCoroAlloc: + case IrInstructionIdCoroSize: + case IrInstructionIdCoroSuspend: + case IrInstructionIdCoroFree: + case IrInstructionIdCoroPromise: + case IrInstructionIdPromiseResultType: + case IrInstructionIdSqrt: + case IrInstructionIdAtomicLoad: + case IrInstructionIdIntCast: + case IrInstructionIdFloatCast: + case IrInstructionIdErrSetCast: + case IrInstructionIdIntToFloat: + case IrInstructionIdFloatToInt: + case IrInstructionIdBoolToInt: + case IrInstructionIdFromBytes: + case IrInstructionIdToBytes: + case IrInstructionIdEnumToInt: + case IrInstructionIdAsm: + case IrInstructionIdUnwrapErrPayload: + return nullptr; + } + zig_unreachable(); +} + +static IrResultLocation *create_alloca_result_loc(IrAnalyze *ira, ZigType *ty, bool from_call) { + ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); + if (fn_entry == nullptr) + return nullptr; + if (type_has_bits(ty) && handle_is_ptr(ty)) { + IrResultLocationAlloca *alloca_loc = allocate(1); + alloca_loc->base.id = IrResultLocationIdAlloca; + alloca_loc->base.from_call = from_call; + alloca_loc->ty = ty; + fn_entry->result_loc_alloca_list.append(alloca_loc); + return &alloca_loc->base; + } + return nullptr; +} + +static IrResultLocation *ir_analyze_result_location(IrAnalyze *ira, IrResultLocation *result_location, + ZigType *ty, bool from_call) +{ + if (result_location != nullptr) { + result_location->from_call = from_call; + if (result_location->id == IrResultLocationIdLVal) { + IrResultLocationLVal *lval_loc = reinterpret_cast(result_location); + if (lval_loc->parent_instruction->value.special == ConstValSpecialStatic && + lval_loc->parent_instruction->value.type->id == ZigTypeIdPointer && + lval_loc->parent_instruction->value.data.x_ptr.special == ConstPtrSpecialDiscard) + { + // We have to convert this to an Alloca because the function is sret + // and so even though we want to discard the result, we need a stack allocation + // to pass as the sret pointer. + return create_alloca_result_loc(ira, ty, from_call); + } + } else if (result_location->id == IrResultLocationIdVar) { + // We have to resolve the variable in case of an inline loop. + IrResultLocationVar *var_loc = reinterpret_cast(result_location); + IrResultLocationVar *new_var_loc = allocate(1); + new_var_loc->base.id = IrResultLocationIdVar; + new_var_loc->base.from_call = from_call; + new_var_loc->var = var_loc->var; + while (new_var_loc->var->next_var != nullptr) { + new_var_loc->var = new_var_loc->var->next_var; + } + return &var_loc->base; + } + return result_location; + } + return create_alloca_result_loc(ira, ty, from_call); +} + static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) { Error err; - if ((err = type_resolve(ira->codegen, value->value.type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { + assert(value->value.type->id == ZigTypeIdPointer); + ZigType *array_type = value->value.type->data.pointer.child_type; + + if ((err = type_resolve(ira->codegen, array_type, ResolveStatusAlignmentKnown))) { return ira->codegen->invalid_instruction; } @@ -9317,8 +9629,6 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc if (pointee == nullptr) return ira->codegen->invalid_instruction; if (pointee->special != ConstValSpecialRuntime) { - assert(value->value.type->id == ZigTypeIdPointer); - ZigType *array_type = value->value.type->data.pointer.child_type; assert(is_slice(wanted_type)); bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const; @@ -9332,11 +9642,26 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc } } - IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, - wanted_type, value, CastOpPtrOfArrayToSlice); - result->value.type = wanted_type; - ir_add_alloca(ira, result, wanted_type); - return result; + IrResultLocation *result_location = ir_get_result_location(value); + if (result_location == nullptr) { + result_location = create_alloca_result_loc(ira, wanted_type, false); + IrInstruction *result = ir_build_ptr_of_array_to_slice(&ira->new_irb, source_instr->scope, + source_instr->source_node, value, result_location); + result->value.type = wanted_type; + return result; + } else { + IrResultLocationArrayToSlice *new_result_location = allocate(1); + new_result_location->base.id = IrResultLocationIdArrayToSlice; + new_result_location->base.parent = result_location; + new_result_location->base.from_call = result_location->from_call; + new_result_location->len = array_type->data.array.len; + assert(result_location->child == nullptr); + result_location->child = &new_result_location->base; + IrInstruction *result = ir_build_result_loc(&ira->new_irb, source_instr->scope, + source_instr->source_node, &new_result_location->base, value); + result->value.type = wanted_type; + return result; + } } static bool is_container(ZigType *type) { @@ -9651,10 +9976,29 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc return &const_instruction->base; } - IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node, value); + // If we have a result location and the type handle is pointer, we push a special + // OptionalWrap result location value to the result location stack. + IrResultLocation *result_location = ir_get_result_location(value); + if (result_location != nullptr) { + IrResultLocationOptionalUnwrap *new_result_location = allocate(1); + new_result_location->base.id = IrResultLocationIdOptionalUnwrap; + new_result_location->base.parent = result_location; + new_result_location->base.from_call = result_location->from_call; + assert(result_location->child == nullptr); + result_location->child = &new_result_location->base; + IrInstruction *result = ir_build_result_loc(&ira->new_irb, source_instr->scope, + source_instr->source_node, &new_result_location->base, value); + result->value.data.rh_maybe = RuntimeHintOptionalNonNull; + result->value.type = wanted_type; + return result; + } else { + result_location = create_alloca_result_loc(ira, wanted_type, false); + } + + IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node, + value, result_location); result->value.type = wanted_type; result->value.data.rh_maybe = RuntimeHintOptionalNonNull; - ir_add_alloca(ira, result, wanted_type); return result; } @@ -9682,10 +10026,27 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction return &const_instruction->base; } - IrInstruction *result = ir_build_err_wrap_payload(&ira->new_irb, source_instr->scope, source_instr->source_node, value); + IrResultLocation *result_location = ir_get_result_location(value); + if (result_location != nullptr) { + IrResultLocationErrorUnionPayload *new_result_location = allocate(1); + new_result_location->base.id = IrResultLocationIdErrorUnionPayload; + new_result_location->base.parent = result_location; + new_result_location->base.from_call = result_location->from_call; + assert(result_location->child == nullptr); + result_location->child = &new_result_location->base; + IrInstruction *result = ir_build_result_loc(&ira->new_irb, source_instr->scope, + source_instr->source_node, &new_result_location->base, value); + result->value.data.rh_error_union = RuntimeHintErrorUnionNonError; + result->value.type = wanted_type; + return result; + } else { + result_location = create_alloca_result_loc(ira, wanted_type, false); + } + + IrInstruction *result = ir_build_err_wrap_payload(&ira->new_irb, source_instr->scope, + source_instr->source_node, value, result_location); result->value.type = wanted_type; result->value.data.rh_error_union = RuntimeHintErrorUnionNonError; - ir_add_alloca(ira, result, wanted_type); return result; } @@ -9751,11 +10112,28 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so return &const_instruction->base; } - IrInstruction *result = ir_build_err_wrap_code(&ira->new_irb, source_instr->scope, source_instr->source_node, value); - result->value.type = wanted_type; - result->value.data.rh_error_union = RuntimeHintErrorUnionError; - ir_add_alloca(ira, result, wanted_type); - return result; + IrResultLocation *result_location = ir_get_result_location(value); + if (result_location == nullptr) { + result_location = create_alloca_result_loc(ira, wanted_type, false); + IrInstruction *result = ir_build_err_wrap_code(&ira->new_irb, source_instr->scope, source_instr->source_node, + value, result_location); + result->value.type = wanted_type; + result->value.data.rh_error_union = RuntimeHintErrorUnionError; + return result; + } else { + IrResultLocationErrorUnionCode *new_result_location = allocate(1); + new_result_location->base.id = IrResultLocationIdErrorUnionCode; + new_result_location->base.parent = result_location; + new_result_location->base.from_call = result_location->from_call; + assert(result_location->child == nullptr); + result_location->child = &new_result_location->base; + IrInstruction *result = ir_build_result_loc(&ira->new_irb, source_instr->scope, + source_instr->source_node, &new_result_location->base, value); + result->value.type = wanted_type; + result->value.data.rh_error_union = RuntimeHintErrorUnionError; + return result; + } + } static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) { @@ -9802,11 +10180,6 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi source_instruction->source_node, value, is_const, is_volatile); new_instruction->value.type = ptr_type; new_instruction->value.data.rh_ptr = RuntimeHintPtrStack; - if (type_has_bits(ptr_type)) { - ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); - assert(fn_entry); - fn_entry->alloca_list.append(new_instruction); - } return new_instruction; } @@ -9846,12 +10219,27 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false); - IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope, - source_instr->source_node, array_ptr, start, end, false); + IrResultLocation *result_location = ir_get_result_location(array_arg); + IrInstruction *result; + if (result_location == nullptr) { + result_location = create_alloca_result_loc(ira, wanted_type, false); + result = ir_build_slice(&ira->new_irb, source_instr->scope, + source_instr->source_node, array_ptr, start, end, false, result_location); + } else { + IrResultLocationArrayToSlice *new_result_location = allocate(1); + new_result_location->base.id = IrResultLocationIdArrayToSlice; + new_result_location->base.parent = result_location; + new_result_location->base.from_call = result_location->from_call; + new_result_location->len = array_type->data.array.len; + assert(result_location->child == nullptr); + result_location->child = &new_result_location->base; + result = ir_build_result_loc(&ira->new_irb, source_instr->scope, + source_instr->source_node, &new_result_location->base, array_arg); + } + result->value.type = wanted_type; result->value.data.rh_slice.id = RuntimeHintSliceIdLen; result->value.data.rh_slice.len = array_type->data.array.len; - ir_add_alloca(ira, result, result->value.type); return result; } @@ -10423,7 +10811,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (const_cast_result.id == ConstCastResultIdInvalid) return ira->codegen->invalid_instruction; if (const_cast_result.id == ConstCastResultIdOk) { - return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop); } // widening conversion @@ -10748,7 +11136,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } else { zig_unreachable(); } - return ir_resolve_cast(ira, source_instr, value, wanted_type, op, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, op); } else { return ira->codegen->invalid_instruction; } @@ -10950,9 +11338,13 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc } } } - // TODO if the instruction is a const ref instruction we can skip it + IrResultLocation *result_location = nullptr; + if (source_instruction->id == IrInstructionIdLoadPtr) { + IrInstructionLoadPtr *load_ptr = reinterpret_cast(source_instruction); + result_location = ir_analyze_result_location(ira, load_ptr->result_location, child_type, false); + } IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope, - source_instruction->source_node, ptr); + source_instruction->source_node, ptr, result_location); load_ptr_instruction->value.type = child_type; return load_ptr_instruction; } else { @@ -12807,8 +13199,12 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c ZigType *promise_type = get_promise_type(ira->codegen, return_type); ZigType *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type); + IrResultLocation *result_location = ir_analyze_result_location(ira, call_instruction->result_location, + async_return_type, false); + IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node, - fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst, nullptr); + fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst, nullptr, + result_location); result->value.type = async_return_type; return result; } @@ -12946,9 +13342,7 @@ static ZigVar *get_fn_var_by_index(ZigFn *fn_entry, size_t index) { return fn_entry->variable_list.at(next_var_i); } -static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, - ZigVar *var) -{ +static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) { while (var->next_var != nullptr) { var = var->next_var; } @@ -13002,10 +13396,16 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, no_mem_slot: - IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, - instruction->scope, instruction->source_node, var); - var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type, + ZigType *result_type = get_pointer_to_type_extra(ira->codegen, var->value->type, var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0); + IrResultLocation *result_location = nullptr; + if (instruction->id == IrInstructionIdVarPtr) { + IrInstructionVarPtr *var_inst = reinterpret_cast(instruction); + result_location = ir_analyze_result_location(ira, var_inst->result_location, result_type, false); + } + IrInstruction *var_ptr_instruction = ir_build_var_ptr_x(&ira->new_irb, + instruction->scope, instruction->source_node, var, nullptr, result_location); + var_ptr_instruction->value.type = result_type; bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; @@ -13452,19 +13852,19 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call if (call_instruction->is_async) { IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, fn_ref, casted_args, impl_param_count, async_allocator_inst); - ir_add_alloca(ira, result, result->value.type); return ir_finish_anal(ira, result); } assert(async_allocator_inst == nullptr); + IrResultLocation *result_location = ir_analyze_result_location(ira, call_instruction->result_location, + return_type, true); + IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node, impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline, - call_instruction->is_async, nullptr, casted_new_stack); + call_instruction->is_async, nullptr, casted_new_stack, result_location); new_call_instruction->value.type = return_type; - ir_add_alloca(ira, new_call_instruction, return_type); - return ir_finish_anal(ira, new_call_instruction); } @@ -13548,7 +13948,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref, casted_args, call_param_count, async_allocator_inst); - ir_add_alloca(ira, result, result->value.type); return ir_finish_anal(ira, result); } @@ -13558,11 +13957,14 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call return ira->codegen->invalid_instruction; } + IrResultLocation *result_location = ir_analyze_result_location(ira, call_instruction->result_location, + return_type, true); + IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node, - fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr, casted_new_stack); + fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr, casted_new_stack, + result_location); new_call_instruction->value.type = return_type; - ir_add_alloca(ira, new_call_instruction, return_type); return ir_finish_anal(ira, new_call_instruction); } @@ -15903,7 +16305,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, IrInstruction *result = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, switch_target_instruction->base.source_node, - target_value_ptr); + target_value_ptr, nullptr); result->value.type = target_type; return result; } @@ -15934,7 +16336,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, } IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, target_value_ptr); + switch_target_instruction->base.source_node, 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, @@ -15959,7 +16361,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, } IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, target_value_ptr); + switch_target_instruction->base.source_node, target_value_ptr, nullptr); enum_value->value.type = target_type; return enum_value; } @@ -16126,7 +16528,7 @@ static IrInstruction *ir_analyze_instruction_array_len(IrAnalyze *ira, array_len_instruction->base.source_node, array_value, field); len_ptr->value.type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_usize, true); IrInstruction *result = ir_build_load_ptr(&ira->new_irb, - array_len_instruction->base.scope, array_len_instruction->base.source_node, len_ptr); + array_len_instruction->base.scope, array_len_instruction->base.source_node, len_ptr, nullptr); result->value.type = ira->codegen->builtin_types.entry_usize; return result; } else { @@ -16207,7 +16609,6 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI instruction->scope, instruction->source_node, container_type, type_field, casted_field_value); new_instruction->value.type = container_type; - ir_add_alloca(ira, new_instruction, container_type); return new_instruction; } @@ -16331,7 +16732,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc instruction->scope, instruction->source_node, container_type, actual_field_count, new_fields); new_instruction->value.type = container_type; - ir_add_alloca(ira, new_instruction, container_type); return new_instruction; } @@ -16436,7 +16836,6 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, instruction->base.scope, instruction->base.source_node, container_type_value, elem_count, new_items); new_instruction->value.type = fixed_size_array_type; - ir_add_alloca(ira, new_instruction, fixed_size_array_type); return new_instruction; } else if (container_type->id == ZigTypeIdVoid) { if (elem_count != 0) { @@ -18062,7 +18461,6 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak, operand_type, success_order, failure_order); result->value.type = get_optional_type(ira->codegen, operand_type); - ir_add_alloca(ira, result, result->value.type); return result; } @@ -18145,7 +18543,7 @@ static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstruct if (target->value.type->id == ZigTypeIdComptimeInt) { if (ir_num_lit_fits_in_other_type(ira, target, dest_type, true)) { - return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpNumLitToConcrete, false); + return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpNumLitToConcrete); } else { return ira->codegen->invalid_instruction; } @@ -18185,7 +18583,7 @@ static IrInstruction *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstru } else { op = CastOpNumLitToConcrete; } - return ir_resolve_cast(ira, &instruction->base, target, dest_type, op, false); + return ir_resolve_cast(ira, &instruction->base, target, dest_type, op); } else { return ira->codegen->invalid_instruction; } @@ -18324,7 +18722,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru } } - return ir_resolve_cast(ira, &instruction->base, casted_value, dest_slice_type, CastOpResizeSlice, true); + return ir_resolve_cast(ira, &instruction->base, casted_value, dest_slice_type, CastOpResizeSlice); } static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToBytes *instruction) { @@ -18351,7 +18749,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct alignment, 0, 0); ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type); - return ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true); + return ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice); } static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) { @@ -18369,7 +18767,7 @@ static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInst return ira->codegen->invalid_instruction; } - return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpIntToFloat, false); + return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpIntToFloat); } static IrInstruction *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrInstructionFloatToInt *instruction) { @@ -18391,7 +18789,7 @@ static IrInstruction *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrInst return ira->codegen->invalid_instruction; } - return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpFloatToInt, false); + return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpFloatToInt); } static IrInstruction *ir_analyze_instruction_err_to_int(IrAnalyze *ira, IrInstructionErrToInt *instruction) { @@ -18443,7 +18841,7 @@ static IrInstruction *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, IrInstr } ZigType *u1_type = get_int_type(ira->codegen, false, 1); - return ir_resolve_cast(ira, &instruction->base, target, u1_type, CastOpBoolToInt, false); + return ir_resolve_cast(ira, &instruction->base, target, u1_type, CastOpBoolToInt); } static IrInstruction *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstructionIntType *instruction) { @@ -18999,9 +19397,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction IrInstruction *new_instruction = ir_build_slice(&ira->new_irb, instruction->base.scope, instruction->base.source_node, - ptr_ptr, casted_start, end, instruction->safety_check_on); + ptr_ptr, casted_start, end, instruction->safety_check_on, nullptr); new_instruction->value.type = return_type; - ir_add_alloca(ira, new_instruction, return_type); return new_instruction; } @@ -21031,6 +21428,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio case IrInstructionIdErrWrapCode: case IrInstructionIdErrWrapPayload: case IrInstructionIdCast: + case IrInstructionIdResultLoc: + case IrInstructionIdPtrOfArrayToSlice: zig_unreachable(); case IrInstructionIdReturn: @@ -21522,6 +21921,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdFromBytes: case IrInstructionIdToBytes: case IrInstructionIdEnumToInt: + case IrInstructionIdResultLoc: + case IrInstructionIdPtrOfArrayToSlice: return false; case IrInstructionIdAsm: diff --git a/src/ir.hpp b/src/ir.hpp index b298750decdd..91d76c7676cd 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -24,4 +24,6 @@ ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_ bool ir_has_side_effects(IrInstruction *instruction); ConstExprValue *const_ptr_pointee(CodeGen *codegen, ConstExprValue *const_val); +IrResultLocation *ir_get_result_location(IrInstruction *base); + #endif diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 3bed716756b0..9c70b6713bee 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -965,6 +965,16 @@ static void ir_print_check_runtime_scope(IrPrint *irp, IrInstructionCheckRuntime fprintf(irp->f, ")"); } +static void ir_print_result_loc(IrPrint *irp, IrInstructionResultLoc *instruction) { + fprintf(irp->f, "resultloc "); + ir_print_other_instruction(irp, instruction->value); +} + +static void ir_print_ptr_of_array_to_slice(IrPrint *irp, IrInstructionPtrOfArrayToSlice *instruction) { + fprintf(irp->f, "PtrOfArrayToSlice "); + ir_print_other_instruction(irp, instruction->value); +} + static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { fprintf(irp->f, "inttoerr "); ir_print_other_instruction(irp, instruction->target); @@ -1771,6 +1781,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdCheckRuntimeScope: ir_print_check_runtime_scope(irp, (IrInstructionCheckRuntimeScope *)instruction); break; + case IrInstructionIdResultLoc: + ir_print_result_loc(irp, (IrInstructionResultLoc *)instruction); + break; + case IrInstructionIdPtrOfArrayToSlice: + ir_print_ptr_of_array_to_slice(irp, (IrInstructionPtrOfArrayToSlice *)instruction); + break; } fprintf(irp->f, "\n"); }