From 5e1003bc81466b8ca0e3a3adb613bac8f34f2712 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 1 May 2019 01:56:06 -0400 Subject: no-copy semantics for basic runtime function call variable init ```zig export fn entry() void { var x: Foo = foo(); } ``` ```llvm define void @entry() #2 !dbg !37 { Entry: %x = alloca %Foo, align 4 call fastcc void @foo(%Foo* sret %x), !dbg !48 call void @llvm.dbg.declare(metadata %Foo* %x, metadata !41, metadata !DIExpression()), !dbg !49 ret void, !dbg !50 } ``` --- src/codegen.cpp | 90 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 36 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 826a9463ac..2cb3584e68 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1982,6 +1982,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty } static void gen_var_debug_decl(CodeGen *g, ZigVar *var) { + if (g->strip_debug_symbols) return; assert(var->di_loc_var != nullptr); AstNode *source_node = var->decl_node; ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc((unsigned)source_node->line + 1, @@ -2288,7 +2289,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { return; } if (fn_walk->id == FnWalkIdCall) { - IrInstructionCall *instruction = fn_walk->data.call.inst; + IrInstructionCallGen *instruction = fn_walk->data.call.inst; bool is_var_args = fn_walk->data.call.is_var_args; for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) { IrInstruction *param_instruction = instruction->args[call_i]; @@ -3328,10 +3329,8 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, ""); } -static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, - IrInstructionDeclVarGen *decl_var_instruction) -{ - ZigVar *var = decl_var_instruction->var; +static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstructionDeclVarGen *instruction) { + ZigVar *var = instruction->var; if (!type_has_bits(var->var_type)) return nullptr; @@ -3339,20 +3338,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, if (var->ref_count == 0 && g->build_mode != BuildModeDebug) return nullptr; - IrInstruction *init_value = decl_var_instruction->init_value; - - bool have_init_expr = !value_is_all_undef(&init_value->value); - - if (have_init_expr) { - ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->var_type, false, false, - PtrLenSingle, var->align_bytes, 0, 0, false); - LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value); - gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val); - } else if (ir_want_runtime_safety(g, &decl_var_instruction->base)) { - uint32_t align_bytes = (var->align_bytes == 0) ? get_abi_alignment(g, var->var_type) : var->align_bytes; - gen_undef_init(g, align_bytes, var->var_type, var->value_ref); - } - + var->value_ref = ir_llvm_value(g, instruction->var_ptr); gen_var_debug_decl(g, var); return nullptr; } @@ -3568,6 +3554,13 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn } } +static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable, + IrInstructionReturnPtr *instruction) +{ + assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type)); + return g->cur_ret_ptr; +} + static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrInstructionElemPtr *instruction) { LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->array_ptr); ZigType *array_ptr_type = instruction->array_ptr->value.type; @@ -3719,7 +3712,7 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) { LLVMAddCallSiteAttribute(call_instr, 1, sret_attr); } -static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) { +static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) { LLVMValueRef fn_val; ZigType *fn_type; if (instruction->fn_entry) { @@ -3742,8 +3735,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr 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; ZigList gen_param_values = {}; + LLVMValueRef result_loc = first_arg_ret ? ir_llvm_value(g, instruction->result_loc) : nullptr; if (first_arg_ret) { - gen_param_values.append(instruction->tmp_ptr); + gen_param_values.append(result_loc); } if (prefix_arg_err_ret_stack) { gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope)); @@ -3751,7 +3745,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, result_loc, err_union_err_index, ""); gen_param_values.append(err_val_ptr); } FnWalk fn_walk = {}; @@ -3794,9 +3788,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, result_loc, err_union_payload_index, ""); LLVMBuildStore(g->builder, result, payload_ptr); - return instruction->tmp_ptr; + return result_loc; } if (src_return_type->id == ZigTypeIdUnreachable) { @@ -3805,11 +3799,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; + return result_loc; } 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; + LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc); + LLVMSetAlignment(store_instr, LLVMGetAlignment(result_loc)); + return result_loc; } else { return result; } @@ -5535,7 +5529,9 @@ static void set_debug_location(CodeGen *g, IrInstruction *instruction) { } static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) { - set_debug_location(g, instruction); + if (!g->strip_debug_symbols) { + set_debug_location(g, instruction); + } switch (instruction->id) { case IrInstructionIdInvalid: @@ -5608,8 +5604,13 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdGlobalAsm: case IrInstructionIdHasDecl: case IrInstructionIdUndeclaredIdent: + case IrInstructionIdCallSrc: + case IrInstructionIdAllocaSrc: zig_unreachable(); + case IrInstructionIdAllocaGen: + return nullptr; + case IrInstructionIdDeclVarGen: return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction); case IrInstructionIdReturn: @@ -5632,10 +5633,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_store_ptr(g, executable, (IrInstructionStorePtr *)instruction); case IrInstructionIdVarPtr: return ir_render_var_ptr(g, executable, (IrInstructionVarPtr *)instruction); + case IrInstructionIdReturnPtr: + return ir_render_return_ptr(g, executable, (IrInstructionReturnPtr *)instruction); case IrInstructionIdElemPtr: return ir_render_elem_ptr(g, executable, (IrInstructionElemPtr *)instruction); - case IrInstructionIdCall: - return ir_render_call(g, executable, (IrInstructionCall *)instruction); + case IrInstructionIdCallGen: + return ir_render_call(g, executable, (IrInstructionCallGen *)instruction); case IrInstructionIdStructFieldPtr: return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); case IrInstructionIdUnionFieldPtr: @@ -6851,6 +6854,26 @@ static void do_code_gen(CodeGen *g) { } // allocate temporary stack data + for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) { + IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i); + ZigType *ptr_type = instruction->base.value.type; + assert(ptr_type->id == ZigTypeIdPointer); + ZigType *child_type = ptr_type->data.pointer.child_type; + if (!type_has_bits(child_type)) + continue; + if (instruction->base.ref_count == 0) + continue; + if (instruction->base.value.special != ConstValSpecialRuntime) { + if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special != + ConstValSpecialRuntime) + { + continue; + } + } + instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint, + get_ptr_align(g, ptr_type)); + } + 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; @@ -6873,9 +6896,6 @@ static void do_code_gen(CodeGen *g) { } 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; @@ -6939,8 +6959,6 @@ static void do_code_gen(CodeGen *g) { } if (var->src_arg_index == SIZE_MAX) { - var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes); - var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name), import->data.structure.root_struct->di_file, (unsigned)(var->decl_node->line + 1), get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0); -- cgit v1.2.3 From a4aca787229e3b0b3dc992b747cc72a561c2078c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 30 May 2019 17:05:06 -0400 Subject: no-copy semantics for if expr ```zig export fn entry() void { var c = true; var x = if (c) u8(4) else u32(10); } ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %c = alloca i1, align 1 %x = alloca i32, align 4 store i1 true, i1* %c, align 1, !dbg !44 call void @llvm.dbg.declare(metadata i1* %c, metadata !39, metadata !DIExpression()), !dbg !45 %0 = load i1, i1* %c, align 1, !dbg !46 br i1 %0, label %Then, label %Else, !dbg !46 Then: ; preds = %Entry br label %EndIf, !dbg !47 Else: ; preds = %Entry br label %EndIf, !dbg !47 EndIf: ; preds = %Else, %Then %1 = phi i32 [ 4, %Then ], [ 10, %Else ], !dbg !47 store i32 %1, i32* %x, align 4, !dbg !47 call void @llvm.dbg.declare(metadata i32* %x, metadata !42, metadata !DIExpression()), !dbg !48 ret void, !dbg !49 } ``` --- BRANCH_TODO | 18 ++ src/all_types.hpp | 43 ++++- src/codegen.cpp | 5 +- src/ir.cpp | 483 +++++++++++++++++++++++++++++++++++------------------- src/ir_print.cpp | 27 +++ 5 files changed, 404 insertions(+), 172 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 294d3e677f..ffcf35d810 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -8,3 +8,21 @@ migrate all the alloca_list to alloca_gen_list migrate ir_build_var_decl_src to use ir_build_alloca_src and explicitly initialize inferred comptime + + + if (lval == LValNone) { + if (result_loc->id == ResultLocIdNone) + return value; + } + + assert(lval == LValPtr); + + // We needed a pointer to a value, but we got a value. So we create + // an instruction which just makes a pointer of it. + return ir_build_ref(irb, scope, value->source_node, value, false, false); + +handle if with no else + +handle comptime if condition + +handle mixed runtime and comptime peers diff --git a/src/all_types.hpp b/src/all_types.hpp index ae8d9c3fb8..79ad2f8958 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -42,6 +42,7 @@ struct Tld; struct TldExport; struct IrAnalyze; struct ResultLoc; +struct ResultLocPeer; enum X64CABIClass { X64CABIClass_Unknown, @@ -2127,6 +2128,8 @@ struct IrBasicBlock { const char *name_hint; size_t debug_id; size_t ref_count; + // index into the basic block list + size_t index; LLVMBasicBlockRef llvm_block; LLVMBasicBlockRef llvm_exit_block; // The instruction that referenced this basic block and caused us to @@ -2315,10 +2318,14 @@ enum IrInstructionId { IrInstructionIdUndeclaredIdent, IrInstructionIdAllocaSrc, IrInstructionIdAllocaGen, + IrInstructionIdEndExpr, }; struct IrInstruction { IrInstructionId id; + // true if this instruction was generated by zig and not from user code + bool is_gen; + Scope *scope; AstNode *source_node; ConstExprValue value; @@ -2332,8 +2339,6 @@ struct IrInstruction { // with this child field. IrInstruction *child; IrBasicBlock *owner_bb; - // true if this instruction was generated by zig and not from user code - bool is_gen; }; struct IrInstructionDeclVarSrc { @@ -3571,16 +3576,28 @@ struct IrInstructionAllocaGen { const char *name_hint; }; +struct IrInstructionEndExpr { + IrInstruction base; + + IrInstruction *value; + ResultLoc *result_loc; + LVal lval; +}; + enum ResultLocId { ResultLocIdInvalid, ResultLocIdNone, ResultLocIdVar, ResultLocIdReturn, + ResultLocIdPeer, + ResultLocIdPeerParent, }; struct ResultLoc { ResultLocId id; IrInstruction *source_instruction; + IrInstruction *gen_instruction; + ZigType *implicit_elem_type; }; struct ResultLocNone { @@ -3597,6 +3614,28 @@ struct ResultLocReturn { ResultLoc base; }; +struct ResultLocPeerParent { + ResultLoc base; + + ResultLoc *parent; + ResultLocPeer *peers; + size_t peer_count; + ZigType *resolved_type; +}; + +struct IrSuspendPosition { + size_t basic_block_index; + size_t instruction_index; +}; + +struct ResultLocPeer { + ResultLoc base; + + ResultLocPeerParent *parent; + IrBasicBlock *next_bb; + IrSuspendPosition suspend_pos; +}; + 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 2cb3584e68..ccbf911686 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5606,10 +5606,9 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdUndeclaredIdent: case IrInstructionIdCallSrc: case IrInstructionIdAllocaSrc: - zig_unreachable(); - + case IrInstructionIdEndExpr: case IrInstructionIdAllocaGen: - return nullptr; + zig_unreachable(); case IrInstructionIdDeclVarGen: return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction); diff --git a/src/ir.cpp b/src/ir.cpp index 5b6ce22620..c406a809ca 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -38,6 +38,7 @@ struct IrAnalyze { ZigType *explicit_return_type; AstNode *explicit_return_type_source_node; ZigList src_implicit_return_type_list; + ZigList resume_stack; IrBasicBlock *const_predecessor_bb; }; @@ -159,7 +160,6 @@ enum UndefAllowed { static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, ResultLoc *result_loc); -static IrInstruction *ir_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); static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg); @@ -167,7 +167,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type); static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var); static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op); -static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval); +static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval, ResultLoc *result_loc); static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align); static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val); @@ -184,6 +184,7 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc ZigType *ptr_type); static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *dest_type); +static IrInstruction *ir_resolve_result_runtime(IrAnalyze *ira, ResultLoc *result_loc, ZigType *elem_type); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -387,6 +388,7 @@ static IrBasicBlock *ir_create_basic_block(IrBuilder *irb, Scope *scope, const c result->scope = scope; result->name_hint = name_hint; result->debug_id = exec_next_debug_id(irb->exec); + result->index = SIZE_MAX; // set later return result; } @@ -1036,6 +1038,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAllocaGen *) { return IrInstructionIdAllocaGen; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionEndExpr *) { + return IrInstructionIdEndExpr; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -1373,10 +1379,11 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, FnInline fn_inline, bool is_async, IrInstruction *async_allocator, IrInstruction *new_stack, - IrInstruction *result_loc) + ResultLoc *result_loc, ZigType *return_type) { IrInstructionCallGen *call_instruction = ir_build_instruction(&ira->new_irb, source_instruction->scope, source_instruction->source_node); + call_instruction->base.value.type = return_type; call_instruction->fn_entry = fn_entry; call_instruction->fn_ref = fn_ref; call_instruction->fn_inline = fn_inline; @@ -1385,14 +1392,14 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in call_instruction->is_async = is_async; call_instruction->async_allocator = async_allocator; call_instruction->new_stack = new_stack; - call_instruction->result_loc = result_loc; + call_instruction->result_loc = ir_resolve_result_runtime(ira, result_loc, return_type); if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ira->new_irb.current_basic_block); for (size_t i = 0; i < arg_count; i += 1) ir_ref_instruction(args[i], ira->new_irb.current_basic_block); if (async_allocator != nullptr) ir_ref_instruction(async_allocator, ira->new_irb.current_basic_block); if (new_stack != nullptr) ir_ref_instruction(new_stack, ira->new_irb.current_basic_block); - if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); + if (call_instruction->result_loc != nullptr) ir_ref_instruction(call_instruction->result_loc, ira->new_irb.current_basic_block); return &call_instruction->base; } @@ -3187,6 +3194,19 @@ static IrInstructionAllocaGen *ir_create_alloca_gen(IrAnalyze *ira, IrInstructio return instruction; } +static IrInstruction *ir_build_end_expr(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value, LVal lval, ResultLoc *result_loc) +{ + IrInstructionEndExpr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->value = value; + instruction->lval = lval; + instruction->result_loc = result_loc; + + 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; @@ -3287,6 +3307,7 @@ static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { } static void ir_set_cursor_at_end_and_append_block(IrBuilder *irb, IrBasicBlock *basic_block) { + basic_block->index = irb->exec->basic_block_list.length; irb->exec->basic_block_list.append(basic_block); ir_set_cursor_at_end(irb, basic_block); } @@ -3623,6 +3644,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode // keep the last noreturn statement value around in case we need to return it noreturn_return_value = statement_value; } + // This logic must be kept in sync with + // [STMT_EXPR_TEST_THING] <--- (search this token) if (statement_node->type == NodeTypeDefer && statement_value != irb->codegen->invalid_instruction) { // defer starts a new scope child_scope = statement_node->data.defer.child_scope; @@ -4164,7 +4187,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg; IrInstruction *type_of = ir_build_typeof(irb, scope, node, arg); - return ir_lval_wrap(irb, scope, type_of, lval); + return ir_lval_wrap(irb, scope, type_of, lval, result_loc); } case BuiltinFnIdSetCold: { @@ -4174,7 +4197,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *set_cold = ir_build_set_cold(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_cold, lval); + return ir_lval_wrap(irb, scope, set_cold, lval, result_loc); } case BuiltinFnIdSetRuntimeSafety: { @@ -4184,7 +4207,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *set_safety = ir_build_set_runtime_safety(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_safety, lval); + return ir_lval_wrap(irb, scope, set_safety, lval, result_loc); } case BuiltinFnIdSetFloatMode: { @@ -4194,7 +4217,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *set_float_mode = ir_build_set_float_mode(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_float_mode, lval); + return ir_lval_wrap(irb, scope, set_float_mode, lval, result_loc); } case BuiltinFnIdSizeof: { @@ -4204,7 +4227,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, size_of, lval); + return ir_lval_wrap(irb, scope, size_of, lval, result_loc); } case BuiltinFnIdImport: { @@ -4214,12 +4237,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *import = ir_build_import(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, import, lval); + return ir_lval_wrap(irb, scope, import, lval, result_loc); } case BuiltinFnIdCImport: { IrInstruction *c_import = ir_build_c_import(irb, scope, node); - return ir_lval_wrap(irb, scope, c_import, lval); + return ir_lval_wrap(irb, scope, c_import, lval, result_loc); } case BuiltinFnIdCInclude: { @@ -4234,7 +4257,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } IrInstruction *c_include = ir_build_c_include(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, c_include, lval); + return ir_lval_wrap(irb, scope, c_include, lval, result_loc); } case BuiltinFnIdCDefine: { @@ -4254,7 +4277,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } IrInstruction *c_define = ir_build_c_define(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, c_define, lval); + return ir_lval_wrap(irb, scope, c_define, lval, result_loc); } case BuiltinFnIdCUndef: { @@ -4269,7 +4292,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } IrInstruction *c_undef = ir_build_c_undef(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, c_undef, lval); + return ir_lval_wrap(irb, scope, c_undef, lval, result_loc); } case BuiltinFnIdCompileErr: { @@ -4279,7 +4302,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *compile_err = ir_build_compile_err(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, compile_err, lval); + return ir_lval_wrap(irb, scope, compile_err, lval, result_loc); } case BuiltinFnIdCompileLog: { @@ -4293,7 +4316,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } IrInstruction *compile_log = ir_build_compile_log(irb, scope, node, actual_param_count, args); - return ir_lval_wrap(irb, scope, compile_log, lval); + return ir_lval_wrap(irb, scope, compile_log, lval, result_loc); } case BuiltinFnIdErrName: { @@ -4303,7 +4326,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *err_name = ir_build_err_name(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, err_name, lval); + return ir_lval_wrap(irb, scope, err_name, lval, result_loc); } case BuiltinFnIdEmbedFile: { @@ -4313,7 +4336,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *embed_file = ir_build_embed_file(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, embed_file, lval); + return ir_lval_wrap(irb, scope, embed_file, lval, result_loc); } case BuiltinFnIdCmpxchgWeak: case BuiltinFnIdCmpxchgStrong: @@ -4350,7 +4373,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value, arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak)); - return ir_lval_wrap(irb, scope, cmpxchg, lval); + return ir_lval_wrap(irb, scope, cmpxchg, lval, result_loc); } case BuiltinFnIdFence: { @@ -4360,7 +4383,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *fence = ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered); - return ir_lval_wrap(irb, scope, fence, lval); + return ir_lval_wrap(irb, scope, fence, lval, result_loc); } case BuiltinFnIdDivExact: { @@ -4375,7 +4398,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivExact, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdDivTrunc: { @@ -4390,7 +4413,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivTrunc, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdDivFloor: { @@ -4405,7 +4428,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivFloor, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdRem: { @@ -4420,7 +4443,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemRem, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdMod: { @@ -4435,7 +4458,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemMod, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdSqrt: { @@ -4450,7 +4473,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *ir_sqrt = ir_build_sqrt(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, ir_sqrt, lval); + return ir_lval_wrap(irb, scope, ir_sqrt, lval, result_loc); } case BuiltinFnIdTruncate: { @@ -4465,7 +4488,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *truncate = ir_build_truncate(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, truncate, lval); + return ir_lval_wrap(irb, scope, truncate, lval, result_loc); } case BuiltinFnIdIntCast: { @@ -4480,7 +4503,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_int_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdFloatCast: { @@ -4495,7 +4518,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_float_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdErrSetCast: { @@ -4510,7 +4533,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_err_set_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdFromBytes: { @@ -4525,7 +4548,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdToBytes: { @@ -4535,7 +4558,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *result = ir_build_to_bytes(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdIntToFloat: { @@ -4550,7 +4573,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_int_to_float(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdFloatToInt: { @@ -4565,7 +4588,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_float_to_int(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdErrToInt: { @@ -4575,7 +4598,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *result = ir_build_err_to_int(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdIntToErr: { @@ -4585,7 +4608,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *result = ir_build_int_to_err(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdBoolToInt: { @@ -4595,7 +4618,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *result = ir_build_bool_to_int(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdIntType: { @@ -4610,7 +4633,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, int_type, lval); + return ir_lval_wrap(irb, scope, int_type, lval, result_loc); } case BuiltinFnIdVectorType: { @@ -4625,7 +4648,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, vector_type, lval); + return ir_lval_wrap(irb, scope, vector_type, lval, result_loc); } case BuiltinFnIdMemcpy: { @@ -4645,7 +4668,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg2_value; IrInstruction *ir_memcpy = ir_build_memcpy(irb, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(irb, scope, ir_memcpy, lval); + return ir_lval_wrap(irb, scope, ir_memcpy, lval, result_loc); } case BuiltinFnIdMemset: { @@ -4665,7 +4688,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg2_value; IrInstruction *ir_memset = ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(irb, scope, ir_memset, lval); + return ir_lval_wrap(irb, scope, ir_memset, lval, result_loc); } case BuiltinFnIdMemberCount: { @@ -4675,7 +4698,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *member_count = ir_build_member_count(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, member_count, lval); + return ir_lval_wrap(irb, scope, member_count, lval, result_loc); } case BuiltinFnIdMemberType: { @@ -4691,7 +4714,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *member_type = ir_build_member_type(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, member_type, lval); + return ir_lval_wrap(irb, scope, member_type, lval, result_loc); } case BuiltinFnIdMemberName: { @@ -4707,7 +4730,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *member_name = ir_build_member_name(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, member_name, lval); + return ir_lval_wrap(irb, scope, member_name, lval, result_loc); } case BuiltinFnIdField: { @@ -4736,14 +4759,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *type_info = ir_build_type_info(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, type_info, lval); + return ir_lval_wrap(irb, scope, type_info, lval, result_loc); } case BuiltinFnIdBreakpoint: - return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval, result_loc); case BuiltinFnIdReturnAddress: - return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval, result_loc); case BuiltinFnIdFrameAddress: - return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval, result_loc); case BuiltinFnIdHandle: if (!irb->exec->fn_entry) { add_node_error(irb->codegen, node, buf_sprintf("@handle() called outside of function definition")); @@ -4753,7 +4776,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo add_node_error(irb->codegen, node, buf_sprintf("@handle() in non-async function")); return irb->codegen->invalid_instruction; } - return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval, result_loc); case BuiltinFnIdAlignOf: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -4762,16 +4785,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *align_of = ir_build_align_of(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, align_of, lval); + return ir_lval_wrap(irb, scope, align_of, lval, result_loc); } case BuiltinFnIdAddWithOverflow: - return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd), lval); + return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd), lval, result_loc); case BuiltinFnIdSubWithOverflow: - return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub), lval); + return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub), lval, result_loc); case BuiltinFnIdMulWithOverflow: - return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval); + return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval, result_loc); case BuiltinFnIdShlWithOverflow: - return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval); + return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval, result_loc); case BuiltinFnIdTypeName: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -4780,7 +4803,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *type_name = ir_build_type_name(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, type_name, lval); + return ir_lval_wrap(irb, scope, type_name, lval, result_loc); } case BuiltinFnIdPanic: { @@ -4790,7 +4813,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *panic = ir_build_panic(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, panic, lval); + return ir_lval_wrap(irb, scope, panic, lval, result_loc); } case BuiltinFnIdPtrCast: { @@ -4805,7 +4828,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, ptr_cast, lval); + return ir_lval_wrap(irb, scope, ptr_cast, lval, result_loc); } case BuiltinFnIdBitCast: { @@ -4820,7 +4843,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bit_cast = ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, bit_cast, lval); + return ir_lval_wrap(irb, scope, bit_cast, lval, result_loc); } case BuiltinFnIdIntToPtr: { @@ -4835,7 +4858,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *int_to_ptr = ir_build_int_to_ptr(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, int_to_ptr, lval); + return ir_lval_wrap(irb, scope, int_to_ptr, lval, result_loc); } case BuiltinFnIdPtrToInt: { @@ -4845,7 +4868,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *ptr_to_int = ir_build_ptr_to_int(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, ptr_to_int, lval); + return ir_lval_wrap(irb, scope, ptr_to_int, lval, result_loc); } case BuiltinFnIdTagName: { @@ -4856,7 +4879,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value); IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, actual_tag); - return ir_lval_wrap(irb, scope, tag_name, lval); + return ir_lval_wrap(irb, scope, tag_name, lval, result_loc); } case BuiltinFnIdTagType: { @@ -4866,7 +4889,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *tag_type = ir_build_tag_type(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, tag_type, lval); + return ir_lval_wrap(irb, scope, tag_type, lval, result_loc); } case BuiltinFnIdFieldParentPtr: { @@ -4886,7 +4909,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg2_value; IrInstruction *field_parent_ptr = ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr); - return ir_lval_wrap(irb, scope, field_parent_ptr, lval); + return ir_lval_wrap(irb, scope, field_parent_ptr, lval, result_loc); } case BuiltinFnIdByteOffsetOf: { @@ -4901,7 +4924,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *offset_of = ir_build_byte_offset_of(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, offset_of, lval); + return ir_lval_wrap(irb, scope, offset_of, lval, result_loc); } case BuiltinFnIdBitOffsetOf: { @@ -4916,7 +4939,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *offset_of = ir_build_bit_offset_of(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, offset_of, lval); + return ir_lval_wrap(irb, scope, offset_of, lval, result_loc); } case BuiltinFnIdInlineCall: case BuiltinFnIdNoInlineCall: @@ -4944,7 +4967,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr, result_loc); - return ir_lval_wrap(irb, scope, call, lval); + return ir_lval_wrap(irb, scope, call, lval, result_loc); } case BuiltinFnIdNewStackCall: { @@ -4975,7 +4998,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, false, nullptr, new_stack, result_loc); - return ir_lval_wrap(irb, scope, call, lval); + return ir_lval_wrap(irb, scope, call, lval, result_loc); } case BuiltinFnIdTypeId: { @@ -4985,7 +5008,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *type_id = ir_build_type_id(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, type_id, lval); + return ir_lval_wrap(irb, scope, type_id, lval, result_loc); } case BuiltinFnIdShlExact: { @@ -5000,7 +5023,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdShrExact: { @@ -5015,7 +5038,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdSetEvalBranchQuota: { @@ -5025,7 +5048,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *set_eval_branch_quota = ir_build_set_eval_branch_quota(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_eval_branch_quota, lval); + return ir_lval_wrap(irb, scope, set_eval_branch_quota, lval, result_loc); } case BuiltinFnIdAlignCast: { @@ -5040,17 +5063,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *align_cast = ir_build_align_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, align_cast, lval); + return ir_lval_wrap(irb, scope, align_cast, lval, result_loc); } case BuiltinFnIdOpaqueType: { IrInstruction *opaque_type = ir_build_opaque_type(irb, scope, node); - return ir_lval_wrap(irb, scope, opaque_type, lval); + return ir_lval_wrap(irb, scope, opaque_type, lval, result_loc); } case BuiltinFnIdThis: { IrInstruction *this_inst = ir_gen_this(irb, scope, node); - return ir_lval_wrap(irb, scope, this_inst, lval); + return ir_lval_wrap(irb, scope, this_inst, lval, result_loc); } case BuiltinFnIdSetAlignStack: { @@ -5060,7 +5083,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *set_align_stack = ir_build_set_align_stack(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_align_stack, lval); + return ir_lval_wrap(irb, scope, set_align_stack, lval, result_loc); } case BuiltinFnIdArgType: { @@ -5075,7 +5098,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *arg_type = ir_build_arg_type(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, arg_type, lval); + return ir_lval_wrap(irb, scope, arg_type, lval, result_loc); } case BuiltinFnIdExport: { @@ -5095,12 +5118,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg2_value; IrInstruction *ir_export = ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(irb, scope, ir_export, lval); + return ir_lval_wrap(irb, scope, ir_export, lval, result_loc); } case BuiltinFnIdErrorReturnTrace: { IrInstruction *error_return_trace = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null); - return ir_lval_wrap(irb, scope, error_return_trace, lval); + return ir_lval_wrap(irb, scope, error_return_trace, lval, result_loc); } case BuiltinFnIdAtomicRmw: { @@ -5168,7 +5191,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_int_to_enum(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdEnumToInt: { @@ -5178,7 +5201,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *result = ir_build_enum_to_int(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdCtz: case BuiltinFnIdPopCount: @@ -5216,7 +5239,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo default: zig_unreachable(); } - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdHasDecl: { @@ -5231,7 +5254,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *has_decl = ir_build_has_decl(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, has_decl, lval); + return ir_lval_wrap(irb, scope, has_decl, lval, result_loc); } } zig_unreachable(); @@ -5271,10 +5294,12 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr, result_loc); - return ir_lval_wrap(irb, scope, fn_call, lval); + return ir_lval_wrap(irb, scope, fn_call, lval, result_loc); } -static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) { +static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ assert(node->type == NodeTypeIfBoolExpr); IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope); @@ -5295,12 +5320,29 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "Else"); IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "EndIf"); - ir_build_cond_br(irb, scope, condition->source_node, condition, then_block, else_block, is_comptime); + IrInstruction *cond_br_inst = ir_build_cond_br(irb, scope, condition->source_node, condition, + then_block, else_block, is_comptime); + + ResultLocPeerParent *peer_parent = allocate(1); + peer_parent->base.id = ResultLocIdPeerParent; + peer_parent->base.source_instruction = cond_br_inst; + peer_parent->parent = result_loc; + peer_parent->peer_count = 2; + peer_parent->peers = allocate(2); + peer_parent->peers[0].base.id = ResultLocIdPeer; + peer_parent->peers[0].base.source_instruction = cond_br_inst; + peer_parent->peers[0].parent = peer_parent; + peer_parent->peers[0].next_bb = else_block; + peer_parent->peers[1].base.id = ResultLocIdPeer; + peer_parent->peers[1].base.source_instruction = cond_br_inst; + peer_parent->peers[1].parent = peer_parent; + peer_parent->peers[1].next_bb = endif_block; ir_set_cursor_at_end_and_append_block(irb, then_block); Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); - IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope); + IrInstruction *then_expr_result = ir_gen_node_extra(irb, then_node, subexpr_scope, lval, + &peer_parent->peers[0].base); if (then_expr_result == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; IrBasicBlock *after_then_block = irb->current_basic_block; @@ -5310,7 +5352,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode ir_set_cursor_at_end_and_append_block(irb, else_block); IrInstruction *else_expr_result; if (else_node) { - else_expr_result = ir_gen_node(irb, else_node, subexpr_scope); + else_expr_result = ir_gen_node_extra(irb, else_node, subexpr_scope, lval, &peer_parent->peers[1].base); if (else_expr_result == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; } else { @@ -5328,7 +5370,8 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode incoming_blocks[0] = after_then_block; incoming_blocks[1] = after_else_block; - return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); + IrInstruction *phi = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); + return ir_lval_wrap(irb, scope, phi, lval, result_loc); } static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) { @@ -5346,15 +5389,28 @@ static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LValNone); } -static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval) { - if (lval != LValPtr) - return value; - if (value == irb->codegen->invalid_instruction) +static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval, + ResultLoc *result_loc) +{ + // This logic must be kept in sync with + // [STMT_EXPR_TEST_THING] <--- (search this token) + if (value == irb->codegen->invalid_instruction || + instr_is_unreachable(value) || + value->source_node->type == NodeTypeDefer || + value->id == IrInstructionIdDeclVarSrc) + { return value; + } + + if (lval == LValPtr) { + // We needed a pointer to a value, but we got a value. So we create + // an instruction which just makes a pointer of it. + return ir_build_ref(irb, scope, value->source_node, value, false, false); + } - // We needed a pointer to a value, but we got a value. So we create - // an instruction which just makes a const pointer of it. - return ir_build_ref(irb, scope, value->source_node, value, false, false); + // TODO remove the lval parameter here + ir_build_end_expr(irb, scope, value->source_node, value, lval, result_loc); + return value; } static PtrLen star_token_to_ptr_len(TokenId token_id) { @@ -5455,7 +5511,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, + ResultLoc *result_loc) +{ assert(node->type == NodeTypePrefixOpExpr); PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; @@ -5464,18 +5522,18 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod case PrefixOpInvalid: zig_unreachable(); case PrefixOpBoolNot: - return ir_lval_wrap(irb, scope, ir_gen_bool_not(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_bool_not(irb, scope, node), lval, result_loc); case PrefixOpBinNot: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot), lval); + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot), lval, result_loc); case PrefixOpNegation: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval); + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval, result_loc); case PrefixOpNegationWrap: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval); + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval, result_loc); case PrefixOpOptional: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval); + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval, result_loc); 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, nullptr), lval); + return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr), lval, result_loc); } } zig_unreachable(); @@ -7677,33 +7735,33 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeTestDecl: zig_unreachable(); case NodeTypeBlock: - return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval, result_loc); case NodeTypeGroupedExpr: return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval, result_loc); case NodeTypeBinOpExpr: - return ir_lval_wrap(irb, scope, ir_gen_bin_op(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_bin_op(irb, scope, node), lval, result_loc); case NodeTypeIntLiteral: - return ir_lval_wrap(irb, scope, ir_gen_int_lit(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_int_lit(irb, scope, node), lval, result_loc); case NodeTypeFloatLiteral: - return ir_lval_wrap(irb, scope, ir_gen_float_lit(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_float_lit(irb, scope, node), lval, result_loc); case NodeTypeCharLiteral: - return ir_lval_wrap(irb, scope, ir_gen_char_lit(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_char_lit(irb, scope, node), lval, result_loc); case NodeTypeSymbol: return ir_gen_symbol(irb, scope, node, lval); case NodeTypeFnCallExpr: return ir_gen_fn_call(irb, scope, node, lval, result_loc); case NodeTypeIfBoolExpr: - return ir_lval_wrap(irb, scope, ir_gen_if_bool_expr(irb, scope, node), lval); + return ir_gen_if_bool_expr(irb, scope, node, lval, result_loc); case NodeTypePrefixOpExpr: - return ir_gen_prefix_op_expr(irb, scope, node, lval); + return ir_gen_prefix_op_expr(irb, scope, node, lval, result_loc); case NodeTypeContainerInitExpr: - return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node), lval, result_loc); case NodeTypeVariableDeclaration: - return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval, result_loc); case NodeTypeWhileExpr: - return ir_lval_wrap(irb, scope, ir_gen_while_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_while_expr(irb, scope, node), lval, result_loc); case NodeTypeForExpr: - return ir_lval_wrap(irb, scope, ir_gen_for_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_for_expr(irb, scope, node), lval, result_loc); case NodeTypeArrayAccessExpr: return ir_gen_array_access(irb, scope, node, lval); case NodeTypeReturnExpr: @@ -7743,59 +7801,59 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); } case NodeTypeBoolLiteral: - return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval, result_loc); case NodeTypeArrayType: - return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval, result_loc); case NodeTypePointerType: - return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval, result_loc); case NodeTypePromiseType: - return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval, result_loc); case NodeTypeStringLiteral: - return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval, result_loc); case NodeTypeUndefinedLiteral: - return ir_lval_wrap(irb, scope, ir_gen_undefined_literal(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_undefined_literal(irb, scope, node), lval, result_loc); case NodeTypeAsmExpr: - return ir_lval_wrap(irb, scope, ir_gen_asm_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_asm_expr(irb, scope, node), lval, result_loc); case NodeTypeNullLiteral: - return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval, result_loc); case NodeTypeIfErrorExpr: - return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval, result_loc); case NodeTypeIfOptional: - return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval, result_loc); case NodeTypeSwitchExpr: - return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval, result_loc); case NodeTypeCompTime: return ir_gen_comptime(irb, scope, node, lval); case NodeTypeErrorType: - return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval, result_loc); case NodeTypeBreak: - return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval, result_loc); case NodeTypeContinue: - return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval, result_loc); case NodeTypeUnreachable: - return ir_lval_wrap(irb, scope, ir_build_unreachable(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_build_unreachable(irb, scope, node), lval, result_loc); case NodeTypeDefer: - return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval, result_loc); 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), lval, result_loc); case NodeTypeUnwrapErrorExpr: - return ir_lval_wrap(irb, scope, ir_gen_catch(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_catch(irb, scope, node), lval, result_loc); case NodeTypeContainerDecl: - return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval, result_loc); case NodeTypeFnProto: - return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval, result_loc); case NodeTypeErrorSetDecl: - return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval, result_loc); case NodeTypeCancel: - return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval, result_loc); case NodeTypeResume: - return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval, result_loc); case NodeTypeAwaitExpr: - return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval, result_loc); case NodeTypeSuspend: - return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval, result_loc); case NodeTypeEnumLiteral: - return ir_lval_wrap(irb, scope, ir_gen_enum_literal(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_enum_literal(irb, scope, node), lval, result_loc); } zig_unreachable(); } @@ -10415,6 +10473,33 @@ static void ir_start_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrBasicBlock *cons ira->const_predecessor_bb = const_predecessor_bb; } +static IrInstruction *ira_suspend(IrAnalyze *ira, IrInstruction *old_instruction, IrBasicBlock *next_bb, + IrSuspendPosition *suspend_pos) +{ + suspend_pos->basic_block_index = ira->old_bb_index; + suspend_pos->instruction_index = ira->instruction_index; + + ira->old_bb_index = next_bb->index; + ira->old_irb.current_basic_block = ira->old_irb.exec->basic_block_list.at(ira->old_bb_index); + assert(ira->old_irb.current_basic_block == next_bb); + ira->instruction_index = 0; + ira->const_predecessor_bb = nullptr; + next_bb->other = ir_get_new_bb_runtime(ira, next_bb, old_instruction); + ira->new_irb.current_basic_block = next_bb->other; + return ira->codegen->unreach_instruction; +} + +static IrInstruction *ira_resume(IrAnalyze *ira) { + IrSuspendPosition pos = ira->resume_stack.pop(); + ira->old_bb_index = pos.basic_block_index; + ira->old_irb.current_basic_block = ira->old_irb.exec->basic_block_list.at(ira->old_bb_index); + ira->instruction_index = pos.instruction_index; + ira->const_predecessor_bb = nullptr; + ira->new_irb.current_basic_block = ira->old_irb.current_basic_block->other; + assert(ira->new_irb.current_basic_block != nullptr); + return ira->codegen->unreach_instruction; +} + static void ir_finish_bb(IrAnalyze *ira) { ira->new_irb.exec->basic_block_list.append(ira->new_irb.current_basic_block); ira->instruction_index += 1; @@ -10442,8 +10527,15 @@ static void ir_finish_bb(IrAnalyze *ira) { ira->old_bb_index += 1; continue; } - ira->new_irb.current_basic_block = old_bb->other; + // if there is a resume_stack, pop one from there rather than moving on. + // the last item of the resume stack will be a basic block that will + // move on to the next one below + if (ira->resume_stack.length != 0) { + ira_resume(ira); + return; + } + ira->new_irb.current_basic_block = old_bb->other; ir_start_bb(ira, old_bb, nullptr); return; } @@ -14232,9 +14324,26 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in return &result->base; } -static IrInstruction *ir_resolve_result_loc(IrAnalyze *ira, ResultLoc *result_loc, ZigType *elem_type) { +static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, ResultLoc *result_loc) { + switch (result_loc->id) { + case ResultLocIdInvalid: + case ResultLocIdPeerParent: + case ResultLocIdPeer: + zig_unreachable(); + case ResultLocIdNone: + case ResultLocIdVar: + return nullptr; + case ResultLocIdReturn: + return ira->explicit_return_type; + } + zig_unreachable(); +} + +static IrInstruction *ir_resolve_result_runtime(IrAnalyze *ira, ResultLoc *result_loc, ZigType *elem_type) { + result_loc->implicit_elem_type = elem_type; switch (result_loc->id) { case ResultLocIdInvalid: + case ResultLocIdPeerParent: zig_unreachable(); case ResultLocIdNone: return nullptr; @@ -14254,14 +14363,21 @@ static IrInstruction *ir_resolve_result_loc(IrAnalyze *ira, ResultLoc *result_lo return alloca_src->base.child; } case ResultLocIdReturn: { - //ResultLocReturn *result_loc_ret = reinterpret_cast(result_loc); - // TODO implicit cast? - return ir_build_return_ptr(ira, result_loc->source_instruction, elem_type); + ZigType *ptr_return_type = get_pointer_to_type(ira->codegen, ira->explicit_return_type, false); + return ir_build_return_ptr(ira, result_loc->source_instruction, ptr_return_type); } + case ResultLocIdPeer: + return nullptr; } zig_unreachable(); } +static IrInstruction *ir_resolve_result(IrAnalyze *ira, ResultLoc *result_loc, IrInstruction *value) { + IrInstruction *result_inst = ir_resolve_result_runtime(ira, result_loc, value->value.type); + result_loc->gen_instruction = value; + return result_inst; +} + static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst) @@ -14295,12 +14411,9 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc 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); - IrInstruction *result_loc = ir_resolve_result_loc(ira, call_instruction->result_loc, async_return_type); - - IrInstruction *result = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, - casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, result_loc); - result->value.type = async_return_type; - return result; + return ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, + casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, call_instruction->result_loc, + async_return_type); } static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, @@ -15053,12 +15166,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c } assert(async_allocator_inst == nullptr); - IrInstruction *result_loc = ir_resolve_result_loc(ira, call_instruction->result_loc, - impl_fn_type_id->return_type); IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, impl_fn, nullptr, impl_param_count, casted_args, fn_inline, - call_instruction->is_async, nullptr, casted_new_stack, result_loc); - new_call_instruction->value.type = impl_fn_type_id->return_type; + call_instruction->is_async, nullptr, casted_new_stack, call_instruction->result_loc, + impl_fn_type_id->return_type); return ir_finish_anal(ira, new_call_instruction); } @@ -15152,10 +15263,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c return ira->codegen->invalid_instruction; } - IrInstruction *result_loc = ir_resolve_result_loc(ira, call_instruction->result_loc, return_type); IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, - call_param_count, casted_args, fn_inline, false, nullptr, casted_new_stack, result_loc); - new_call_instruction->value.type = return_type; + call_param_count, casted_args, fn_inline, false, nullptr, casted_new_stack, + call_instruction->result_loc, return_type); return ir_finish_anal(ira, new_call_instruction); } @@ -23466,7 +23576,47 @@ static IrInstruction *ir_analyze_instruction_undeclared_ident(IrAnalyze *ira, Ir return ira->codegen->invalid_instruction; } -static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { +static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstructionEndExpr *instruction) { + IrInstruction *value = instruction->value->child; + if (type_is_invalid(value->value.type)) + return ira->codegen->invalid_instruction; + + assert(instruction->lval == LValNone); + + if (instruction->result_loc->id == ResultLocIdPeer) { + ResultLocPeer *result_peer = reinterpret_cast(instruction->result_loc); + ResultLocPeerParent *peer_parent = result_peer->parent; + + if (peer_parent->resolved_type == nullptr && !ira->const_predecessor_bb) { + instruction->result_loc->implicit_elem_type = value->value.type; + instruction->result_loc->gen_instruction = value; + IrInstruction *suspended_inst = ira_suspend(ira, &instruction->base, result_peer->next_bb, + &result_peer->suspend_pos); + bool last_one = (result_peer == &peer_parent->peers[peer_parent->peer_count - 1]); + if (!last_one) { + return suspended_inst; + } + IrInstruction **instructions = allocate(peer_parent->peer_count); + for (size_t i = 0; i < peer_parent->peer_count; i += 1) { + instructions[i] = peer_parent->peers[i].base.gen_instruction; + ira->resume_stack.append(peer_parent->peers[peer_parent->peer_count - i - 1].suspend_pos); + } + ZigType *expected_type = ir_result_loc_expected_type(ira, peer_parent->parent); + peer_parent->resolved_type = ir_resolve_peer_types(ira, + peer_parent->base.source_instruction->source_node, expected_type, instructions, + peer_parent->peer_count); + return ira_resume(ira); + } + } + IrInstruction *result_loc = ir_resolve_result(ira, instruction->result_loc, value); + if (result_loc != nullptr) { + ir_analyze_store_ptr(ira, &instruction->base, result_loc, value); + } + + return ir_const_void(ira, &instruction->base); +} + +static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: case IrInstructionIdWidenOrShorten: @@ -23769,17 +23919,12 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_undeclared_ident(ira, (IrInstructionUndeclaredIdent *)instruction); case IrInstructionIdAllocaSrc: return nullptr; + case IrInstructionIdEndExpr: + return ir_analyze_instruction_end_expr(ira, (IrInstructionEndExpr *)instruction); } zig_unreachable(); } -static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *old_instruction) { - IrInstruction *new_instruction = ir_analyze_instruction_nocast(ira, old_instruction); - ir_assert(new_instruction->value.type != nullptr || new_instruction->value.type != nullptr, old_instruction); - old_instruction->child = new_instruction; - return new_instruction; -} - // This function attempts to evaluate IR code while doing type checking and other analysis. // It emits a new IrExecutable which is partially evaluated IR code. ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec, @@ -23825,8 +23970,11 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ continue; } - IrInstruction *new_instruction = ir_analyze_instruction(ira, old_instruction); + IrInstruction *new_instruction = ir_analyze_instruction_base(ira, old_instruction); if (new_instruction != nullptr) { + ir_assert(new_instruction->value.type != nullptr || new_instruction->value.type != nullptr, old_instruction); + old_instruction->child = new_instruction; + if (type_is_invalid(new_instruction->value.type) && ir_should_inline(new_exec, old_instruction->scope)) { return ira->codegen->builtin_types.entry_invalid; } @@ -23907,6 +24055,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdResizeSlice: case IrInstructionIdGlobalAsm: case IrInstructionIdUndeclaredIdent: + case IrInstructionIdEndExpr: return true; case IrInstructionIdPhi: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 20581a65cf..8eb693671a 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -158,6 +158,16 @@ static const char *ir_un_op_id_str(IrUnOp op_id) { zig_unreachable(); } +static const char *ir_lval_str(LVal lval) { + switch (lval) { + case LValNone: + return "None"; + case LValPtr: + return "Ptr"; + } + zig_unreachable(); +} + static void ir_print_un_op(IrPrint *irp, IrInstructionUnOp *un_op_instruction) { fprintf(irp->f, "%s ", ir_un_op_id_str(un_op_instruction->op_id)); ir_print_other_instruction(irp, un_op_instruction->value); @@ -219,6 +229,12 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) { return; case ResultLocIdVar: return ir_print_result_loc_var(irp, (ResultLocVar *)result_loc); + case ResultLocIdPeer: + fprintf(irp->f, "peer"); + return; + case ResultLocIdPeerParent: + fprintf(irp->f, "peer_parent"); + return; } zig_unreachable(); } @@ -1128,6 +1144,14 @@ static void ir_print_alloca_gen(IrPrint *irp, IrInstructionAllocaGen *instructio fprintf(irp->f, "Alloca(align=%" PRIu32 ",name=%s)", instruction->align, instruction->name_hint); } +static void ir_print_end_expr(IrPrint *irp, IrInstructionEndExpr *instruction) { + fprintf(irp->f, "EndExpr(result="); + ir_print_result_loc(irp, instruction->result_loc); + fprintf(irp->f, ",value="); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ",lval=%s)", ir_lval_str(instruction->lval)); +} + static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { fprintf(irp->f, "inttoerr "); ir_print_other_instruction(irp, instruction->target); @@ -2014,6 +2038,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdAllocaGen: ir_print_alloca_gen(irp, (IrInstructionAllocaGen *)instruction); break; + case IrInstructionIdEndExpr: + ir_print_end_expr(irp, (IrInstructionEndExpr *)instruction); + break; } fprintf(irp->f, "\n"); } -- cgit v1.2.3 From ccce3d852681bfe60bce92a6766b4f431dd73571 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 31 May 2019 01:36:57 -0400 Subject: no-copy semantics for function forwarding ```zig fn foo() Foo { return bar(); } ``` ```llvm define internal fastcc void @foo(%Foo* nonnull sret) unnamed_addr #2 !dbg !48 { Entry: call fastcc void @bar(%Foo* sret %0), !dbg !52 ret void, !dbg !54 } ``` --- src/analyze.cpp | 2 +- src/codegen.cpp | 8 ++++++-- src/ir.cpp | 11 +++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index a62c24460e..24c81d2a3f 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -7278,6 +7278,6 @@ void src_assert(bool ok, AstNode *source_node) { buf_ptr(source_node->owner->data.structure.root_struct->path), (unsigned)source_node->line + 1, (unsigned)source_node->column + 1); } - const char *msg = "assertion failed"; + const char *msg = "assertion failed. This is a bug in the Zig compiler."; stage2_panic(msg, strlen(msg)); } diff --git a/src/codegen.cpp b/src/codegen.cpp index ccbf911686..d468b60183 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1995,7 +1995,7 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { if (!type_has_bits(instruction->value.type)) return nullptr; if (!instruction->llvm_value) { - assert(instruction->value.special != ConstValSpecialRuntime); + src_assert(instruction->value.special != ConstValSpecialRuntime, instruction->source_node); assert(instruction->value.type); render_const_val(g, &instruction->value, ""); // we might have to do some pointer casting here due to the way union @@ -2388,7 +2388,11 @@ 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); + if (return_instruction->value->value.special != ConstValSpecialRuntime) { + // if it's comptime we have to do this but if it's runtime trust that + // result location mechanism took care of it. + gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); + } LLVMBuildRetVoid(g->builder); } else if (handle_is_ptr(return_type)) { LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, ""); diff --git a/src/ir.cpp b/src/ir.cpp index f700404f29..3420a85fce 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1382,6 +1382,9 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in FnInline fn_inline, bool is_async, IrInstruction *async_allocator, IrInstruction *new_stack, ResultLoc *result_loc, ZigType *return_type) { + // must be resolved before building the call instruction + IrInstruction *resolved_result_loc = ir_resolve_result(ira, result_loc, return_type, nullptr); + IrInstructionCallGen *call_instruction = ir_build_instruction(&ira->new_irb, source_instruction->scope, source_instruction->source_node); call_instruction->base.value.type = return_type; @@ -1393,7 +1396,7 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in call_instruction->is_async = is_async; call_instruction->async_allocator = async_allocator; call_instruction->new_stack = new_stack; - call_instruction->result_loc = ir_resolve_result(ira, result_loc, return_type, nullptr); + call_instruction->result_loc = resolved_result_loc; if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ira->new_irb.current_basic_block); for (size_t i = 0; i < arg_count; i += 1) @@ -14347,10 +14350,14 @@ static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, ResultLoc *result_lo } // give nullptr for value to resolve it at runtime -// returns a result location, or nullptr if the result location was already taken care of by this function +// returns a result location, or nullptr if the result location was already taken care of static IrInstruction *ir_resolve_result(IrAnalyze *ira, ResultLoc *result_loc, ZigType *value_type, IrInstruction *value) { + if (result_loc->implicit_elem_type != nullptr) { + // already resolved + return nullptr; + } result_loc->gen_instruction = value; result_loc->implicit_elem_type = value_type; switch (result_loc->id) { -- cgit v1.2.3 From eb8a132d23c5c2a365eb3a8034a381cb74c3436c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Jun 2019 17:46:58 -0400 Subject: var types, alignment, and comptime --- BRANCH_TODO | 47 ++++++++++++++++++ src/all_types.hpp | 9 +++- src/codegen.cpp | 1 + src/ir.cpp | 145 +++++++++++++++++++++++++++--------------------------- src/ir_print.cpp | 23 ++++----- 5 files changed, 141 insertions(+), 84 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 85fc9d9e18..6509246908 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,6 +1,14 @@ Scratch pad for stuff to do before merging master ================================================= + * alignment of consts + * implicit casts + * for loops + * switch expression + * struct initializations + * function call parameters + * bitCast + look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated migrate all the alloca_list to alloca_gen_list @@ -22,3 +30,42 @@ inferred comptime return ir_build_ref(irb, scope, value->source_node, value, false, false); handle if with no else + +for loops: + IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val_ptr); + + IrInstruction *elem_var_type; + if (node->data.for_expr.elem_is_ptr) { + elem_var_type = pointer_type; + } else { + elem_var_type = ir_build_ptr_type_child(irb, parent_scope, elem_node, pointer_type); + } + IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize); +- do they need to have an implicit cast in there for the elem variable? +static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { + IrInstructionToPtrType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->ptr = ptr; + + ir_ref_instruction(ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value) +{ + IrInstructionPtrTypeChild *instruction = ir_build_instruction( + irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +coroutines + ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); + IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); +- implicit cast for the var decl + IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, + get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); diff --git a/src/all_types.hpp b/src/all_types.hpp index 79ad2f8958..c6346ca009 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2277,6 +2277,7 @@ enum IrInstructionId { IrInstructionIdSetEvalBranchQuota, IrInstructionIdPtrType, IrInstructionIdAlignCast, + IrInstructionIdImplicitCast, IrInstructionIdOpaqueType, IrInstructionIdSetAlignStack, IrInstructionIdArgType, @@ -3581,7 +3582,13 @@ struct IrInstructionEndExpr { IrInstruction *value; ResultLoc *result_loc; - LVal lval; +}; + +struct IrInstructionImplicitCast { + IrInstruction base; + + IrInstruction *dest_type; + IrInstruction *target; }; enum ResultLocId { diff --git a/src/codegen.cpp b/src/codegen.cpp index d468b60183..da4be1bf23 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5612,6 +5612,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdAllocaSrc: case IrInstructionIdEndExpr: case IrInstructionIdAllocaGen: + case IrInstructionIdImplicitCast: zig_unreachable(); case IrInstructionIdDeclVarGen: diff --git a/src/ir.cpp b/src/ir.cpp index 3007edff84..35e71be1c2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -891,6 +891,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignCast *) { return IrInstructionIdAlignCast; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionImplicitCast *) { + return IrInstructionIdImplicitCast; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) { return IrInstructionIdOpaqueType; } @@ -1574,17 +1578,15 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode * } static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node, - ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *ptr) + ZigVar *var, IrInstruction *align_value, IrInstruction *ptr) { IrInstructionDeclVarSrc *decl_var_instruction = ir_build_instruction(irb, scope, source_node); decl_var_instruction->base.value.special = ConstValSpecialStatic; decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void; decl_var_instruction->var = var; - decl_var_instruction->var_type = var_type; decl_var_instruction->align_value = align_value; decl_var_instruction->ptr = ptr; - if (var_type != nullptr) ir_ref_instruction(var_type, irb->current_basic_block); if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); ir_ref_instruction(ptr, irb->current_basic_block); @@ -1655,27 +1657,6 @@ static IrInstruction *ir_build_typeof(IrBuilder *irb, Scope *scope, AstNode *sou return &instruction->base; } -static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { - IrInstructionToPtrType *instruction = ir_build_instruction(irb, scope, source_node); - instruction->ptr = ptr; - - ir_ref_instruction(ptr, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value) -{ - IrInstructionPtrTypeChild *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstruction *ir_build_set_cold(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *is_cold) { IrInstructionSetCold *instruction = ir_build_instruction(irb, scope, source_node); instruction->is_cold = is_cold; @@ -2780,6 +2761,19 @@ static IrInstruction *ir_build_align_cast(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } +static IrInstruction *ir_build_implicit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *dest_type, IrInstruction *target) +{ + IrInstructionImplicitCast *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_type = dest_type; + instruction->target = target; + + ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionOpaqueType *instruction = ir_build_instruction(irb, scope, source_node); @@ -3199,11 +3193,10 @@ static IrInstructionAllocaGen *ir_create_alloca_gen(IrAnalyze *ira, IrInstructio } static IrInstruction *ir_build_end_expr(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value, LVal lval, ResultLoc *result_loc) + IrInstruction *value, ResultLoc *result_loc) { IrInstructionEndExpr *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; - instruction->lval = lval; instruction->result_loc = result_loc; ir_ref_instruction(value, irb->current_basic_block); @@ -5399,8 +5392,7 @@ static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode } static IrInstruction *ir_expr_wrap(IrBuilder *irb, Scope *scope, IrInstruction *inst, ResultLoc *result_loc) { - // TODO remove the lval parameter here - ir_build_end_expr(irb, scope, inst->source_node, inst, LValNone, result_loc); + ir_build_end_expr(irb, scope, inst->source_node, inst, result_loc); return inst; } @@ -5607,9 +5599,12 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod return irb->codegen->invalid_instruction; } + // Used for the type expr and the align expr + Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope); + IrInstruction *type_instruction; if (variable_declaration->type != nullptr) { - type_instruction = ir_gen_node(irb, variable_declaration->type, scope); + type_instruction = ir_gen_node(irb, variable_declaration->type, comptime_scope); if (type_instruction == irb->codegen->invalid_instruction) return type_instruction; } else { @@ -5635,7 +5630,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod IrInstruction *align_value = nullptr; if (variable_declaration->align_expr != nullptr) { - align_value = ir_gen_node(irb, variable_declaration->align_expr, scope); + align_value = ir_gen_node(irb, variable_declaration->align_expr, comptime_scope); if (align_value == irb->codegen->invalid_instruction) return align_value; } @@ -5656,19 +5651,24 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod result_loc_var->base.id = ResultLocIdVar; result_loc_var->base.source_instruction = alloca; result_loc_var->var = var; + ResultLoc *init_result_loc = (type_instruction == nullptr) ? &result_loc_var->base : nullptr; // 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_extra(irb, variable_declaration->expr, scope, LValNone, - &result_loc_var->base); + IrInstruction *init_value = ir_gen_node_extra(irb, variable_declaration->expr, scope, LValNone, init_result_loc); irb->exec->name = old_exec_name; if (init_value == irb->codegen->invalid_instruction) - return init_value; + return irb->codegen->invalid_instruction; + + if (type_instruction != nullptr) { + IrInstruction *implicit_cast = ir_build_implicit_cast(irb, scope, node, type_instruction, init_value); + ir_build_end_expr(irb, scope, node, implicit_cast, &result_loc_var->base); + } - return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, alloca); + return ir_build_var_decl_src(irb, scope, node, var, align_value, alloca); } static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -5725,7 +5725,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n 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); - ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value); + ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_value); } ZigList incoming_values = {0}; @@ -5767,7 +5767,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n true, false, false, is_comptime); Scope *err_scope = err_var->child_scope; IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); - ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value); + ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, err_var_value); IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope); if (else_result == irb->codegen->invalid_instruction) @@ -5811,7 +5811,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(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); - ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value); + ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_value); ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; @@ -5953,14 +5953,6 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo if (array_val_ptr == irb->codegen->invalid_instruction) return array_val_ptr; - IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val_ptr); - IrInstruction *elem_var_type; - if (node->data.for_expr.elem_is_ptr) { - elem_var_type = pointer_type; - } else { - elem_var_type = ir_build_ptr_type_child(irb, parent_scope, elem_node, pointer_type); - } - IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); @@ -5970,7 +5962,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo Scope *child_scope = elem_var->child_scope; IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node); - ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value); + ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, nullptr, undefined_value); IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var); AstNode *index_var_source_node; @@ -5985,10 +5977,9 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo } child_scope = index_var->child_scope; - IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize); IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0); IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1); - ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero); + ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, nullptr, zero); IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var); @@ -6380,7 +6371,6 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); Scope *var_scope; if (var_symbol) { - IrInstruction *var_type = nullptr; bool is_shadowable = false; bool is_const = true; ZigVar *var = ir_create_var(irb, node, subexpr_scope, @@ -6388,7 +6378,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(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); - ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_value); var_scope = var->child_scope; } else { var_scope = subexpr_scope; @@ -6455,7 +6445,6 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); Scope *var_scope; if (var_symbol) { - IrInstruction *var_type = nullptr; bool is_shadowable = false; IrInstruction *var_is_comptime = force_comptime ? ir_build_const_bool(irb, subexpr_scope, node, true) : ir_build_test_comptime(irb, subexpr_scope, node, err_val); ZigVar *var = ir_create_var(irb, node, subexpr_scope, @@ -6463,7 +6452,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * 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); - ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_value); var_scope = var->child_scope; } else { var_scope = subexpr_scope; @@ -6481,14 +6470,13 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * if (else_node) { Scope *err_var_scope; if (err_symbol) { - IrInstruction *var_type = nullptr; bool is_shadowable = false; bool is_const = true; ZigVar *var = ir_create_var(irb, node, subexpr_scope, err_symbol, is_const, is_const, is_shadowable, is_comptime); IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr); - ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_value); err_var_scope = var->child_scope; } else { err_var_scope = subexpr_scope; @@ -6551,8 +6539,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); } - IrInstruction *var_type = nullptr; // infer the type - ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, scope, var_symbol_node, var, nullptr, var_value); } else { child_scope = scope; } @@ -7018,7 +7005,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode is_const, is_const, is_shadowable, is_comptime); err_scope = var->child_scope; IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); - ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, err_val); + ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, err_val); } else { err_scope = parent_scope; } @@ -7509,7 +7496,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst); IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type); ir_build_await_bookkeeping(irb, scope, node, promise_result_type); - ir_build_var_decl_src(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value); + ir_build_var_decl_src(irb, scope, node, result_var, nullptr, undefined_value); IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var); ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr); IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle); @@ -7940,17 +7927,13 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node); - ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); - IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa - ir_build_var_decl_src(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef); + ir_build_var_decl_src(irb, coro_scope, node, promise_var, nullptr, undef); coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var); ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); - IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, - get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); - ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); + ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, nullptr, null_value); irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var); u8_ptr_type = ir_build_const_type(irb, coro_scope, node, @@ -7960,11 +7943,11 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); - ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); + ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, coro_size); IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node, ImplicitAllocatorIdArg); irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false); - ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); + ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, implicit_allocator_ptr); Buf *realloc_field_name = buf_create_from_str(ASYNC_REALLOC_FIELD_NAME); IrInstruction *realloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, realloc_field_name); IrInstruction *realloc_fn = ir_build_load_ptr(irb, coro_scope, node, realloc_fn_ptr); @@ -14375,20 +14358,24 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, ResultLoc *result_loc, Z case ResultLocIdNone: return nullptr; case ResultLocIdVar: { - // TODO implicit cast? ResultLocVar *result_loc_var = reinterpret_cast(result_loc); assert(result_loc->source_instruction->id == IrInstructionIdAllocaSrc); IrInstructionAllocaSrc *alloca_src = reinterpret_cast(result_loc->source_instruction); if (alloca_src->base.child == nullptr) { - uint32_t align = 0; // TODO - bool force_comptime = false; // TODO bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime && result_loc_var->var->gen_is_const; IrInstruction *alloca_gen; if (is_comptime) { alloca_gen = ir_get_ref(ira, result_loc->source_instruction, value, true, false); } else { + uint32_t align = 0; + if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, &align)) { + return ira->codegen->invalid_instruction; + } + bool force_comptime; + if (!ir_resolve_comptime(ira, alloca_src->is_comptime->child, &force_comptime)) + return ira->codegen->invalid_instruction; alloca_gen = ir_analyze_alloca(ira, result_loc->source_instruction, value_type, align, alloca_src->name_hint, force_comptime); } @@ -14409,6 +14396,19 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, ResultLoc *result_loc, Z zig_unreachable(); } +static IrInstruction *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, IrInstructionImplicitCast *instruction) { + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); + if (type_is_invalid(dest_type)) + return ira->codegen->invalid_instruction; + + IrInstruction *target = instruction->target->child; + if (type_is_invalid(target->value.type)) + return ira->codegen->invalid_instruction; + + return ir_implicit_cast(ira, target, dest_type); +} + + static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst) @@ -23612,8 +23612,6 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; - assert(instruction->lval == LValNone); - if (instruction->result_loc->id == ResultLocIdPeer) { ResultLocPeer *result_peer = reinterpret_cast(instruction->result_loc); ResultLocPeerParent *peer_parent = result_peer->parent; @@ -23640,7 +23638,7 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct } } IrInstruction *result_loc = ir_resolve_result(ira, instruction->result_loc, value->value.type, value); - if (result_loc != nullptr) { + if (result_loc != nullptr && !type_is_invalid(result_loc->value.type)) { ir_analyze_store_ptr(ira, &instruction->base, result_loc, value); } @@ -23874,6 +23872,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_ptr_type(ira, (IrInstructionPtrType *)instruction); case IrInstructionIdAlignCast: return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction); + case IrInstructionIdImplicitCast: + return ir_analyze_instruction_implicit_cast(ira, (IrInstructionImplicitCast *)instruction); case IrInstructionIdOpaqueType: return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction); case IrInstructionIdSetAlignStack: @@ -24165,6 +24165,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdTypeInfo: case IrInstructionIdTypeId: case IrInstructionIdAlignCast: + case IrInstructionIdImplicitCast: case IrInstructionIdOpaqueType: case IrInstructionIdArgType: case IrInstructionIdTagType: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 8eb693671a..fca5f2edc2 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -158,16 +158,6 @@ static const char *ir_un_op_id_str(IrUnOp op_id) { zig_unreachable(); } -static const char *ir_lval_str(LVal lval) { - switch (lval) { - case LValNone: - return "None"; - case LValPtr: - return "Ptr"; - } - zig_unreachable(); -} - static void ir_print_un_op(IrPrint *irp, IrInstructionUnOp *un_op_instruction) { fprintf(irp->f, "%s ", ir_un_op_id_str(un_op_instruction->op_id)); ir_print_other_instruction(irp, un_op_instruction->value); @@ -1149,7 +1139,7 @@ static void ir_print_end_expr(IrPrint *irp, IrInstructionEndExpr *instruction) { ir_print_result_loc(irp, instruction->result_loc); fprintf(irp->f, ",value="); ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ",lval=%s)", ir_lval_str(instruction->lval)); + fprintf(irp->f, ")"); } static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { @@ -1274,6 +1264,14 @@ static void ir_print_align_cast(IrPrint *irp, IrInstructionAlignCast *instructio fprintf(irp->f, ")"); } +static void ir_print_implicit_cast(IrPrint *irp, IrInstructionImplicitCast *instruction) { + fprintf(irp->f, "@implicitCast("); + ir_print_other_instruction(irp, instruction->dest_type); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->target); + fprintf(irp->f, ")"); +} + static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) { fprintf(irp->f, "@OpaqueType()"); } @@ -1912,6 +1910,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdAlignCast: ir_print_align_cast(irp, (IrInstructionAlignCast *)instruction); break; + case IrInstructionIdImplicitCast: + ir_print_implicit_cast(irp, (IrInstructionImplicitCast *)instruction); + break; case IrInstructionIdOpaqueType: ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction); break; -- cgit v1.2.3 From b6108eed522b7a0122d305dc1a74de8f12f20d5b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Jun 2019 19:11:41 -0400 Subject: fix alignment of consts --- BRANCH_TODO | 1 - src/all_types.hpp | 1 + src/codegen.cpp | 3 ++- src/ir.cpp | 21 ++++++++++++--------- 4 files changed, 15 insertions(+), 11 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 6509246908..e809e2b4d8 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,7 +1,6 @@ Scratch pad for stuff to do before merging master ================================================= - * alignment of consts * implicit casts * for loops * switch expression diff --git a/src/all_types.hpp b/src/all_types.hpp index c6346ca009..0df5384c7a 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -292,6 +292,7 @@ struct RuntimeHintSlice { struct ConstGlobalRefs { LLVMValueRef llvm_value; LLVMValueRef llvm_global; + uint32_t align; }; struct ConstExprValue { diff --git a/src/codegen.cpp b/src/codegen.cpp index da4be1bf23..b03068eb7d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6599,7 +6599,8 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const LLVMSetLinkage(global_value, LLVMInternalLinkage); LLVMSetGlobalConstant(global_value, true); LLVMSetUnnamedAddr(global_value, true); - LLVMSetAlignment(global_value, get_abi_alignment(g, const_val->type)); + LLVMSetAlignment(global_value, (const_val->global_refs->align == 0) ? + get_abi_alignment(g, const_val->type) : const_val->global_refs->align); const_val->global_refs->llvm_global = global_value; } diff --git a/src/ir.cpp b/src/ir.cpp index 35e71be1c2..f8e77cdd72 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14363,19 +14363,22 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, ResultLoc *result_loc, Z IrInstructionAllocaSrc *alloca_src = reinterpret_cast(result_loc->source_instruction); if (alloca_src->base.child == nullptr) { - bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime && - result_loc_var->var->gen_is_const; + bool force_comptime; + if (!ir_resolve_comptime(ira, alloca_src->is_comptime->child, &force_comptime)) + return ira->codegen->invalid_instruction; + bool is_comptime = force_comptime || (value != nullptr && + value->value.special != ConstValSpecialRuntime && result_loc_var->var->gen_is_const); + uint32_t align = 0; + if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, &align)) { + return ira->codegen->invalid_instruction; + } IrInstruction *alloca_gen; if (is_comptime) { + if (align > value->value.global_refs->align) { + value->value.global_refs->align = align; + } alloca_gen = ir_get_ref(ira, result_loc->source_instruction, value, true, false); } else { - uint32_t align = 0; - if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, &align)) { - return ira->codegen->invalid_instruction; - } - bool force_comptime; - if (!ir_resolve_comptime(ira, alloca_src->is_comptime->child, &force_comptime)) - return ira->codegen->invalid_instruction; alloca_gen = ir_analyze_alloca(ira, result_loc->source_instruction, value_type, align, alloca_src->name_hint, force_comptime); } -- cgit v1.2.3 From d4054e35fe3a6ba4b4f0d1a0da0e0149f21b49a4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Jun 2019 20:56:22 -0400 Subject: while loops Note that neither the payload capture variable nor the error capture variable require a stack allocation. ```zig export fn entry() void { var c: anyerror!i32 = 1234; while (c) |hi| {} else |e| {} } ``` ```llvm define void @entry() #2 !dbg !39 { Entry: %c = alloca { i16, i32 }, align 4 %0 = bitcast { i16, i32 }* %c to i8*, !dbg !52 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast ({ i16, i32 }* @0 to i8*), i64 8, i1 false), !dbg !52 call void @llvm.dbg.declare(metadata { i16, i32 }* %c, metadata !43, metadata !DIExpression()), !dbg !52 br label %WhileCond, !dbg !53 WhileCond: ; preds = %WhileBody, %Entry %1 = getelementptr inbounds { i16, i32 }, { i16, i32 }* %c, i32 0, i32 0, !dbg !54 %2 = load i16, i16* %1, align 2, !dbg !54 %3 = icmp ne i16 %2, 0, !dbg !54 br i1 %3, label %WhileElse, label %WhileBody, !dbg !54 WhileBody: ; preds = %WhileCond %4 = getelementptr inbounds { i16, i32 }, { i16, i32 }* %c, i32 0, i32 1, !dbg !53 call void @llvm.dbg.declare(metadata i32* %4, metadata !50, metadata !DIExpression()), !dbg !53 br label %WhileCond, !dbg !53 WhileElse: ; preds = %WhileCond %5 = getelementptr inbounds { i16, i32 }, { i16, i32 }* %c, i32 0, i32 0, !dbg !55 call void @llvm.dbg.declare(metadata i16* %5, metadata !51, metadata !DIExpression()), !dbg !55 ret void, !dbg !56 } ``` --- BRANCH_TODO | 43 ++-------------------- src/all_types.hpp | 3 +- src/codegen.cpp | 14 ++++---- src/ir.cpp | 106 ++++++++++++++++++++++++++++++++++++++---------------- src/ir_print.cpp | 2 +- 5 files changed, 86 insertions(+), 82 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index e809e2b4d8..c85a7aea81 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,7 +1,8 @@ Scratch pad for stuff to do before merging master ================================================= - * implicit casts +migrate ir_build_var_decl_src to use ir_build_alloca_src and explicitly initialize + * for loops * switch expression * struct initializations @@ -12,8 +13,6 @@ look at all the ir_gen_node ir_gen_node_extra calls and make sure result locatio migrate all the alloca_list to alloca_gen_list -migrate ir_build_var_decl_src to use ir_build_alloca_src and explicitly initialize - inferred comptime @@ -30,41 +29,3 @@ inferred comptime handle if with no else -for loops: - IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val_ptr); - - IrInstruction *elem_var_type; - if (node->data.for_expr.elem_is_ptr) { - elem_var_type = pointer_type; - } else { - elem_var_type = ir_build_ptr_type_child(irb, parent_scope, elem_node, pointer_type); - } - IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize); -- do they need to have an implicit cast in there for the elem variable? -static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { - IrInstructionToPtrType *instruction = ir_build_instruction(irb, scope, source_node); - instruction->ptr = ptr; - - ir_ref_instruction(ptr, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value) -{ - IrInstructionPtrTypeChild *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - -coroutines - ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); - IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); -- implicit cast for the var decl - IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, - get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); diff --git a/src/all_types.hpp b/src/all_types.hpp index 0df5384c7a..8726c562d9 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3087,10 +3087,11 @@ struct IrInstructionTestErr { IrInstruction *value; }; +// Takes an error union pointer, returns a pointer to the error code. struct IrInstructionUnwrapErrCode { IrInstruction base; - IrInstruction *err_union; + IrInstruction *err_union_ptr; }; struct IrInstructionUnwrapErrPayload { diff --git a/src/codegen.cpp b/src/codegen.cpp index b03068eb7d..84d5777530 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4878,18 +4878,16 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) { - ZigType *ptr_type = instruction->err_union->value.type; + ZigType *ptr_type = instruction->err_union_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *err_union_type = ptr_type->data.pointer.child_type; ZigType *payload_type = err_union_type->data.error_union.payload_type; - LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union); - LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); - - if (type_has_bits(payload_type)) { - LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); - return gen_load_untyped(g, err_val_ptr, 0, false, ""); + LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union_ptr); + if (!type_has_bits(payload_type)) { + return err_union_ptr; } else { - return err_union_handle; + LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); + return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); } } diff --git a/src/ir.cpp b/src/ir.cpp index f8e77cdd72..1afa435d19 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1657,6 +1657,27 @@ static IrInstruction *ir_build_typeof(IrBuilder *irb, Scope *scope, AstNode *sou return &instruction->base; } +static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { + IrInstructionToPtrType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->ptr = ptr; + + ir_ref_instruction(ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value) +{ + IrInstructionPtrTypeChild *instruction = ir_build_instruction( + irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_set_cold(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *is_cold) { IrInstructionSetCold *instruction = ir_build_instruction(irb, scope, source_node); instruction->is_cold = is_cold; @@ -2371,12 +2392,12 @@ static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *s } static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *err_union) + IrInstruction *err_union_ptr) { IrInstructionUnwrapErrCode *instruction = ir_build_instruction(irb, scope, source_node); - instruction->err_union = err_union; + instruction->err_union_ptr = err_union_ptr; - ir_ref_instruction(err_union, irb->current_basic_block); + ir_ref_instruction(err_union_ptr, irb->current_basic_block); return &instruction->base; } @@ -3505,7 +3526,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, ir_set_cursor_at_end_and_append_block(irb, return_block); if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) { - IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr); + IrInstruction *err_val_ptr = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr); + IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); if (irb->codegen->have_err_ret_tracing && !should_inline) { ir_build_save_err_ret_addr(irb, scope, node); } @@ -5721,11 +5743,11 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_set_cursor_at_end_and_append_block(irb, body_block); if (var_symbol) { - IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node, + IrInstruction *payload_ptr = 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); - ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_value); + IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ? + ir_build_ref(irb, payload_scope, symbol_node, payload_ptr, true, false) : payload_ptr; + ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_ptr); } ZigList incoming_values = {0}; @@ -5766,8 +5788,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ZigVar *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol, true, false, false, is_comptime); Scope *err_scope = err_var->child_scope; - IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); - ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, err_var_value); + IrInstruction *err_ptr = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); + ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, err_ptr); IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope); if (else_result == irb->codegen->invalid_instruction) @@ -5808,10 +5830,10 @@ 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_optional_unwrap_ptr(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); - ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_value); + IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false); + IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ? + ir_build_ref(irb, child_scope, symbol_node, payload_ptr, true, false) : payload_ptr; + ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_ptr); ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; @@ -5953,6 +5975,15 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo if (array_val_ptr == irb->codegen->invalid_instruction) return array_val_ptr; + IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val_ptr); + + IrInstruction *elem_var_type; + if (node->data.for_expr.elem_is_ptr) { + elem_var_type = pointer_type; + } else { + elem_var_type = ir_build_ptr_type_child(irb, parent_scope, elem_node, pointer_type); + } + IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); @@ -5961,8 +5992,9 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); Scope *child_scope = elem_var->child_scope; - IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node); - ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, nullptr, undefined_value); + IrInstruction *undef = ir_build_const_undefined(irb, parent_scope, elem_node); + IrInstruction *undef_elem_var_type = ir_build_implicit_cast(irb, parent_scope, elem_node, elem_var_type, undef); + ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, nullptr, undef_elem_var_type); IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var); AstNode *index_var_source_node; @@ -6475,8 +6507,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * ZigVar *var = ir_create_var(irb, node, subexpr_scope, err_symbol, is_const, is_const, is_shadowable, is_comptime); - IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr); - ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_value); + IrInstruction *err_ptr = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr); + ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, err_ptr); err_var_scope = var->child_scope; } else { err_var_scope = subexpr_scope; @@ -7004,8 +7036,8 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode ZigVar *var = ir_create_var(irb, node, parent_scope, var_name, is_const, is_const, is_shadowable, is_comptime); err_scope = var->child_scope; - IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); - ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, err_val); + IrInstruction *err_ptr = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); + ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, err_ptr); } else { err_scope = parent_scope; } @@ -7482,7 +7514,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise); IrInstruction *const_bool_false = ir_build_const_bool(irb, scope, node, false); - IrInstruction *undefined_value = ir_build_const_undefined(irb, scope, node); + IrInstruction *undef = ir_build_const_undefined(irb, scope, node); IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize); IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0); IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111 @@ -7496,7 +7528,8 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst); IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type); ir_build_await_bookkeeping(irb, scope, node, promise_result_type); - ir_build_var_decl_src(irb, scope, node, result_var, nullptr, undefined_value); + IrInstruction *undef_promise_result = ir_build_implicit_cast(irb, scope, node, promise_result_type, undef); + ir_build_var_decl_src(irb, scope, node, result_var, nullptr, undef_promise_result); IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var); ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr); IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle); @@ -7928,12 +7961,18 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node); // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa - ir_build_var_decl_src(irb, coro_scope, node, promise_var, nullptr, undef); + ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); + IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); + IrInstruction *undef_coro_frame = ir_build_implicit_cast(irb, coro_scope, node, coro_frame_type_value, undef); + ir_build_var_decl_src(irb, coro_scope, node, promise_var, nullptr, undef_coro_frame); coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var); ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); - ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, nullptr, null_value); + IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, + get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); + IrInstruction *null_await_handle = ir_build_implicit_cast(irb, coro_scope, node, await_handle_type_val, null_value); + ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, nullptr, null_await_handle); irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var); u8_ptr_type = ir_build_const_type(irb, coro_scope, node, @@ -13872,7 +13911,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, return ira->codegen->invalid_instruction; } - assert(var_ptr->value.type->id == ZigTypeIdPointer); + // The ir_build_var_decl_src call is supposed to pass a pointer to the allocation, not an initialization value. + ir_assert(var_ptr->value.type->id == ZigTypeIdPointer, &decl_var_instruction->base); ZigType *result_type = var_ptr->value.type->data.pointer.child_type; if (type_is_invalid(result_type)) { @@ -21526,13 +21566,14 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrInstructionUnwrapErrCode *instruction) { - IrInstruction *base_ptr = instruction->err_union->child; + IrInstruction *base_ptr = instruction->err_union_ptr->child; if (type_is_invalid(base_ptr->value.type)) return ira->codegen->invalid_instruction; ZigType *ptr_type = base_ptr->value.type; // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. assert(ptr_type->id == ZigTypeIdPointer); + bool is_ptr_const = ptr_type->data.pointer.is_const; ZigType *type_entry = ptr_type->data.pointer.child_type; if (type_is_invalid(type_entry)) @@ -21554,19 +21595,22 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrI return ira->codegen->invalid_instruction; if (err_union_val->special != ConstValSpecialRuntime) { ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; - assert(err); + assert(err != nullptr); - IrInstruction *result = ir_const(ira, &instruction->base, + IrInstruction *err_set_val = ir_const(ira, &instruction->base, type_entry->data.error_union.err_set_type); - result->value.data.x_err_set = err; - return result; + err_set_val->value.data.x_err_set = err; + err_set_val->value.parent.id = ConstParentIdErrUnionCode; + err_set_val->value.parent.data.p_err_union_code.err_union_val = err_union_val; + + return ir_get_ref(ira, &instruction->base, err_set_val, is_ptr_const, false); } } } IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb, instruction->base.scope, instruction->base.source_node, base_ptr); - result->value.type = type_entry->data.error_union.err_set_type; + result->value.type = get_pointer_to_type(ira->codegen, type_entry->data.error_union.err_set_type, is_ptr_const); return result; } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index fca5f2edc2..7906d57be0 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -957,7 +957,7 @@ static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) { static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) { fprintf(irp->f, "UnwrapErrorCode("); - ir_print_other_instruction(irp, instruction->err_union); + ir_print_other_instruction(irp, instruction->err_union_ptr); fprintf(irp->f, ")"); } -- cgit v1.2.3 From 143d6ada8f93872b94a8f20927e11cae243028d9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Jun 2019 21:40:56 -0400 Subject: no-copy semantics for for loops Note that only the index variable requires a stack allocation, and the memcpy for the element is gone. ```zig export fn entry() void { var buf: [10]i32 = undefined; for (buf) |x| {} } ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %buf = alloca [10 x i32], align 4 %i = alloca i64, align 8 %0 = bitcast [10 x i32]* %buf to i8*, !dbg !47 call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 -86, i64 40, i1 false), !dbg !47 call void @llvm.dbg.declare(metadata [10 x i32]* %buf, metadata !39, metadata !DIExpression()), !dbg !47 store i64 0, i64* %i, align 8, !dbg !48 call void @llvm.dbg.declare(metadata i64* %i, metadata !45, metadata !DIExpression()), !dbg !48 br label %ForCond, !dbg !48 ForCond: ; preds = %ForBody, %Entry %1 = load i64, i64* %i, align 8, !dbg !48 %2 = icmp ult i64 %1, 10, !dbg !48 br i1 %2, label %ForBody, label %ForEnd, !dbg !48 ForBody: ; preds = %ForCond %3 = getelementptr inbounds [10 x i32], [10 x i32]* %buf, i64 0, i64 %1, !dbg !48 call void @llvm.dbg.declare(metadata i32* %3, metadata !46, metadata !DIExpression()), !dbg !49 %4 = add nuw i64 %1, 1, !dbg !48 store i64 %4, i64* %i, align 8, !dbg !48 br label %ForCond, !dbg !48 ForEnd: ; preds = %ForCond ret void, !dbg !50 } ``` --- BRANCH_TODO | 1 - src/all_types.hpp | 14 ---- src/codegen.cpp | 2 - src/ir.cpp | 187 +++++++++++++----------------------------------------- src/ir_print.cpp | 18 ------ 5 files changed, 44 insertions(+), 178 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index c85a7aea81..70fad23791 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -3,7 +3,6 @@ Scratch pad for stuff to do before merging master migrate ir_build_var_decl_src to use ir_build_alloca_src and explicitly initialize - * for loops * switch expression * struct initializations * function call parameters diff --git a/src/all_types.hpp b/src/all_types.hpp index 8726c562d9..6f504efd9c 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2191,8 +2191,6 @@ enum IrInstructionId { IrInstructionIdUnionInit, IrInstructionIdUnreachable, IrInstructionIdTypeOf, - IrInstructionIdToPtrType, - IrInstructionIdPtrTypeChild, IrInstructionIdSetCold, IrInstructionIdSetRuntimeSafety, IrInstructionIdSetFloatMode, @@ -2679,18 +2677,6 @@ struct IrInstructionTypeOf { IrInstruction *value; }; -struct IrInstructionToPtrType { - IrInstruction base; - - IrInstruction *ptr; -}; - -struct IrInstructionPtrTypeChild { - IrInstruction base; - - IrInstruction *value; -}; - struct IrInstructionSetCold { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index 84d5777530..eecc2239db 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5539,8 +5539,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdInvalid: case IrInstructionIdConst: case IrInstructionIdTypeOf: - case IrInstructionIdToPtrType: - case IrInstructionIdPtrTypeChild: case IrInstructionIdFieldPtr: case IrInstructionIdSetCold: case IrInstructionIdSetRuntimeSafety: diff --git a/src/ir.cpp b/src/ir.cpp index 1afa435d19..3b0ed7a17d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -523,14 +523,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeOf *) { return IrInstructionIdTypeOf; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionToPtrType *) { - return IrInstructionIdToPtrType; -} - -static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrTypeChild *) { - return IrInstructionIdPtrTypeChild; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionSetCold *) { return IrInstructionIdSetCold; } @@ -1657,27 +1649,6 @@ static IrInstruction *ir_build_typeof(IrBuilder *irb, Scope *scope, AstNode *sou return &instruction->base; } -static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { - IrInstructionToPtrType *instruction = ir_build_instruction(irb, scope, source_node); - instruction->ptr = ptr; - - ir_ref_instruction(ptr, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value) -{ - IrInstructionPtrTypeChild *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstruction *ir_build_set_cold(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *is_cold) { IrInstructionSetCold *instruction = ir_build_instruction(irb, scope, source_node); instruction->is_cold = is_cold; @@ -5611,6 +5582,14 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A } } +static ResultLocVar *create_var_result_loc(IrInstruction *alloca, ZigVar *var) { + ResultLocVar *result_loc_var = allocate(1); + result_loc_var->base.id = ResultLocIdVar; + result_loc_var->base.source_instruction = alloca; + result_loc_var->var = var; + return result_loc_var; +} + static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeVariableDeclaration); @@ -5669,10 +5648,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod buf_ptr(variable_declaration->symbol), is_comptime); // Create a result location for the initialization expression. - ResultLocVar *result_loc_var = allocate(1); - result_loc_var->base.id = ResultLocIdVar; - result_loc_var->base.source_instruction = alloca; - result_loc_var->var = var; + ResultLocVar *result_loc_var = create_var_result_loc(alloca, var); ResultLoc *init_result_loc = (type_instruction == nullptr) ? &result_loc_var->base : nullptr; // Temporarily set the name of the IrExecutable to the VariableDeclaration @@ -5975,73 +5951,62 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo if (array_val_ptr == irb->codegen->invalid_instruction) return array_val_ptr; - IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val_ptr); - - IrInstruction *elem_var_type; - if (node->data.for_expr.elem_is_ptr) { - elem_var_type = pointer_type; - } else { - elem_var_type = ir_build_ptr_type_child(irb, parent_scope, elem_node, pointer_type); - } - IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); - // TODO make it an error to write to element variable or i variable. - Buf *elem_var_name = elem_node->data.symbol_expr.symbol; - ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); - Scope *child_scope = elem_var->child_scope; - - IrInstruction *undef = ir_build_const_undefined(irb, parent_scope, elem_node); - IrInstruction *undef_elem_var_type = ir_build_implicit_cast(irb, parent_scope, elem_node, elem_var_type, undef); - ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, nullptr, undef_elem_var_type); - IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var); - AstNode *index_var_source_node; ZigVar *index_var; + const char *index_var_name; if (index_node) { index_var_source_node = index_node; - Buf *index_var_name = index_node->data.symbol_expr.symbol; - index_var = ir_create_var(irb, index_node, child_scope, index_var_name, true, false, false, is_comptime); + Buf *index_var_name_buf = index_node->data.symbol_expr.symbol; + index_var = ir_create_var(irb, index_node, parent_scope, index_var_name_buf, true, false, false, is_comptime); + index_var_name = buf_ptr(index_var_name_buf); } else { index_var_source_node = node; - index_var = ir_create_var(irb, node, child_scope, nullptr, true, false, true, is_comptime); + index_var = ir_create_var(irb, node, parent_scope, nullptr, true, false, true, is_comptime); + index_var_name = "i"; } - child_scope = index_var->child_scope; + parent_scope = index_var->parent_scope; - IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0); - IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1); - ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, nullptr, zero); - IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var); + IrInstruction *index_alloca = ir_build_alloca_src(irb, parent_scope, node, nullptr, index_var_name, is_comptime); + ResultLocVar *var_result_loc = create_var_result_loc(index_alloca, index_var); + IrInstruction *zero = ir_build_const_usize(irb, parent_scope, node, 0); + ir_build_end_expr(irb, parent_scope, node, zero, &var_result_loc->base); + ir_build_var_decl_src(irb, parent_scope, index_var_source_node, index_var, nullptr, index_alloca); + IrInstruction *one = ir_build_const_usize(irb, parent_scope, node, 1); + IrInstruction *index_ptr = ir_build_var_ptr(irb, parent_scope, node, index_var); - IrBasicBlock *cond_block = ir_create_basic_block(irb, child_scope, "ForCond"); - IrBasicBlock *body_block = ir_create_basic_block(irb, child_scope, "ForBody"); - IrBasicBlock *end_block = ir_create_basic_block(irb, child_scope, "ForEnd"); - IrBasicBlock *else_block = else_node ? ir_create_basic_block(irb, child_scope, "ForElse") : end_block; - IrBasicBlock *continue_block = ir_create_basic_block(irb, child_scope, "ForContinue"); + + IrBasicBlock *cond_block = ir_create_basic_block(irb, parent_scope, "ForCond"); + IrBasicBlock *body_block = ir_create_basic_block(irb, parent_scope, "ForBody"); + IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "ForEnd"); + IrBasicBlock *else_block = else_node ? ir_create_basic_block(irb, parent_scope, "ForElse") : end_block; + IrBasicBlock *continue_block = ir_create_basic_block(irb, parent_scope, "ForContinue"); Buf *len_field_name = buf_create_from_str("len"); - IrInstruction *len_ref = ir_build_field_ptr(irb, child_scope, node, array_val_ptr, len_field_name); - IrInstruction *len_val = ir_build_load_ptr(irb, child_scope, node, len_ref); - ir_build_br(irb, child_scope, node, cond_block, is_comptime); + IrInstruction *len_ref = ir_build_field_ptr(irb, parent_scope, node, array_val_ptr, len_field_name); + IrInstruction *len_val = ir_build_load_ptr(irb, parent_scope, node, len_ref); + ir_build_br(irb, parent_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 *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false); + IrInstruction *index_val = ir_build_load_ptr(irb, parent_scope, node, index_ptr); + IrInstruction *cond = ir_build_bin_op(irb, parent_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)); - ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, else_block, is_comptime)); + ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, cond, body_block, else_block, is_comptime)); ir_set_cursor_at_end_and_append_block(irb, body_block); - IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, false, PtrLenSingle); - IrInstruction *elem_val; - 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); - } - ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val)); + IrInstruction *elem_ptr = ir_build_elem_ptr(irb, parent_scope, node, array_val_ptr, index_val, false, PtrLenSingle); + // TODO make it an error to write to element variable or i variable. + Buf *elem_var_name = elem_node->data.symbol_expr.symbol; + ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); + Scope *child_scope = elem_var->child_scope; + + IrInstruction *var_ptr = node->data.for_expr.elem_is_ptr ? + ir_build_ref(irb, parent_scope, elem_node, elem_ptr, true, false) : elem_ptr; + ir_build_var_decl_src(irb, parent_scope, elem_node, elem_var, nullptr, var_ptr); ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; @@ -16901,64 +16866,6 @@ static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructio return ir_const_type(ira, &typeof_instruction->base, type_entry); } -static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, - IrInstructionToPtrType *to_ptr_type_instruction) -{ - Error err; - IrInstruction *ptr_ptr = to_ptr_type_instruction->ptr->child; - if (type_is_invalid(ptr_ptr->value.type)) - return ira->codegen->invalid_instruction; - - ZigType *ptr_ptr_type = ptr_ptr->value.type; - assert(ptr_ptr_type->id == ZigTypeIdPointer); - ZigType *type_entry = ptr_ptr_type->data.pointer.child_type; - - ZigType *ptr_type; - if (type_entry->id == ZigTypeIdArray) { - ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.array.child_type, ptr_ptr_type->data.pointer.is_const); - } else if (is_array_ref(type_entry)) { - ptr_type = get_pointer_to_type(ira->codegen, - type_entry->data.pointer.child_type->data.array.child_type, type_entry->data.pointer.is_const); - } else if (is_slice(type_entry)) { - ZigType *slice_ptr_type = type_entry->data.structure.fields[0].type_entry; - ptr_type = adjust_ptr_len(ira->codegen, slice_ptr_type, PtrLenSingle); - // If the pointer is over-aligned, we may have to reduce it based on the alignment of the element type. - if (slice_ptr_type->data.pointer.explicit_alignment != 0) { - ZigType *elem_type = slice_ptr_type->data.pointer.child_type; - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_instruction; - uint32_t elem_align = get_abi_alignment(ira->codegen, elem_type); - uint32_t reduced_align = min(elem_align, slice_ptr_type->data.pointer.explicit_alignment); - ptr_type = adjust_ptr_align(ira->codegen, ptr_type, reduced_align); - } - } else if (type_entry->id == ZigTypeIdArgTuple) { - zig_panic("TODO for loop on var args"); - } else { - ir_add_error_node(ira, to_ptr_type_instruction->base.source_node, - buf_sprintf("expected array type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_instruction; - } - - return ir_const_type(ira, &to_ptr_type_instruction->base, ptr_type); -} - -static IrInstruction *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, - IrInstructionPtrTypeChild *ptr_type_child_instruction) -{ - IrInstruction *type_value = ptr_type_child_instruction->value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_instruction; - - if (type_entry->id != ZigTypeIdPointer) { - ir_add_error_node(ira, ptr_type_child_instruction->base.source_node, - buf_sprintf("expected pointer type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_instruction; - } - - return ir_const_type(ira, &ptr_type_child_instruction->base, type_entry->data.pointer.child_type); -} - static IrInstruction *ir_analyze_instruction_set_cold(IrAnalyze *ira, IrInstructionSetCold *instruction) { if (ira->new_irb.exec->is_inline) { // ignore setCold when running functions at compile time @@ -23751,10 +23658,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_phi(ira, (IrInstructionPhi *)instruction); case IrInstructionIdTypeOf: return ir_analyze_instruction_typeof(ira, (IrInstructionTypeOf *)instruction); - case IrInstructionIdToPtrType: - return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction); - case IrInstructionIdPtrTypeChild: - return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction); case IrInstructionIdSetCold: return ir_analyze_instruction_set_cold(ira, (IrInstructionSetCold *)instruction); case IrInstructionIdSetRuntimeSafety: @@ -24152,8 +24055,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdVarPtr: case IrInstructionIdReturnPtr: case IrInstructionIdTypeOf: - case IrInstructionIdToPtrType: - case IrInstructionIdPtrTypeChild: case IrInstructionIdStructFieldPtr: case IrInstructionIdUnionFieldPtr: case IrInstructionIdArrayType: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 7906d57be0..dbc5ea364c 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -414,18 +414,6 @@ static void ir_print_typeof(IrPrint *irp, IrInstructionTypeOf *instruction) { fprintf(irp->f, ")"); } -static void ir_print_to_ptr_type(IrPrint *irp, IrInstructionToPtrType *instruction) { - fprintf(irp->f, "@toPtrType("); - ir_print_other_instruction(irp, instruction->ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_ptr_type_child(IrPrint *irp, IrInstructionPtrTypeChild *instruction) { - fprintf(irp->f, "@ptrTypeChild("); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); -} - static void ir_print_field_ptr(IrPrint *irp, IrInstructionFieldPtr *instruction) { if (instruction->field_name_buffer) { fprintf(irp->f, "fieldptr "); @@ -1625,12 +1613,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTypeOf: ir_print_typeof(irp, (IrInstructionTypeOf *)instruction); break; - case IrInstructionIdToPtrType: - ir_print_to_ptr_type(irp, (IrInstructionToPtrType *)instruction); - break; - case IrInstructionIdPtrTypeChild: - ir_print_ptr_type_child(irp, (IrInstructionPtrTypeChild *)instruction); - break; case IrInstructionIdFieldPtr: ir_print_field_ptr(irp, (IrInstructionFieldPtr *)instruction); break; -- cgit v1.2.3 From 771e88951a9af48335abe14e4c44b5c4f5b252de Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 8 Jun 2019 18:51:31 -0400 Subject: result location mechanism for struct initialization ```zig export fn entry() void { const static = Foo{ .x = 9, .bar = Bar{ .y = 10 }, }; const runtime = foo(true); } fn foo(c: bool) Foo { return Foo{ .x = 12, .bar = if (c) bar1() else bar2(), }; } fn bar1() Bar { return Bar{ .y = 34 }; } fn bar2() Bar { return Bar{ .y = 56 }; } ``` ```llvm @0 = internal unnamed_addr constant %Foo { i32 9, %Bar { i32 10 } }, align 4 @1 = internal unnamed_addr constant %Bar { i32 34 }, align 4 @2 = internal unnamed_addr constant %Bar { i32 56 }, align 4 define void @entry() #2 !dbg !35 { Entry: %runtime = alloca %Foo, align 4 call void @llvm.dbg.declare(metadata %Foo* @0, metadata !39, metadata !DIExpression()), !dbg !50 call fastcc void @foo(%Foo* sret %runtime, i1 true), !dbg !51 call void @llvm.dbg.declare(metadata %Foo* %runtime, metadata !49, metadata !DIExpression()), !dbg !52 ret void, !dbg !53 } define internal fastcc void @foo(%Foo* nonnull sret, i1) unnamed_addr #2 !dbg !54 { Entry: %c = alloca i1, align 1 store i1 %1, i1* %c, align 1 call void @llvm.dbg.declare(metadata i1* %c, metadata !60, metadata !DIExpression()), !dbg !61 %2 = getelementptr inbounds %Foo, %Foo* %0, i32 0, i32 0, !dbg !62 store i32 12, i32* %2, align 4, !dbg !62 %3 = getelementptr inbounds %Foo, %Foo* %0, i32 0, i32 1, !dbg !64 %4 = load i1, i1* %c, align 1, !dbg !65 br i1 %4, label %Then, label %Else, !dbg !65 Then: ; preds = %Entry call fastcc void @bar1(%Bar* sret %3), !dbg !66 br label %EndIf, !dbg !64 Else: ; preds = %Entry call fastcc void @bar2(%Bar* sret %3), !dbg !67 br label %EndIf, !dbg !64 EndIf: ; preds = %Else, %Then ret void, !dbg !68 } define internal fastcc void @bar1(%Bar* nonnull sret) unnamed_addr #2 !dbg !69 { Entry: %1 = bitcast %Bar* %0 to i8*, !dbg !73 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 bitcast (%Bar* @1 to i8*), i64 4, i1 false), !dbg !73 ret void, !dbg !73 } define internal fastcc void @bar2(%Bar* nonnull sret) unnamed_addr #2 !dbg !75 { Entry: %1 = bitcast %Bar* %0 to i8*, !dbg !76 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 bitcast (%Bar* @2 to i8*), i64 4, i1 false), !dbg !76 ret void, !dbg !76 } !39 = !DILocalVariable(name: "static", scope: !40, file: !5, line: 2, type: !41) !49 = !DILocalVariable(name: "runtime", scope: !40, file: !5, line: 6, type: !41) ``` --- BRANCH_TODO | 8 +- src/all_types.hpp | 49 ++++++++---- src/analyze.cpp | 6 ++ src/analyze.hpp | 1 + src/codegen.cpp | 73 +++++++++-------- src/ir.cpp | 236 +++++++++++++++++++++++++++++++++++++----------------- src/ir_print.cpp | 40 +++++---- 7 files changed, 270 insertions(+), 143 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index fc8a654772..843703e20b 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,8 +1,8 @@ Scratch pad for stuff to do before merging master ================================================= - * struct initializations - * function call parameters + * array initializations + * union initializations * bitCast look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated @@ -25,7 +25,3 @@ inferred comptime return ir_build_ref(irb, scope, value->source_node, value, false, false); handle if with no else - - - - diff --git a/src/all_types.hpp b/src/all_types.hpp index 0061b5999f..fbd788c9d9 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1957,6 +1957,7 @@ enum ScopeId { ScopeIdCompTime, ScopeIdCoroPrelude, ScopeIdRuntime, + ScopeIdElide, }; struct Scope { @@ -1970,6 +1971,14 @@ struct Scope { ScopeId id; }; +// This scope, when activated, causes all the instructions in the scope to be omitted +// from the generated code. +struct ScopeElide { + Scope base; + + bool activated; +}; + // This scope comes from global declarations or from // declarations in a container declaration // NodeTypeContainerDecl @@ -2189,7 +2198,6 @@ enum IrInstructionId { IrInstructionIdResizeSlice, IrInstructionIdContainerInitList, IrInstructionIdContainerInitFields, - IrInstructionIdStructInit, IrInstructionIdUnionInit, IrInstructionIdUnreachable, IrInstructionIdTypeOf, @@ -2279,6 +2287,7 @@ enum IrInstructionId { IrInstructionIdPtrType, IrInstructionIdAlignCast, IrInstructionIdImplicitCast, + IrInstructionIdResolveResult, IrInstructionIdOpaqueType, IrInstructionIdSetAlignStack, IrInstructionIdArgType, @@ -2366,6 +2375,7 @@ struct IrInstructionCondBr { IrBasicBlock *then_block; IrBasicBlock *else_block; IrInstruction *is_comptime; + ResultLoc *result_loc; }; struct IrInstructionBr { @@ -2646,20 +2656,6 @@ struct IrInstructionContainerInitFields { IrInstructionContainerInitFieldsField *fields; }; -struct IrInstructionStructInitField { - IrInstruction *value; - TypeStructField *type_struct_field; -}; - -struct IrInstructionStructInit { - IrInstruction base; - - ZigType *struct_type; - size_t field_count; - IrInstructionStructInitField *fields; - LLVMValueRef tmp_ptr; -}; - struct IrInstructionUnionInit { IrInstruction base; @@ -3581,13 +3577,22 @@ struct IrInstructionImplicitCast { IrInstruction *target; }; +struct IrInstructionResolveResult { + IrInstruction base; + + ResultLoc *result_loc; + IrInstruction *ty; +}; + enum ResultLocId { ResultLocIdInvalid, ResultLocIdNone, ResultLocIdVar, + ResultLocIdField, ResultLocIdReturn, ResultLocIdPeer, ResultLocIdPeerParent, + ResultLocIdInstruction, }; struct ResultLoc { @@ -3597,6 +3602,7 @@ struct ResultLoc { IrInstruction *source_instruction; IrInstruction *gen_instruction; // value to store to the result loc ZigType *implicit_elem_type; + ScopeElide *scope_elide; }; struct ResultLocNone { @@ -3609,6 +3615,14 @@ struct ResultLocVar { ZigVar *var; }; +struct ResultLocField { + ResultLoc base; + + ResultLoc *parent; + Buf *name; + IrInstruction *container_type; +}; + struct ResultLocReturn { ResultLoc base; }; @@ -3636,6 +3650,11 @@ struct ResultLocPeer { IrSuspendPosition suspend_pos; }; +// The result location is the source instruction +struct ResultLocInstruction { + ResultLoc base; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 771e11e93f..6299ac6699 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -166,6 +166,12 @@ Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruct return &scope->base; } +ScopeElide *create_elide_scope(CodeGen *g, AstNode *node, Scope *parent) { + ScopeElide *scope = allocate(1); + init_scope(g, &scope->base, ScopeIdElide, node, parent); + return scope; +} + ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent) { assert(node->type == NodeTypeSuspend); ScopeSuspend *scope = allocate(1); diff --git a/src/analyze.hpp b/src/analyze.hpp index 57f1072355..2f3ec663da 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -121,6 +121,7 @@ ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn * Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent); Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent); Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime); +ScopeElide *create_elide_scope(CodeGen *g, AstNode *node, Scope *parent); void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); diff --git a/src/codegen.cpp b/src/codegen.cpp index eecc2239db..4fa13c39a2 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -715,6 +715,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { case ScopeIdCompTime: case ScopeIdCoroPrelude: case ScopeIdRuntime: + case ScopeIdElide: return get_di_scope(g, scope->parent); } zig_unreachable(); @@ -2383,7 +2384,6 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut } static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { - LLVMValueRef value = ir_llvm_value(g, return_instruction->value); ZigType *return_type = return_instruction->value->value.type; if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) { @@ -2391,13 +2391,16 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns if (return_instruction->value->value.special != ConstValSpecialRuntime) { // if it's comptime we have to do this but if it's runtime trust that // result location mechanism took care of it. + LLVMValueRef value = ir_llvm_value(g, return_instruction->value); gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); } LLVMBuildRetVoid(g->builder); } else if (handle_is_ptr(return_type)) { + LLVMValueRef value = ir_llvm_value(g, return_instruction->value); LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, ""); LLVMBuildRet(g->builder, by_val_value); } else { + LLVMValueRef value = ir_llvm_value(g, return_instruction->value); LLVMBuildRet(g->builder, value); } return nullptr; @@ -5032,29 +5035,6 @@ static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, Ir return get_handle_value(g, tag_field_ptr, tag_type, ptr_type); } -static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, IrInstructionStructInit *instruction) { - 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, - (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); - - ZigType *ptr_type = get_pointer_to_type_extra(g, type_struct_field->type_entry, - false, false, PtrLenSingle, field_align_bytes, - (uint32_t)type_struct_field->bit_offset_in_host, host_int_bytes, false); - - gen_assign_raw(g, field_ptr, ptr_type, value); - } - return instruction->tmp_ptr; -} - static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) { TypeUnionField *type_union_field = instruction->field; @@ -5531,10 +5511,6 @@ static void set_debug_location(CodeGen *g, IrInstruction *instruction) { } static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) { - if (!g->strip_debug_symbols) { - set_debug_location(g, instruction); - } - switch (instruction->id) { case IrInstructionIdInvalid: case IrInstructionIdConst: @@ -5609,6 +5585,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdEndExpr: case IrInstructionIdAllocaGen: case IrInstructionIdImplicitCast: + case IrInstructionIdResolveResult: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -5705,8 +5682,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction); case IrInstructionIdUnionTag: return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction); - case IrInstructionIdStructInit: - return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); case IrInstructionIdUnionInit: return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); case IrInstructionIdPtrCastGen: @@ -5791,6 +5766,34 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, zig_unreachable(); } +static bool scope_is_elided(Scope *scope) { + for (;;) { + switch (scope->id) { + case ScopeIdDecls: + case ScopeIdCompTime: + case ScopeIdCImport: + zig_unreachable(); + case ScopeIdElide: + if (reinterpret_cast(scope)->activated) + return true; + // fallthrough + case ScopeIdBlock: + case ScopeIdDefer: + case ScopeIdDeferExpr: + case ScopeIdVarDecl: + case ScopeIdLoop: + case ScopeIdSuspend: + case ScopeIdCoroPrelude: + case ScopeIdRuntime: + scope = scope->parent; + continue; + case ScopeIdFnDef: + return false; + } + zig_unreachable(); + } +} + static void ir_render(CodeGen *g, ZigFn *fn_entry) { assert(fn_entry); @@ -5806,7 +5809,12 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { if (instruction->ref_count == 0 && !ir_has_side_effects(instruction)) continue; - instruction->llvm_value = ir_render_instruction(g, executable, instruction); + if (!scope_is_elided(instruction->scope)) { + if (!g->strip_debug_symbols) { + set_debug_location(g, instruction); + } + instruction->llvm_value = ir_render_instruction(g, executable, instruction); + } } current_block->llvm_exit_block = LLVMGetInsertBlock(g->builder); } @@ -6891,9 +6899,6 @@ static void do_code_gen(CodeGen *g) { } 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; diff --git a/src/ir.cpp b/src/ir.cpp index 7f5b7da6e1..d34630554c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -616,10 +616,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionRef *) { return IrInstructionIdRef; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { - return IrInstructionIdStructInit; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) { return IrInstructionIdUnionInit; } @@ -888,6 +884,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionImplicitCast *) return IrInstructionIdImplicitCast; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionResolveResult *) { + return IrInstructionIdResolveResult; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) { return IrInstructionIdOpaqueType; } @@ -1517,20 +1517,6 @@ static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, Scope *scop return &container_init_fields_instruction->base; } -static IrInstruction *ir_build_struct_init(IrBuilder *irb, Scope *scope, AstNode *source_node, - ZigType *struct_type, size_t field_count, IrInstructionStructInitField *fields) -{ - IrInstructionStructInit *struct_init_instruction = ir_build_instruction(irb, scope, source_node); - struct_init_instruction->struct_type = struct_type; - struct_init_instruction->field_count = field_count; - struct_init_instruction->fields = fields; - - for (size_t i = 0; i < field_count; i += 1) - ir_ref_instruction(fields[i].value, irb->current_basic_block); - - return &struct_init_instruction->base; -} - static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigType *union_type, TypeUnionField *field, IrInstruction *init_value) { @@ -2764,6 +2750,18 @@ static IrInstruction *ir_build_implicit_cast(IrBuilder *irb, Scope *scope, AstNo return &instruction->base; } +static IrInstruction *ir_build_resolve_result(IrBuilder *irb, Scope *scope, AstNode *source_node, + ResultLoc *result_loc, IrInstruction *ty) +{ + IrInstructionResolveResult *instruction = ir_build_instruction(irb, scope, source_node); + instruction->result_loc = result_loc; + instruction->ty = ty; + + ir_ref_instruction(ty, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionOpaqueType *instruction = ir_build_instruction(irb, scope, source_node); @@ -3220,6 +3218,7 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco case ScopeIdSuspend: case ScopeIdCompTime: case ScopeIdRuntime: + case ScopeIdElide: scope = scope->parent; continue; case ScopeIdDeferExpr: @@ -3276,6 +3275,7 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o case ScopeIdSuspend: case ScopeIdCompTime: case ScopeIdRuntime: + case ScopeIdElide: scope = scope->parent; continue; case ScopeIdDeferExpr: @@ -5549,7 +5549,9 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod zig_unreachable(); } -static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node) { +static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ assert(node->type == NodeTypeContainerInitExpr); AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; @@ -5559,39 +5561,61 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A if (container_type == irb->codegen->invalid_instruction) return container_type; - if (kind == ContainerInitKindStruct) { - size_t field_count = container_init_expr->entries.length; - IrInstructionContainerInitFieldsField *fields = allocate(field_count); - for (size_t i = 0; i < field_count; i += 1) { - AstNode *entry_node = container_init_expr->entries.at(i); - assert(entry_node->type == NodeTypeStructValueField); - - Buf *name = entry_node->data.struct_val_field.name; - AstNode *expr_node = entry_node->data.struct_val_field.expr; - IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope); - if (expr_value == irb->codegen->invalid_instruction) - return expr_value; - - fields[i].name = name; - fields[i].value = expr_value; - fields[i].source_node = entry_node; - } - return ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields); - } else if (kind == ContainerInitKindArray) { - size_t item_count = container_init_expr->entries.length; - IrInstruction **values = allocate(item_count); - for (size_t i = 0; i < item_count; i += 1) { - AstNode *expr_node = container_init_expr->entries.at(i); - IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope); - if (expr_value == irb->codegen->invalid_instruction) - return expr_value; - - values[i] = expr_value; - } - return ir_build_container_init_list(irb, scope, node, container_type, item_count, values); - } else { - zig_unreachable(); + switch (kind) { + case ContainerInitKindStruct: { + src_assert(result_loc->scope_elide == nullptr, node); + result_loc->scope_elide = create_elide_scope(irb->codegen, node, scope); + size_t field_count = container_init_expr->entries.length; + IrInstructionContainerInitFieldsField *fields = allocate(field_count); + for (size_t i = 0; i < field_count; i += 1) { + AstNode *entry_node = container_init_expr->entries.at(i); + assert(entry_node->type == NodeTypeStructValueField); + + Buf *name = entry_node->data.struct_val_field.name; + AstNode *expr_node = entry_node->data.struct_val_field.expr; + + ResultLoc *child_result_loc = nullptr; + if (result_loc != nullptr) { + IrInstruction *container_ptr = ir_build_resolve_result(irb, &result_loc->scope_elide->base, + expr_node, result_loc, container_type); + IrInstruction *field_ptr = ir_build_field_ptr(irb, &result_loc->scope_elide->base, expr_node, + container_ptr, name); + ResultLocInstruction *result_loc_inst = allocate(1); + result_loc_inst->base.id = ResultLocIdInstruction; + result_loc_inst->base.source_instruction = field_ptr; + ir_ref_instruction(field_ptr, irb->current_basic_block); + child_result_loc = &result_loc_inst->base; + } + + IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, &result_loc->scope_elide->base, + LValNone, child_result_loc); + if (expr_value == irb->codegen->invalid_instruction) + return expr_value; + + fields[i].name = name; + fields[i].value = expr_value; + fields[i].source_node = entry_node; + } + IrInstruction *init_fields = ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields); + + return ir_lval_wrap(irb, scope, init_fields, lval, result_loc); + } + case ContainerInitKindArray: { + size_t item_count = container_init_expr->entries.length; + IrInstruction **values = allocate(item_count); + for (size_t i = 0; i < item_count; i += 1) { + AstNode *expr_node = container_init_expr->entries.at(i); + IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope); + if (expr_value == irb->codegen->invalid_instruction) + return expr_value; + + values[i] = expr_value; + } + IrInstruction *init_list = ir_build_container_init_list(irb, scope, node, container_type, item_count, values); + return ir_lval_wrap(irb, scope, init_list, lval, result_loc); + } } + zig_unreachable(); } static ResultLocVar *create_var_result_loc(IrInstruction *alloca, ZigVar *var) { @@ -7885,7 +7909,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypePrefixOpExpr: return ir_gen_prefix_op_expr(irb, scope, node, lval, result_loc); case NodeTypeContainerInitExpr: - return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node), lval, result_loc); + return ir_gen_container_init_expr(irb, scope, node, lval, result_loc); case NodeTypeVariableDeclaration: return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval, result_loc); case NodeTypeWhileExpr: @@ -14468,7 +14492,9 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in return &result->base; } -static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, ResultLoc *result_loc) { +static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, IrInstruction *suspend_source_instr, + ResultLoc *result_loc) +{ switch (result_loc->id) { case ResultLocIdInvalid: case ResultLocIdPeerParent: @@ -14476,6 +14502,30 @@ static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, ResultLoc *result_lo case ResultLocIdNone: case ResultLocIdVar: return nullptr; + case ResultLocIdInstruction: + return result_loc->source_instruction->child->value.type; + case ResultLocIdField: { + if (result_loc->resolved_loc != nullptr) { + ZigType *ptr_type = result_loc->resolved_loc->value.type; + assert(ptr_type->id == ZigTypeIdPointer); + return ptr_type->data.pointer.child_type; + } + ResultLocField *result_loc_field = reinterpret_cast(result_loc); + ZigType *container_type = ir_resolve_type(ira, result_loc_field->container_type->child); + if (type_is_invalid(container_type)) + return ira->codegen->builtin_types.entry_invalid; + if (container_type->id == ZigTypeIdStruct) { + TypeStructField *field = find_struct_type_field(container_type, result_loc_field->name); + if (field == nullptr) { + return ira->codegen->builtin_types.entry_invalid; + } + return field->type_entry; + } else if (container_type->id == ZigTypeIdUnion) { + zig_panic("TODO"); + } else { + zig_unreachable(); + } + } case ResultLocIdReturn: return ira->explicit_return_type; case ResultLocIdPeer: @@ -14491,7 +14541,10 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s ResultLoc *result_loc, ZigType *value_type, IrInstruction *value) { if (result_loc->resolved_loc != nullptr) { - return result_loc->resolved_loc; + // allow to redo the result location if the value is known and comptime and the previous one isn't + if (value == nullptr || !instr_is_comptime(value) || instr_is_comptime(result_loc->resolved_loc)) { + return result_loc->resolved_loc; + } } result_loc->gen_instruction = value; result_loc->implicit_elem_type = value_type; @@ -14524,7 +14577,7 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s return ira->codegen->invalid_instruction; bool is_comptime = force_comptime || (value != nullptr && value->value.special != ConstValSpecialRuntime && result_loc_var->var->gen_is_const); - if (alloca_src->base.child == nullptr) { + if (alloca_src->base.child == nullptr || is_comptime) { uint32_t align = 0; if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, &align)) { return ira->codegen->invalid_instruction; @@ -14539,12 +14592,40 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s alloca_gen = ir_analyze_alloca(ira, result_loc->source_instruction, value_type, align, alloca_src->name_hint, force_comptime); } + if (alloca_src->base.child != nullptr) { + alloca_src->base.child->ref_count = 0; + } alloca_src->base.child = alloca_gen; } result_loc->written = true; result_loc->resolved_loc = is_comptime ? nullptr : alloca_src->base.child; return result_loc->resolved_loc; } + case ResultLocIdInstruction: { + result_loc->written = true; + result_loc->resolved_loc = result_loc->source_instruction->child; + return result_loc->resolved_loc; + } + case ResultLocIdField: { + ResultLocField *result_loc_field = reinterpret_cast(result_loc); + + ZigType *container_type = ir_resolve_type(ira, result_loc_field->container_type->child); + if (type_is_invalid(container_type)) + return ira->codegen->invalid_instruction; + + IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, + result_loc_field->parent, container_type, nullptr); + if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || + parent_result_loc->value.type->id == ZigTypeIdUnreachable) + { + return parent_result_loc; + } + + result_loc->written = true; + result_loc->resolved_loc = ir_analyze_container_field_ptr(ira, result_loc_field->name, + suspend_source_instr, parent_result_loc, container_type); + return result_loc->resolved_loc; + } case ResultLocIdReturn: { bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime; if (is_comptime) return nullptr; @@ -14593,7 +14674,7 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s ira->resume_stack.append(opposite_peer->suspend_pos); } } - ZigType *expected_type = ir_result_loc_expected_type(ira, peer_parent->parent); + ZigType *expected_type = ir_result_loc_expected_type(ira, suspend_source_instr, peer_parent->parent); peer_parent->resolved_type = ir_resolve_peer_types(ira, peer_parent->base.source_instruction->source_node, expected_type, instructions, peer_parent->peer_count); @@ -14626,6 +14707,12 @@ static IrInstruction *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, IrIns return ir_implicit_cast(ira, target, dest_type); } +static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrInstructionResolveResult *instruction) { + ZigType *ty = ir_resolve_type(ira, instruction->ty->child); + if (type_is_invalid(ty)) + return ira->codegen->invalid_instruction; + return ir_resolve_result(ira, &instruction->base, instruction->result_loc, ty, nullptr); +} static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, @@ -18330,8 +18417,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc AstNode **field_assign_nodes = allocate(actual_field_count); - IrInstructionStructInitField *new_fields = allocate(actual_field_count); - bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope) || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; @@ -18371,9 +18456,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc } field_assign_nodes[field_index] = field->source_node; - new_fields[field_index].value = casted_field_value; - new_fields[field_index].type_struct_field = type_field; - if (const_val.special == ConstValSpecialStatic) { if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) { ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk); @@ -18416,9 +18498,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc IrInstruction *runtime_inst = ir_const(ira, instruction, field->init_val->type); copy_const_val(&runtime_inst->value, field->init_val, true); - new_fields[i].value = runtime_inst; - new_fields[i].type_struct_field = field; - if (const_val.special == ConstValSpecialStatic) { copy_const_val(&const_val.data.x_struct.fields[i], field->init_val, true); } @@ -18451,12 +18530,11 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc return ira->codegen->invalid_instruction; } - IrInstruction *new_instruction = ir_build_struct_init(&ira->new_irb, - 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; + // this instruction should not get to codegen + IrInstruction *result = ir_const(ira, instruction, container_type); + // this is how we signal to EndExpr the value is not comptime known + result->value.special = ConstValSpecialRuntime; + return result; } static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, @@ -23794,7 +23872,18 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; - if (!instruction->result_loc->written) { + bool want_resolve_result = instruction->result_loc->written; + if (instruction->result_loc->written) { + if (instruction->result_loc->scope_elide != nullptr && instr_is_comptime(value)) { + want_resolve_result = true; + instruction->result_loc->scope_elide->activated = true; + } else { + want_resolve_result = false; + } + } else { + want_resolve_result = true; + } + if (want_resolve_result) { IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, value->value.type, value); if (result_loc != nullptr) { @@ -23815,7 +23904,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction switch (instruction->id) { case IrInstructionIdInvalid: case IrInstructionIdWidenOrShorten: - case IrInstructionIdStructInit: case IrInstructionIdUnionInit: case IrInstructionIdStructFieldPtr: case IrInstructionIdUnionFieldPtr: @@ -24036,6 +24124,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction); case IrInstructionIdImplicitCast: return ir_analyze_instruction_implicit_cast(ira, (IrInstructionImplicitCast *)instruction); + case IrInstructionIdResolveResult: + return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction); case IrInstructionIdOpaqueType: return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction); case IrInstructionIdSetAlignStack: @@ -24260,7 +24350,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCast: case IrInstructionIdContainerInitList: case IrInstructionIdContainerInitFields: - case IrInstructionIdStructInit: case IrInstructionIdUnionInit: case IrInstructionIdFieldPtr: case IrInstructionIdElemPtr: @@ -24326,6 +24415,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdTypeId: case IrInstructionIdAlignCast: case IrInstructionIdImplicitCast: + case IrInstructionIdResolveResult: case IrInstructionIdOpaqueType: case IrInstructionIdArgType: case IrInstructionIdTagType: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 7d56b157d5..0f80a9b9e3 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -207,6 +207,18 @@ static void ir_print_result_loc_var(IrPrint *irp, ResultLocVar *result_loc_var) fprintf(irp->f, ")"); } +static void ir_print_result_loc_instruction(IrPrint *irp, ResultLocInstruction *result_loc_inst) { + fprintf(irp->f, "inst("); + ir_print_other_instruction(irp, result_loc_inst->base.source_instruction); + fprintf(irp->f, ")"); +} + +static void ir_print_result_loc_field(IrPrint *irp, ResultLocField *result_loc_field) { + fprintf(irp->f, "field(name=%s,type=", buf_ptr(result_loc_field->name)); + ir_print_other_instruction(irp, result_loc_field->container_type); + fprintf(irp->f, ")"); +} + static void ir_print_result_loc_peer(IrPrint *irp, ResultLocPeer *result_loc_peer) { fprintf(irp->f, "peer(next="); ir_print_other_block(irp, result_loc_peer->next_bb); @@ -225,6 +237,10 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) { return; case ResultLocIdVar: return ir_print_result_loc_var(irp, (ResultLocVar *)result_loc); + case ResultLocIdInstruction: + return ir_print_result_loc_instruction(irp, (ResultLocInstruction *)result_loc); + case ResultLocIdField: + return ir_print_result_loc_field(irp, (ResultLocField *)result_loc); case ResultLocIdPeer: return ir_print_result_loc_peer(irp, (ResultLocPeer *)result_loc); case ResultLocIdPeerParent: @@ -352,18 +368,6 @@ static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerI fprintf(irp->f, "} // container init"); } -static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruction) { - fprintf(irp->f, "%s {", buf_ptr(&instruction->struct_type->name)); - for (size_t i = 0; i < instruction->field_count; i += 1) { - IrInstructionStructInitField *field = &instruction->fields[i]; - Buf *field_name = field->type_struct_field->name; - const char *comma = (i == 0) ? "" : ", "; - fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field_name)); - ir_print_other_instruction(irp, field->value); - } - fprintf(irp->f, "} // struct init"); -} - static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) { Buf *field_name = instruction->field->enum_field->name; @@ -1265,6 +1269,12 @@ static void ir_print_implicit_cast(IrPrint *irp, IrInstructionImplicitCast *inst fprintf(irp->f, ")"); } +static void ir_print_resolve_result(IrPrint *irp, IrInstructionResolveResult *instruction) { + fprintf(irp->f, "ResolveResult("); + ir_print_result_loc(irp, instruction->result_loc); + fprintf(irp->f, ")"); +} + static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) { fprintf(irp->f, "@OpaqueType()"); } @@ -1588,9 +1598,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdContainerInitFields: ir_print_container_init_fields(irp, (IrInstructionContainerInitFields *)instruction); break; - case IrInstructionIdStructInit: - ir_print_struct_init(irp, (IrInstructionStructInit *)instruction); - break; case IrInstructionIdUnionInit: ir_print_union_init(irp, (IrInstructionUnionInit *)instruction); break; @@ -1900,6 +1907,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdImplicitCast: ir_print_implicit_cast(irp, (IrInstructionImplicitCast *)instruction); break; + case IrInstructionIdResolveResult: + ir_print_resolve_result(irp, (IrInstructionResolveResult *)instruction); + break; case IrInstructionIdOpaqueType: ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction); break; -- cgit v1.2.3 From 4e2b2822f18577edb614bdc3ec6808a0587662e5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 9 Jun 2019 19:55:15 -0400 Subject: inferred array size of array literals works --- src/codegen.cpp | 27 +-------------------------- src/ir.cpp | 35 ++++++++++++++--------------------- 2 files changed, 15 insertions(+), 47 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 763e1e1c50..b28f041391 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5072,30 +5072,6 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I return instruction->tmp_ptr; } -static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable, - IrInstructionContainerInitList *instruction) -{ - ZigType *array_type = instruction->base.value.type; - assert(array_type->id == ZigTypeIdArray); - LLVMValueRef tmp_array_ptr = instruction->tmp_ptr; - 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->llvm_type), - LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 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); - } - - return tmp_array_ptr; -} - static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) { gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope)); return nullptr; @@ -5586,6 +5562,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdAllocaGen: case IrInstructionIdImplicitCast: case IrInstructionIdResolveResult: + case IrInstructionIdContainerInitList: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -5700,8 +5677,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_int_to_err(g, executable, (IrInstructionIntToErr *)instruction); case IrInstructionIdErrToInt: return ir_render_err_to_int(g, executable, (IrInstructionErrToInt *)instruction); - case IrInstructionIdContainerInitList: - return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction); case IrInstructionIdPanic: return ir_render_panic(g, executable, (IrInstructionPanic *)instruction); case IrInstructionIdTagName: diff --git a/src/ir.cpp b/src/ir.cpp index 84c7dc6342..b29af2a1e2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1484,17 +1484,15 @@ static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *sour } static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *container_type, IrInstruction *elem_type, size_t item_count, IrInstruction **items) + IrInstruction *container_type, size_t item_count, IrInstruction **items) { IrInstructionContainerInitList *container_init_list_instruction = ir_build_instruction(irb, scope, source_node); container_init_list_instruction->container_type = container_type; - container_init_list_instruction->elem_type = elem_type; container_init_list_instruction->item_count = item_count; container_init_list_instruction->items = items; - if (container_type != nullptr) ir_ref_instruction(container_type, irb->current_basic_block); - if (elem_type != nullptr) ir_ref_instruction(elem_type, irb->current_basic_block); + ir_ref_instruction(container_type, irb->current_basic_block); for (size_t i = 0; i < item_count; i += 1) { ir_ref_instruction(items[i], irb->current_basic_block); } @@ -5620,11 +5618,17 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A src_assert(result_loc->scope_elide == nullptr, node); result_loc->scope_elide = create_elide_scope(irb->codegen, node, scope); + size_t item_count = container_init_expr->entries.length; + + if (container_type == nullptr) { + IrInstruction *item_count_inst = ir_build_const_usize(irb, scope, node, item_count); + container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type); + } + src_assert(result_loc != nullptr, node); IrInstruction *container_ptr = ir_build_resolve_result(irb, &result_loc->scope_elide->base, node, result_loc, container_type); - size_t item_count = container_init_expr->entries.length; IrInstruction **values = allocate(item_count); for (size_t i = 0; i < item_count; i += 1) { AstNode *expr_node = container_init_expr->entries.at(i); @@ -5644,7 +5648,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A values[i] = expr_value; } - IrInstruction *init_list = ir_build_container_init_list(irb, scope, node, container_type, elem_type, + IrInstruction *init_list = ir_build_container_init_list(irb, scope, node, container_type, item_count, values); return ir_lval_wrap(irb, scope, init_list, lval, result_loc); } @@ -18538,22 +18542,11 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, { Error err; - size_t elem_count = instruction->item_count; + ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); + if (type_is_invalid(container_type)) + return ira->codegen->invalid_instruction; - ZigType *container_type; - if (instruction->container_type != nullptr) { - container_type = ir_resolve_type(ira, instruction->container_type->child); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_instruction; - } else { - ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child); - if (type_is_invalid(elem_type)) - return ira->codegen->invalid_instruction; - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) { - return ira->codegen->invalid_instruction; - } - container_type = get_array_type(ira->codegen, elem_type, elem_count); - } + size_t elem_count = instruction->item_count; if (is_slice(container_type)) { ir_add_error(ira, &instruction->base, -- cgit v1.2.3 From 1a51bf63047e9a3cd6ae3273296fded82009235c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 11:15:32 -0400 Subject: hook up result locations for union initializations ```zig export fn entry() void { var x = Foo{ .bar = bar() }; } ``` ```llvm define void @entry() #2 !dbg !44 { Entry: %x = alloca %Foo, align 4 %0 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 1, !dbg !68 store i1 true, i1* %0, align 1, !dbg !68 %1 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0, !dbg !68 %2 = bitcast { i32, [4 x i8] }* %1 to %Bar*, !dbg !68 call fastcc void @bar(%Bar* sret %2), !dbg !68 call void @llvm.dbg.declare(metadata %Foo* %x, metadata !48, metadata !DIExpression()), !dbg !69 ret void, !dbg !70 } ``` --- BRANCH_TODO | 1 - src/all_types.hpp | 13 +------ src/codegen.cpp | 49 +++--------------------- src/ir.cpp | 109 ++++++++++++++++++++++++------------------------------ src/ir_print.cpp | 12 ------ 5 files changed, 56 insertions(+), 128 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index df4375ad7d..2744901bfa 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,7 +1,6 @@ Scratch pad for stuff to do before merging master ================================================= - * union initializations * bitCast look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated diff --git a/src/all_types.hpp b/src/all_types.hpp index 703ff5aea1..35e9786baa 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2204,7 +2204,6 @@ enum IrInstructionId { IrInstructionIdResizeSlice, IrInstructionIdContainerInitList, IrInstructionIdContainerInitFields, - IrInstructionIdUnionInit, IrInstructionIdUnreachable, IrInstructionIdTypeOf, IrInstructionIdSetCold, @@ -2520,6 +2519,7 @@ struct IrInstructionStorePtr { struct IrInstructionFieldPtr { IrInstruction base; + bool initializing; IrInstruction *container_ptr; Buf *field_name_buffer; IrInstruction *field_name_expr; @@ -2536,9 +2536,9 @@ struct IrInstructionStructFieldPtr { struct IrInstructionUnionFieldPtr { IrInstruction base; + bool initializing; IrInstruction *union_ptr; TypeUnionField *field; - bool is_const; }; struct IrInstructionElemPtr { @@ -2663,15 +2663,6 @@ struct IrInstructionContainerInitFields { IrInstructionContainerInitFieldsField *fields; }; -struct IrInstructionUnionInit { - IrInstruction base; - - ZigType *union_type; - TypeUnionField *field; - IrInstruction *init_value; - LLVMValueRef tmp_ptr; -}; - struct IrInstructionUnreachable { IrInstruction base; }; diff --git a/src/codegen.cpp b/src/codegen.cpp index b28f041391..eb2e92f627 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3859,7 +3859,12 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab return bitcasted_union_field_ptr; } - if (ir_want_runtime_safety(g, &instruction->base)) { + if (instruction->initializing) { + LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, ""); + LLVMValueRef tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type), + &field->enum_field->value); + gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); + } else if (ir_want_runtime_safety(g, &instruction->base)) { LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, ""); LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, ""); @@ -5035,43 +5040,6 @@ static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, Ir return get_handle_value(g, tag_field_ptr, tag_type, ptr_type); } -static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) { - TypeUnionField *type_union_field = instruction->field; - - if (!type_has_bits(type_union_field->type_entry)) - return nullptr; - - 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, - 0, 0, false); - - LLVMValueRef uncasted_union_ptr; - // Even if safety is off in this block, if the union type has the safety field, we have to populate it - // 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, - union_type->data.unionation.gen_tag_index, ""); - - LLVMValueRef tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type), - &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, - (unsigned)union_type->data.unionation.gen_union_index, ""); - } else { - uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, ""); - } - - LLVMValueRef field_ptr = LLVMBuildBitCast(g->builder, uncasted_union_ptr, get_llvm_type(g, ptr_type), ""); - LLVMValueRef value = ir_llvm_value(g, instruction->init_value); - - gen_assign_raw(g, field_ptr, ptr_type, value); - - return instruction->tmp_ptr; -} - static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) { gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope)); return nullptr; @@ -5659,8 +5627,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction); case IrInstructionIdUnionTag: return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction); - case IrInstructionIdUnionInit: - return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); case IrInstructionIdPtrCastGen: return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction); case IrInstructionIdBitCastGen: @@ -6874,9 +6840,6 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdContainerInitList) { IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction; slot = &container_init_list_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdUnionInit) { - IrInstructionUnionInit *union_init_instruction = (IrInstructionUnionInit *)instruction; - slot = &union_init_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdSlice) { IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction; slot = &slice_instruction->tmp_ptr; diff --git a/src/ir.cpp b/src/ir.cpp index b29af2a1e2..05f95a2480 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -164,7 +164,7 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Zig static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr); static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg); static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, - IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type); + IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing); static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var); static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op); static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval, ResultLoc *result_loc); @@ -616,10 +616,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionRef *) { return IrInstructionIdRef; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) { - return IrInstructionIdUnionInit; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileErr *) { return IrInstructionIdCompileErr; } @@ -1312,12 +1308,13 @@ static IrInstruction *ir_build_field_ptr_instruction(IrBuilder *irb, Scope *scop } static IrInstruction *ir_build_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *container_ptr, Buf *field_name) + IrInstruction *container_ptr, Buf *field_name, bool initializing) { IrInstructionFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->container_ptr = container_ptr; instruction->field_name_buffer = field_name; instruction->field_name_expr = nullptr; + instruction->initializing = initializing; ir_ref_instruction(container_ptr, irb->current_basic_block); @@ -1337,9 +1334,10 @@ static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, Scope *scope, As } static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *union_ptr, TypeUnionField *field) + IrInstruction *union_ptr, TypeUnionField *field, bool initializing) { IrInstructionUnionFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->initializing = initializing; instruction->union_ptr = union_ptr; instruction->field = field; @@ -1517,19 +1515,6 @@ static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, Scope *scop return &container_init_fields_instruction->base; } -static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node, - ZigType *union_type, TypeUnionField *field, IrInstruction *init_value) -{ - IrInstructionUnionInit *union_init_instruction = ir_build_instruction(irb, scope, source_node); - union_init_instruction->union_type = union_type; - union_init_instruction->field = field; - union_init_instruction->init_value = init_value; - - ir_ref_instruction(init_value, irb->current_basic_block); - - return &union_init_instruction->base; -} - static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionUnreachable *unreachable_instruction = ir_build_instruction(irb, scope, source_node); @@ -4121,7 +4106,7 @@ static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode if (container_ref_instruction == irb->codegen->invalid_instruction) return container_ref_instruction; - return ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name); + return ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name, false); } static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *node, IrOverflowOp op) { @@ -5594,7 +5579,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A AstNode *expr_node = entry_node->data.struct_val_field.expr; IrInstruction *field_ptr = ir_build_field_ptr(irb, &result_loc->scope_elide->base, expr_node, - container_ptr, name); + container_ptr, name, true); ResultLocInstruction *result_loc_inst = allocate(1); result_loc_inst->base.id = ResultLocIdInstruction; result_loc_inst->base.source_instruction = field_ptr; @@ -6105,7 +6090,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo IrBasicBlock *continue_block = ir_create_basic_block(irb, parent_scope, "ForContinue"); Buf *len_field_name = buf_create_from_str("len"); - IrInstruction *len_ref = ir_build_field_ptr(irb, parent_scope, node, array_val_ptr, len_field_name); + IrInstruction *len_ref = ir_build_field_ptr(irb, parent_scope, node, array_val_ptr, len_field_name, false); IrInstruction *len_val = ir_build_load_ptr(irb, parent_scope, node, len_ref); ir_build_br(irb, parent_scope, node, cond_block, is_comptime); @@ -7496,7 +7481,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, - atomic_state_field_name); + atomic_state_field_name, false); // set the is_canceled bit IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, @@ -7575,7 +7560,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, - atomic_state_field_name); + atomic_state_field_name, false); // clear the is_suspended bit IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, @@ -7642,12 +7627,12 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, target_inst); Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); - IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name); + IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name, false); if (irb->codegen->have_err_ret_tracing) { IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull); 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 *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name, false); ir_build_store_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr); } @@ -7669,7 +7654,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, - atomic_state_field_name); + atomic_state_field_name, false); IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise); IrInstruction *const_bool_false = ir_build_const_bool(irb, scope, node, false); @@ -7723,12 +7708,12 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_set_cursor_at_end_and_append_block(irb, no_suspend_block); if (irb->codegen->have_err_ret_tracing) { Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME); - IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name); + IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name, false); IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull); ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr); } Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); - IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name); + IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name, false); // 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); @@ -8152,7 +8137,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec build_decl_var_and_init(irb, coro_scope, node, irb->exec->coro_allocator_var, implicit_allocator_ptr, "allocator", const_bool_false); Buf *realloc_field_name = buf_create_from_str(ASYNC_REALLOC_FIELD_NAME); - IrInstruction *realloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, realloc_field_name); + IrInstruction *realloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, realloc_field_name, false); IrInstruction *realloc_fn = ir_build_load_ptr(irb, coro_scope, node, realloc_fn_ptr); IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, realloc_fn, coro_size); IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr); @@ -8172,30 +8157,30 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); irb->exec->atomic_state_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, - atomic_state_field_name); + atomic_state_field_name, false); IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0); ir_build_store_ptr(irb, scope, node, irb->exec->atomic_state_field_ptr, zero); Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); - irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name); + irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name, false); result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); - irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name); + irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name, false); ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr); if (irb->codegen->have_err_ret_tracing) { // initialize the error return trace Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME); - IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name); + IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name, false); Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME); - err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name); + err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name, false); ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr); // coordinate with builtin.zig Buf *index_name = buf_create_from_str("index"); - IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name); + IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name, false); ir_build_store_ptr(irb, scope, node, index_ptr, zero); 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 *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name, false); IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false); ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value); @@ -8256,7 +8241,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 *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name, false); IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr); ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr); } @@ -8291,7 +8276,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec Buf *shrink_field_name = buf_create_from_str(ASYNC_SHRINK_FIELD_NAME); IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node, ImplicitAllocatorIdLocalVar); - IrInstruction *shrink_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, shrink_field_name); + IrInstruction *shrink_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, shrink_field_name, false); IrInstruction *shrink_fn = ir_build_load_ptr(irb, scope, node, shrink_fn_ptr); 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); @@ -14722,7 +14707,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc ir_assert(async_allocator_inst->value.type->id == ZigTypeIdPointer, &call_instruction->base); ZigType *container_type = async_allocator_inst->value.type->data.pointer.child_type; IrInstruction *field_ptr_inst = ir_analyze_container_field_ptr(ira, realloc_field_name, &call_instruction->base, - async_allocator_inst, container_type); + async_allocator_inst, container_type, false); if (type_is_invalid(field_ptr_inst->value.type)) { return ira->codegen->invalid_instruction; } @@ -16580,7 +16565,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, } static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, - IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type) + IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing) { Error err; @@ -16664,15 +16649,19 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ if (type_is_invalid(union_val->type)) return ira->codegen->invalid_instruction; - TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag); - if (actual_field == nullptr) - zig_unreachable(); + if (initializing) { + bigint_init_bigint(&union_val->data.x_union.tag, &field->enum_field->value); + } else { + TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag); + if (actual_field == nullptr) + zig_unreachable(); - if (field != actual_field) { - ir_add_error_node(ira, source_instr->source_node, - buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name), - buf_ptr(actual_field->name))); - return ira->codegen->invalid_instruction; + if (field != actual_field) { + ir_add_error_node(ira, source_instr->source_node, + buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name), + buf_ptr(actual_field->name))); + return ira->codegen->invalid_instruction; + } } ConstExprValue *payload_val = union_val->data.x_union.payload; @@ -16690,7 +16679,8 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ } } - IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field); + IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, + source_instr->source_node, container_ptr, field, initializing); result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); return result; @@ -16826,10 +16816,10 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc if (container_type->id == ZigTypeIdPointer) { ZigType *bare_type = container_ref_type(container_type); IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr); - IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_child, bare_type); + IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_child, bare_type, field_ptr_instruction->initializing); return result; } else { - IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_ptr, container_type); + IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_ptr, container_type, field_ptr_instruction->initializing); return result; } } else if (is_array_ref(container_type)) { @@ -18120,7 +18110,7 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru } IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, target_value_ptr, field); + instruction->base.scope, instruction->base.source_node, target_value_ptr, field, false); result->value.type = get_pointer_to_type(ira->codegen, field->type_entry, target_value_ptr->value.type->data.pointer.is_const); return result; @@ -18386,11 +18376,10 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI return result; } - IrInstruction *new_instruction = ir_build_union_init(&ira->new_irb, - 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); + // this instruction should not get to codegen + IrInstruction *new_instruction = ir_const(ira, instruction, container_type); + // this is how we signal to EndExpr the value is not comptime known + new_instruction->value.special = ConstValSpecialRuntime; return new_instruction; } @@ -23907,7 +23896,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction switch (instruction->id) { case IrInstructionIdInvalid: case IrInstructionIdWidenOrShorten: - case IrInstructionIdUnionInit: case IrInstructionIdStructFieldPtr: case IrInstructionIdUnionFieldPtr: case IrInstructionIdOptionalWrap: @@ -24353,7 +24341,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCast: case IrInstructionIdContainerInitList: case IrInstructionIdContainerInitFields: - case IrInstructionIdUnionInit: case IrInstructionIdFieldPtr: case IrInstructionIdElemPtr: case IrInstructionIdVarPtr: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 9181f66be5..42b93aec4e 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -360,15 +360,6 @@ static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerI fprintf(irp->f, "} // container init"); } -static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) { - Buf *field_name = instruction->field->enum_field->name; - - fprintf(irp->f, "%s {", buf_ptr(&instruction->union_type->name)); - fprintf(irp->f, ".%s = ", buf_ptr(field_name)); - ir_print_other_instruction(irp, instruction->init_value); - fprintf(irp->f, "} // union init"); -} - static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) { fprintf(irp->f, "unreachable"); } @@ -1590,9 +1581,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdContainerInitFields: ir_print_container_init_fields(irp, (IrInstructionContainerInitFields *)instruction); break; - case IrInstructionIdUnionInit: - ir_print_union_init(irp, (IrInstructionUnionInit *)instruction); - break; case IrInstructionIdUnreachable: ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction); break; -- cgit v1.2.3 From 17b1ac5d03cd32e047d917a88e029c143cb5d119 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 12:24:19 -0400 Subject: result location semantics for `@bitCast` ```zig export fn entry() void { var x = @bitCast(f32, foo()); } ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %x = alloca float, align 4 %0 = bitcast float* %x to %Foo*, !dbg !42 call fastcc void @foo(%Foo* sret %0), !dbg !42 call void @llvm.dbg.declare(metadata float* %x, metadata !39, metadata !DIExpression()), !dbg !43 ret void, !dbg !44 } ``` --- BRANCH_TODO | 4 +- src/all_types.hpp | 18 +++--- src/codegen.cpp | 14 +---- src/ir.cpp | 178 ++++++++++++++++++++++++++---------------------------- src/ir_print.cpp | 19 +++--- 5 files changed, 103 insertions(+), 130 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 2744901bfa..296d8a24fd 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,8 +1,6 @@ Scratch pad for stuff to do before merging master ================================================= - * bitCast - look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated return ir_gen_comptime(irb, scope, node, lval); @@ -23,3 +21,5 @@ inferred comptime return ir_build_ref(irb, scope, value->source_node, value, false, false); handle if with no else + + diff --git a/src/all_types.hpp b/src/all_types.hpp index 35e9786baa..ef4d94880b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2267,7 +2267,6 @@ enum IrInstructionId { IrInstructionIdTestComptime, IrInstructionIdPtrCastSrc, IrInstructionIdPtrCastGen, - IrInstructionIdBitCast, IrInstructionIdBitCastGen, IrInstructionIdWidenOrShorten, IrInstructionIdIntToPtr, @@ -2645,7 +2644,6 @@ struct IrInstructionContainerInitList { IrInstruction *elem_type; size_t item_count; IrInstruction **items; - LLVMValueRef tmp_ptr; }; struct IrInstructionContainerInitFieldsField { @@ -3136,18 +3134,10 @@ struct IrInstructionPtrCastGen { bool safety_check_on; }; -struct IrInstructionBitCast { - IrInstruction base; - - IrInstruction *dest_type; - IrInstruction *value; -}; - struct IrInstructionBitCastGen { IrInstruction base; IrInstruction *operand; - LLVMValueRef tmp_ptr; }; struct IrInstructionWidenOrShorten { @@ -3590,6 +3580,7 @@ enum ResultLocId { ResultLocIdPeer, ResultLocIdPeerParent, ResultLocIdInstruction, + ResultLocIdBitCast, }; struct ResultLoc { @@ -3644,6 +3635,13 @@ struct ResultLocInstruction { ResultLoc base; }; +// The source_instruction is the destination type +struct ResultLocBitCast { + ResultLoc base; + + ResultLoc *parent; +}; + 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 eb2e92f627..894d22d471 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3145,12 +3145,7 @@ static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable, uint32_t alignment = get_abi_alignment(g, actual_type); return gen_load_untyped(g, bitcasted_ptr, alignment, false, ""); } else { - assert(instruction->tmp_ptr != nullptr); - LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(get_llvm_type(g, actual_type), 0); - LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, wanted_ptr_type_ref, ""); - uint32_t alignment = get_abi_alignment(g, wanted_type); - gen_store_untyped(g, value, bitcasted_ptr, alignment, false); - return instruction->tmp_ptr; + zig_unreachable(); } } @@ -5520,7 +5515,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdPtrCastSrc: case IrInstructionIdCmpxchgSrc: case IrInstructionIdLoadPtr: - case IrInstructionIdBitCast: case IrInstructionIdGlobalAsm: case IrInstructionIdHasDecl: case IrInstructionIdUndeclaredIdent: @@ -6837,9 +6831,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdContainerInitList) { - IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction; - slot = &container_init_list_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdSlice) { IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction; slot = &slice_instruction->tmp_ptr; @@ -6861,9 +6852,6 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdLoadPtrGen) { IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction; slot = &load_ptr_inst->tmp_ptr; - } else if (instruction->id == IrInstructionIdBitCastGen) { - IrInstructionBitCastGen *bit_cast_inst = (IrInstructionBitCastGen *)instruction; - slot = &bit_cast_inst->tmp_ptr; } else if (instruction->id == IrInstructionIdVectorToArray) { IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction; alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type); diff --git a/src/ir.cpp b/src/ir.cpp index 05f95a2480..26d0d59b28 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -780,10 +780,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) { return IrInstructionIdPtrCastGen; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) { - return IrInstructionIdBitCast; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastGen *) { return IrInstructionIdBitCastGen; } @@ -2429,20 +2425,6 @@ static IrInstruction *ir_build_load_ptr_gen(IrAnalyze *ira, IrInstruction *sourc return &instruction->base; } -static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *dest_type, IrInstruction *value) -{ - IrInstructionBitCast *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->dest_type = dest_type; - instruction->value = value; - - ir_ref_instruction(dest_type, irb->current_basic_block); - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstruction *ir_build_bit_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *operand, ZigType *ty) { @@ -4836,18 +4818,23 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } case BuiltinFnIdBitCast: { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_instruction) - return arg0_value; + AstNode *dest_type_node = node->data.fn_call_expr.params.at(0); + IrInstruction *dest_type = ir_gen_node(irb, dest_type_node, scope); + if (dest_type == irb->codegen->invalid_instruction) + return dest_type; + + ResultLocBitCast *result_loc_bit_cast = allocate(1); + result_loc_bit_cast->base.id = ResultLocIdBitCast; + result_loc_bit_cast->base.source_instruction = dest_type; + result_loc_bit_cast->parent = result_loc; AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + IrInstruction *arg1_value = ir_gen_node_extra(irb, arg1_node, scope, LValNone, + &result_loc_bit_cast->base); if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *bit_cast = ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, bit_cast, lval, result_loc); + return ir_lval_wrap(irb, scope, arg1_value, lval, result_loc); } case BuiltinFnIdIntToPtr: { @@ -14059,9 +14046,10 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, bool var_class_requires_const = false; IrInstruction *var_ptr = decl_var_instruction->ptr->child; - // if this assertion trips there may be a missing ir_expr_wrap in pass1 IR generation. - ir_assert(var_ptr != nullptr, &decl_var_instruction->base); - if (type_is_invalid(var_ptr->value.type)) { + // if this is null, a compiler error happened and did not initialize the variable. + // if there are no compile errors there may be a missing ir_expr_wrap in pass1 IR generation. + if (var_ptr == nullptr || type_is_invalid(var_ptr->value.type)) { + ir_assert(var_ptr != nullptr || ira->codegen->errors.length != 0, &decl_var_instruction->base); var->var_type = ira->codegen->builtin_types.entry_invalid; return ira->codegen->invalid_instruction; } @@ -14528,6 +14516,7 @@ static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, IrInstruction *suspe zig_unreachable(); case ResultLocIdNone: case ResultLocIdVar: + case ResultLocIdBitCast: return nullptr; case ResultLocIdInstruction: return result_loc->source_instruction->child->value.type; @@ -14539,6 +14528,28 @@ static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, IrInstruction *suspe zig_unreachable(); } +static bool type_can_bit_cast(ZigType *t) { + switch (t->id) { + case ZigTypeIdInvalid: + zig_unreachable(); + case ZigTypeIdMetaType: + case ZigTypeIdOpaque: + case ZigTypeIdBoundFn: + case ZigTypeIdArgTuple: + case ZigTypeIdUnreachable: + case ZigTypeIdComptimeFloat: + case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: + case ZigTypeIdUndefined: + case ZigTypeIdNull: + case ZigTypeIdPointer: + return false; + default: + // TODO list these types out explicitly, there are probably some other invalid ones here + return true; + } +} + // give nullptr for value to resolve it at runtime // returns a result location, or nullptr if the result location was already taken care of // when calling this function, at the callsite must check for result type noreturn and propagate it up @@ -14676,6 +14687,50 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s result_loc->resolved_loc = parent_result_loc; return result_loc->resolved_loc; } + case ResultLocIdBitCast: { + ResultLocBitCast *result_bit_cast = reinterpret_cast(result_loc); + ZigType *dest_type = ir_resolve_type(ira, result_bit_cast->base.source_instruction->child); + if (type_is_invalid(dest_type)) + return ira->codegen->invalid_instruction; + + if (get_codegen_ptr_type(dest_type) != nullptr) { + ir_add_error(ira, result_loc->source_instruction, + buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + + if (!type_can_bit_cast(dest_type)) { + ir_add_error(ira, result_loc->source_instruction, + buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + + if (get_codegen_ptr_type(value_type) != nullptr) { + ir_add_error(ira, suspend_source_instr, + buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&value_type->name))); + return ira->codegen->invalid_instruction; + } + + if (!type_can_bit_cast(value_type)) { + ir_add_error(ira, suspend_source_instr, + buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&value_type->name))); + return ira->codegen->invalid_instruction; + } + + + IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_bit_cast->parent, + dest_type, nullptr); + if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || + parent_result_loc->value.type->id == ZigTypeIdUnreachable) + { + return parent_result_loc; + } + ZigType *ptr_type = get_pointer_to_type(ira->codegen, value_type, false); + result_loc->written = true; + result_loc->resolved_loc = ir_analyze_ptr_cast(ira, suspend_source_instr, parent_result_loc, + ptr_type, result_bit_cast->base.source_instruction, false); + return result_loc->resolved_loc; + } } zig_unreachable(); } @@ -22755,28 +22810,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou zig_unreachable(); } -static bool type_can_bit_cast(ZigType *t) { - switch (t->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdArgTuple: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdPointer: - return false; - default: - // TODO list these types out explicitly, there are probably some other invalid ones here - return true; - } -} - static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *dest_type) { @@ -22829,50 +22862,10 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_ } IrInstruction *result = ir_build_bit_cast_gen(ira, source_instr, value, dest_type); - if (handle_is_ptr(dest_type) && !handle_is_ptr(src_type)) { - ir_add_alloca(ira, result, dest_type); - } + assert(!(handle_is_ptr(dest_type) && !handle_is_ptr(src_type))); return result; } -static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { - IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_instruction; - - IrInstruction *value = instruction->value->child; - ZigType *src_type = value->value.type; - if (type_is_invalid(src_type)) - return ira->codegen->invalid_instruction; - - if (get_codegen_ptr_type(src_type) != nullptr) { - ir_add_error(ira, value, - buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&src_type->name))); - return ira->codegen->invalid_instruction; - } - - if (!type_can_bit_cast(src_type)) { - ir_add_error(ira, dest_type_value, - buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name))); - return ira->codegen->invalid_instruction; - } - - if (get_codegen_ptr_type(dest_type) != nullptr) { - ir_add_error(ira, dest_type_value, - buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - } - - if (!type_can_bit_cast(dest_type)) { - ir_add_error(ira, dest_type_value, - buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - } - - return ir_analyze_bit_cast(ira, &instruction->base, value, dest_type); -} - static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, ZigType *ptr_type) { @@ -24089,8 +24082,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction); case IrInstructionIdPtrCastSrc: return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCastSrc *)instruction); - case IrInstructionIdBitCast: - return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction); case IrInstructionIdIntToPtr: return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction); case IrInstructionIdPtrToInt: @@ -24386,7 +24377,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: case IrInstructionIdPtrCastGen: - case IrInstructionIdBitCast: case IrInstructionIdBitCastGen: case IrInstructionIdWidenOrShorten: case IrInstructionIdPtrToInt: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 42b93aec4e..925d802e6d 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -219,6 +219,12 @@ static void ir_print_result_loc_peer(IrPrint *irp, ResultLocPeer *result_loc_pee fprintf(irp->f, ")"); } +static void ir_print_result_loc_bit_cast(IrPrint *irp, ResultLocBitCast *result_loc_bit_cast) { + fprintf(irp->f, "bitcast(ty="); + ir_print_other_instruction(irp, result_loc_bit_cast->base.source_instruction); + fprintf(irp->f, ")"); +} + static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) { switch (result_loc->id) { case ResultLocIdInvalid: @@ -235,6 +241,8 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) { return ir_print_result_loc_instruction(irp, (ResultLocInstruction *)result_loc); case ResultLocIdPeer: return ir_print_result_loc_peer(irp, (ResultLocPeer *)result_loc); + case ResultLocIdBitCast: + return ir_print_result_loc_bit_cast(irp, (ResultLocBitCast *)result_loc); case ResultLocIdPeerParent: fprintf(irp->f, "peer_parent"); return; @@ -1011,14 +1019,6 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc fprintf(irp->f, ")"); } -static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { - fprintf(irp->f, "@bitCast("); - ir_print_other_instruction(irp, instruction->dest_type); - fprintf(irp->f, ","); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); -} - static void ir_print_bit_cast_gen(IrPrint *irp, IrInstructionBitCastGen *instruction) { fprintf(irp->f, "@bitCast("); ir_print_other_instruction(irp, instruction->operand); @@ -1818,9 +1818,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdPtrCastGen: ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction); break; - case IrInstructionIdBitCast: - ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); - break; case IrInstructionIdBitCastGen: ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction); break; -- cgit v1.2.3 From c36289511629e01bbd32bc5f1133f5ed5997d1e0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 15:49:45 -0400 Subject: result location semantics for slices ```zig export fn entry() void { var buf: [10]u8 = undefined; const slice1: []const u8 = &buf; const slice2 = buf[0..]; } ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %buf = alloca [10 x i8], align 1 %slice1 = alloca %"[]u8", align 8 %slice2 = alloca %"[]u8", align 8 %0 = bitcast [10 x i8]* %buf to i8*, !dbg !46 call void @llvm.memset.p0i8.i64(i8* align 1 %0, i8 -86, i64 10, i1 false), !dbg !46 call void @llvm.dbg.declare(metadata [10 x i8]* %buf, metadata !39, metadata !DIExpression()), !dbg !46 %1 = getelementptr inbounds %"[]u8", %"[]u8"* %slice1, i32 0, i32 0, !dbg !47 %2 = getelementptr inbounds [10 x i8], [10 x i8]* %buf, i64 0, i64 0, !dbg !47 store i8* %2, i8** %1, align 8, !dbg !47 %3 = getelementptr inbounds %"[]u8", %"[]u8"* %slice1, i32 0, i32 1, !dbg !47 store i64 10, i64* %3, align 8, !dbg !47 call void @llvm.dbg.declare(metadata %"[]u8"* %slice1, metadata !44, metadata !DIExpression()), !dbg !48 %4 = getelementptr inbounds %"[]u8", %"[]u8"* %slice2, i32 0, i32 0, !dbg !49 %5 = getelementptr inbounds [10 x i8], [10 x i8]* %buf, i64 0, i64 0, !dbg !49 store i8* %5, i8** %4, align 8, !dbg !49 %6 = getelementptr inbounds %"[]u8", %"[]u8"* %slice2, i32 0, i32 1, !dbg !49 store i64 10, i64* %6, align 8, !dbg !49 call void @llvm.dbg.declare(metadata %"[]u8"* %slice2, metadata !45, metadata !DIExpression()), !dbg !50 ret void, !dbg !51 } ``` --- BRANCH_TODO | 3 - src/all_types.hpp | 27 +++++++-- src/codegen.cpp | 72 ++++++++++++----------- src/ir.cpp | 172 +++++++++++++++++++++++++++++++++++++----------------- src/ir_print.cpp | 33 +++++++++-- 5 files changed, 210 insertions(+), 97 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 296d8a24fd..e744162fa0 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -20,6 +20,3 @@ inferred comptime // an instruction which just makes a pointer of it. return ir_build_ref(irb, scope, value->source_node, value, false, false); -handle if with no else - - diff --git a/src/all_types.hpp b/src/all_types.hpp index ef4d94880b..73580619ed 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2248,7 +2248,8 @@ enum IrInstructionId { IrInstructionIdBoolNot, IrInstructionIdMemset, IrInstructionIdMemcpy, - IrInstructionIdSlice, + IrInstructionIdSliceSrc, + IrInstructionIdSliceGen, IrInstructionIdMemberCount, IrInstructionIdMemberType, IrInstructionIdMemberName, @@ -2334,6 +2335,7 @@ enum IrInstructionId { IrInstructionIdAllocaSrc, IrInstructionIdAllocaGen, IrInstructionIdEndExpr, + IrInstructionIdPtrOfArrayToSlice, }; struct IrInstruction { @@ -2617,7 +2619,6 @@ enum CastOp { CastOpNumLitToConcrete, CastOpErrSet, CastOpBitCast, - CastOpPtrOfArrayToSlice, }; // TODO get rid of this instruction, replace with instructions for each op code @@ -2989,14 +2990,24 @@ struct IrInstructionMemcpy { IrInstruction *count; }; -struct IrInstructionSlice { +struct IrInstructionSliceSrc { IrInstruction base; + bool safety_check_on; IrInstruction *ptr; IrInstruction *start; IrInstruction *end; + ResultLoc *result_loc; +}; + +struct IrInstructionSliceGen { + IrInstruction base; + bool safety_check_on; - LLVMValueRef tmp_ptr; + IrInstruction *ptr; + IrInstruction *start; + IrInstruction *end; + IrInstruction *result_loc; }; struct IrInstructionMemberCount { @@ -3563,6 +3574,7 @@ struct IrInstructionImplicitCast { IrInstruction *dest_type; IrInstruction *target; + ResultLoc *result_loc; }; struct IrInstructionResolveResult { @@ -3572,6 +3584,13 @@ struct IrInstructionResolveResult { IrInstruction *ty; }; +struct IrInstructionPtrOfArrayToSlice { + IrInstruction base; + + IrInstruction *operand; + IrInstruction *result_loc; +}; + enum ResultLocId { ResultLocIdInvalid, ResultLocIdNone, diff --git a/src/codegen.cpp b/src/codegen.cpp index 894d22d471..f748c575b0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3072,33 +3072,39 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, return expr_val; case CastOpBitCast: return LLVMBuildBitCast(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - 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->llvm_type), - LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 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->llvm_type, - 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->operand->value.type; + LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand); + assert(expr_val); + + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); + + 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->llvm_type), + LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 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->llvm_type, + 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, IrInstructionPtrCastGen *instruction) { @@ -4603,16 +4609,14 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns return nullptr; } -static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSlice *instruction) { - assert(instruction->tmp_ptr); - +static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSliceGen *instruction) { LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr); ZigType *array_ptr_type = instruction->ptr->value.type; assert(array_ptr_type->id == ZigTypeIdPointer); 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; + LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); @@ -4630,7 +4634,9 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst end_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false); } if (want_runtime_safety) { - add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); + if (instruction->start->value.special == ConstValSpecialRuntime || instruction->end) { + add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); + } if (instruction->end) { LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false); @@ -5525,6 +5531,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdImplicitCast: case IrInstructionIdResolveResult: case IrInstructionIdContainerInitList: + case IrInstructionIdSliceSrc: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -5595,8 +5602,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_memset(g, executable, (IrInstructionMemset *)instruction); case IrInstructionIdMemcpy: return ir_render_memcpy(g, executable, (IrInstructionMemcpy *)instruction); - case IrInstructionIdSlice: - return ir_render_slice(g, executable, (IrInstructionSlice *)instruction); + case IrInstructionIdSliceGen: + return ir_render_slice(g, executable, (IrInstructionSliceGen *)instruction); case IrInstructionIdBreakpoint: return ir_render_breakpoint(g, executable, (IrInstructionBreakpoint *)instruction); case IrInstructionIdReturnAddress: @@ -5697,6 +5704,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_assert_non_null(g, executable, (IrInstructionAssertNonNull *)instruction); case IrInstructionIdResizeSlice: return ir_render_resize_slice(g, executable, (IrInstructionResizeSlice *)instruction); + case IrInstructionIdPtrOfArrayToSlice: + return ir_render_ptr_of_array_to_slice(g, executable, (IrInstructionPtrOfArrayToSlice *)instruction); } zig_unreachable(); } @@ -6831,9 +6840,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == 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; diff --git a/src/ir.cpp b/src/ir.cpp index 26d0d59b28..cc28d3981c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -700,8 +700,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMemcpy *) { return IrInstructionIdMemcpy; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionSlice *) { - return IrInstructionIdSlice; +static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceSrc *) { + return IrInstructionIdSliceSrc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceGen *) { + return IrInstructionIdSliceGen; } static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberCount *) { @@ -880,6 +884,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResolveResult *) return IrInstructionIdResolveResult; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) { + return IrInstructionIdPtrOfArrayToSlice; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) { return IrInstructionIdOpaqueType; } @@ -2216,14 +2224,15 @@ static IrInstruction *ir_build_memcpy(IrBuilder *irb, Scope *scope, AstNode *sou return &instruction->base; } -static IrInstruction *ir_build_slice(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on) +static IrInstruction *ir_build_slice_src(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on, ResultLoc *result_loc) { - IrInstructionSlice *instruction = ir_build_instruction(irb, scope, source_node); + IrInstructionSliceSrc *instruction = ir_build_instruction(irb, scope, source_node); instruction->ptr = ptr; instruction->start = start; instruction->end = end; instruction->safety_check_on = safety_check_on; + instruction->result_loc = result_loc; ir_ref_instruction(ptr, irb->current_basic_block); ir_ref_instruction(start, irb->current_basic_block); @@ -2232,6 +2241,26 @@ static IrInstruction *ir_build_slice(IrBuilder *irb, Scope *scope, AstNode *sour return &instruction->base; } +static IrInstruction *ir_build_slice_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *slice_type, + IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on, IrInstruction *result_loc) +{ + IrInstructionSliceGen *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = slice_type; + instruction->ptr = ptr; + instruction->start = start; + instruction->end = end; + instruction->safety_check_on = safety_check_on; + instruction->result_loc = result_loc; + + ir_ref_instruction(ptr, ira->new_irb.current_basic_block); + ir_ref_instruction(start, ira->new_irb.current_basic_block); + if (end) ir_ref_instruction(end, ira->new_irb.current_basic_block); + ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_member_count(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *container) { IrInstructionMemberCount *instruction = ir_build_instruction(irb, scope, source_node); instruction->container = container; @@ -2705,11 +2734,12 @@ static IrInstruction *ir_build_align_cast(IrBuilder *irb, Scope *scope, AstNode } static IrInstruction *ir_build_implicit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *dest_type, IrInstruction *target) + IrInstruction *dest_type, IrInstruction *target, ResultLoc *result_loc) { IrInstructionImplicitCast *instruction = ir_build_instruction(irb, scope, source_node); instruction->dest_type = dest_type; instruction->target = target; + instruction->result_loc = result_loc; ir_ref_instruction(dest_type, irb->current_basic_block); ir_ref_instruction(target, irb->current_basic_block); @@ -3082,6 +3112,21 @@ static IrInstruction *ir_build_vector_to_array(IrAnalyze *ira, IrInstruction *so return &instruction->base; } +static IrInstruction *ir_build_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instruction, + ZigType *result_type, IrInstruction *operand, IrInstruction *result_loc) +{ + IrInstructionPtrOfArrayToSlice *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; + instruction->operand = operand; + instruction->result_loc = result_loc; + + ir_ref_instruction(operand, ira->new_irb.current_basic_block); + ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_array_to_vector(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *array, ZigType *result_type) { @@ -5717,7 +5762,8 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod return irb->codegen->invalid_instruction; if (type_instruction != nullptr) { - IrInstruction *implicit_cast = ir_build_implicit_cast(irb, scope, node, type_instruction, init_value); + IrInstruction *implicit_cast = ir_build_implicit_cast(irb, scope, node, type_instruction, init_value, + &result_loc_var->base); ir_build_end_expr(irb, scope, node, implicit_cast, &result_loc_var->base); } @@ -7086,7 +7132,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, LVal lval, ResultLoc *result_loc) { assert(node->type == NodeTypeSliceExpr); AstNodeSliceExpr *slice_expr = &node->data.slice_expr; @@ -7111,7 +7157,8 @@ 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); + IrInstruction *slice = ir_build_slice_src(irb, scope, node, ptr_value, start_value, end_value, true, result_loc); + return ir_lval_wrap(irb, scope, slice, lval, result_loc); } static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval, @@ -7659,7 +7706,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst); IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type); ir_build_await_bookkeeping(irb, scope, node, promise_result_type); - IrInstruction *undef_promise_result = ir_build_implicit_cast(irb, scope, node, promise_result_type, undef); + IrInstruction *undef_promise_result = ir_build_implicit_cast(irb, scope, node, promise_result_type, undef, nullptr); build_decl_var_and_init(irb, scope, node, result_var, undef_promise_result, "result", const_bool_false); IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var); ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr); @@ -8001,7 +8048,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, result_loc); case NodeTypeSliceExpr: - return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval, result_loc); + return ir_gen_slice(irb, scope, node, lval, result_loc); case NodeTypeCatchExpr: return ir_gen_catch(irb, scope, node, lval, result_loc); case NodeTypeContainerDecl: @@ -8028,15 +8075,19 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop zig_unreachable(); } +static ResultLoc *no_result_loc(void) { + ResultLocNone *result_loc_none = allocate(1); + result_loc_none->base.id = ResultLocIdNone; + return &result_loc_none->base; +} + static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, ResultLoc *result_loc) { if (result_loc == nullptr) { // Create a result location indicating there is none - but if one gets created // it will be properly distributed. - ResultLocNone *result_loc_none = allocate(1); - result_loc_none->base.id = ResultLocIdNone; - result_loc = &result_loc_none->base; + result_loc = no_result_loc(); } IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc); irb->exec->invalid = irb->exec->invalid || (result == irb->codegen->invalid_instruction); @@ -8098,7 +8149,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); - IrInstruction *undef_coro_frame = ir_build_implicit_cast(irb, coro_scope, node, coro_frame_type_value, undef); + IrInstruction *undef_coro_frame = ir_build_implicit_cast(irb, coro_scope, node, coro_frame_type_value, undef, nullptr); build_decl_var_and_init(irb, coro_scope, node, promise_var, undef_coro_frame, "promise", const_bool_false); coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var); @@ -8106,7 +8157,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); - IrInstruction *null_await_handle = ir_build_implicit_cast(irb, coro_scope, node, await_handle_type_val, null_value); + IrInstruction *null_await_handle = ir_build_implicit_cast(irb, coro_scope, node, await_handle_type_val, null_value, nullptr); build_decl_var_and_init(irb, coro_scope, node, await_handle_var, null_await_handle, "await_handle", const_bool_false); irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var); @@ -8169,7 +8220,7 @@ 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, false); - IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false); + IrInstruction *slice_value = ir_build_slice_src(irb, scope, node, return_addresses_ptr, zero, nullptr, false, no_result_loc()); ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value); } @@ -8275,7 +8326,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec 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 *mem_slice = ir_build_slice_src(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false, + no_result_loc()); size_t arg_count = 5; IrInstruction **args = allocate(arg_count); args[0] = implicit_allocator_ptr; // self @@ -10417,7 +10469,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: { @@ -10574,7 +10625,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, } static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *value, ZigType *wanted_type) + IrInstruction *value, ZigType *wanted_type, ResultLoc *result_loc) { Error err; @@ -10605,11 +10656,12 @@ 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; + if (result_loc == nullptr) result_loc = no_result_loc(); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } + return ir_build_ptr_of_array_to_slice(ira, source_instr, wanted_type, value, result_loc_inst); } static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrInstruction *ref_old_instruction) { @@ -11195,7 +11247,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi } static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *array_arg, ZigType *wanted_type) + IrInstruction *array_arg, ZigType *wanted_type, ResultLoc *result_loc) { assert(is_slice(wanted_type)); // In this function we honor the const-ness of wanted_type, because @@ -11227,12 +11279,14 @@ 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); - result->value.type = wanted_type; + if (result_loc == nullptr) result_loc = no_result_loc(); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } + IrInstruction *result = ir_build_slice_gen(ira, source_instr, wanted_type, array_ptr, start, end, false, result_loc_inst); 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; } @@ -11929,7 +11983,7 @@ static bool is_pointery_and_elem_is_not_pointery(ZigType *ty) { } static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, - ZigType *wanted_type, IrInstruction *value) + ZigType *wanted_type, IrInstruction *value, ResultLoc *result_loc) { Error err; ZigType *actual_type = value->value.type; @@ -12017,11 +12071,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdComptimeFloat) { - IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value, nullptr); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1, result_loc); if (type_is_invalid(cast2->value.type)) return ira->codegen->invalid_instruction; @@ -12103,7 +12157,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type); + return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type, result_loc); } } @@ -12120,11 +12174,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) { - IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value); + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value, nullptr); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1, result_loc); if (type_is_invalid(cast2->value.type)) return ira->codegen->invalid_instruction; @@ -12167,7 +12221,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst array_type->data.array.child_type, source_node, !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk) { - return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type); + return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type, result_loc); } } @@ -12198,11 +12252,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) { - IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value, nullptr); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1, result_loc); if (type_is_invalid(cast2->value.type)) return ira->codegen->invalid_instruction; @@ -12380,7 +12434,9 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ira->codegen->invalid_instruction; } -static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type) { +static IrInstruction *ir_implicit_cast_with_result(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type, + ResultLoc *result_loc) +{ assert(value); assert(value != ira->codegen->invalid_instruction); assert(!expected_type || !type_is_invalid(expected_type)); @@ -12393,7 +12449,11 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Zig if (value->value.type->id == ZigTypeIdUnreachable) return value; - return ir_analyze_cast(ira, value, expected_type, value); + return ir_analyze_cast(ira, value, expected_type, value, result_loc); +} + +static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type) { + return ir_implicit_cast_with_result(ira, value, expected_type, nullptr); } static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) { @@ -14744,7 +14804,7 @@ static IrInstruction *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, IrIns if (type_is_invalid(target->value.type)) return ira->codegen->invalid_instruction; - return ir_implicit_cast(ira, target, dest_type); + return ir_implicit_cast_with_result(ira, target, dest_type, instruction->result_loc); } static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrInstructionResolveResult *instruction) { @@ -15687,7 +15747,8 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC IrInstruction *arg = call_instruction->args[0]->child; - IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, dest_type, arg); + IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, dest_type, arg, + call_instruction->result_loc); if (type_is_invalid(cast_instruction->value.type)) return ira->codegen->invalid_instruction; return ir_finish_anal(ira, cast_instruction); @@ -21165,7 +21226,7 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio return result; } -static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice *instruction) { +static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSliceSrc *instruction) { IrInstruction *ptr_ptr = instruction->ptr->child; if (type_is_invalid(ptr_ptr->value.type)) return ira->codegen->invalid_instruction; @@ -21454,12 +21515,13 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction return result; } - 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); - new_instruction->value.type = return_type; - ir_add_alloca(ira, new_instruction, return_type); - return new_instruction; + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + return_type, nullptr); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + return ir_build_slice_gen(ira, &instruction->base, return_type, + ptr_ptr, casted_start, end, instruction->safety_check_on, result_loc); } static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInstructionMemberCount *instruction) { @@ -23900,6 +23962,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction case IrInstructionIdCmpxchgGen: case IrInstructionIdArrayToVector: case IrInstructionIdVectorToArray: + case IrInstructionIdPtrOfArrayToSlice: case IrInstructionIdAssertZero: case IrInstructionIdAssertNonNull: case IrInstructionIdResizeSlice: @@ -23908,6 +23971,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction case IrInstructionIdCallGen: case IrInstructionIdReturnPtr: case IrInstructionIdAllocaGen: + case IrInstructionIdSliceGen: zig_unreachable(); case IrInstructionIdReturn: @@ -24042,8 +24106,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_memset(ira, (IrInstructionMemset *)instruction); case IrInstructionIdMemcpy: return ir_analyze_instruction_memcpy(ira, (IrInstructionMemcpy *)instruction); - case IrInstructionIdSlice: - return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction); + case IrInstructionIdSliceSrc: + return ir_analyze_instruction_slice(ira, (IrInstructionSliceSrc *)instruction); case IrInstructionIdMemberCount: return ir_analyze_instruction_member_count(ira, (IrInstructionMemberCount *)instruction); case IrInstructionIdMemberType: @@ -24321,6 +24385,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdGlobalAsm: case IrInstructionIdUndeclaredIdent: case IrInstructionIdEndExpr: + case IrInstructionIdPtrOfArrayToSlice: + case IrInstructionIdSliceGen: return true; case IrInstructionIdPhi: @@ -24360,7 +24426,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdIntType: case IrInstructionIdVectorType: case IrInstructionIdBoolNot: - case IrInstructionIdSlice: + case IrInstructionIdSliceSrc: case IrInstructionIdMemberCount: case IrInstructionIdMemberType: case IrInstructionIdMemberName: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 925d802e6d..e80ddf401b 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -858,14 +858,26 @@ static void ir_print_memcpy(IrPrint *irp, IrInstructionMemcpy *instruction) { fprintf(irp->f, ")"); } -static void ir_print_slice(IrPrint *irp, IrInstructionSlice *instruction) { +static void ir_print_slice_src(IrPrint *irp, IrInstructionSliceSrc *instruction) { ir_print_other_instruction(irp, instruction->ptr); fprintf(irp->f, "["); ir_print_other_instruction(irp, instruction->start); fprintf(irp->f, ".."); if (instruction->end) ir_print_other_instruction(irp, instruction->end); - fprintf(irp->f, "]"); + fprintf(irp->f, "]result="); + ir_print_result_loc(irp, instruction->result_loc); +} + +static void ir_print_slice_gen(IrPrint *irp, IrInstructionSliceGen *instruction) { + ir_print_other_instruction(irp, instruction->ptr); + fprintf(irp->f, "["); + ir_print_other_instruction(irp, instruction->start); + fprintf(irp->f, ".."); + if (instruction->end) + ir_print_other_instruction(irp, instruction->end); + fprintf(irp->f, "]result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_member_count(IrPrint *irp, IrInstructionMemberCount *instruction) { @@ -1086,6 +1098,13 @@ static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *i fprintf(irp->f, ")"); } +static void ir_print_ptr_of_array_to_slice(IrPrint *irp, IrInstructionPtrOfArrayToSlice *instruction) { + fprintf(irp->f, "PtrOfArrayToSlice("); + ir_print_other_instruction(irp, instruction->operand); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); +} + static void ir_print_assert_zero(IrPrint *irp, IrInstructionAssertZero *instruction) { fprintf(irp->f, "AssertZero("); ir_print_other_instruction(irp, instruction->target); @@ -1758,8 +1777,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdMemcpy: ir_print_memcpy(irp, (IrInstructionMemcpy *)instruction); break; - case IrInstructionIdSlice: - ir_print_slice(irp, (IrInstructionSlice *)instruction); + case IrInstructionIdSliceSrc: + ir_print_slice_src(irp, (IrInstructionSliceSrc *)instruction); + break; + case IrInstructionIdSliceGen: + ir_print_slice_gen(irp, (IrInstructionSliceGen *)instruction); break; case IrInstructionIdMemberCount: ir_print_member_count(irp, (IrInstructionMemberCount *)instruction); @@ -1992,6 +2014,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdVectorToArray: ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction); break; + case IrInstructionIdPtrOfArrayToSlice: + ir_print_ptr_of_array_to_slice(irp, (IrInstructionPtrOfArrayToSlice *)instruction); + break; case IrInstructionIdAssertZero: ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction); break; -- cgit v1.2.3 From eaa9d8bdac7f64e38a39607e5d5574f88f8fe875 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 16:20:13 -0400 Subject: result location semantics for optional wrap --- src/all_types.hpp | 4 ++-- src/codegen.cpp | 13 +++++-------- src/ir.cpp | 33 +++++++++++++++++++++------------ src/ir_print.cpp | 11 ++++++----- 4 files changed, 34 insertions(+), 27 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 73580619ed..d2e7a7f631 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3095,8 +3095,8 @@ struct IrInstructionUnwrapErrPayload { struct IrInstructionOptionalWrap { IrInstruction base; - IrInstruction *value; - LLVMValueRef tmp_ptr; + IrInstruction *operand; + IrInstruction *result_loc; }; struct IrInstructionErrWrapPayload { diff --git a/src/codegen.cpp b/src/codegen.cpp index f748c575b0..e88cee4186 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4956,20 +4956,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); + LLVMValueRef payload_val = ir_llvm_value(g, instruction->operand); if (!handle_is_ptr(wanted_type)) { return payload_val; } - assert(instruction->tmp_ptr); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); + 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, ""); + 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) { @@ -6840,9 +6840,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == 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; diff --git a/src/ir.cpp b/src/ir.cpp index cc28d3981c..58f6b14450 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1758,11 +1758,17 @@ static IrInstruction *ir_build_optional_unwrap_ptr(IrBuilder *irb, Scope *scope, return &instruction->base; } -static IrInstruction *ir_build_maybe_wrap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { - IrInstructionOptionalWrap *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; +static IrInstruction *ir_build_optional_wrap(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *result_ty, + IrInstruction *operand, IrInstruction *result_loc) +{ + IrInstructionOptionalWrap *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_ty; + instruction->operand = operand; + instruction->result_loc = result_loc; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(operand, ira->new_irb.current_basic_block); + ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -11035,7 +11041,7 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { } static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, - ZigType *wanted_type) + ZigType *wanted_type, ResultLoc *result_loc) { assert(wanted_type->id == ZigTypeIdOptional); @@ -11061,10 +11067,13 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so return &const_instruction->base; } - IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node, value); - result->value.type = wanted_type; + if (result_loc == nullptr) result_loc = no_result_loc(); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } + IrInstruction *result = ir_build_optional_wrap(ira, source_instr, wanted_type, value, result_loc_inst); result->value.data.rh_maybe = RuntimeHintOptionalNonNull; - ir_add_alloca(ira, result, wanted_type); return result; } @@ -12009,12 +12018,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type); + return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type, result_loc); } else if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdComptimeFloat) { if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { - return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type); + return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type, result_loc); } else { return ira->codegen->invalid_instruction; } @@ -12038,7 +12047,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_child_type); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type); + return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type, result_loc); } } } @@ -24387,6 +24396,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdEndExpr: case IrInstructionIdPtrOfArrayToSlice: case IrInstructionIdSliceGen: + case IrInstructionIdOptionalWrap: return true; case IrInstructionIdPhi: @@ -24436,7 +24446,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdHandle: case IrInstructionIdTestErr: case IrInstructionIdUnwrapErrCode: - case IrInstructionIdOptionalWrap: case IrInstructionIdErrWrapCode: case IrInstructionIdErrWrapPayload: case IrInstructionIdFnProto: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index e80ddf401b..6cad5c1dea 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -970,10 +970,11 @@ static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayl } } -static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) { - fprintf(irp->f, "@maybeWrap("); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); +static void ir_print_optional_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) { + fprintf(irp->f, "@optionalWrap("); + ir_print_other_instruction(irp, instruction->operand); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_err_wrap_code(IrPrint *irp, IrInstructionErrWrapCode *instruction) { @@ -1820,7 +1821,7 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_unwrap_err_payload(irp, (IrInstructionUnwrapErrPayload *)instruction); break; case IrInstructionIdOptionalWrap: - ir_print_maybe_wrap(irp, (IrInstructionOptionalWrap *)instruction); + ir_print_optional_wrap(irp, (IrInstructionOptionalWrap *)instruction); break; case IrInstructionIdErrWrapCode: ir_print_err_wrap_code(irp, (IrInstructionErrWrapCode *)instruction); -- cgit v1.2.3 From 4f085b8d2c8ffb03dd15b789ad5867904faae13d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 16:55:07 -0400 Subject: result location semantics for error union wrapping a payload --- BRANCH_TODO | 14 +------------- src/all_types.hpp | 4 ++-- src/codegen.cpp | 16 +++++++--------- src/ir.cpp | 43 ++++++++++++++++++++++++++++++------------- src/ir_print.cpp | 5 +++-- 5 files changed, 43 insertions(+), 39 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index e744162fa0..f6fd78dbaa 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -6,17 +6,5 @@ look at all the ir_gen_node ir_gen_node_extra calls and make sure result locatio migrate all the alloca_list to alloca_gen_list -inferred comptime - - - if (lval == LValNone) { - if (result_loc->id == ResultLocIdNone) - return value; - } - - assert(lval == LValPtr); - - // We needed a pointer to a value, but we got a value. So we create - // an instruction which just makes a pointer of it. - return ir_build_ref(irb, scope, value->source_node, value, false, false); +comptime expressions diff --git a/src/all_types.hpp b/src/all_types.hpp index d2e7a7f631..f13f16152d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3102,8 +3102,8 @@ struct IrInstructionOptionalWrap { struct IrInstructionErrWrapPayload { IrInstruction base; - IrInstruction *value; - LLVMValueRef tmp_ptr; + IrInstruction *operand; + IrInstruction *result_loc; }; struct IrInstructionErrWrapCode { diff --git a/src/codegen.cpp b/src/codegen.cpp index e88cee4186..69b234d160 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5002,7 +5002,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa ZigType *err_set_type = wanted_type->data.error_union.err_set_type; if (!type_has_bits(err_set_type)) { - return ir_llvm_value(g, instruction->value); + return ir_llvm_value(g, instruction->operand); } LLVMValueRef ok_err_val = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); @@ -5010,17 +5010,18 @@ 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 = ir_llvm_value(g, instruction->result_loc); - LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); + LLVMValueRef payload_val = ir_llvm_value(g, instruction->operand); + + 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, ""); + LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, result_loc, err_union_payload_index, ""); gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, payload_type, false), payload_val); - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, IrInstructionUnionTag *instruction) { @@ -6840,9 +6841,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == 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; diff --git a/src/ir.cpp b/src/ir.cpp index 58f6b14450..10752cdc64 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1773,11 +1773,17 @@ static IrInstruction *ir_build_optional_wrap(IrAnalyze *ira, IrInstruction *sour return &instruction->base; } -static IrInstruction *ir_build_err_wrap_payload(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { - IrInstructionErrWrapPayload *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; +static IrInstruction *ir_build_err_wrap_payload(IrAnalyze *ira, IrInstruction *source_instruction, + ZigType *result_type, IrInstruction *operand, IrInstruction *result_loc) +{ + IrInstructionErrWrapPayload *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; + instruction->operand = operand; + instruction->result_loc = result_loc; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(operand, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -11078,12 +11084,13 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so } static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *value, ZigType *wanted_type) + IrInstruction *value, ZigType *wanted_type, ResultLoc *result_loc) { assert(wanted_type->id == ZigTypeIdErrorUnion); + ZigType *payload_type = wanted_type->data.error_union.payload_type; + ZigType *err_set_type = wanted_type->data.error_union.err_set_type; if (instr_is_comptime(value)) { - ZigType *payload_type = wanted_type->data.error_union.payload_type; IrInstruction *casted_payload = ir_implicit_cast(ira, value, payload_type); if (type_is_invalid(casted_payload->value.type)) return ira->codegen->invalid_instruction; @@ -11093,7 +11100,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction return ira->codegen->invalid_instruction; ConstExprValue *err_set_val = create_const_vals(1); - err_set_val->type = wanted_type->data.error_union.err_set_type; + err_set_val->type = err_set_type; err_set_val->special = ConstValSpecialStatic; err_set_val->data.x_err_set = nullptr; @@ -11106,10 +11113,19 @@ 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); - result->value.type = wanted_type; + IrInstruction *result_loc_inst; + if (handle_is_ptr(wanted_type)) { + if (result_loc == nullptr) result_loc = no_result_loc(); + result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } + } else { + result_loc_inst = nullptr; + } + + IrInstruction *result = ir_build_err_wrap_payload(ira, source_instr, wanted_type, value, result_loc_inst); result->value.data.rh_error_union = RuntimeHintErrorUnionNonError; - ir_add_alloca(ira, result, wanted_type); return result; } @@ -12057,12 +12073,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); + return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type, result_loc); } else if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdComptimeFloat) { if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) { - return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); + return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type, result_loc); } else { return ira->codegen->invalid_instruction; } @@ -24447,7 +24463,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdTestErr: case IrInstructionIdUnwrapErrCode: case IrInstructionIdErrWrapCode: - case IrInstructionIdErrWrapPayload: case IrInstructionIdFnProto: case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: @@ -24512,6 +24527,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { (IrInstructionUnwrapErrPayload *)instruction; return unwrap_err_payload_instruction->safety_check_on; } + case IrInstructionIdErrWrapPayload: + return reinterpret_cast(instruction)->result_loc != nullptr; } zig_unreachable(); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 6cad5c1dea..7cff6f3d70 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -985,8 +985,9 @@ static void ir_print_err_wrap_code(IrPrint *irp, IrInstructionErrWrapCode *instr static void ir_print_err_wrap_payload(IrPrint *irp, IrInstructionErrWrapPayload *instruction) { fprintf(irp->f, "@errWrapPayload("); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); + ir_print_other_instruction(irp, instruction->operand); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_fn_proto(IrPrint *irp, IrInstructionFnProto *instruction) { -- cgit v1.2.3 From b9c033ae1ac9c21a5729407b9a6ede88854654aa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 17:28:25 -0400 Subject: result location semantics for error union wrapping an error --- src/all_types.hpp | 4 +-- src/codegen.cpp | 18 ++++++-------- src/ir.cpp | 73 +++++++++++++++++++++++++++++++++++++------------------ src/ir_print.cpp | 5 ++-- 4 files changed, 61 insertions(+), 39 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index f13f16152d..7c06719e90 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3109,8 +3109,8 @@ struct IrInstructionErrWrapPayload { struct IrInstructionErrWrapCode { IrInstruction base; - IrInstruction *value; - LLVMValueRef tmp_ptr; + IrInstruction *operand; + IrInstruction *result_loc; }; struct IrInstructionFnProto { diff --git a/src/codegen.cpp b/src/codegen.cpp index 69b234d160..ce844806d9 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4977,20 +4977,19 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable assert(wanted_type->id == ZigTypeIdErrorUnion); - ZigType *payload_type = wanted_type->data.error_union.payload_type; - ZigType *err_set_type = wanted_type->data.error_union.err_set_type; + LLVMValueRef err_val = ir_llvm_value(g, instruction->operand); - LLVMValueRef err_val = ir_llvm_value(g, instruction->value); - - if (!type_has_bits(payload_type) || !type_has_bits(err_set_type)) + if (!handle_is_ptr(wanted_type)) return err_val; - assert(instruction->tmp_ptr); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - 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; + // TODO store undef to the payload + + return result_loc; } static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapPayload *instruction) { @@ -6841,9 +6840,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdErrWrapCode) { - IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; - slot = &err_wrap_code_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdCmpxchgGen) { IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction; slot = &cmpxchg_instruction->tmp_ptr; diff --git a/src/ir.cpp b/src/ir.cpp index 10752cdc64..1a0c7d3144 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1788,11 +1788,17 @@ static IrInstruction *ir_build_err_wrap_payload(IrAnalyze *ira, IrInstruction *s return &instruction->base; } -static IrInstruction *ir_build_err_wrap_code(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { - IrInstructionErrWrapCode *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; +static IrInstruction *ir_build_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instruction, + ZigType *result_type, IrInstruction *operand, IrInstruction *result_loc) +{ + IrInstructionErrWrapCode *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; + instruction->operand = operand; + instruction->result_loc = result_loc; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(operand, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -11172,7 +11178,9 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou return result; } -static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) { +static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, + ZigType *wanted_type, ResultLoc *result_loc) +{ assert(wanted_type->id == ZigTypeIdErrorUnion); IrInstruction *casted_value = ir_implicit_cast(ira, value, wanted_type->data.error_union.err_set_type); @@ -11196,10 +11204,20 @@ 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; + IrInstruction *result_loc_inst; + if (handle_is_ptr(wanted_type)) { + if (result_loc == nullptr) result_loc = no_result_loc(); + result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } + } else { + result_loc_inst = nullptr; + } + + + IrInstruction *result = ir_build_err_wrap_code(ira, source_instr, wanted_type, value, result_loc_inst); result->value.data.rh_error_union = RuntimeHintErrorUnionError; - ir_add_alloca(ira, result, wanted_type); return result; } @@ -12293,7 +12311,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (wanted_type->id == ZigTypeIdErrorUnion && actual_type->id == ZigTypeIdErrorSet) { - return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type); + return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type, result_loc); } // cast from typed number to integer or float literal. @@ -15615,12 +15633,16 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c } FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id; - IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, - impl_fn_type_id->return_type, nullptr); - if (result_loc != nullptr && - (type_is_invalid(result_loc->value.type) || result_loc->value.type->id == ZigTypeIdUnreachable)) - { - return result_loc; + IrInstruction *result_loc; + if (handle_is_ptr(impl_fn_type_id->return_type)) { + result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, + impl_fn_type_id->return_type, nullptr); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + call_instruction->result_loc->written = true; + } else { + result_loc = nullptr; } if (fn_type_can_fail(impl_fn_type_id)) { @@ -15634,7 +15656,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c return ir_finish_anal(ira, result); } - call_instruction->result_loc->written = handle_is_ptr(impl_fn_type_id->return_type); assert(async_allocator_inst == nullptr); IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, impl_fn, nullptr, impl_param_count, casted_args, fn_inline, @@ -15733,15 +15754,18 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c return ira->codegen->invalid_instruction; } - IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, - return_type, nullptr); - if (result_loc != nullptr && - (type_is_invalid(result_loc->value.type) || result_loc->value.type->id == ZigTypeIdUnreachable)) - { - return result_loc; + IrInstruction *result_loc; + if (handle_is_ptr(return_type)) { + result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, + return_type, nullptr); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + call_instruction->result_loc->written = true; + } else { + result_loc = nullptr; } - call_instruction->result_loc->written = handle_is_ptr(return_type); IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, call_param_count, casted_args, fn_inline, false, nullptr, casted_new_stack, result_loc, return_type); @@ -24462,7 +24486,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdHandle: case IrInstructionIdTestErr: case IrInstructionIdUnwrapErrCode: - case IrInstructionIdErrWrapCode: case IrInstructionIdFnProto: case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: @@ -24529,6 +24552,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { } case IrInstructionIdErrWrapPayload: return reinterpret_cast(instruction)->result_loc != nullptr; + case IrInstructionIdErrWrapCode: + return reinterpret_cast(instruction)->result_loc != nullptr; } zig_unreachable(); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 7cff6f3d70..30ca2aa73e 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -979,8 +979,9 @@ static void ir_print_optional_wrap(IrPrint *irp, IrInstructionOptionalWrap *inst static void ir_print_err_wrap_code(IrPrint *irp, IrInstructionErrWrapCode *instruction) { fprintf(irp->f, "@errWrapCode("); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); + ir_print_other_instruction(irp, instruction->operand); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_err_wrap_payload(IrPrint *irp, IrInstructionErrWrapPayload *instruction) { -- cgit v1.2.3 From ee3f7e20f64d715ff22eeff0b7b355bca1981ea1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 17:49:36 -0400 Subject: result location semantics for cmpxchg --- src/all_types.hpp | 12 ++++++------ src/codegen.cpp | 19 ++++++++----------- src/ir.cpp | 33 +++++++++++++++++++++++---------- src/ir_print.cpp | 6 ++++-- 4 files changed, 41 insertions(+), 29 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 7c06719e90..7a4a450c49 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2862,26 +2862,26 @@ struct IrInstructionEmbedFile { struct IrInstructionCmpxchgSrc { IrInstruction base; + bool is_weak; IrInstruction *type_value; IrInstruction *ptr; IrInstruction *cmp_value; IrInstruction *new_value; IrInstruction *success_order_value; IrInstruction *failure_order_value; - - bool is_weak; + ResultLoc *result_loc; }; struct IrInstructionCmpxchgGen { IrInstruction base; + bool is_weak; + AtomicOrder success_order; + AtomicOrder failure_order; IrInstruction *ptr; IrInstruction *cmp_value; IrInstruction *new_value; - LLVMValueRef tmp_ptr; - AtomicOrder success_order; - AtomicOrder failure_order; - bool is_weak; + IrInstruction *result_loc; }; struct IrInstructionFence { diff --git a/src/codegen.cpp b/src/codegen.cpp index ce844806d9..7845ee7289 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4516,28 +4516,28 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val, success_order, failure_order, instruction->is_weak); - ZigType *maybe_type = instruction->base.value.type; - assert(maybe_type->id == ZigTypeIdOptional); - ZigType *child_type = maybe_type->data.maybe.child_type; + ZigType *optional_type = instruction->base.value.type; + assert(optional_type->id == ZigTypeIdOptional); + ZigType *child_type = optional_type->data.maybe.child_type; - if (!handle_is_ptr(maybe_type)) { + if (!handle_is_ptr(optional_type)) { LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, ""); } - assert(instruction->tmp_ptr != nullptr); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); assert(type_has_bits(child_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, child_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) { @@ -6840,9 +6840,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdCmpxchgGen) { - IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction; - slot = &cmpxchg_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdResizeSlice) { IrInstructionResizeSlice *resize_slice_instruction = (IrInstructionResizeSlice *)instruction; slot = &resize_slice_instruction->tmp_ptr; diff --git a/src/ir.cpp b/src/ir.cpp index 1a0c7d3144..6a2ad9125c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2032,8 +2032,7 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, - IrInstruction *success_order_value, IrInstruction *failure_order_value, - bool is_weak) + IrInstruction *success_order_value, IrInstruction *failure_order_value, bool is_weak, ResultLoc *result_loc) { IrInstructionCmpxchgSrc *instruction = ir_build_instruction(irb, scope, source_node); instruction->type_value = type_value; @@ -2043,6 +2042,7 @@ static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode instruction->success_order_value = success_order_value; instruction->failure_order_value = failure_order_value; instruction->is_weak = is_weak; + instruction->result_loc = result_loc; ir_ref_instruction(type_value, irb->current_basic_block); ir_ref_instruction(ptr, irb->current_basic_block); @@ -2054,22 +2054,25 @@ static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } -static IrInstruction *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInstruction *source_instruction, +static IrInstruction *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *result_type, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, - AtomicOrder success_order, AtomicOrder failure_order, bool is_weak) + AtomicOrder success_order, AtomicOrder failure_order, bool is_weak, IrInstruction *result_loc) { IrInstructionCmpxchgGen *instruction = ir_build_instruction(&ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; instruction->ptr = ptr; instruction->cmp_value = cmp_value; instruction->new_value = new_value; instruction->success_order = success_order; instruction->failure_order = failure_order; instruction->is_weak = is_weak; + instruction->result_loc = result_loc; ir_ref_instruction(ptr, ira->new_irb.current_basic_block); ir_ref_instruction(cmp_value, ira->new_irb.current_basic_block); ir_ref_instruction(new_value, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -4420,7 +4423,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg5_value; IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value, - arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak)); + arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak), + result_loc); return ir_lval_wrap(irb, scope, cmpxchg, lval, result_loc); } case BuiltinFnIdFence: @@ -20439,6 +20443,18 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi if (type_is_invalid(ptr->value.type)) return ira->codegen->invalid_instruction; + ZigType *result_type = get_optional_type(ira->codegen, operand_type); + IrInstruction *result_loc; + if (handle_is_ptr(result_type)) { + result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + result_type, nullptr); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + } else { + result_loc = nullptr; + } + // TODO let this be volatile ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false); IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr, ptr_type); @@ -20502,12 +20518,9 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi zig_panic("TODO compile-time execution of cmpxchg"); } - IrInstruction *result = ir_build_cmpxchg_gen(ira, &instruction->base, + return ir_build_cmpxchg_gen(ira, &instruction->base, result_type, casted_ptr, casted_cmp_value, casted_new_value, - success_order, failure_order, instruction->is_weak); - result->value.type = get_optional_type(ira->codegen, operand_type); - ir_add_alloca(ira, result, result->value.type); - return result; + success_order, failure_order, instruction->is_weak, result_loc); } static IrInstruction *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructionFence *instruction) { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 30ca2aa73e..1dd84254fc 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -730,7 +730,8 @@ static void ir_print_cmpxchg_src(IrPrint *irp, IrInstructionCmpxchgSrc *instruct ir_print_other_instruction(irp, instruction->success_order_value); fprintf(irp->f, ", "); ir_print_other_instruction(irp, instruction->failure_order_value); - fprintf(irp->f, ")"); + fprintf(irp->f, ")result="); + ir_print_result_loc(irp, instruction->result_loc); } static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) { @@ -740,7 +741,8 @@ static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruct ir_print_other_instruction(irp, instruction->cmp_value); fprintf(irp->f, ", "); ir_print_other_instruction(irp, instruction->new_value); - fprintf(irp->f, ", TODO print atomic orders)"); + fprintf(irp->f, ", TODO print atomic orders)result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) { -- cgit v1.2.3 From 65f6ea66f4a86c45004547bb5ac079b8286f980e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 18:34:27 -0400 Subject: result loc semantics for `@sliceToBytes` and `@bytesToSlice` --- src/all_types.hpp | 4 +++- src/codegen.cpp | 13 ++++--------- src/ir.cpp | 42 ++++++++++++++++++++++++++++++------------ src/ir_print.cpp | 3 ++- 4 files changed, 39 insertions(+), 23 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 7a4a450c49..e196b6f38f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2635,7 +2635,7 @@ struct IrInstructionResizeSlice { IrInstruction base; IrInstruction *operand; - LLVMValueRef tmp_ptr; + IrInstruction *result_loc; }; struct IrInstructionContainerInitList { @@ -2925,6 +2925,7 @@ struct IrInstructionToBytes { IrInstruction base; IrInstruction *target; + ResultLoc *result_loc; }; struct IrInstructionFromBytes { @@ -2932,6 +2933,7 @@ struct IrInstructionFromBytes { IrInstruction *dest_child_type; IrInstruction *target; + ResultLoc *result_loc; }; struct IrInstructionIntToFloat { diff --git a/src/codegen.cpp b/src/codegen.cpp index 7845ee7289..d84bcd1327 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2943,7 +2943,7 @@ static LLVMValueRef ir_render_resize_slice(CodeGen *g, IrExecutable *executable, LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand); assert(expr_val); - assert(instruction->tmp_ptr); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); assert(wanted_type->id == ZigTypeIdStruct); assert(wanted_type->data.structure.is_slice); assert(actual_type->id == ZigTypeIdStruct); @@ -2964,7 +2964,7 @@ static LLVMValueRef ir_render_resize_slice(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, get_llvm_type(g, wanted_type->data.structure.fields[0].type_entry), ""); - LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, 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); @@ -2997,12 +2997,10 @@ static LLVMValueRef ir_render_resize_slice(CodeGen *g, IrExecutable *executable, zig_unreachable(); } - LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, - (unsigned)wanted_len_index, ""); + 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 instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, @@ -6840,9 +6838,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdResizeSlice) { - IrInstructionResizeSlice *resize_slice_instruction = (IrInstructionResizeSlice *)instruction; - slot = &resize_slice_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdLoadPtrGen) { IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction; slot = &load_ptr_inst->tmp_ptr; diff --git a/src/ir.cpp b/src/ir.cpp index 6a2ad9125c..31235acb85 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1574,14 +1574,16 @@ static IrInstruction *ir_build_var_decl_gen(IrAnalyze *ira, IrInstruction *sourc } static IrInstruction *ir_build_resize_slice(IrAnalyze *ira, IrInstruction *source_instruction, - IrInstruction *operand, ZigType *ty) + IrInstruction *operand, ZigType *ty, IrInstruction *result_loc) { IrInstructionResizeSlice *instruction = ir_build_instruction(&ira->new_irb, source_instruction->scope, source_instruction->source_node); instruction->base.value.type = ty; instruction->operand = operand; + instruction->result_loc = result_loc; ir_ref_instruction(operand, ira->new_irb.current_basic_block); + ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -2131,19 +2133,25 @@ static IrInstruction *ir_build_err_set_cast(IrBuilder *irb, Scope *scope, AstNod return &instruction->base; } -static IrInstruction *ir_build_to_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) { +static IrInstruction *ir_build_to_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target, + ResultLoc *result_loc) +{ IrInstructionToBytes *instruction = ir_build_instruction(irb, scope, source_node); instruction->target = target; + instruction->result_loc = result_loc; ir_ref_instruction(target, irb->current_basic_block); return &instruction->base; } -static IrInstruction *ir_build_from_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_child_type, IrInstruction *target) { +static IrInstruction *ir_build_from_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *dest_child_type, IrInstruction *target, ResultLoc *result_loc) +{ IrInstructionFromBytes *instruction = ir_build_instruction(irb, scope, source_node); instruction->dest_child_type = dest_child_type; instruction->target = target; + instruction->result_loc = result_loc; ir_ref_instruction(dest_child_type, irb->current_basic_block); ir_ref_instruction(target, irb->current_basic_block); @@ -4599,7 +4607,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value); + IrInstruction *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value, result_loc); return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdToBytes: @@ -4609,7 +4617,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; - IrInstruction *result = ir_build_to_bytes(irb, scope, node, arg0_value); + IrInstruction *result = ir_build_to_bytes(irb, scope, node, arg0_value, result_loc); return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdIntToFloat: @@ -5681,7 +5689,8 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A ir_ref_instruction(elem_ptr, irb->current_basic_block); ResultLoc *child_result_loc = &result_loc_inst->base; - IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, child_result_loc); + IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, &result_loc->scope_elide->base, + LValNone, child_result_loc); if (expr_value == irb->codegen->invalid_instruction) return expr_value; @@ -14687,6 +14696,7 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s if (fn_entry != nullptr) { fn_entry->alloca_gen_list.append(alloca_gen); } + result_loc->written = true; result_loc->resolved_loc = &alloca_gen->base; return result_loc->resolved_loc; } @@ -20766,6 +20776,12 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru } } + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + dest_slice_type, nullptr); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + if (casted_value->value.data.rh_slice.id == RuntimeHintSliceIdLen) { known_len = casted_value->value.data.rh_slice.len; have_known_len = true; @@ -20785,9 +20801,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru } } - IrInstruction *result = ir_build_resize_slice(ira, &instruction->base, casted_value, dest_slice_type); - ir_add_alloca(ira, result, dest_slice_type); - return result; + return ir_build_resize_slice(ira, &instruction->base, casted_value, dest_slice_type, result_loc); } static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToBytes *instruction) { @@ -20839,9 +20853,13 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct return result; } - IrInstruction *result = ir_build_resize_slice(ira, &instruction->base, target, dest_slice_type); - ir_add_alloca(ira, result, dest_slice_type); - return result; + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + dest_slice_type, nullptr); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + + return ir_build_resize_slice(ira, &instruction->base, target, dest_slice_type, result_loc); } static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1dd84254fc..3729fab308 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1125,7 +1125,8 @@ static void ir_print_assert_non_null(IrPrint *irp, IrInstructionAssertNonNull *i static void ir_print_resize_slice(IrPrint *irp, IrInstructionResizeSlice *instruction) { fprintf(irp->f, "@resizeSlice("); ir_print_other_instruction(irp, instruction->operand); - fprintf(irp->f, ")"); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_alloca_src(IrPrint *irp, IrInstructionAllocaSrc *instruction) { -- cgit v1.2.3 From 9a324ecb42f69791d49bc8e62e935aec75b5e920 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 19:11:34 -0400 Subject: result loc semantics for loading packed struct pointer to packed struct ```zig export fn entry() void { var x = foo(); var ptr = &x.b; var y = ptr.*; } const Foo = packed struct { a: u24 = 1, b: Bar = Bar{}, }; const Bar = packed struct { a: u4 = 2, b: u4 = 3, }; ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %x = alloca %Foo, align 1 %ptr = alloca i32*, align 8 %y = alloca %Bar, align 1 call fastcc void @foo(%Foo* sret %x), !dbg !55 call void @llvm.dbg.declare(metadata %Foo* %x, metadata !39, metadata !DIExpression()), !dbg !56 %0 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0, !dbg !57 store i32* %0, i32** %ptr, align 8, !dbg !57 call void @llvm.dbg.declare(metadata i32** %ptr, metadata !51, metadata !DIExpression()), !dbg !58 %1 = load i32*, i32** %ptr, align 8, !dbg !59 %2 = load i32, i32* %1, align 1, !dbg !60 %3 = lshr i32 %2, 24, !dbg !60 %4 = trunc i32 %3 to i8, !dbg !60 %5 = bitcast %Bar* %y to i8*, !dbg !60 store i8 %4, i8* %5, !dbg !60 call void @llvm.dbg.declare(metadata %Bar* %y, metadata !54, metadata !DIExpression()), !dbg !61 ret void, !dbg !62 } ``` --- src/all_types.hpp | 5 +- src/codegen.cpp | 9 ++-- src/ir.cpp | 145 ++++++++++++++++++++++++++++++------------------------ src/ir_print.cpp | 4 +- 4 files changed, 90 insertions(+), 73 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index e196b6f38f..d7e11f7102 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2449,8 +2449,9 @@ struct IrInstructionUnOp { IrInstruction base; IrUnOp op_id; - IrInstruction *value; LVal lval; + IrInstruction *value; + ResultLoc *result_loc; }; enum IrBinOp { @@ -2507,7 +2508,7 @@ struct IrInstructionLoadPtrGen { IrInstruction base; IrInstruction *ptr; - LLVMValueRef tmp_ptr; + IrInstruction *result_loc; }; struct IrInstructionStorePtr { diff --git a/src/codegen.cpp b/src/codegen.cpp index d84bcd1327..994194c5eb 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3376,13 +3376,13 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, ""); if (handle_is_ptr(child_type)) { - assert(instruction->tmp_ptr != nullptr); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); LLVMTypeRef same_size_int = LLVMIntType(size_in_bits); LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, ""); - LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, + LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, result_loc, LLVMPointerType(same_size_int, 0), ""); LLVMBuildStore(g->builder, truncated_int, bitcasted_ptr); - return instruction->tmp_ptr; + return result_loc; } if (child_type->id == ZigTypeIdFloat) { @@ -6838,9 +6838,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdLoadPtrGen) { - IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction; - slot = &load_ptr_inst->tmp_ptr; } else if (instruction->id == IrInstructionIdVectorToArray) { IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction; alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type); diff --git a/src/ir.cpp b/src/ir.cpp index 31235acb85..305b534791 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -161,7 +161,8 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, ResultLoc *result_loc); static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type); -static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr); +static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr, + ResultLoc *result_loc); static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg); static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing); @@ -1467,12 +1468,13 @@ static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *s } static IrInstruction *ir_build_un_op_lval(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id, - IrInstruction *value, LVal lval) + IrInstruction *value, LVal lval, ResultLoc *result_loc) { IrInstructionUnOp *instruction = ir_build_instruction(irb, scope, source_node); instruction->op_id = op_id; instruction->value = value; instruction->lval = lval; + instruction->result_loc = result_loc; ir_ref_instruction(value, irb->current_basic_block); @@ -1482,7 +1484,7 @@ static IrInstruction *ir_build_un_op_lval(IrBuilder *irb, Scope *scope, AstNode static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id, IrInstruction *value) { - return ir_build_un_op_lval(irb, scope, source_node, op_id, value, LValNone); + return ir_build_un_op_lval(irb, scope, source_node, op_id, value, LValNone, nullptr); } static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, AstNode *source_node, @@ -2471,14 +2473,16 @@ static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *sourc } static IrInstruction *ir_build_load_ptr_gen(IrAnalyze *ira, IrInstruction *source_instruction, - IrInstruction *ptr, ZigType *ty) + IrInstruction *ptr, ZigType *ty, IrInstruction *result_loc) { IrInstructionLoadPtrGen *instruction = ir_build_instruction( &ira->new_irb, source_instruction->scope, source_instruction->source_node); instruction->base.value.type = ty; instruction->ptr = ptr; + instruction->result_loc = result_loc; ir_ref_instruction(ptr, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -8028,7 +8032,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop // We essentially just converted any lvalue from &(x.*) to (&x).*; // this inhibits checking that x is a pointer later, so we directly // record whether the pointer check is needed - return ir_build_un_op_lval(irb, scope, node, IrUnOpDereference, value, lval); + IrInstruction *un_op = ir_build_un_op_lval(irb, scope, node, IrUnOpDereference, value, lval, result_loc); + return ir_expr_wrap(irb, scope, un_op, result_loc); } case NodeTypeUnwrapOptional: { AstNode *expr_node = node->data.unwrap_optional.expr; @@ -11312,7 +11317,7 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s IrInstruction *array_ptr = nullptr; IrInstruction *array; if (array_arg->value.type->id == ZigTypeIdPointer) { - array = ir_get_deref(ira, source_instr, array_arg); + array = ir_get_deref(ira, source_instr, array_arg, nullptr); array_ptr = array_arg; } else { array = array_arg; @@ -12512,60 +12517,71 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Zig return ir_implicit_cast_with_result(ira, value, expected_type, nullptr); } -static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) { +static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr, + ResultLoc *result_loc) +{ Error err; ZigType *type_entry = ptr->value.type; - if (type_is_invalid(type_entry)) { + if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - } else if (type_entry->id == ZigTypeIdPointer) { - ZigType *child_type = type_entry->data.pointer.child_type; - // if the child type has one possible value, the deref is comptime - switch (type_has_one_possible_value(ira->codegen, child_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_instruction; - case OnePossibleValueYes: - return ir_const(ira, source_instruction, child_type); - case OnePossibleValueNo: - break; + + if (type_entry->id != ZigTypeIdPointer) { + ir_add_error_node(ira, source_instruction->source_node, + buf_sprintf("attempt to dereference non-pointer type '%s'", + buf_ptr(&type_entry->name))); + return ira->codegen->invalid_instruction; + } + + ZigType *child_type = type_entry->data.pointer.child_type; + // if the child type has one possible value, the deref is comptime + switch (type_has_one_possible_value(ira->codegen, child_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueYes: + return ir_const(ira, source_instruction, child_type); + case OnePossibleValueNo: + break; + } + if (instr_is_comptime(ptr)) { + if (ptr->value.special == ConstValSpecialUndef) { + ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value")); + return ira->codegen->invalid_instruction; } - if (instr_is_comptime(ptr)) { - if (ptr->value.special == ConstValSpecialUndef) { - ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value")); - return ira->codegen->invalid_instruction; - } - if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst || - ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) - { - ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); - if (pointee->special != ConstValSpecialRuntime) { - IrInstruction *result = ir_const(ira, source_instruction, child_type); + if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst || + ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) + { + ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); + if (pointee->special != ConstValSpecialRuntime) { + IrInstruction *result = ir_const(ira, source_instruction, child_type); - if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value, - &ptr->value))) - { - return ira->codegen->invalid_instruction; - } - result->value.type = child_type; - return result; + if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value, + &ptr->value))) + { + return ira->codegen->invalid_instruction; } + result->value.type = child_type; + return result; } } - // if the instruction is a const ref instruction we can skip it - if (ptr->id == IrInstructionIdRef) { - IrInstructionRef *ref_inst = reinterpret_cast(ptr); - return ref_inst->value; - } - IrInstruction *result = ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type); - if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) { - ir_add_alloca(ira, result, child_type); + } + // if the instruction is a const ref instruction we can skip it + if (ptr->id == IrInstructionIdRef) { + IrInstructionRef *ref_inst = reinterpret_cast(ptr); + return ref_inst->value; + } + + IrInstruction *result_loc_inst; + if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) { + if (result_loc == nullptr) result_loc = no_result_loc(); + result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; } - return result; } else { - ir_add_error_node(ira, source_instruction->source_node, - buf_sprintf("attempt to dereference non-pointer type '%s'", - buf_ptr(&type_entry->name))); - return ira->codegen->invalid_instruction; + result_loc_inst = nullptr; } + + return ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type, result_loc_inst); } static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) { @@ -14585,7 +14601,7 @@ IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_i ZigVar *coro_allocator_var = ira->old_irb.exec->coro_allocator_var; assert(coro_allocator_var != nullptr); IrInstruction *var_ptr_inst = ir_get_var_ptr(ira, source_instr, coro_allocator_var); - IrInstruction *result = ir_get_deref(ira, source_instr, var_ptr_inst); + IrInstruction *result = ir_get_deref(ira, source_instr, var_ptr_inst, nullptr); assert(result->value.type != nullptr); return result; } @@ -15313,7 +15329,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) { first_arg = first_arg_ptr; } else { - first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr); + first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr, nullptr); if (type_is_invalid(first_arg->value.type)) return ira->codegen->invalid_instruction; } @@ -15472,7 +15488,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) { first_arg = first_arg_ptr; } else { - first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr); + first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr, nullptr); if (type_is_invalid(first_arg->value.type)) return ira->codegen->invalid_instruction; } @@ -15516,7 +15532,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c if (type_is_invalid(arg_var_ptr_inst->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *arg_tuple_arg = ir_get_deref(ira, arg, arg_var_ptr_inst); + IrInstruction *arg_tuple_arg = ir_get_deref(ira, arg, arg_var_ptr_inst, nullptr); if (type_is_invalid(arg_tuple_arg->value.type)) return ira->codegen->invalid_instruction; @@ -15702,7 +15718,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c { first_arg = first_arg_ptr; } else { - first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr); + first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr, nullptr); if (type_is_invalid(first_arg->value.type)) return ira->codegen->invalid_instruction; } @@ -16113,7 +16129,7 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_get_deref(ira, &instruction->base, ptr); + IrInstruction *result = ir_get_deref(ira, &instruction->base, ptr, instruction->result_loc); if (result == ira->codegen->invalid_instruction) return ira->codegen->invalid_instruction; @@ -16994,7 +17010,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc assert(container_ptr->value.type->id == ZigTypeIdPointer); if (container_type->id == ZigTypeIdPointer) { ZigType *bare_type = container_ref_type(container_type); - IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr); + IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr, nullptr); IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_child, bare_type, field_ptr_instruction->initializing); return result; } else { @@ -17339,7 +17355,7 @@ static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruct IrInstruction *ptr = instruction->ptr->child; if (type_is_invalid(ptr->value.type)) return ira->codegen->invalid_instruction; - return ir_get_deref(ira, &instruction->base, ptr); + return ir_get_deref(ira, &instruction->base, ptr, nullptr); } static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) { @@ -17807,7 +17823,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr } if (!safety_check_on) return base_ptr; - IrInstruction *c_ptr_val = ir_get_deref(ira, source_instr, base_ptr); + IrInstruction *c_ptr_val = ir_get_deref(ira, source_instr, base_ptr, nullptr); ir_build_assert_non_null(ira, source_instr, c_ptr_val); return base_ptr; } @@ -18162,7 +18178,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, return result; } - IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); + IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr, nullptr); result->value.type = target_type; return result; } @@ -18192,7 +18208,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, return result; } - IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); + IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr, nullptr); union_value->value.type = target_type; IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope, @@ -18216,7 +18232,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, return result; } - IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); + IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr, nullptr); enum_value->value.type = target_type; return enum_value; } @@ -23105,7 +23121,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, if (lval == LValPtr) { return var_ptr; } else { - return ir_get_deref(ira, &instruction->base, var_ptr); + return ir_get_deref(ira, &instruction->base, var_ptr, nullptr); } } case TldIdFn: { @@ -23640,7 +23656,7 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr } if (instr_is_comptime(casted_ptr)) { - IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr); + IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr, nullptr); ir_assert(result->value.type != nullptr, &instruction->base); return result; } @@ -24474,7 +24490,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdUnOp: case IrInstructionIdBinOp: case IrInstructionIdLoadPtr: - case IrInstructionIdLoadPtrGen: case IrInstructionIdConst: case IrInstructionIdCast: case IrInstructionIdContainerInitList: @@ -24585,6 +24600,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { return reinterpret_cast(instruction)->result_loc != nullptr; case IrInstructionIdErrWrapCode: return reinterpret_cast(instruction)->result_loc != nullptr; + case IrInstructionIdLoadPtrGen: + return reinterpret_cast(instruction)->result_loc != nullptr; } zig_unreachable(); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 3729fab308..4bec292997 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -397,8 +397,10 @@ static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) { } static void ir_print_load_ptr_gen(IrPrint *irp, IrInstructionLoadPtrGen *instruction) { + fprintf(irp->f, "loadptr("); ir_print_other_instruction(irp, instruction->ptr); - fprintf(irp->f, ".*"); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) { -- cgit v1.2.3 From 4582ec518f9984a26c68b8427a914bad6dc80c4a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 19:49:24 -0400 Subject: result location semantics for vector to array ```zig export fn entry() void { var x: @Vector(4, i32) = undefined; var y: [4]i32 = x; } ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %x = alloca <4 x i32>, align 16 %y = alloca [4 x i32], align 4 %0 = bitcast <4 x i32>* %x to i8*, !dbg !47 call void @llvm.memset.p0i8.i64(i8* align 16 %0, i8 -86, i64 16, i1 false), !dbg !47 call void @llvm.dbg.declare(metadata <4 x i32>* %x, metadata !39, metadata !DIExpression()), !dbg !47 %1 = load <4 x i32>, <4 x i32>* %x, align 16, !dbg !48 %2 = bitcast [4 x i32]* %y to <4 x i32>*, !dbg !48 store <4 x i32> %1, <4 x i32>* %2, align 16, !dbg !48 call void @llvm.dbg.declare(metadata [4 x i32]* %y, metadata !45, metadata !DIExpression()), !dbg !49 ret void, !dbg !50 } ``` --- src/all_types.hpp | 2 +- src/codegen.cpp | 10 +++------- src/ir.cpp | 18 +++++++++++------- src/ir_print.cpp | 3 ++- 4 files changed, 17 insertions(+), 16 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index d7e11f7102..6e04fada04 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3522,7 +3522,7 @@ struct IrInstructionVectorToArray { IrInstruction base; IrInstruction *vector; - LLVMValueRef tmp_ptr; + IrInstruction *result_loc; }; struct IrInstructionAssertZero { diff --git a/src/codegen.cpp b/src/codegen.cpp index 994194c5eb..53800d4eec 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5386,12 +5386,12 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab ZigType *array_type = instruction->base.value.type; assert(array_type->id == ZigTypeIdArray); assert(handle_is_ptr(array_type)); - assert(instruction->tmp_ptr); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); LLVMValueRef vector = ir_llvm_value(g, instruction->vector); - LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, + LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc, LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), ""); gen_store_untyped(g, vector, casted_ptr, 0, false); - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executable, @@ -6838,10 +6838,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdVectorToArray) { - IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction; - alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type); - slot = &vector_to_array_instruction->tmp_ptr; } else { zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 305b534791..8282b8de2a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3131,16 +3131,16 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, } static IrInstruction *ir_build_vector_to_array(IrAnalyze *ira, IrInstruction *source_instruction, - IrInstruction *vector, ZigType *result_type) + ZigType *result_type, IrInstruction *vector, IrInstruction *result_loc) { IrInstructionVectorToArray *instruction = ir_build_instruction(&ira->new_irb, source_instruction->scope, source_instruction->source_node); instruction->base.value.type = result_type; instruction->vector = vector; + instruction->result_loc = result_loc; ir_ref_instruction(vector, ira->new_irb.current_basic_block); - - ir_add_alloca(ira, &instruction->base, result_type); + ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -11985,7 +11985,7 @@ static IrInstruction *ir_analyze_array_to_vector(IrAnalyze *ira, IrInstruction * } static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *vector, ZigType *array_type) + IrInstruction *vector, ZigType *array_type, ResultLoc *result_loc) { if (instr_is_comptime(vector)) { // arrays and vectors have the same ConstExprValue representation @@ -11994,7 +11994,11 @@ static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction * result->value.type = array_type; return result; } - return ir_build_vector_to_array(ira, source_instr, vector, array_type); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, array_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } + return ir_build_vector_to_array(ira, source_instr, array_type, vector, result_loc_inst); } static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *source_instr, @@ -12453,7 +12457,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, wanted_type->data.array.child_type, actual_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_vector_to_array(ira, source_instr, value, wanted_type); + return ir_analyze_vector_to_array(ira, source_instr, value, wanted_type, result_loc); } // cast from [N]T to @Vector(N, T) @@ -24484,6 +24488,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdPtrOfArrayToSlice: case IrInstructionIdSliceGen: case IrInstructionIdOptionalWrap: + case IrInstructionIdVectorToArray: return true; case IrInstructionIdPhi: @@ -24578,7 +24583,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdFromBytes: case IrInstructionIdToBytes: case IrInstructionIdEnumToInt: - case IrInstructionIdVectorToArray: case IrInstructionIdArrayToVector: case IrInstructionIdHasDecl: case IrInstructionIdAllocaSrc: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 4bec292997..90fd5aa069 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1102,7 +1102,8 @@ static void ir_print_array_to_vector(IrPrint *irp, IrInstructionArrayToVector *i static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *instruction) { fprintf(irp->f, "VectorToArray("); ir_print_other_instruction(irp, instruction->vector); - fprintf(irp->f, ")"); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_ptr_of_array_to_slice(IrPrint *irp, IrInstructionPtrOfArrayToSlice *instruction) { -- cgit v1.2.3 From f6d4e2565e7c0eea7e50e50dd808246d65d9f200 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 23:51:43 -0400 Subject: use result loc for ref instruction --- src/all_types.hpp | 9 ++++++++- src/codegen.cpp | 22 +++++++++------------- src/ir.cpp | 44 ++++++++++++++++++++++++++++++++------------ src/ir_print.cpp | 10 ++++++++++ 4 files changed, 59 insertions(+), 26 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index a758f5d906..bd72a4fccf 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2234,6 +2234,7 @@ enum IrInstructionId { IrInstructionIdCDefine, IrInstructionIdCUndef, IrInstructionIdRef, + IrInstructionIdRefGen, IrInstructionIdCompileErr, IrInstructionIdCompileLog, IrInstructionIdErrName, @@ -2812,11 +2813,17 @@ struct IrInstructionRef { IrInstruction base; IrInstruction *value; - LLVMValueRef tmp_ptr; bool is_const; bool is_volatile; }; +struct IrInstructionRefGen { + IrInstruction base; + + IrInstruction *operand; + IrInstruction *result_loc; +}; + struct IrInstructionCompileErr { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index 53800d4eec..5e3938a4ae 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4212,17 +4212,17 @@ static LLVMValueRef ir_render_phi(CodeGen *g, IrExecutable *executable, IrInstru return phi; } -static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstructionRef *instruction) { +static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstructionRefGen *instruction) { if (!type_has_bits(instruction->base.value.type)) { return nullptr; } - LLVMValueRef value = ir_llvm_value(g, instruction->value); - if (handle_is_ptr(instruction->value->value.type)) { + LLVMValueRef value = ir_llvm_value(g, instruction->operand); + if (handle_is_ptr(instruction->operand->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 = ir_llvm_value(g, instruction->result_loc); + gen_store_untyped(g, value, result_loc, 0, false); + return result_loc; } } @@ -5530,6 +5530,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdResolveResult: case IrInstructionIdContainerInitList: case IrInstructionIdSliceSrc: + case IrInstructionIdRef: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -5584,8 +5585,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction); case IrInstructionIdPhi: return ir_render_phi(g, executable, (IrInstructionPhi *)instruction); - case IrInstructionIdRef: - return ir_render_ref(g, executable, (IrInstructionRef *)instruction); + case IrInstructionIdRefGen: + return ir_render_ref(g, executable, (IrInstructionRefGen *)instruction); case IrInstructionIdErrName: return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction); case IrInstructionIdCmpxchgGen: @@ -6833,11 +6834,6 @@ static void do_code_gen(CodeGen *g) { 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 { zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 16638de6b3..d132f5110f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -617,6 +617,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionRef *) { return IrInstructionIdRef; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionRefGen *) { + return IrInstructionIdRefGen; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileErr *) { return IrInstructionIdCompileErr; } @@ -1961,6 +1965,21 @@ static IrInstruction *ir_build_ref(IrBuilder *irb, Scope *scope, AstNode *source return &instruction->base; } +static IrInstruction *ir_build_ref_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *result_type, + IrInstruction *operand, IrInstruction *result_loc) +{ + IrInstructionRefGen *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; + instruction->operand = operand; + instruction->result_loc = result_loc; + + ir_ref_instruction(operand, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_compile_err(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *msg) { IrInstructionCompileErr *instruction = ir_build_instruction(irb, scope, source_node); instruction->msg = msg; @@ -2636,11 +2655,8 @@ static IrInstruction *ir_build_type_name(IrBuilder *irb, Scope *scope, AstNode * return &instruction->base; } -static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, - Tld *tld, LVal lval) -{ - IrInstructionDeclRef *instruction = ir_build_instruction( - irb, scope, source_node); +static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, Tld *tld, LVal lval) { + IrInstructionDeclRef *instruction = ir_build_instruction(irb, scope, source_node); instruction->tld = tld; instruction->lval = lval; @@ -11335,15 +11351,16 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type, is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); - IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope, - source_instruction->source_node, value, is_const, is_volatile); - new_instruction->value.type = ptr_type; - new_instruction->value.data.rh_ptr = RuntimeHintPtrStack; + + IrInstruction *result_loc; if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) { - ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); - assert(fn_entry); - fn_entry->alloca_list.append(new_instruction); + result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr); + } else { + result_loc = nullptr; } + + IrInstruction *new_instruction = ir_build_ref_gen(ira, source_instruction, ptr_type, value, result_loc); + new_instruction->value.data.rh_ptr = RuntimeHintPtrStack; return new_instruction; } @@ -24119,6 +24136,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction case IrInstructionIdReturnPtr: case IrInstructionIdAllocaGen: case IrInstructionIdSliceGen: + case IrInstructionIdRefGen: zig_unreachable(); case IrInstructionIdReturn: @@ -24653,6 +24671,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { return reinterpret_cast(instruction)->result_loc != nullptr; case IrInstructionIdLoadPtrGen: return reinterpret_cast(instruction)->result_loc != nullptr; + case IrInstructionIdRefGen: + return reinterpret_cast(instruction)->result_loc != nullptr; } zig_unreachable(); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 90fd5aa069..1935c0d7f6 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -668,6 +668,13 @@ static void ir_print_ref(IrPrint *irp, IrInstructionRef *instruction) { ir_print_other_instruction(irp, instruction->value); } +static void ir_print_ref_gen(IrPrint *irp, IrInstructionRefGen *instruction) { + fprintf(irp->f, "@ref("); + ir_print_other_instruction(irp, instruction->operand); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); +} + static void ir_print_compile_err(IrPrint *irp, IrInstructionCompileErr *instruction) { fprintf(irp->f, "@compileError("); ir_print_other_instruction(irp, instruction->msg); @@ -1711,6 +1718,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdRef: ir_print_ref(irp, (IrInstructionRef *)instruction); break; + case IrInstructionIdRefGen: + ir_print_ref_gen(irp, (IrInstructionRefGen *)instruction); + break; case IrInstructionIdCompileErr: ir_print_compile_err(irp, (IrInstructionCompileErr *)instruction); break; -- cgit v1.2.3 From d504318f2e0f3054c772abbd34f938f2cefa6ccc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 23:54:28 -0400 Subject: remove the final legacy stack allocation --- BRANCH_TODO | 3 --- src/all_types.hpp | 2 -- src/codegen.cpp | 14 -------------- src/ir.cpp | 25 ++++++------------------- 4 files changed, 6 insertions(+), 38 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index f6fd78dbaa..f730eb64f5 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -4,7 +4,4 @@ Scratch pad for stuff to do before merging master look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated return ir_gen_comptime(irb, scope, node, lval); -migrate all the alloca_list to alloca_gen_list - comptime expressions - diff --git a/src/all_types.hpp b/src/all_types.hpp index bd72a4fccf..1d935fee2b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1369,7 +1369,6 @@ struct ZigFn { AstNode *fn_no_inline_set_node; AstNode *fn_static_eval_set_node; - ZigList alloca_list; ZigList alloca_gen_list; ZigList variable_list; @@ -2635,7 +2634,6 @@ struct IrInstructionCast { IrInstruction *value; ZigType *dest_type; CastOp cast_op; - LLVMValueRef tmp_ptr; }; struct IrInstructionResizeSlice { diff --git a/src/codegen.cpp b/src/codegen.cpp index 5e3938a4ae..a75ef29169 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6826,20 +6826,6 @@ static void do_code_gen(CodeGen *g) { get_ptr_align(g, ptr_type)); } - 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; - uint32_t alignment_bytes = 0; - if (instruction->id == IrInstructionIdCast) { - IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction; - slot = &cast_instruction->tmp_ptr; - } else { - zig_unreachable(); - } - *slot = build_alloca(g, slot_type, "", alignment_bytes); - } - ZigType *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 d132f5110f..07df62fd02 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -181,7 +181,6 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); -static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry); static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, ZigType *ptr_type); static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, @@ -10497,15 +10496,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; assert(!same_global_refs || src->global_refs != nullptr); @@ -10631,7 +10621,7 @@ static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, Z } 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)) { IrInstruction *result = ir_const(ira, source_instr, wanted_type); @@ -10644,9 +10634,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; } } @@ -12121,7 +12108,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); } // cast from T to ?T @@ -20752,7 +20739,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; } @@ -20975,7 +20962,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) { @@ -20997,7 +20984,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) { @@ -21049,7 +21036,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) { -- cgit v1.2.3 From 7411a88d5f8109ced238cf14205ae36575f02f21 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Jun 2019 00:27:10 -0400 Subject: fix comptime function calls --- BRANCH_TODO | 4 ++-- src/analyze.cpp | 28 ++++++++++++++++++++++++++++ src/analyze.hpp | 1 + src/codegen.cpp | 28 ---------------------------- src/ir.cpp | 2 ++ 5 files changed, 33 insertions(+), 30 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index f730eb64f5..854b2c0ee7 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,7 +1,7 @@ Scratch pad for stuff to do before merging master ================================================= +uncomment all the behavior tests + look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated return ir_gen_comptime(irb, scope, node, lval); - -comptime expressions diff --git a/src/analyze.cpp b/src/analyze.cpp index 0168dad6ea..beaa9f1486 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -7293,3 +7293,31 @@ void src_assert(bool ok, AstNode *source_node) { const char *msg = "assertion failed. This is a bug in the Zig compiler."; stage2_panic(msg, strlen(msg)); } + +bool scope_is_elided(Scope *scope) { + for (;;) { + switch (scope->id) { + case ScopeIdElide: + if (reinterpret_cast(scope)->activated) + return true; + // fallthrough + case ScopeIdBlock: + case ScopeIdDefer: + case ScopeIdDeferExpr: + case ScopeIdVarDecl: + case ScopeIdLoop: + case ScopeIdSuspend: + case ScopeIdCoroPrelude: + case ScopeIdRuntime: + scope = scope->parent; + continue; + case ScopeIdFnDef: + case ScopeIdCompTime: + case ScopeIdDecls: + case ScopeIdCImport: + return false; + } + zig_unreachable(); + } +} + diff --git a/src/analyze.hpp b/src/analyze.hpp index 2f3ec663da..2c5250d7e9 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -253,5 +253,6 @@ void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_pa void src_assert(bool ok, AstNode *source_node); bool is_container(ZigType *type_entry); ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name); +bool scope_is_elided(Scope *scope); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index a75ef29169..7ee299aab7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5709,34 +5709,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, zig_unreachable(); } -static bool scope_is_elided(Scope *scope) { - for (;;) { - switch (scope->id) { - case ScopeIdDecls: - case ScopeIdCompTime: - case ScopeIdCImport: - zig_unreachable(); - case ScopeIdElide: - if (reinterpret_cast(scope)->activated) - return true; - // fallthrough - case ScopeIdBlock: - case ScopeIdDefer: - case ScopeIdDeferExpr: - case ScopeIdVarDecl: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCoroPrelude: - case ScopeIdRuntime: - scope = scope->parent; - continue; - case ScopeIdFnDef: - return false; - } - zig_unreachable(); - } -} - static void ir_render(CodeGen *g, ZigFn *fn_entry) { assert(fn_entry); diff --git a/src/ir.cpp b/src/ir.cpp index 07df62fd02..1ea509745e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8503,6 +8503,8 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec IrBasicBlock *bb = exec->basic_block_list.at(0); for (size_t i = 0; i < bb->instruction_list.length; i += 1) { IrInstruction *instruction = bb->instruction_list.at(i); + if (scope_is_elided(instruction->scope)) + continue; if (instruction->id == IrInstructionIdReturn) { IrInstructionReturn *ret_inst = (IrInstructionReturn *)instruction; IrInstruction *value = ret_inst->value; -- cgit v1.2.3 From 06f307ff77adac0451b10643a033714c1d309010 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Jun 2019 12:19:57 -0400 Subject: fix implicit casting return value struct/arary init to optional --- BRANCH_TODO | 3 +++ src/all_types.hpp | 3 ++- src/codegen.cpp | 37 ++++++++++++++++++++++--------------- src/ir.cpp | 49 +++++++++++++++++++++++++++++++++++-------------- src/ir_print.cpp | 5 +++-- 5 files changed, 65 insertions(+), 32 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 854b2c0ee7..fba18ed35b 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,6 +1,9 @@ Scratch pad for stuff to do before merging master ================================================= +struct & array init when the result is casted to anyerror!T +struct & array init when the result is casted to anyerror!?T + uncomment all the behavior tests look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated diff --git a/src/all_types.hpp b/src/all_types.hpp index 1d935fee2b..35f8745fd6 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2770,8 +2770,9 @@ struct IrInstructionTestNonNull { struct IrInstructionOptionalUnwrapPtr { IrInstruction base; - IrInstruction *base_ptr; bool safety_check_on; + bool initializing; + IrInstruction *base_ptr; }; struct IrInstructionCtz { diff --git a/src/codegen.cpp b/src/codegen.cpp index 7ee299aab7..2d1ea07bf3 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -838,9 +838,7 @@ static LLVMValueRef gen_store_untyped(CodeGen *g, LLVMValueRef value, LLVMValueR { LLVMValueRef instruction = LLVMBuildStore(g->builder, value, ptr); if (is_volatile) LLVMSetVolatile(instruction, true); - if (alignment == 0) { - LLVMSetAlignment(instruction, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(value))); - } else { + if (alignment != 0) { LLVMSetAlignment(instruction, alignment); } return instruction; @@ -2384,16 +2382,19 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut } static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { + if (return_instruction->value == nullptr) { + LLVMBuildRetVoid(g->builder); + return nullptr; + } + ZigType *return_type = return_instruction->value->value.type; if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) { assert(g->cur_ret_ptr); - if (return_instruction->value->value.special != ConstValSpecialRuntime) { - // if it's comptime we have to do this but if it's runtime trust that - // result location mechanism took care of it. - LLVMValueRef value = ir_llvm_value(g, return_instruction->value); - gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); - } + src_assert(return_instruction->value->value.special != ConstValSpecialRuntime, + return_instruction->base.source_node); + LLVMValueRef value = ir_llvm_value(g, return_instruction->value); + gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); LLVMBuildRetVoid(g->builder); } else if (handle_is_ptr(return_type)) { LLVMValueRef value = ir_llvm_value(g, return_instruction->value); @@ -4068,9 +4069,9 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec ZigType *maybe_type = ptr_type->data.pointer.child_type; assert(maybe_type->id == ZigTypeIdOptional); ZigType *child_type = maybe_type->data.maybe.child_type; - LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->base_ptr); - if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) { - LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); + LLVMValueRef base_ptr = ir_llvm_value(g, instruction->base_ptr); + if (instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base)) { + LLVMValueRef maybe_handle = get_handle_value(g, base_ptr, maybe_type, ptr_type); LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail"); LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); @@ -4086,10 +4087,16 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec } else { bool is_scalar = !handle_is_ptr(maybe_type); if (is_scalar) { - return maybe_ptr; + return base_ptr; } else { - LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); - return LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_child_index, ""); + LLVMValueRef optional_struct_ref = get_handle_value(g, base_ptr, maybe_type, ptr_type); + if (instruction->initializing) { + LLVMValueRef non_null_bit_ptr = LLVMBuildStructGEP(g->builder, optional_struct_ref, + maybe_null_index, ""); + LLVMValueRef non_null_bit = LLVMConstInt(LLVMInt1Type(), 1, false); + gen_store_untyped(g, non_null_bit, non_null_bit_ptr, 0, false); + } + return LLVMBuildStructGEP(g->builder, optional_struct_ref, maybe_child_index, ""); } } } diff --git a/src/ir.cpp b/src/ir.cpp index b05fe835b7..31c40ac168 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -187,6 +187,8 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_ ZigType *dest_type); static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr, ResultLoc *result_loc, ZigType *value_type, IrInstruction *value); +static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool safety_check_on, bool initializing); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -1095,13 +1097,15 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so return &cond_br_instruction->base; } -static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *return_value) { +static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *return_value) +{ IrInstructionReturn *return_instruction = ir_build_instruction(irb, scope, source_node); return_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable; return_instruction->base.value.special = ConstValSpecialStatic; return_instruction->value = return_value; - ir_ref_instruction(return_value, irb->current_basic_block); + if (return_value != nullptr) ir_ref_instruction(return_value, irb->current_basic_block); return &return_instruction->base; } @@ -1756,11 +1760,12 @@ static IrInstruction *ir_build_test_nonnull(IrBuilder *irb, Scope *scope, AstNod } static IrInstruction *ir_build_optional_unwrap_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *base_ptr, bool safety_check_on) + IrInstruction *base_ptr, bool safety_check_on, bool initializing) { IrInstructionOptionalUnwrapPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->base_ptr = base_ptr; instruction->safety_check_on = safety_check_on; + instruction->initializing = initializing; ir_ref_instruction(base_ptr, irb->current_basic_block); @@ -3918,7 +3923,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); ir_set_cursor_at_end_and_append_block(irb, ok_block); - IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false); + IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false, false); IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); ir_build_end_expr(irb, parent_scope, node, unwrapped_payload, &peer_parent->peers[1].base); IrBasicBlock *after_ok_block = irb->current_basic_block; @@ -6009,7 +6014,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, end_block, result_loc); ir_set_cursor_at_end_and_append_block(irb, body_block); - IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false); + IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false, false); IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ? ir_build_ref(irb, child_scope, symbol_node, payload_ptr, true, false) : payload_ptr; ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_ptr); @@ -6609,7 +6614,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN ZigVar *var = ir_create_var(irb, node, subexpr_scope, var_symbol, is_const, is_const, is_shadowable, is_comptime); - IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false); + IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false, false); IrInstruction *var_ptr = var_is_ptr ? ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr; ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_ptr); var_scope = var->child_scope; @@ -8094,7 +8099,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop if (maybe_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true); + IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true, false); if (lval == LValPtr) return unwrapped_ptr; @@ -8375,7 +8380,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec // a register or local variable which does not get spilled into the frame, // otherwise llvm tries to access memory inside the destroyed frame. IrInstruction *unwrapped_await_handle_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, - irb->exec->await_handle_var_ptr, false); + irb->exec->await_handle_var_ptr, false, false); IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr); ir_build_br(irb, scope, node, check_free_block, const_bool_false); @@ -12871,6 +12876,14 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio if (type_is_invalid(value->value.type)) return ir_unreach_error(ira); + if (!instr_is_comptime(value) && handle_is_ptr(ira->explicit_return_type)) { + // result location mechanism took care of it. + IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr); + result->value.type = ira->codegen->builtin_types.entry_unreachable; + return ir_finish_anal(ira, result); + } + IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type); if (type_is_invalid(casted_value->value.type)) { AstNode *source_node = ira->explicit_return_type_source_node; @@ -14925,10 +14938,17 @@ static IrInstruction *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, IrIns } static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrInstructionResolveResult *instruction) { - ZigType *ty = ir_resolve_type(ira, instruction->ty->child); - if (type_is_invalid(ty)) + ZigType *implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); + if (type_is_invalid(implicit_elem_type)) return ira->codegen->invalid_instruction; - return ir_resolve_result(ira, &instruction->base, instruction->result_loc, ty, nullptr); + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + implicit_elem_type, nullptr); + ir_assert(result_loc->value.type->id == ZigTypeIdPointer, &instruction->base); + ZigType *actual_elem_type = result_loc->value.type->data.pointer.child_type; + if (actual_elem_type->id == ZigTypeIdOptional && implicit_elem_type->id != ZigTypeIdOptional) { + return ir_analyze_unwrap_optional_payload(ira, &instruction->base, result_loc, false, true); + } + return result_loc; } static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, @@ -17876,7 +17896,7 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns } static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *base_ptr, bool safety_check_on) + IrInstruction *base_ptr, bool safety_check_on, bool initializing) { ZigType *ptr_type = base_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); @@ -17948,7 +17968,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr } IrInstruction *result = ir_build_optional_unwrap_ptr(&ira->new_irb, source_instr->scope, - source_instr->source_node, base_ptr, safety_check_on); + source_instr->source_node, base_ptr, safety_check_on, initializing); result->value.type = result_type; return result; } @@ -17960,7 +17980,8 @@ static IrInstruction *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira, if (type_is_invalid(base_ptr->value.type)) return ira->codegen->invalid_instruction; - return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, instruction->safety_check_on); + return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, + instruction->safety_check_on, false); } static IrInstruction *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *instruction) { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1935c0d7f6..64e6f07ade 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -61,9 +61,10 @@ static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) { } static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instruction) { - assert(return_instruction->value); fprintf(irp->f, "return "); - ir_print_other_instruction(irp, return_instruction->value); + if (return_instruction->value != nullptr) { + ir_print_other_instruction(irp, return_instruction->value); + } } static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) { -- cgit v1.2.3 From fc8d8812404e79716e15fd301058032485e8bb64 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Jun 2019 13:27:01 -0400 Subject: fix struct and array init when result casted to anyerror!?T --- BRANCH_TODO | 1 - src/all_types.hpp | 10 +++++----- src/codegen.cpp | 7 ++++++- src/ir.cpp | 54 +++++++++++++++++++++++++++++++++--------------------- 4 files changed, 44 insertions(+), 28 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index fba18ed35b..881a2f7d26 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,7 +1,6 @@ Scratch pad for stuff to do before merging master ================================================= -struct & array init when the result is casted to anyerror!T struct & array init when the result is casted to anyerror!?T uncomment all the behavior tests diff --git a/src/all_types.hpp b/src/all_types.hpp index 35f8745fd6..598394cb45 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2343,10 +2343,6 @@ enum IrInstructionId { }; struct IrInstruction { - IrInstructionId id; - // true if this instruction was generated by zig and not from user code - bool is_gen; - Scope *scope; AstNode *source_node; ConstExprValue value; @@ -2360,6 +2356,9 @@ 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; }; struct IrInstructionDeclVarSrc { @@ -3102,8 +3101,9 @@ struct IrInstructionUnwrapErrCode { struct IrInstructionUnwrapErrPayload { IrInstruction base; - IrInstruction *value; bool safety_check_on; + bool initializing; + IrInstruction *value; }; struct IrInstructionOptionalWrap { diff --git a/src/codegen.cpp b/src/codegen.cpp index 2d1ea07bf3..a040d377cf 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4908,7 +4908,7 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) { - bool want_safety = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && + bool want_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base) && g->errors_by_index.length > 1; if (!want_safety && !type_has_bits(instruction->base.value.type)) return nullptr; @@ -4944,6 +4944,11 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu } if (type_has_bits(payload_type)) { + if (instruction->initializing) { + LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); + LLVMValueRef ok_err_val = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); + gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false); + } return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, ""); } else { return nullptr; diff --git a/src/ir.cpp b/src/ir.cpp index 31c40ac168..b841f8032f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -189,6 +189,8 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s ResultLoc *result_loc, ZigType *value_type, IrInstruction *value); static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *base_ptr, bool safety_check_on, bool initializing); +static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool safety_check_on, bool initializing); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -2424,11 +2426,12 @@ static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, Ast } static IrInstruction *ir_build_unwrap_err_payload(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value, bool safety_check_on) + IrInstruction *value, bool safety_check_on, bool initializing) { IrInstructionUnwrapErrPayload *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; instruction->safety_check_on = safety_check_on; + instruction->initializing = initializing; ir_ref_instruction(value, irb->current_basic_block); @@ -3572,7 +3575,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, } ir_set_cursor_at_end_and_append_block(irb, continue_block); - IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false); + IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false, false); if (lval == LValPtr) return unwrapped_ptr; else @@ -5578,7 +5581,7 @@ static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, Ast if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, source_node, err_union_ptr, true); + IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, source_node, err_union_ptr, true, false); if (payload_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -5915,7 +5918,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_set_cursor_at_end_and_append_block(irb, body_block); if (var_symbol) { IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node, - err_val_ptr, false); + err_val_ptr, false, false); IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ? ir_build_ref(irb, payload_scope, symbol_node, payload_ptr, true, false) : payload_ptr; ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_ptr); @@ -6694,7 +6697,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * ZigVar *var = ir_create_var(irb, node, subexpr_scope, var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime); - IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false); + IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false, false); IrInstruction *var_ptr = var_is_ptr ? ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr; ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_ptr); @@ -7316,7 +7319,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode ir_mark_gen(ir_build_br(irb, err_scope, node, end_block, is_comptime)); 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_ptr = ir_build_unwrap_err_payload(irb, parent_scope, node, err_union_ptr, false, false); IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); ir_build_end_expr(irb, parent_scope, node, unwrapped_payload, &peer_parent->peers[1].base); IrBasicBlock *after_ok_block = irb->current_basic_block; @@ -14947,6 +14950,8 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn ZigType *actual_elem_type = result_loc->value.type->data.pointer.child_type; if (actual_elem_type->id == ZigTypeIdOptional && implicit_elem_type->id != ZigTypeIdOptional) { return ir_analyze_unwrap_optional_payload(ira, &instruction->base, result_loc, false, true); + } else if (actual_elem_type->id == ZigTypeIdErrorUnion && implicit_elem_type->id != ZigTypeIdErrorUnion) { + return ir_analyze_unwrap_error_payload(ira, &instruction->base, result_loc, false, true); } return result_loc; } @@ -22136,14 +22141,10 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrI return result; } -static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, - IrInstructionUnwrapErrPayload *instruction) +static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool safety_check_on, bool initializing) { - assert(instruction->value->child); - IrInstruction *value = instruction->value->child; - if (type_is_invalid(value->value.type)) - return ira->codegen->invalid_instruction; - ZigType *ptr_type = value->value.type; + ZigType *ptr_type = base_ptr->value.type; // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. assert(ptr_type->id == ZigTypeIdPointer); @@ -22153,7 +22154,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, return ira->codegen->invalid_instruction; if (type_entry->id != ZigTypeIdErrorUnion) { - ir_add_error(ira, value, + ir_add_error(ira, base_ptr, buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); return ira->codegen->invalid_instruction; } @@ -22165,23 +22166,23 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0, false); - if (instr_is_comptime(value)) { - ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); + if (instr_is_comptime(base_ptr)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); if (!ptr_val) return ira->codegen->invalid_instruction; if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); + ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); if (err_union_val == nullptr) return ira->codegen->invalid_instruction; if (err_union_val->special != ConstValSpecialRuntime) { ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; if (err != nullptr) { - ir_add_error(ira, &instruction->base, + ir_add_error(ira, source_instr, buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name))); return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_const(ira, &instruction->base, result_type); + IrInstruction *result = ir_const(ira, source_instr, result_type); result->value.data.x_ptr.special = ConstPtrSpecialRef; result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload; return result; @@ -22189,12 +22190,23 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, } } - IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on); + IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb, source_instr->scope, + source_instr->source_node, base_ptr, safety_check_on, initializing); result->value.type = result_type; return result; } +static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, + IrInstructionUnwrapErrPayload *instruction) +{ + assert(instruction->value->child); + IrInstruction *value = instruction->value->child; + if (type_is_invalid(value->value.type)) + return ira->codegen->invalid_instruction; + + return ir_analyze_unwrap_error_payload(ira, &instruction->base, value, instruction->safety_check_on, false); +} + static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) { AstNode *proto_node = instruction->base.source_node; assert(proto_node->type == NodeTypeFnProto); -- cgit v1.2.3 From e1d14e73b5f9c7a8d1a92ccd36cb689d625faf57 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Jun 2019 15:44:06 -0400 Subject: fix `@bitCast` semantics when there is no parent result loc --- src/all_types.hpp | 9 +++++++++ src/codegen.cpp | 1 + src/ir.cpp | 41 +++++++++++++++++++++++++++++++++++++++-- src/ir_print.cpp | 10 ++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 598394cb45..7a6123b145 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -44,6 +44,7 @@ struct IrAnalyze; struct ResultLoc; struct ResultLocPeer; struct ResultLocPeerParent; +struct ResultLocBitCast; enum X64CABIClass { X64CABIClass_Unknown, @@ -2272,6 +2273,7 @@ enum IrInstructionId { IrInstructionIdTestComptime, IrInstructionIdPtrCastSrc, IrInstructionIdPtrCastGen, + IrInstructionIdBitCastSrc, IrInstructionIdBitCastGen, IrInstructionIdWidenOrShorten, IrInstructionIdIntToPtr, @@ -3159,6 +3161,13 @@ struct IrInstructionPtrCastGen { bool safety_check_on; }; +struct IrInstructionBitCastSrc { + IrInstruction base; + + IrInstruction *operand; + ResultLocBitCast *result_loc_bit_cast; +}; + struct IrInstructionBitCastGen { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index a040d377cf..beee678888 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5543,6 +5543,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdContainerInitList: case IrInstructionIdSliceSrc: case IrInstructionIdRef: + case IrInstructionIdBitCastSrc: zig_unreachable(); case IrInstructionIdDeclVarGen: diff --git a/src/ir.cpp b/src/ir.cpp index d1289bb89d..df7a593601 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -792,6 +792,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) { return IrInstructionIdPtrCastGen; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastSrc *) { + return IrInstructionIdBitCastSrc; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastGen *) { return IrInstructionIdBitCastGen; } @@ -2515,6 +2519,18 @@ static IrInstruction *ir_build_load_ptr_gen(IrAnalyze *ira, IrInstruction *sourc return &instruction->base; } +static IrInstruction *ir_build_bit_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *operand, ResultLocBitCast *result_loc_bit_cast) +{ + IrInstructionBitCastSrc *instruction = ir_build_instruction(irb, scope, source_node); + instruction->operand = operand; + instruction->result_loc_bit_cast = result_loc_bit_cast; + + ir_ref_instruction(operand, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_bit_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *operand, ZigType *ty) { @@ -4941,7 +4957,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - return ir_lval_wrap(irb, scope, arg1_value, lval, result_loc); + IrInstruction *bitcast = ir_build_bit_cast_src(irb, scope, arg1_node, arg1_value, result_loc_bit_cast); + return ir_lval_wrap(irb, scope, bitcast, lval, result_loc); } case BuiltinFnIdIntToPtr: { @@ -14910,9 +14927,15 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s return ira->codegen->invalid_instruction; } + IrInstruction *bitcasted_value; + if (value != nullptr) { + bitcasted_value = ir_analyze_bit_cast(ira, result_loc->source_instruction, value, dest_type); + } else { + bitcasted_value = nullptr; + } IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_bit_cast->parent, - dest_type, nullptr); + dest_type, bitcasted_value); if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || parent_result_loc->value.type->id == ZigTypeIdUnreachable) { @@ -24168,6 +24191,17 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct return ir_const_void(ira, &instruction->base); } +static IrInstruction *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, IrInstructionBitCastSrc *instruction) { + IrInstruction *operand = instruction->operand->child; + if (type_is_invalid(operand->value.type) || instr_is_comptime(operand) || + instruction->result_loc_bit_cast->parent->gen_instruction == nullptr) + { + return operand; + } + + return instruction->result_loc_bit_cast->parent->gen_instruction; +} + static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -24472,6 +24506,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return nullptr; case IrInstructionIdEndExpr: return ir_analyze_instruction_end_expr(ira, (IrInstructionEndExpr *)instruction); + case IrInstructionIdBitCastSrc: + return ir_analyze_instruction_bit_cast_src(ira, (IrInstructionBitCastSrc *)instruction); } zig_unreachable(); } @@ -24663,6 +24699,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: case IrInstructionIdPtrCastGen: + case IrInstructionIdBitCastSrc: case IrInstructionIdBitCastGen: case IrInstructionIdWidenOrShorten: case IrInstructionIdPtrToInt: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 64e6f07ade..4b8b175be0 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1046,6 +1046,13 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc fprintf(irp->f, ")"); } +static void ir_print_bit_cast_src(IrPrint *irp, IrInstructionBitCastSrc *instruction) { + fprintf(irp->f, "@bitCast("); + ir_print_other_instruction(irp, instruction->operand); + fprintf(irp->f, ")result="); + ir_print_result_loc(irp, &instruction->result_loc_bit_cast->base); +} + static void ir_print_bit_cast_gen(IrPrint *irp, IrInstructionBitCastGen *instruction) { fprintf(irp->f, "@bitCast("); ir_print_other_instruction(irp, instruction->operand); @@ -1860,6 +1867,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdPtrCastGen: ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction); break; + case IrInstructionIdBitCastSrc: + ir_print_bit_cast_src(irp, (IrInstructionBitCastSrc *)instruction); + break; case IrInstructionIdBitCastGen: ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction); break; -- cgit v1.2.3 From b3a4ec1bd209c022445b6f70385b3f88517e72f9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Jun 2019 16:04:04 -0400 Subject: fix returning scalar values ```zig export fn entry1() i32 { return bar(); } ``` ```llvm define i32 @entry1() #2 !dbg !35 { Entry: %0 = call fastcc i32 @bar(), !dbg !39 ret i32 %0, !dbg !41 } ``` --- src/codegen.cpp | 3 ++- src/ir.cpp | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index beee678888..a035c6b332 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3564,7 +3564,8 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable, IrInstructionReturnPtr *instruction) { - assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type)); + src_assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type), + instruction->base.source_node); return g->cur_ret_ptr; } diff --git a/src/ir.cpp b/src/ir.cpp index df7a593601..b3d5109e93 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14866,7 +14866,11 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s } case ResultLocIdReturn: { bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime; - if (is_comptime) return nullptr; + if (is_comptime) + return nullptr; + if (!type_has_bits(ira->explicit_return_type) || !handle_is_ptr(ira->explicit_return_type)) + return nullptr; + ZigType *ptr_return_type = get_pointer_to_type(ira->codegen, ira->explicit_return_type, false); result_loc->written = true; result_loc->resolved_loc = ir_build_return_ptr(ira, result_loc->source_instruction, ptr_return_type); -- cgit v1.2.3 From 4ea7685a5bf2abc504571939984b9eda7441ef5d Mon Sep 17 00:00:00 2001 From: emekoi Date: Tue, 11 Jun 2019 16:05:56 -0500 Subject: made root package available to all other packages --- src/codegen.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 12b07ea6bc..cb767bcea7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8505,10 +8505,8 @@ static ZigType *add_special_code(CodeGen *g, ZigPackage *package, const char *ba return add_source_file(g, package, resolved_path, import_code, SourceKindPkgMain); } -static ZigPackage *create_bootstrap_pkg(CodeGen *g, ZigPackage *pkg_with_main) { - ZigPackage *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special"); - package->package_table.put(buf_create_from_str("@root"), pkg_with_main); - return package; +static ZigPackage *create_bootstrap_pkg(CodeGen *g) { + return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special"); } static ZigPackage *create_test_runner_pkg(CodeGen *g) { @@ -8632,12 +8630,12 @@ static void gen_root_source(CodeGen *g) { !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap.zig"); + g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap.zig"); } if (g->zig_target->os == OsWindows && !g->have_dllmain_crt_startup && g->out_type == OutTypeLib && g->is_dynamic) { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig"); + g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap_lib.zig"); } if (!g->error_during_imports) { @@ -8645,7 +8643,7 @@ static void gen_root_source(CodeGen *g) { } if (g->is_test_build) { create_test_compile_var_and_add_test_runner(g); - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->test_runner_package), "bootstrap.zig"); + g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap.zig"); if (!g->error_during_imports) { semantic_analyze(g); @@ -9629,6 +9627,13 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c if (g->std_package != nullptr) { assert(g->compile_var_package != nullptr); pkg->package_table.put(buf_create_from_str("std"), g->std_package); + + if (g->is_test_build) { + pkg->package_table.put(buf_create_from_str("@root"), g->test_runner_package); + } else { + pkg->package_table.put(buf_create_from_str("@root"), g->root_package); + } + pkg->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); } return pkg; -- cgit v1.2.3 From e12c7d88b28200bc64a538cd4812bfe58a6b6b78 Mon Sep 17 00:00:00 2001 From: emekoi Date: Tue, 11 Jun 2019 16:06:24 -0500 Subject: made root package available to itself --- src/codegen.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index cb767bcea7..a50a416e40 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -180,6 +180,8 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget g->root_package = new_package(".", "", ""); } + g->root_package->package_table.put(buf_create_from_str("@root"), g->root_package); + g->zig_std_special_dir = buf_alloc(); os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir); -- cgit v1.2.3 From 3ed6acd2d20de0a2a08ddf6549fb06a66687d96a Mon Sep 17 00:00:00 2001 From: emekoi Date: Tue, 11 Jun 2019 18:40:55 -0500 Subject: fixed infinite loop when caching packages --- src/codegen.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index a50a416e40..56bc9827c5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -9373,6 +9373,8 @@ static void add_cache_pkg(CodeGen *g, CacheHash *ch, ZigPackage *pkg) { // TODO: I think we need a more sophisticated detection of // packages we have already seen if (entry->value != pkg) { + auto root = pkg->package_table.maybe_get(buf_create_from_str("@root")); + if (root != nullptr && entry->value == root->value) continue; cache_buf(ch, entry->key); add_cache_pkg(g, ch, entry->value); } -- cgit v1.2.3 From 2ba29a1907264d6466f187cd89552a63160d3922 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 14 Jun 2019 11:01:38 -0400 Subject: fix peer result location with error code and payload --- src/all_types.hpp | 1 + src/codegen.cpp | 1 + src/ir.cpp | 67 ++++++++++++++++++++++++++++++++++++------------ test/stage1/behavior.zig | 14 +++++----- 4 files changed, 59 insertions(+), 24 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index d81fec19e9..4609d246b6 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3099,6 +3099,7 @@ struct IrInstructionTestErr { struct IrInstructionUnwrapErrCode { IrInstruction base; + bool initializing; IrInstruction *err_union_ptr; }; diff --git a/src/codegen.cpp b/src/codegen.cpp index a035c6b332..def2f6f8eb 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4901,6 +4901,7 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab if (!type_has_bits(payload_type)) { return err_union_ptr; } else { + // TODO assign undef to the payload LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); } diff --git a/src/ir.cpp b/src/ir.cpp index a292f9a79b..5dfd84ff15 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -193,6 +193,8 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr IrInstruction *base_ptr, bool safety_check_on, bool initializing); static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *base_ptr, bool safety_check_on, bool initializing); +static IrInstruction *ir_analyze_unwrap_err_code(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool initializing); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -15016,13 +15018,17 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s if (actual_elem_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional) { return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr, result_loc, false, true); } else if (actual_elem_type->id == ZigTypeIdErrorUnion && value_type->id != ZigTypeIdErrorUnion) { - IrInstruction *unwrapped_err_ptr = ir_analyze_unwrap_error_payload(ira, suspend_source_instr, - result_loc, false, true); - ZigType *actual_payload_type = actual_elem_type->data.error_union.payload_type; - if (actual_payload_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional) { - return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr, unwrapped_err_ptr, false, true); + if (value_type->id == ZigTypeIdErrorSet) { + return ir_analyze_unwrap_err_code(ira, suspend_source_instr, result_loc, true); } else { - return unwrapped_err_ptr; + IrInstruction *unwrapped_err_ptr = ir_analyze_unwrap_error_payload(ira, suspend_source_instr, + result_loc, false, true); + ZigType *actual_payload_type = actual_elem_type->data.error_union.payload_type; + if (actual_payload_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional) { + return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr, unwrapped_err_ptr, false, true); + } else { + return unwrapped_err_ptr; + } } } return result_loc; @@ -16437,6 +16443,9 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh peer_parent->base.source_instruction->source_node, expected_type, instructions, peer_parent->peer_count); + // the logic below assumes there are no instructions in the new current basic block yet + ir_assert(ira->new_irb.current_basic_block->instruction_list.length == 0, &phi_instruction->base); + // In case resolving the parent activates a suspend, do it now IrInstruction *parent_result_loc = ir_resolve_result(ira, &phi_instruction->base, peer_parent->parent, peer_parent->resolved_type, nullptr); @@ -16445,6 +16454,21 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh { return parent_result_loc; } + // If the above code generated any instructions in the current basic block, we need + // to move them to the peer parent predecessor. + ZigList instrs_to_move = {}; + while (ira->new_irb.current_basic_block->instruction_list.length != 0) { + instrs_to_move.append(ira->new_irb.current_basic_block->instruction_list.pop()); + } + if (instrs_to_move.length != 0) { + IrBasicBlock *predecessor = peer_parent->base.source_instruction->child->owner_bb; + IrInstruction *branch_instruction = predecessor->instruction_list.pop(); + ir_assert(branch_instruction->value.type->id == ZigTypeIdUnreachable, &phi_instruction->base); + while (instrs_to_move.length != 0) { + predecessor->instruction_list.append(instrs_to_move.pop()); + } + predecessor->instruction_list.append(branch_instruction); + } } IrSuspendPosition suspend_pos; @@ -22213,10 +22237,9 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct } } -static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrInstructionUnwrapErrCode *instruction) { - IrInstruction *base_ptr = instruction->err_union_ptr->child; - if (type_is_invalid(base_ptr->value.type)) - return ira->codegen->invalid_instruction; +static IrInstruction *ir_analyze_unwrap_err_code(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool initializing) +{ ZigType *ptr_type = base_ptr->value.type; // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. @@ -22238,30 +22261,38 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrI if (!ptr_val) return ira->codegen->invalid_instruction; if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); + ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); if (err_union_val == nullptr) return ira->codegen->invalid_instruction; if (err_union_val->special != ConstValSpecialRuntime) { ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; assert(err != nullptr); - IrInstruction *err_set_val = ir_const(ira, &instruction->base, - type_entry->data.error_union.err_set_type); + IrInstruction *err_set_val = ir_const(ira, source_instr, type_entry->data.error_union.err_set_type); err_set_val->value.data.x_err_set = err; err_set_val->value.parent.id = ConstParentIdErrUnionCode; err_set_val->value.parent.data.p_err_union_code.err_union_val = err_union_val; - return ir_get_ref(ira, &instruction->base, err_set_val, is_ptr_const, false); + return ir_get_ref(ira, source_instr, err_set_val, is_ptr_const, false); } } } IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, base_ptr); + source_instr->scope, source_instr->source_node, base_ptr); result->value.type = get_pointer_to_type(ira->codegen, type_entry->data.error_union.err_set_type, is_ptr_const); return result; } +static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, + IrInstructionUnwrapErrCode *instruction) +{ + IrInstruction *base_ptr = instruction->err_union_ptr->child; + if (type_is_invalid(base_ptr->value.type)) + return ira->codegen->invalid_instruction; + return ir_analyze_unwrap_err_code(ira, &instruction->base, base_ptr, false); +} + static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *base_ptr, bool safety_check_on, bool initializing) { @@ -24783,7 +24814,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdFrameAddress: case IrInstructionIdHandle: case IrInstructionIdTestErr: - case IrInstructionIdUnwrapErrCode: case IrInstructionIdFnProto: case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: @@ -24846,8 +24876,11 @@ bool ir_has_side_effects(IrInstruction *instruction) { { IrInstructionUnwrapErrPayload *unwrap_err_payload_instruction = (IrInstructionUnwrapErrPayload *)instruction; - return unwrap_err_payload_instruction->safety_check_on; + return unwrap_err_payload_instruction->safety_check_on || + unwrap_err_payload_instruction->initializing; } + case IrInstructionIdUnwrapErrCode: + return reinterpret_cast(instruction)->initializing; case IrInstructionIdErrWrapPayload: return reinterpret_cast(instruction)->result_loc != nullptr; case IrInstructionIdErrWrapCode: diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 56a3860199..56862e07a7 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -21,7 +21,7 @@ comptime { _ = @import("behavior/bugs/1486.zig"); _ = @import("behavior/bugs/1500.zig"); _ = @import("behavior/bugs/1607.zig"); - //_ = @import("behavior/bugs/1851.zig"); + _ = @import("behavior/bugs/1851.zig"); _ = @import("behavior/bugs/1914.zig"); _ = @import("behavior/bugs/2006.zig"); _ = @import("behavior/bugs/2114.zig"); @@ -41,16 +41,16 @@ comptime { _ = @import("behavior/byval_arg_var.zig"); //_ = @import("behavior/cancel.zig"); //_ = @import("behavior/cast.zig"); - //_ = @import("behavior/const_slice_child.zig"); + _ = @import("behavior/const_slice_child.zig"); //_ = @import("behavior/coroutine_await_struct.zig"); //_ = @import("behavior/coroutines.zig"); - //_ = @import("behavior/defer.zig"); + _ = @import("behavior/defer.zig"); //_ = @import("behavior/enum.zig"); //_ = @import("behavior/enum_with_members.zig"); //_ = @import("behavior/error.zig"); //_ = @import("behavior/eval.zig"); _ = @import("behavior/field_parent_ptr.zig"); - //_ = @import("behavior/fn.zig"); + _ = @import("behavior/fn.zig"); _ = @import("behavior/fn_in_struct_in_comptime.zig"); _ = @import("behavior/for.zig"); //_ = @import("behavior/generics.zig"); @@ -59,13 +59,13 @@ comptime { //_ = @import("behavior/import.zig"); _ = @import("behavior/incomplete_struct_param_tld.zig"); _ = @import("behavior/inttoptr.zig"); - //_ = @import("behavior/ir_block_deps.zig"); + _ = @import("behavior/ir_block_deps.zig"); //_ = @import("behavior/math.zig"); //_ = @import("behavior/merge_error_sets.zig"); //_ = @import("behavior/misc.zig"); _ = @import("behavior/namespace_depends_on_compile_var.zig"); _ = @import("behavior/new_stack_call.zig"); - //_ = @import("behavior/null.zig"); + _ = @import("behavior/null.zig"); //_ = @import("behavior/optional.zig"); //_ = @import("behavior/pointers.zig"); _ = @import("behavior/popcount.zig"); @@ -93,7 +93,7 @@ comptime { //_ = @import("behavior/union.zig"); _ = @import("behavior/var_args.zig"); _ = @import("behavior/vector.zig"); - //_ = @import("behavior/void.zig"); + _ = @import("behavior/void.zig"); //_ = @import("behavior/while.zig"); _ = @import("behavior/widening.zig"); } -- cgit v1.2.3 From 6bf193af192ffaf3465958a243ec8fc8941cfe4d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 15 Jun 2019 12:28:21 -0400 Subject: better result location semantics with optionals and return locations somewhere along this branch, #1901 has been fixed. --- BRANCH_TODO | 5 +- src/all_types.hpp | 24 +++++++- src/codegen.cpp | 36 ++++++++---- src/ir.cpp | 114 ++++++++++++++++++++++++++++---------- src/ir_print.cpp | 33 ++++++++--- std/os.zig | 2 +- std/special/panic.zig | 23 ++++++-- std/special/test_runner.zig | 22 +++----- test/stage1/behavior.zig | 18 +++--- test/stage1/behavior/cast.zig | 16 +++--- test/stage1/behavior/error.zig | 84 ++++++++++++++-------------- test/stage1/behavior/generics.zig | 26 ++++----- test/stage1/behavior/optional.zig | 3 +- test/stage1/behavior/while.zig | 44 +++++++-------- 14 files changed, 281 insertions(+), 169 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 79616923bd..011630f315 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -4,10 +4,7 @@ Scratch pad for stuff to do before merging master uncomment all the behavior tests diff master branch to make sure -restore test_runner.zig to master branch - - also the default panic function and unexpected_error_tracing. see the commit - that adds this text to BRANCH_TODO file. - - and std/specia/bootstrap.zig +restore bootstrap.zig to master get an empty file compiling successfully (with no panic fn override) diff --git a/src/all_types.hpp b/src/all_types.hpp index 4497f7bfc7..73726de39b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2257,7 +2257,8 @@ enum IrInstructionId { IrInstructionIdHandle, IrInstructionIdAlignOf, IrInstructionIdOverflowOp, - IrInstructionIdTestErr, + IrInstructionIdTestErrSrc, + IrInstructionIdTestErrGen, IrInstructionIdUnwrapErrCode, IrInstructionIdUnwrapErrPayload, IrInstructionIdErrWrapCode, @@ -2292,6 +2293,7 @@ enum IrInstructionId { IrInstructionIdAlignCast, IrInstructionIdImplicitCast, IrInstructionIdResolveResult, + IrInstructionIdResultPtr, IrInstructionIdOpaqueType, IrInstructionIdSetAlignStack, IrInstructionIdArgType, @@ -3082,10 +3084,16 @@ struct IrInstructionAlignOf { }; // returns true if error, returns false if not error -struct IrInstructionTestErr { +struct IrInstructionTestErrSrc { IrInstruction base; - IrInstruction *value; + IrInstruction *base_ptr; +}; + +struct IrInstructionTestErrGen { + IrInstruction base; + + IrInstruction *err_union; }; // Takes an error union pointer, returns a pointer to the error code. @@ -3596,6 +3604,7 @@ struct IrInstructionImplicitCast { ResultLoc *result_loc; }; +// This one is for writing through the result pointer. struct IrInstructionResolveResult { IrInstruction base; @@ -3603,6 +3612,15 @@ struct IrInstructionResolveResult { IrInstruction *ty; }; +// This one is when you want to read the value of the result. +// You have to give the value in case it is comptime. +struct IrInstructionResultPtr { + IrInstruction base; + + ResultLoc *result_loc; + IrInstruction *result; +}; + struct IrInstructionPtrOfArrayToSlice { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index 764f79b130..42670f9005 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1323,7 +1323,9 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) { LLVMBuildRetVoid(g->builder); LLVMPositionBuilderAtEnd(g->builder, prev_block); - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + if (!g->strip_debug_symbols) { + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + } g->add_error_return_trace_addr_fn_val = fn_val; return fn_val; @@ -1454,7 +1456,9 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { LLVMBuildBr(g->builder, loop_block); LLVMPositionBuilderAtEnd(g->builder, prev_block); - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + if (!g->strip_debug_symbols) { + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + } g->merge_err_ret_traces_fn_val = fn_val; return fn_val; @@ -1510,7 +1514,9 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { LLVMBuildRetVoid(g->builder); LLVMPositionBuilderAtEnd(g->builder, prev_block); - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + if (!g->strip_debug_symbols) { + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + } g->return_err_fn = fn_val; return fn_val; @@ -1638,7 +1644,9 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { gen_panic(g, msg_slice, err_ret_trace_arg); LLVMPositionBuilderAtEnd(g->builder, prev_block); - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + if (!g->strip_debug_symbols) { + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + } g->safety_crash_err_fn = fn_val; return fn_val; @@ -4353,7 +4361,9 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) { g->cur_fn = prev_cur_fn; g->cur_fn_val = prev_cur_fn_val; LLVMPositionBuilderAtEnd(g->builder, prev_block); - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + if (!g->strip_debug_symbols) { + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + } enum_type->data.enumeration.name_function = fn_val; return fn_val; @@ -4880,10 +4890,10 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable, return overflow_bit; } -static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) { - ZigType *err_union_type = instruction->value->value.type; +static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErrGen *instruction) { + ZigType *err_union_type = instruction->err_union->value.type; ZigType *payload_type = err_union_type->data.error_union.payload_type; - LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value); + LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->err_union); LLVMValueRef err_val; if (type_has_bits(payload_type)) { @@ -5276,7 +5286,9 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f g->cur_fn = prev_cur_fn; g->cur_fn_val = prev_cur_fn_val; LLVMPositionBuilderAtEnd(g->builder, prev_block); - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + if (!g->strip_debug_symbols) { + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + } g->coro_alloc_helper_fn_val = fn_val; return fn_val; @@ -5549,10 +5561,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdAllocaGen: case IrInstructionIdImplicitCast: case IrInstructionIdResolveResult: + case IrInstructionIdResultPtr: case IrInstructionIdContainerInitList: case IrInstructionIdSliceSrc: case IrInstructionIdRef: case IrInstructionIdBitCastSrc: + case IrInstructionIdTestErrSrc: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -5635,8 +5649,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_handle(g, executable, (IrInstructionHandle *)instruction); case IrInstructionIdOverflowOp: return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction); - case IrInstructionIdTestErr: - return ir_render_test_err(g, executable, (IrInstructionTestErr *)instruction); + case IrInstructionIdTestErrGen: + return ir_render_test_err(g, executable, (IrInstructionTestErrGen *)instruction); case IrInstructionIdUnwrapErrCode: return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction); case IrInstructionIdUnwrapErrPayload: diff --git a/src/ir.cpp b/src/ir.cpp index 01d824b80c..b6f45a5325 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -756,8 +756,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOverflowOp *) { return IrInstructionIdOverflowOp; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErr *) { - return IrInstructionIdTestErr; +static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErrSrc *) { + return IrInstructionIdTestErrSrc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErrGen *) { + return IrInstructionIdTestErrGen; } static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrCode *) { @@ -900,6 +904,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResolveResult *) return IrInstructionIdResolveResult; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtr *) { + return IrInstructionIdResultPtr; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) { return IrInstructionIdPtrOfArrayToSlice; } @@ -2418,13 +2426,26 @@ static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *s return &instruction->base; } -static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value) +static IrInstruction *ir_build_test_err_src(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *base_ptr) { - IrInstructionTestErr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; + IrInstructionTestErrSrc *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base_ptr = base_ptr; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(base_ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstruction *ir_build_test_err_gen(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *err_union) +{ + IrInstructionTestErrGen *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = ira->codegen->builtin_types.entry_bool; + instruction->err_union = err_union; + + ir_ref_instruction(err_union, ira->new_irb.current_basic_block); return &instruction->base; } @@ -2844,6 +2865,18 @@ static IrInstruction *ir_build_resolve_result(IrBuilder *irb, Scope *scope, AstN return &instruction->base; } +static IrInstruction *ir_build_result_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, + ResultLoc *result_loc, IrInstruction *result) +{ + IrInstructionResultPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->result_loc = result_loc; + instruction->result = result; + + ir_ref_instruction(result, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionOpaqueType *instruction = ir_build_instruction(irb, scope, source_node); @@ -3531,7 +3564,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, ir_gen_defers_for_block(irb, scope, outer_scope, false); } - IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value); + IrInstruction *ret_ptr = ir_build_result_ptr(irb, scope, node, &result_loc_ret->base, + return_value); + IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, ret_ptr); bool should_inline = ir_should_inline(irb->exec, scope); IrInstruction *is_comptime; @@ -3577,8 +3612,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); 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 *is_err_val = ir_build_test_err(irb, scope, node, err_union_val); + IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr); IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn"); IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue"); @@ -5940,8 +5974,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n LValPtr, nullptr); 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 *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val); + IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr); 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)); IrInstruction *cond_br_inst; @@ -6722,7 +6755,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * return err_val_ptr; IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); - IrInstruction *is_err = ir_build_test_err(irb, scope, node, err_val); + IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr); IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk"); IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse"); @@ -7330,8 +7363,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode 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 *is_err = ir_build_test_err(irb, parent_scope, node, err_union_val); + IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr); IrInstruction *is_comptime; if (ir_should_inline(irb->exec, parent_scope)) { @@ -15010,7 +15042,9 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s return result_loc; ir_assert(result_loc->value.type->id == ZigTypeIdPointer, suspend_source_instr); ZigType *actual_elem_type = result_loc->value.type->data.pointer.child_type; - if (actual_elem_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional) { + if (actual_elem_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional && + value_type->id != ZigTypeIdNull) + { return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr, result_loc, false, true); } else if (actual_elem_type->id == ZigTypeIdErrorUnion && value_type->id != ZigTypeIdErrorUnion) { if (value_type->id == ZigTypeIdErrorSet) { @@ -22190,15 +22224,34 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr return result; } -static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErr *instruction) { - IrInstruction *value = instruction->value->child; - if (type_is_invalid(value->value.type)) +static IrInstruction *ir_analyze_instruction_result_ptr(IrAnalyze *ira, IrInstructionResultPtr *instruction) { + IrInstruction *result = instruction->result->child; + if (type_is_invalid(result->value.type)) + return result; + + if (instruction->result_loc->written && instruction->result_loc->resolved_loc != nullptr && + !instr_is_comptime(result)) + { + IrInstruction *result_ptr = instruction->result_loc->resolved_loc; + // Convert the pointer to the result type. They should be the same, except this will resolve + // inferred error sets. + ZigType *new_ptr_type = get_pointer_to_type(ira->codegen, result->value.type, true); + return ir_analyze_ptr_cast(ira, &instruction->base, result_ptr, new_ptr_type, &instruction->base, false); + } + return ir_get_ref(ira, &instruction->base, result, true, false); +} + +static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErrSrc *instruction) { + IrInstruction *base_ptr = instruction->base_ptr->child; + if (type_is_invalid(base_ptr->value.type)) return ira->codegen->invalid_instruction; + IrInstruction *value = ir_get_deref(ira, &instruction->base, base_ptr, nullptr); ZigType *type_entry = value->value.type; - if (type_is_invalid(type_entry)) { + if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - } else if (type_entry->id == ZigTypeIdErrorUnion) { + + if (type_entry->id == ZigTypeIdErrorUnion) { if (instr_is_comptime(value)) { ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad); if (!err_union_val) @@ -22221,10 +22274,7 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct return ir_const_bool(ira, &instruction->base, false); } - IrInstruction *result = ir_build_test_err(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, value); - result->value.type = ira->codegen->builtin_types.entry_bool; - return result; + return ir_build_test_err_gen(ira, &instruction->base, value); } else if (type_entry->id == ZigTypeIdErrorSet) { return ir_const_bool(ira, &instruction->base, true); } else { @@ -24343,6 +24393,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction case IrInstructionIdAllocaGen: case IrInstructionIdSliceGen: case IrInstructionIdRefGen: + case IrInstructionIdTestErrGen: zig_unreachable(); case IrInstructionIdReturn: @@ -24497,8 +24548,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_align_of(ira, (IrInstructionAlignOf *)instruction); case IrInstructionIdOverflowOp: return ir_analyze_instruction_overflow_op(ira, (IrInstructionOverflowOp *)instruction); - case IrInstructionIdTestErr: - return ir_analyze_instruction_test_err(ira, (IrInstructionTestErr *)instruction); + case IrInstructionIdTestErrSrc: + return ir_analyze_instruction_test_err(ira, (IrInstructionTestErrSrc *)instruction); case IrInstructionIdUnwrapErrCode: return ir_analyze_instruction_unwrap_err_code(ira, (IrInstructionUnwrapErrCode *)instruction); case IrInstructionIdUnwrapErrPayload: @@ -24543,6 +24594,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_implicit_cast(ira, (IrInstructionImplicitCast *)instruction); case IrInstructionIdResolveResult: return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction); + case IrInstructionIdResultPtr: + return ir_analyze_instruction_result_ptr(ira, (IrInstructionResultPtr *)instruction); case IrInstructionIdOpaqueType: return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction); case IrInstructionIdSetAlignStack: @@ -24672,6 +24725,9 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ continue; } + if (ira->codegen->verbose_ir) { + fprintf(stderr, "analyze #%zu\n", old_instruction->debug_id); + } IrInstruction *new_instruction = ir_analyze_instruction_base(ira, old_instruction); if (new_instruction != nullptr) { ir_assert(new_instruction->value.type != nullptr || new_instruction->value.type != nullptr, old_instruction); @@ -24808,7 +24864,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdReturnAddress: case IrInstructionIdFrameAddress: case IrInstructionIdHandle: - case IrInstructionIdTestErr: + case IrInstructionIdTestErrSrc: + case IrInstructionIdTestErrGen: case IrInstructionIdFnProto: case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: @@ -24860,6 +24917,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdHasDecl: case IrInstructionIdAllocaSrc: case IrInstructionIdAllocaGen: + case IrInstructionIdResultPtr: return false; case IrInstructionIdAsm: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 4b8b175be0..9750b30e33 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -961,9 +961,15 @@ static void ir_print_overflow_op(IrPrint *irp, IrInstructionOverflowOp *instruct fprintf(irp->f, ")"); } -static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) { +static void ir_print_test_err_src(IrPrint *irp, IrInstructionTestErrSrc *instruction) { fprintf(irp->f, "@testError("); - ir_print_other_instruction(irp, instruction->value); + ir_print_other_instruction(irp, instruction->base_ptr); + fprintf(irp->f, ")"); +} + +static void ir_print_test_err_gen(IrPrint *irp, IrInstructionTestErrGen *instruction) { + fprintf(irp->f, "@testError("); + ir_print_other_instruction(irp, instruction->err_union); fprintf(irp->f, ")"); } @@ -976,10 +982,7 @@ static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *i static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) { fprintf(irp->f, "ErrorUnionFieldPayload("); ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); - if (!instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } + fprintf(irp->f, ")safety=%d,init=%d",instruction->safety_check_on, instruction->initializing); } static void ir_print_optional_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) { @@ -1301,6 +1304,14 @@ static void ir_print_resolve_result(IrPrint *irp, IrInstructionResolveResult *in fprintf(irp->f, ")"); } +static void ir_print_result_ptr(IrPrint *irp, IrInstructionResultPtr *instruction) { + fprintf(irp->f, "ResultPtr("); + ir_print_result_loc(irp, instruction->result_loc); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->result); + fprintf(irp->f, ")"); +} + static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) { fprintf(irp->f, "@OpaqueType()"); } @@ -1837,8 +1848,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdOverflowOp: ir_print_overflow_op(irp, (IrInstructionOverflowOp *)instruction); break; - case IrInstructionIdTestErr: - ir_print_test_err(irp, (IrInstructionTestErr *)instruction); + case IrInstructionIdTestErrSrc: + ir_print_test_err_src(irp, (IrInstructionTestErrSrc *)instruction); + break; + case IrInstructionIdTestErrGen: + ir_print_test_err_gen(irp, (IrInstructionTestErrGen *)instruction); break; case IrInstructionIdUnwrapErrCode: ir_print_unwrap_err_code(irp, (IrInstructionUnwrapErrCode *)instruction); @@ -1939,6 +1953,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdResolveResult: ir_print_resolve_result(irp, (IrInstructionResolveResult *)instruction); break; + case IrInstructionIdResultPtr: + ir_print_result_ptr(irp, (IrInstructionResultPtr *)instruction); + break; case IrInstructionIdOpaqueType: ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction); break; diff --git a/std/os.zig b/std/os.zig index 3409dcf6c6..a0f8d1f12b 100644 --- a/std/os.zig +++ b/std/os.zig @@ -2487,7 +2487,7 @@ pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 { /// if this happens the fix is to add the error code to the corresponding /// switch expression, possibly introduce a new error in the error set, and /// send a patch to Zig. -pub const unexpected_error_tracing = false; +pub const unexpected_error_tracing = builtin.mode == .Debug; pub const UnexpectedError = error{ /// The Operating System returned an undocumented error code. diff --git a/std/special/panic.zig b/std/special/panic.zig index 50dc5e0c65..92e0d9164c 100644 --- a/std/special/panic.zig +++ b/std/special/panic.zig @@ -7,8 +7,23 @@ const builtin = @import("builtin"); const std = @import("std"); pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { - const stderr = std.io.getStdErr() catch std.process.abort(); - stderr.write("panic: ") catch std.process.abort(); - stderr.write(msg) catch std.process.abort(); - std.process.abort(); + @setCold(true); + switch (builtin.os) { + .freestanding => { + while (true) {} + }, + .wasi => { + std.debug.warn("{}", msg); + _ = std.os.wasi.proc_raise(std.os.wasi.SIGABRT); + unreachable; + }, + .uefi => { + // TODO look into using the debug info and logging helpful messages + std.os.abort(); + }, + else => { + const first_trace_addr = @returnAddress(); + std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg); + }, + } } diff --git a/std/special/test_runner.zig b/std/special/test_runner.zig index 001b26ebb0..db01293059 100644 --- a/std/special/test_runner.zig +++ b/std/special/test_runner.zig @@ -2,34 +2,28 @@ const std = @import("std"); const io = std.io; const builtin = @import("builtin"); const test_fn_list = builtin.test_functions; +const warn = std.debug.warn; -pub fn main() void { - const stderr = io.getStdErr() catch std.process.abort(); - +pub fn main() !void { var ok_count: usize = 0; var skip_count: usize = 0; for (test_fn_list) |test_fn, i| { - stderr.write("test ") catch std.process.abort(); - stderr.write(test_fn.name) catch std.process.abort(); + warn("{}/{} {}...", i + 1, test_fn_list.len, test_fn.name); if (test_fn.func()) |_| { ok_count += 1; - stderr.write("...OK\n") catch std.process.abort(); + warn("OK\n"); } else |err| switch (err) { error.SkipZigTest => { skip_count += 1; - stderr.write("...SKIP\n") catch std.process.abort(); - }, - else => { - stderr.write("error: ") catch std.process.abort(); - stderr.write(@errorName(err)) catch std.process.abort(); - std.process.abort(); + warn("SKIP\n"); }, + else => return err, } } if (ok_count == test_fn_list.len) { - stderr.write("All tests passed.\n") catch std.process.abort(); + warn("All tests passed.\n"); } else { - stderr.write("Some tests skipped.\n") catch std.process.abort(); + warn("{} passed; {} skipped.\n", ok_count, skip_count); } } diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 411785a5c4..90ad30e55c 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -40,46 +40,46 @@ comptime { //_ = @import("behavior/bugs/920.zig"); _ = @import("behavior/byval_arg_var.zig"); //_ = @import("behavior/cancel.zig"); - _ = @import("behavior/cast.zig"); // TODO + _ = @import("behavior/cast.zig"); _ = @import("behavior/const_slice_child.zig"); //_ = @import("behavior/coroutine_await_struct.zig"); //_ = @import("behavior/coroutines.zig"); _ = @import("behavior/defer.zig"); _ = @import("behavior/enum.zig"); _ = @import("behavior/enum_with_members.zig"); - //_ = @import("behavior/error.zig"); + _ = @import("behavior/error.zig"); // TODO _ = @import("behavior/eval.zig"); // TODO _ = @import("behavior/field_parent_ptr.zig"); _ = @import("behavior/fn.zig"); _ = @import("behavior/fn_in_struct_in_comptime.zig"); _ = @import("behavior/for.zig"); - _ = @import("behavior/generics.zig"); // TODO + _ = @import("behavior/generics.zig"); _ = @import("behavior/hasdecl.zig"); _ = @import("behavior/if.zig"); - //_ = @import("behavior/import.zig"); + _ = @import("behavior/import.zig"); _ = @import("behavior/incomplete_struct_param_tld.zig"); _ = @import("behavior/inttoptr.zig"); _ = @import("behavior/ir_block_deps.zig"); - //_ = @import("behavior/math.zig"); + _ = @import("behavior/math.zig"); _ = @import("behavior/merge_error_sets.zig"); _ = @import("behavior/misc.zig"); // TODO _ = @import("behavior/namespace_depends_on_compile_var.zig"); _ = @import("behavior/new_stack_call.zig"); _ = @import("behavior/null.zig"); _ = @import("behavior/optional.zig"); // TODO - //_ = @import("behavior/pointers.zig"); + _ = @import("behavior/pointers.zig"); _ = @import("behavior/popcount.zig"); _ = @import("behavior/ptrcast.zig"); // TODO _ = @import("behavior/pub_enum.zig"); _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); _ = @import("behavior/reflection.zig"); _ = @import("behavior/sizeof_and_typeof.zig"); - //_ = @import("behavior/slice.zig"); + _ = @import("behavior/slice.zig"); _ = @import("behavior/slicetobytes.zig"); //_ = @import("behavior/struct.zig"); _ = @import("behavior/struct_contains_null_ptr_itself.zig"); _ = @import("behavior/struct_contains_slice_of_itself.zig"); - //_ = @import("behavior/switch.zig"); + _ = @import("behavior/switch.zig"); //_ = @import("behavior/switch_prong_err_enum.zig"); _ = @import("behavior/switch_prong_implicit_cast.zig"); _ = @import("behavior/syntax.zig"); @@ -87,7 +87,7 @@ comptime { _ = @import("behavior/truncate.zig"); _ = @import("behavior/try.zig"); _ = @import("behavior/type_info.zig"); - //_ = @import("behavior/typename.zig"); + _ = @import("behavior/typename.zig"); _ = @import("behavior/undefined.zig"); _ = @import("behavior/underscore.zig"); _ = @import("behavior/union.zig"); diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index f659f6d9ae..0a2ffb6c2f 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -124,14 +124,14 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { return null; } -//test "peer type resolution: ?T and T" { -// expect(peerTypeTAndOptionalT(true, false).? == 0); -// expect(peerTypeTAndOptionalT(false, false).? == 3); -// comptime { -// expect(peerTypeTAndOptionalT(true, false).? == 0); -// expect(peerTypeTAndOptionalT(false, false).? == 3); -// } -//} +test "peer type resolution: ?T and T" { + expect(peerTypeTAndOptionalT(true, false).? == 0); + expect(peerTypeTAndOptionalT(false, false).? == 3); + comptime { + expect(peerTypeTAndOptionalT(true, false).? == 0); + expect(peerTypeTAndOptionalT(false, false).? == 3); + } +} fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { if (c) { return if (b) null else usize(0); diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig index babefba6f5..861c500751 100644 --- a/test/stage1/behavior/error.zig +++ b/test/stage1/behavior/error.zig @@ -249,48 +249,48 @@ fn intLiteral(str: []const u8) !?i64 { return error.T; } -test "nested error union function call in optional unwrap" { - const S = struct { - const Foo = struct { - a: i32, - }; - - fn errorable() !i32 { - var x: Foo = (try getFoo()) orelse return error.Other; - return x.a; - } - - fn errorable2() !i32 { - var x: Foo = (try getFoo2()) orelse return error.Other; - return x.a; - } - - fn errorable3() !i32 { - var x: Foo = (try getFoo3()) orelse return error.Other; - return x.a; - } - - fn getFoo() anyerror!?Foo { - return Foo{ .a = 1234 }; - } - - fn getFoo2() anyerror!?Foo { - return error.Failure; - } - - fn getFoo3() anyerror!?Foo { - return null; - } - }; - expect((try S.errorable()) == 1234); - expectError(error.Failure, S.errorable2()); - expectError(error.Other, S.errorable3()); - comptime { - expect((try S.errorable()) == 1234); - expectError(error.Failure, S.errorable2()); - expectError(error.Other, S.errorable3()); - } -} +//test "nested error union function call in optional unwrap" { +// const S = struct { +// const Foo = struct { +// a: i32, +// }; +// +// fn errorable() !i32 { +// var x: Foo = (try getFoo()) orelse return error.Other; +// return x.a; +// } +// +// fn errorable2() !i32 { +// var x: Foo = (try getFoo2()) orelse return error.Other; +// return x.a; +// } +// +// fn errorable3() !i32 { +// var x: Foo = (try getFoo3()) orelse return error.Other; +// return x.a; +// } +// +// fn getFoo() anyerror!?Foo { +// return Foo{ .a = 1234 }; +// } +// +// fn getFoo2() anyerror!?Foo { +// return error.Failure; +// } +// +// fn getFoo3() anyerror!?Foo { +// return null; +// } +// }; +// expect((try S.errorable()) == 1234); +// expectError(error.Failure, S.errorable2()); +// expectError(error.Other, S.errorable3()); +// comptime { +// expect((try S.errorable()) == 1234); +// expectError(error.Failure, S.errorable2()); +// expectError(error.Other, S.errorable3()); +// } +//} test "widen cast integer payload of error union function call" { const S = struct { diff --git a/test/stage1/behavior/generics.zig b/test/stage1/behavior/generics.zig index c514735d17..664b982c21 100644 --- a/test/stage1/behavior/generics.zig +++ b/test/stage1/behavior/generics.zig @@ -80,19 +80,19 @@ test "function with return type type" { expect(list2.prealloc_items.len == 8); } -//test "generic struct" { -// var a1 = GenNode(i32){ -// .value = 13, -// .next = null, -// }; -// var b1 = GenNode(bool){ -// .value = true, -// .next = null, -// }; -// expect(a1.value == 13); -// expect(a1.value == a1.getVal()); -// expect(b1.getVal()); -//} +test "generic struct" { + var a1 = GenNode(i32){ + .value = 13, + .next = null, + }; + var b1 = GenNode(bool){ + .value = true, + .next = null, + }; + expect(a1.value == 13); + expect(a1.value == a1.getVal()); + expect(b1.getVal()); +} fn GenNode(comptime T: type) type { return struct { value: T, diff --git a/test/stage1/behavior/optional.zig b/test/stage1/behavior/optional.zig index 0539d1c201..09260c4778 100644 --- a/test/stage1/behavior/optional.zig +++ b/test/stage1/behavior/optional.zig @@ -76,6 +76,5 @@ test "unwrap function call with optional pointer return value" { } }; S.entry(); - // TODO https://github.com/ziglang/zig/issues/1901 - //comptime S.entry(); + comptime S.entry(); } diff --git a/test/stage1/behavior/while.zig b/test/stage1/behavior/while.zig index 5e486a2495..29ad90ed17 100644 --- a/test/stage1/behavior/while.zig +++ b/test/stage1/behavior/while.zig @@ -82,28 +82,28 @@ test "while with else" { expect(got_else == 1); } -//test "while with optional as condition" { -// numbers_left = 10; -// var sum: i32 = 0; -// while (getNumberOrNull()) |value| { -// sum += value; -// } -// expect(sum == 45); -//} -// -//test "while with optional as condition with else" { -// numbers_left = 10; -// var sum: i32 = 0; -// var got_else: i32 = 0; -// while (getNumberOrNull()) |value| { -// sum += value; -// expect(got_else == 0); -// } else { -// got_else += 1; -// } -// expect(sum == 45); -// expect(got_else == 1); -//} +test "while with optional as condition" { + numbers_left = 10; + var sum: i32 = 0; + while (getNumberOrNull()) |value| { + sum += value; + } + expect(sum == 45); +} + +test "while with optional as condition with else" { + numbers_left = 10; + var sum: i32 = 0; + var got_else: i32 = 0; + while (getNumberOrNull()) |value| { + sum += value; + expect(got_else == 0); + } else { + got_else += 1; + } + expect(sum == 45); + expect(got_else == 1); +} test "while with error union condition" { numbers_left = 10; -- cgit v1.2.3 From 9564c05cd5641095d48baf982a372f00bdf02659 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 15 Jun 2019 19:19:13 -0400 Subject: better result location handling of inline loops --- src/all_types.hpp | 9 ++++ src/codegen.cpp | 1 + src/ir.cpp | 111 ++++++++++++++++++++++++++++++++-------- src/ir_print.cpp | 9 ++++ test/stage1/behavior.zig | 6 +-- test/stage1/behavior/eval.zig | 20 ++++++-- test/stage1/behavior/struct.zig | 40 +++++++-------- 7 files changed, 146 insertions(+), 50 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 73726de39b..49b71e1eed 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2293,6 +2293,7 @@ enum IrInstructionId { IrInstructionIdAlignCast, IrInstructionIdImplicitCast, IrInstructionIdResolveResult, + IrInstructionIdResetResult, IrInstructionIdResultPtr, IrInstructionIdOpaqueType, IrInstructionIdSetAlignStack, @@ -3621,6 +3622,12 @@ struct IrInstructionResultPtr { IrInstruction *result; }; +struct IrInstructionResetResult { + IrInstruction base; + + ResultLoc *result_loc; +}; + struct IrInstructionPtrOfArrayToSlice { IrInstruction base; @@ -3639,6 +3646,8 @@ enum ResultLocId { ResultLocIdBitCast, }; +// Additions to this struct may need to be handled in +// ir_reset_result struct ResultLoc { ResultLocId id; bool written; diff --git a/src/codegen.cpp b/src/codegen.cpp index 42670f9005..4c212c95ab 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5561,6 +5561,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdAllocaGen: case IrInstructionIdImplicitCast: case IrInstructionIdResolveResult: + case IrInstructionIdResetResult: case IrInstructionIdResultPtr: case IrInstructionIdContainerInitList: case IrInstructionIdSliceSrc: diff --git a/src/ir.cpp b/src/ir.cpp index b6f45a5325..d48c013caf 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -166,6 +166,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg); static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing); +static void ir_assert(bool ok, IrInstruction *source_instruction); static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var); static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op); static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval, ResultLoc *result_loc); @@ -904,6 +905,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResolveResult *) return IrInstructionIdResolveResult; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionResetResult *) { + return IrInstructionIdResetResult; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtr *) { return IrInstructionIdResultPtr; } @@ -2865,6 +2870,15 @@ static IrInstruction *ir_build_resolve_result(IrBuilder *irb, Scope *scope, AstN return &instruction->base; } +static IrInstruction *ir_build_reset_result(IrBuilder *irb, Scope *scope, AstNode *source_node, + ResultLoc *result_loc) +{ + IrInstructionResetResult *instruction = ir_build_instruction(irb, scope, source_node); + instruction->result_loc = result_loc; + + return &instruction->base; +} + static IrInstruction *ir_build_result_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, ResultLoc *result_loc, IrInstruction *result) { @@ -3540,6 +3554,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, { ResultLocReturn *result_loc_ret = allocate(1); result_loc_ret->base.id = ResultLocIdReturn; + ir_build_reset_result(irb, scope, node, &result_loc_ret->base); IrInstruction *return_value; if (expr_node) { @@ -3929,7 +3944,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr); } -static ResultLocPeerParent *create_binary_result_peers(IrInstruction *cond_br_inst, +static ResultLocPeerParent *ir_build_binary_result_peers(IrBuilder *irb, IrInstruction *cond_br_inst, IrBasicBlock *else_block, IrBasicBlock *endif_block, ResultLoc *parent, IrInstruction *is_comptime) { ResultLocPeerParent *peer_parent = allocate(1); @@ -3948,6 +3963,13 @@ static ResultLocPeerParent *create_binary_result_peers(IrInstruction *cond_br_in peer_parent->peers[1].base.source_instruction = cond_br_inst; peer_parent->peers[1].parent = peer_parent; peer_parent->peers[1].next_bb = endif_block; + + IrInstruction *popped_inst = irb->current_basic_block->instruction_list.pop(); + ir_assert(popped_inst == cond_br_inst, cond_br_inst); + + ir_build_reset_result(irb, cond_br_inst->scope, cond_br_inst->source_node, &peer_parent->base); + irb->current_basic_block->instruction_list.append(popped_inst); + return peer_parent; } @@ -3978,8 +4000,8 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "OptionalEnd"); IrInstruction *cond_br_inst = ir_build_cond_br(irb, parent_scope, node, is_non_null, ok_block, null_block, is_comptime); - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, ok_block, end_block, result_loc, - is_comptime); + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, ok_block, end_block, + result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, null_block); IrInstruction *null_result = ir_gen_node_extra(irb, op2_node, parent_scope, lval, &peer_parent->peers[0].base); @@ -5006,6 +5028,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo ir_ref_instruction(dest_type, irb->current_basic_block); result_loc_bit_cast->parent = result_loc; + ir_build_reset_result(irb, scope, node, &result_loc_bit_cast->base); + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); IrInstruction *arg1_value = ir_gen_node_extra(irb, arg1_node, scope, LValNone, &result_loc_bit_cast->base); @@ -5494,8 +5518,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode IrInstruction *cond_br_inst = ir_build_cond_br(irb, scope, condition->source_node, condition, then_block, else_block, is_comptime); - - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, endif_block, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, endif_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, then_block); @@ -5832,11 +5855,14 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A zig_unreachable(); } -static ResultLocVar *create_var_result_loc(IrInstruction *alloca, ZigVar *var) { +static ResultLocVar *ir_build_var_result_loc(IrBuilder *irb, IrInstruction *alloca, ZigVar *var) { ResultLocVar *result_loc_var = allocate(1); result_loc_var->base.id = ResultLocIdVar; result_loc_var->base.source_instruction = alloca; result_loc_var->var = var; + + ir_build_reset_result(irb, alloca->scope, alloca->source_node, &result_loc_var->base); + return result_loc_var; } @@ -5844,7 +5870,7 @@ static void build_decl_var_and_init(IrBuilder *irb, Scope *scope, AstNode *sourc IrInstruction *init, const char *name_hint, IrInstruction *is_comptime) { IrInstruction *alloca = ir_build_alloca_src(irb, scope, source_node, nullptr, name_hint, is_comptime); - ResultLocVar *var_result_loc = create_var_result_loc(alloca, var); + ResultLocVar *var_result_loc = ir_build_var_result_loc(irb, alloca, var); ir_build_end_expr(irb, scope, source_node, init, &var_result_loc->base); ir_build_var_decl_src(irb, scope, source_node, var, nullptr, alloca); } @@ -5907,7 +5933,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod buf_ptr(variable_declaration->symbol), is_comptime); // Create a result location for the initialization expression. - ResultLocVar *result_loc_var = create_var_result_loc(alloca, var); + ResultLocVar *result_loc_var = ir_build_var_result_loc(irb, alloca, var); ResultLoc *init_result_loc = (type_instruction == nullptr) ? &result_loc_var->base : nullptr; Scope *init_scope = is_comptime_scalar ? @@ -5983,10 +6009,11 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n else_block, body_block, is_comptime); cond_br_inst->is_gen = true; } else { - cond_br_inst = is_err; // for the purposes of the source instruction to create_binary_result_peers + // for the purposes of the source instruction to ir_build_binary_result_peers + cond_br_inst = irb->current_basic_block->instruction_list.last(); } - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, end_block, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, end_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, body_block); @@ -6085,10 +6112,11 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n body_block, else_block, is_comptime); cond_br_inst->is_gen = true; } else { - cond_br_inst = is_non_null; // for the purposes of source instruction for create_binary_result_peers + // for the purposes of the source instruction to ir_build_binary_result_peers + cond_br_inst = irb->current_basic_block->instruction_list.last(); } - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, end_block, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, end_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, body_block); @@ -6168,10 +6196,11 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n body_block, else_block, is_comptime); cond_br_inst->is_gen = true; } else { - cond_br_inst = cond_val; // for the source instruction arg to create_binary_result_peers + // for the purposes of the source instruction to ir_build_binary_result_peers + cond_br_inst = irb->current_basic_block->instruction_list.last(); } - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, end_block, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, end_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, body_block); @@ -6303,8 +6332,8 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo IrInstruction *cond_br_inst = ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, cond, body_block, else_block, is_comptime)); - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, end_block, result_loc, - is_comptime); + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, end_block, + result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, body_block); IrInstruction *elem_ptr = ir_build_elem_ptr(irb, parent_scope, node, array_val_ptr, index_val, false, @@ -6683,7 +6712,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN IrInstruction *cond_br_inst = ir_build_cond_br(irb, scope, node, is_non_null, then_block, else_block, is_comptime); - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, endif_block, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, endif_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, then_block); @@ -6765,7 +6794,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * IrInstruction *is_comptime = force_comptime ? ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, is_err); IrInstruction *cond_br_inst = ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime); - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, endif_block, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, endif_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, ok_block); @@ -7093,6 +7122,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, check_ranges.items, check_ranges.length, else_prong != nullptr); + ir_build_reset_result(irb, scope, node, &peer_parent->base); + IrInstruction *br_instruction; if (cases.length == 0) { br_instruction = ir_build_br(irb, scope, node, else_block, is_comptime); @@ -7377,7 +7408,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrEnd"); IrInstruction *cond_br_inst = ir_build_cond_br(irb, parent_scope, node, is_err, err_block, ok_block, is_comptime); - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, ok_block, end_block, result_loc, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, ok_block, end_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, err_block); @@ -8268,6 +8299,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc // Create a result location indicating there is none - but if one gets created // it will be properly distributed. result_loc = no_result_loc(); + ir_build_reset_result(irb, scope, node, result_loc); } IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc); irb->exec->invalid = irb->exec->invalid || (result == irb->codegen->invalid_instruction); @@ -8521,10 +8553,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec // non-allocating. Basically coroutines are not supported right now until they are reworked. args[3] = ir_build_const_usize(irb, scope, node, 1); // new_size args[4] = ir_build_const_usize(irb, scope, node, 1); // new_align - ResultLocNone *result_loc_none = allocate(1); - result_loc_none->base.id = ResultLocIdNone; ir_build_call_src(irb, scope, node, nullptr, shrink_fn, arg_count, args, false, FnInlineAuto, false, nullptr, - nullptr, &result_loc_none->base); + nullptr, no_result_loc()); 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); @@ -15082,6 +15112,40 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn return ir_resolve_result(ira, &instruction->base, instruction->result_loc, implicit_elem_type, nullptr); } +static void ir_reset_result(ResultLoc *result_loc) { + result_loc->written = false; + result_loc->resolved_loc = nullptr; + result_loc->gen_instruction = nullptr; + result_loc->implicit_elem_type = nullptr; + // TODO handle result_loc->scope_elide = + switch (result_loc->id) { + case ResultLocIdInvalid: + zig_unreachable(); + case ResultLocIdPeerParent: { + ResultLocPeerParent *peer_parent = reinterpret_cast(result_loc); + peer_parent->skipped = false; + peer_parent->done_resuming = false; + peer_parent->resolved_type = nullptr; + for (size_t i = 0; i < peer_parent->peer_count; i += 1) { + ir_reset_result(&peer_parent->peers[i].base); + } + break; + } + case ResultLocIdPeer: + case ResultLocIdNone: + case ResultLocIdVar: + case ResultLocIdReturn: + case ResultLocIdInstruction: + case ResultLocIdBitCast: + break; + } +} + +static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInstructionResetResult *instruction) { + ir_reset_result(instruction->result_loc); + return ir_const_void(ira, &instruction->base); +} + static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst) @@ -24594,6 +24658,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_implicit_cast(ira, (IrInstructionImplicitCast *)instruction); case IrInstructionIdResolveResult: return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction); + case IrInstructionIdResetResult: + return ir_analyze_instruction_reset_result(ira, (IrInstructionResetResult *)instruction); case IrInstructionIdResultPtr: return ir_analyze_instruction_result_ptr(ira, (IrInstructionResultPtr *)instruction); case IrInstructionIdOpaqueType: @@ -24818,6 +24884,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdSliceGen: case IrInstructionIdOptionalWrap: case IrInstructionIdVectorToArray: + case IrInstructionIdResetResult: return true; case IrInstructionIdPhi: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 9750b30e33..b66827fb92 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1304,6 +1304,12 @@ static void ir_print_resolve_result(IrPrint *irp, IrInstructionResolveResult *in fprintf(irp->f, ")"); } +static void ir_print_reset_result(IrPrint *irp, IrInstructionResetResult *instruction) { + fprintf(irp->f, "ResetResult("); + ir_print_result_loc(irp, instruction->result_loc); + fprintf(irp->f, ")"); +} + static void ir_print_result_ptr(IrPrint *irp, IrInstructionResultPtr *instruction) { fprintf(irp->f, "ResultPtr("); ir_print_result_loc(irp, instruction->result_loc); @@ -1953,6 +1959,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdResolveResult: ir_print_resolve_result(irp, (IrInstructionResolveResult *)instruction); break; + case IrInstructionIdResetResult: + ir_print_reset_result(irp, (IrInstructionResetResult *)instruction); + break; case IrInstructionIdResultPtr: ir_print_result_ptr(irp, (IrInstructionResultPtr *)instruction); break; diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 90ad30e55c..6aa6ab48cb 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -37,7 +37,7 @@ comptime { _ = @import("behavior/bugs/718.zig"); _ = @import("behavior/bugs/726.zig"); _ = @import("behavior/bugs/828.zig"); - //_ = @import("behavior/bugs/920.zig"); + _ = @import("behavior/bugs/920.zig"); _ = @import("behavior/byval_arg_var.zig"); //_ = @import("behavior/cancel.zig"); _ = @import("behavior/cast.zig"); @@ -76,7 +76,7 @@ comptime { _ = @import("behavior/sizeof_and_typeof.zig"); _ = @import("behavior/slice.zig"); _ = @import("behavior/slicetobytes.zig"); - //_ = @import("behavior/struct.zig"); + _ = @import("behavior/struct.zig"); // TODO _ = @import("behavior/struct_contains_null_ptr_itself.zig"); _ = @import("behavior/struct_contains_slice_of_itself.zig"); _ = @import("behavior/switch.zig"); @@ -94,6 +94,6 @@ comptime { _ = @import("behavior/var_args.zig"); _ = @import("behavior/vector.zig"); _ = @import("behavior/void.zig"); - _ = @import("behavior/while.zig"); // TODO + _ = @import("behavior/while.zig"); _ = @import("behavior/widening.zig"); } diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 595e83b087..49c7380f2b 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -176,9 +176,9 @@ test "const slice" { } } -//test "try to trick eval with runtime if" { -// expect(testTryToTrickEvalWithRuntimeIf(true) == 10); -//} +test "try to trick eval with runtime if" { + expect(testTryToTrickEvalWithRuntimeIf(true) == 10); +} fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { comptime var i: usize = 0; @@ -190,6 +190,17 @@ fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { } } +//test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" { +// var runtime = [1]i32{3}; +// comptime var i: usize = 0; +// inline while (i < 2) : (i += 1) { +// const result = if (i == 0) [1]i32{2} else runtime; +// } +// comptime { +// expect(i == 2); +// } +//} + fn max(comptime T: type, a: T, b: T) T { if (T == bool) { return a or b; @@ -756,8 +767,7 @@ test "comptime bitwise operators" { test "*align(1) u16 is the same as *align(1:0:2) u16" { comptime { expect(*align(1:0:2) u16 == *align(1) u16); - // TODO add parsing support for this syntax - //expect(*align(:0:2) u16 == *u16); + expect(*align(:0:2) u16 == *u16); } } diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 0ebd0654d0..ccdff3503e 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -529,26 +529,26 @@ test "access to global struct fields" { expect(g_foo.bar.value == 42); } -test "packed struct with fp fields" { - const S = packed struct { - data: [3]f32, - - pub fn frob(self: *@This()) void { - self.data[0] += self.data[1] + self.data[2]; - self.data[1] += self.data[0] + self.data[2]; - self.data[2] += self.data[0] + self.data[1]; - } - }; - - var s: S = undefined; - s.data[0] = 1.0; - s.data[1] = 2.0; - s.data[2] = 3.0; - s.frob(); - expectEqual(f32(6.0), s.data[0]); - expectEqual(f32(11.0), s.data[1]); - expectEqual(f32(20.0), s.data[2]); -} +//test "packed struct with fp fields" { +// const S = packed struct { +// data: [3]f32, +// +// pub fn frob(self: *@This()) void { +// self.data[0] += self.data[1] + self.data[2]; +// self.data[1] += self.data[0] + self.data[2]; +// self.data[2] += self.data[0] + self.data[1]; +// } +// }; +// +// var s: S = undefined; +// s.data[0] = 1.0; +// s.data[1] = 2.0; +// s.data[2] = 3.0; +// s.frob(); +// expectEqual(f32(6.0), s.data[0]); +// expectEqual(f32(11.0), s.data[1]); +// expectEqual(f32(20.0), s.data[2]); +//} test "use within struct scope" { const S = struct { -- cgit v1.2.3 From b025193de5b951734e5108e4762e5dc40359431b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 17 Jun 2019 13:31:19 -0400 Subject: inferred comptime values rather than elided scopes because of this example: ```zig export fn entry(b: bool) usize { var runtime = [1]i32{3}; comptime var i: usize = 0; inline while (i < 2) : (i += 1) { const result = if (i == 0) [1]i32{2} else runtime; } comptime { return i; } } ``` The problem is that the concept of "resetting" a result location, introduced in the previous commit, cannot handle elision scopes. This concept is inherently broken with inline loops. --- src/all_types.hpp | 14 +- src/analyze.cpp | 35 +---- src/analyze.hpp | 2 - src/codegen.cpp | 9 +- src/ir.cpp | 383 ++++++++++++++++++++++++++++-------------------------- 5 files changed, 208 insertions(+), 235 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 49b71e1eed..f63d6a902b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -203,6 +203,9 @@ enum ConstPtrMut { // The pointer points to memory that is known only at runtime. // For example it may point to the initializer value of a variable. ConstPtrMutRuntimeVar, + // The pointer points to memory for which it must be inferred whether the + // value is comptime known or not. + ConstPtrMutInfer, }; struct ConstPtrValue { @@ -1957,7 +1960,6 @@ enum ScopeId { ScopeIdCompTime, ScopeIdCoroPrelude, ScopeIdRuntime, - ScopeIdElide, }; struct Scope { @@ -1971,14 +1973,6 @@ struct Scope { ScopeId id; }; -// This scope, when activated, causes all the instructions in the scope to be omitted -// from the generated code. -struct ScopeElide { - Scope base; - - bool activated; -}; - // This scope comes from global declarations or from // declarations in a container declaration // NodeTypeContainerDecl @@ -2655,6 +2649,7 @@ struct IrInstructionContainerInitFieldsField { IrInstruction *value; AstNode *source_node; TypeStructField *type_struct_field; + IrInstruction *result_loc; }; struct IrInstructionContainerInitFields { @@ -3655,7 +3650,6 @@ struct ResultLoc { IrInstruction *source_instruction; IrInstruction *gen_instruction; // value to store to the result loc ZigType *implicit_elem_type; - ScopeElide *scope_elide; }; struct ResultLocNone { diff --git a/src/analyze.cpp b/src/analyze.cpp index 1f9b1ffbed..b39b1e35ca 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -166,12 +166,6 @@ Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruct return &scope->base; } -ScopeElide *create_elide_scope(CodeGen *g, AstNode *node, Scope *parent) { - ScopeElide *scope = allocate(1); - init_scope(g, &scope->base, ScopeIdElide, node, parent); - return scope; -} - ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent) { assert(node->type == NodeTypeSuspend); ScopeSuspend *scope = allocate(1); @@ -4187,6 +4181,7 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { case ConstPtrMutComptimeConst: hash_val += (uint32_t)4214318515; break; + case ConstPtrMutInfer: case ConstPtrMutComptimeVar: hash_val += (uint32_t)1103195694; break; @@ -7286,31 +7281,3 @@ void src_assert(bool ok, AstNode *source_node) { const char *msg = "assertion failed. This is a bug in the Zig compiler."; stage2_panic(msg, strlen(msg)); } - -bool scope_is_elided(Scope *scope) { - for (;;) { - switch (scope->id) { - case ScopeIdElide: - if (reinterpret_cast(scope)->activated) - return true; - // fallthrough - case ScopeIdBlock: - case ScopeIdDefer: - case ScopeIdDeferExpr: - case ScopeIdVarDecl: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCoroPrelude: - case ScopeIdRuntime: - scope = scope->parent; - continue; - case ScopeIdFnDef: - case ScopeIdCompTime: - case ScopeIdDecls: - case ScopeIdCImport: - return false; - } - zig_unreachable(); - } -} - diff --git a/src/analyze.hpp b/src/analyze.hpp index c1dd482a7a..8d78ef86e2 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -121,7 +121,6 @@ ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn * Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent); Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent); Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime); -ScopeElide *create_elide_scope(CodeGen *g, AstNode *node, Scope *parent); void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); @@ -254,6 +253,5 @@ void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_pa void src_assert(bool ok, AstNode *source_node); bool is_container(ZigType *type_entry); ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name); -bool scope_is_elided(Scope *scope); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 4c212c95ab..547840514a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -722,7 +722,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { case ScopeIdCompTime: case ScopeIdCoroPrelude: case ScopeIdRuntime: - case ScopeIdElide: return get_di_scope(g, scope->parent); } zig_unreachable(); @@ -5761,12 +5760,10 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { if (instruction->ref_count == 0 && !ir_has_side_effects(instruction)) continue; - if (!scope_is_elided(instruction->scope)) { - if (!g->strip_debug_symbols) { - set_debug_location(g, instruction); - } - instruction->llvm_value = ir_render_instruction(g, executable, instruction); + if (!g->strip_debug_symbols) { + set_debug_location(g, instruction); } + instruction->llvm_value = ir_render_instruction(g, executable, instruction); } current_block->llvm_exit_block = LLVMGetInsertBlock(g->builder); } diff --git a/src/ir.cpp b/src/ir.cpp index d48c013caf..32f6b4c22a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -196,6 +196,8 @@ static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruct IrInstruction *base_ptr, bool safety_check_on, bool initializing); static IrInstruction *ir_analyze_unwrap_err_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *base_ptr, bool initializing); +static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *ptr, IrInstruction *uncasted_value); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -3363,7 +3365,6 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco case ScopeIdSuspend: case ScopeIdCompTime: case ScopeIdRuntime: - case ScopeIdElide: scope = scope->parent; continue; case ScopeIdDeferExpr: @@ -3420,7 +3421,6 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o case ScopeIdSuspend: case ScopeIdCompTime: case ScopeIdRuntime: - case ScopeIdElide: scope = scope->parent; continue; case ScopeIdDeferExpr: @@ -5758,15 +5758,8 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A return irb->codegen->invalid_instruction; } - IrInstruction *container_ptr = nullptr; - if (!ir_should_inline(irb->exec, scope)) { - src_assert(parent_result_loc->scope_elide == nullptr, node); - parent_result_loc->scope_elide = create_elide_scope(irb->codegen, node, scope); - - src_assert(parent_result_loc != nullptr, node); - container_ptr = ir_build_resolve_result(irb, &parent_result_loc->scope_elide->base, - node, parent_result_loc, container_type); - } + IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, parent_result_loc, + container_type); size_t field_count = container_init_expr->entries.length; IrInstructionContainerInitFieldsField *fields = allocate(field_count); @@ -5777,27 +5770,22 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A Buf *name = entry_node->data.struct_val_field.name; AstNode *expr_node = entry_node->data.struct_val_field.expr; - Scope *val_scope = scope; - ResultLoc *child_result_loc = nullptr; - if (container_ptr != nullptr) { - IrInstruction *field_ptr = ir_build_field_ptr(irb, &parent_result_loc->scope_elide->base, - expr_node, container_ptr, name, true); - ResultLocInstruction *result_loc_inst = allocate(1); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = field_ptr; - ir_ref_instruction(field_ptr, irb->current_basic_block); - child_result_loc = &result_loc_inst->base; - val_scope = &parent_result_loc->scope_elide->base; - } + IrInstruction *field_ptr = ir_build_field_ptr(irb, scope, expr_node, container_ptr, name, true); + ResultLocInstruction *result_loc_inst = allocate(1); + result_loc_inst->base.id = ResultLocIdInstruction; + result_loc_inst->base.source_instruction = field_ptr; + ir_ref_instruction(field_ptr, irb->current_basic_block); + ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base); - IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, val_scope, LValNone, - child_result_loc); + IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, + &result_loc_inst->base); if (expr_value == irb->codegen->invalid_instruction) return expr_value; fields[i].name = name; fields[i].value = expr_value; fields[i].source_node = entry_node; + fields[i].result_loc = field_ptr; } IrInstruction *init_fields = ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields, container_ptr); @@ -5812,36 +5800,23 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type); } - IrInstruction *container_ptr = nullptr; - if (!ir_should_inline(irb->exec, scope)) { - src_assert(parent_result_loc->scope_elide == nullptr, node); - parent_result_loc->scope_elide = create_elide_scope(irb->codegen, node, scope); - - container_ptr = ir_build_resolve_result(irb, &parent_result_loc->scope_elide->base, - node, parent_result_loc, container_type); - } + IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, parent_result_loc, + container_type); IrInstruction **values = allocate(item_count); for (size_t i = 0; i < item_count; i += 1) { AstNode *expr_node = container_init_expr->entries.at(i); - ResultLoc *child_result_loc = nullptr; - Scope *val_scope = scope; - if (container_ptr != nullptr) { - IrInstruction *elem_index = ir_build_const_usize(irb, &parent_result_loc->scope_elide->base, - expr_node, i); - IrInstruction *elem_ptr = ir_build_elem_ptr(irb, &parent_result_loc->scope_elide->base, - expr_node, container_ptr, elem_index, false, PtrLenSingle, true); - ResultLocInstruction *result_loc_inst = allocate(1); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = elem_ptr; - ir_ref_instruction(elem_ptr, irb->current_basic_block); - child_result_loc = &result_loc_inst->base; - val_scope = &parent_result_loc->scope_elide->base; - } + IrInstruction *elem_index = ir_build_const_usize(irb, scope, expr_node, i); + IrInstruction *elem_ptr = ir_build_elem_ptr(irb, scope, expr_node, container_ptr, elem_index, + false, PtrLenSingle, true); + ResultLocInstruction *result_loc_inst = allocate(1); + result_loc_inst->base.id = ResultLocIdInstruction; + result_loc_inst->base.source_instruction = elem_ptr; + ir_ref_instruction(elem_ptr, irb->current_basic_block); - IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, val_scope, LValNone, - child_result_loc); + IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, + &result_loc_inst->base); if (expr_value == irb->codegen->invalid_instruction) return expr_value; @@ -8651,8 +8626,6 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec IrBasicBlock *bb = exec->basic_block_list.at(0); for (size_t i = 0; i < bb->instruction_list.length; i += 1) { IrInstruction *instruction = bb->instruction_list.at(i); - if (scope_is_elided(instruction->scope)) - continue; if (instruction->id == IrInstructionIdReturn) { IrInstructionReturn *ret_inst = (IrInstructionReturn *)instruction; IrInstruction *value = ret_inst->value; @@ -12745,9 +12718,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value")); return ira->codegen->invalid_instruction; } - if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst || - ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) - { + if (ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) { ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); if (pointee->special != ConstValSpecialRuntime) { IrInstruction *result = ir_const(ira, source_instruction, child_type); @@ -14487,7 +14458,25 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, } if (init_val != nullptr && init_val->special != ConstValSpecialRuntime) { - if (var->mem_slot_index != SIZE_MAX) { + // Resolve ConstPtrMutInfer + if (var->gen_is_const) { + var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeConst; + } else if (is_comptime_var) { + var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeVar; + } else { + // we need a runtime ptr but we have a comptime val. + // since it's a comptime val there are no instructions for it. + // we memcpy the init value here + IrInstruction *deref = ir_get_deref(ira, var_ptr, var_ptr, nullptr); + // If this assertion trips, something is wrong with the IR instructions, because + // we expected the above deref to return a constant value, but it created a runtime + // instruction. + assert(deref->value.special != ConstValSpecialRuntime); + var_ptr->value.special = ConstValSpecialRuntime; + ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref); + } + + if (var_ptr->value.special == ConstValSpecialStatic && var->mem_slot_index != SIZE_MAX) { assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length); ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index); copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const); @@ -14818,9 +14807,9 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in pointee->special = ConstValSpecialUndef; IrInstructionAllocaGen *result = ir_create_alloca_gen(ira, source_inst, align, name_hint); - result->base.value.special = force_comptime ? ConstValSpecialStatic : ConstValSpecialRuntime; + result->base.value.special = ConstValSpecialStatic; result->base.value.data.x_ptr.special = ConstPtrSpecialRef; - result->base.value.data.x_ptr.mut = force_comptime ? ConstPtrMutComptimeVar : ConstPtrMutRuntimeVar; + result->base.value.data.x_ptr.mut = force_comptime ? ConstPtrMutComptimeVar : ConstPtrMutInfer; result->base.value.data.x_ptr.data.ref.pointee = pointee; if ((err = type_resolve(ira->codegen, var_type, ResolveStatusZeroBitsKnown))) @@ -15109,7 +15098,10 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn ZigType *implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); if (type_is_invalid(implicit_elem_type)) return ira->codegen->invalid_instruction; - return ir_resolve_result(ira, &instruction->base, instruction->result_loc, implicit_elem_type, nullptr); + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, implicit_elem_type, nullptr); + if (result_loc != nullptr) + return result_loc; + zig_panic("TODO"); } static void ir_reset_result(ResultLoc *result_loc) { @@ -15431,7 +15423,9 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant")); return ira->codegen->invalid_instruction; } - if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { + if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar || + ptr->value.data.x_ptr.mut == ConstPtrMutInfer) + { if (instr_is_comptime(value)) { ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, source_instr->source_node); if (dest_val == nullptr) @@ -15451,12 +15445,16 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source return ir_const_void(ira, source_instr); } } - ir_add_error(ira, source_instr, - buf_sprintf("cannot store runtime value in compile time variable")); - ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); - dest_val->type = ira->codegen->builtin_types.entry_invalid; + if (ptr->value.data.x_ptr.mut == ConstPtrMutInfer) { + ptr->value.special = ConstValSpecialRuntime; + } else { + ir_add_error(ira, source_instr, + buf_sprintf("cannot store runtime value in compile time variable")); + ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); + dest_val->type = ira->codegen->builtin_types.entry_invalid; - return ira->codegen->invalid_instruction; + return ira->codegen->invalid_instruction; + } } } @@ -17091,6 +17089,81 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, return ira->codegen->invalid_instruction; } +static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr, + TypeStructField *field, IrInstruction *struct_ptr, ZigType *struct_type, bool initializing) +{ + switch (type_has_one_possible_value(ira->codegen, field->type_entry)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueYes: { + IrInstruction *elem = ir_const(ira, source_instr, field->type_entry); + return ir_get_ref(ira, source_instr, elem, false, false); + } + case OnePossibleValueNo: + break; + } + assert(struct_ptr->value.type->id == ZigTypeIdPointer); + bool is_packed = (struct_type->data.structure.layout == ContainerLayoutPacked); + uint32_t align_bytes = is_packed ? 1 : get_abi_alignment(ira->codegen, field->type_entry); + uint32_t ptr_bit_offset = struct_ptr->value.type->data.pointer.bit_offset_in_host; + uint32_t ptr_host_int_bytes = struct_ptr->value.type->data.pointer.host_int_bytes; + uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? + get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes; + bool is_const = struct_ptr->value.type->data.pointer.is_const; + bool is_volatile = struct_ptr->value.type->data.pointer.is_volatile; + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, + is_const, is_volatile, PtrLenSingle, align_bytes, + (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), + (uint32_t)host_int_bytes_for_result_type, false); + if (instr_is_comptime(struct_ptr)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, struct_ptr, UndefBad); + if (!ptr_val) + return ira->codegen->invalid_instruction; + + if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { + ConstExprValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); + if (struct_val == nullptr) + return ira->codegen->invalid_instruction; + if (type_is_invalid(struct_val->type)) + return ira->codegen->invalid_instruction; + if (struct_val->special == ConstValSpecialUndef && initializing) { + struct_val->data.x_struct.fields = create_const_vals(struct_type->data.structure.src_field_count); + struct_val->special = ConstValSpecialStatic; + for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) { + ConstExprValue *field_val = &struct_val->data.x_struct.fields[i]; + field_val->special = ConstValSpecialUndef; + field_val->type = struct_type->data.structure.fields[i].type_entry; + ConstParent *parent = get_const_val_parent(ira->codegen, field_val); + if (parent != nullptr) { + parent->id = ConstParentIdStruct; + parent->data.p_struct.struct_val = struct_val; + parent->data.p_struct.field_index = i; + } + } + } + IrInstruction *result; + if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { + result = ir_build_struct_field_ptr(&ira->new_irb, source_instr->scope, + source_instr->source_node, struct_ptr, field); + result->value.type = ptr_type; + result->value.special = ConstValSpecialStatic; + } else { + result = ir_const(ira, source_instr, ptr_type); + } + ConstExprValue *const_val = &result->value; + const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct; + const_val->data.x_ptr.mut = struct_ptr->value.data.x_ptr.mut; + const_val->data.x_ptr.data.base_struct.struct_val = struct_val; + const_val->data.x_ptr.data.base_struct.field_index = field->src_index; + return result; + } + } + IrInstruction *result = ir_build_struct_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, + struct_ptr, field); + result->value.type = ptr_type; + return result; +} + static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing) { @@ -17101,59 +17174,10 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ira->codegen->invalid_instruction; assert(container_ptr->value.type->id == ZigTypeIdPointer); - bool is_const = container_ptr->value.type->data.pointer.is_const; - bool is_volatile = container_ptr->value.type->data.pointer.is_volatile; if (bare_type->id == ZigTypeIdStruct) { TypeStructField *field = find_struct_type_field(bare_type, field_name); - if (field) { - switch (type_has_one_possible_value(ira->codegen, field->type_entry)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_instruction; - case OnePossibleValueYes: { - IrInstruction *elem = ir_const(ira, source_instr, field->type_entry); - return ir_get_ref(ira, source_instr, elem, false, false); - } - case OnePossibleValueNo: - break; - } - bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked); - uint32_t align_bytes = is_packed ? 1 : get_abi_alignment(ira->codegen, field->type_entry); - uint32_t ptr_bit_offset = container_ptr->value.type->data.pointer.bit_offset_in_host; - uint32_t ptr_host_int_bytes = container_ptr->value.type->data.pointer.host_int_bytes; - uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? - get_host_int_bytes(ira->codegen, bare_type, field) : ptr_host_int_bytes; - if (instr_is_comptime(container_ptr)) { - ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_instruction; - - if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ConstExprValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); - if (struct_val == nullptr) - return ira->codegen->invalid_instruction; - if (type_is_invalid(struct_val->type)) - return ira->codegen->invalid_instruction; - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, - is_const, is_volatile, PtrLenSingle, align_bytes, - (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), - (uint32_t)host_int_bytes_for_result_type, false); - IrInstruction *result = ir_const(ira, source_instr, ptr_type); - ConstExprValue *const_val = &result->value; - const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct; - const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut; - const_val->data.x_ptr.data.base_struct.struct_val = struct_val; - const_val->data.x_ptr.data.base_struct.field_index = field->src_index; - return result; - } - } - IrInstruction *result = ir_build_struct_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, - container_ptr, field); - result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, - PtrLenSingle, - align_bytes, - (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), - host_int_bytes_for_result_type, false); - return result; + if (field != nullptr) { + return ir_analyze_struct_field_ptr(ira, source_instr, field, container_ptr, bare_type, initializing); } else { return ir_analyze_container_member_access_inner(ira, bare_type, field_name, source_instr, container_ptr, container_type); @@ -17162,6 +17186,9 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ir_analyze_container_member_access_inner(ira, bare_type, field_name, source_instr, container_ptr, container_type); } else if (bare_type->id == ZigTypeIdUnion) { + bool is_const = container_ptr->value.type->data.pointer.is_const; + bool is_volatile = container_ptr->value.type->data.pointer.is_volatile; + TypeUnionField *field = find_union_type_field(bare_type, field_name); if (field) { if (instr_is_comptime(container_ptr)) { @@ -18849,7 +18876,7 @@ static IrInstruction *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRe static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction, ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields, - IrInstruction *old_result_loc) + IrInstruction *result_loc) { Error err; assert(container_type->id == ZigTypeIdUnion); @@ -18905,21 +18932,17 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI return result; } - ir_assert(old_result_loc != nullptr, instruction); - IrInstruction *result_loc = old_result_loc->child; - if (type_is_invalid(result_loc->value.type)) - return result_loc; return ir_get_deref(ira, instruction, result_loc, nullptr); } static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields, - IrInstruction *old_result_loc) + IrInstruction *result_loc) { Error err; if (container_type->id == ZigTypeIdUnion) { return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, - fields, old_result_loc); + fields, result_loc); } if (container_type->id != ZigTypeIdStruct || is_slice(container_type)) { ir_add_error(ira, instruction, @@ -18936,20 +18959,28 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc IrInstruction *first_non_const_instruction = nullptr; AstNode **field_assign_nodes = allocate(actual_field_count); + ZigList const_ptrs = {}; bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope) || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; - ConstExprValue const_val = {}; - const_val.special = ConstValSpecialStatic; - const_val.type = container_type; - // const_val.global_refs = allocate(1); - const_val.data.x_struct.fields = create_const_vals(actual_field_count); + + // Here we iterate over the fields that have been initialized, and emit + // compile errors for missing fields and duplicate fields. + // It is only now that we find out whether the struct initialization can be a comptime + // value, but we have already emitted runtime instructions for the fields that + // were initialized with runtime values, and have omitted instructions that would have + // initialized fields with comptime values. + // So now we must clean up this situation. If it turns out the struct initialization can + // be a comptime value, overwrite ConstPtrMutInfer with ConstPtrMutComptimeConst. + // Otherwise, we must emit instructions to runtime-initialize the fields that have + // comptime-known values. + for (size_t i = 0; i < instr_field_count; i += 1) { IrInstructionContainerInitFieldsField *field = &fields[i]; - IrInstruction *field_value = field->value->child; - if (type_is_invalid(field_value->value.type)) + IrInstruction *field_result_loc = field->result_loc->child; + if (type_is_invalid(field_result_loc->value.type)) return ira->codegen->invalid_instruction; TypeStructField *type_field = find_struct_type_field(container_type, field->name); @@ -18963,10 +18994,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc if (type_is_invalid(type_field->type_entry)) return ira->codegen->invalid_instruction; - IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry); - if (casted_field_value == ira->codegen->invalid_instruction) - return ira->codegen->invalid_instruction; - size_t field_index = type_field->src_index; AstNode *existing_assign_node = field_assign_nodes[field_index]; if (existing_assign_node) { @@ -18976,23 +19003,18 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc } field_assign_nodes[field_index] = field->source_node; - if (const_val.special == ConstValSpecialStatic) { - if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) { - ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk); - if (!field_val) - return ira->codegen->invalid_instruction; - - copy_const_val(&const_val.data.x_struct.fields[field_index], field_val, true); - } else { - first_non_const_instruction = casted_field_value; - const_val.special = ConstValSpecialRuntime; - } + if (instr_is_comptime(field_result_loc) && + field_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) + { + const_ptrs.append(field_result_loc); + } else { + first_non_const_instruction = field_result_loc; } } bool any_missing = false; for (size_t i = 0; i < actual_field_count; i += 1) { - if (field_assign_nodes[i]) continue; + if (field_assign_nodes[i] != nullptr) continue; // look for a default field value TypeStructField *field = &container_type->data.structure.fields[i]; @@ -19018,44 +19040,41 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc IrInstruction *runtime_inst = ir_const(ira, instruction, field->init_val->type); copy_const_val(&runtime_inst->value, field->init_val, true); - if (const_val.special == ConstValSpecialStatic) { - copy_const_val(&const_val.data.x_struct.fields[i], field->init_val, true); + IrInstruction *field_ptr = ir_analyze_struct_field_ptr(ira, instruction, field, result_loc, + container_type, true); + ir_analyze_store_ptr(ira, instruction, field_ptr, runtime_inst); + if (instr_is_comptime(field_ptr) && field_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) { + const_ptrs.append(field_ptr); + } else { + first_non_const_instruction = result_loc; } } if (any_missing) return ira->codegen->invalid_instruction; - if (const_val.special == ConstValSpecialStatic) { - IrInstruction *result = ir_const(ira, instruction, nullptr); - ConstExprValue *out_val = &result->value; - copy_const_val(out_val, &const_val, false); - out_val->type = container_type; - - for (size_t i = 0; i < instr_field_count; i += 1) { - ConstExprValue *field_val = &out_val->data.x_struct.fields[i]; - ConstParent *parent = get_const_val_parent(ira->codegen, field_val); - if (parent != nullptr) { - parent->id = ConstParentIdStruct; - parent->data.p_struct.field_index = i; - parent->data.p_struct.struct_val = out_val; + if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) { + if (const_ptrs.length == actual_field_count) { + result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst; + } else { + result_loc->value.special = ConstValSpecialRuntime; + for (size_t i = 0; i < const_ptrs.length; i += 1) { + IrInstruction *field_result_loc = const_ptrs.at(i); + IrInstruction *deref = ir_get_deref(ira, field_result_loc, field_result_loc, nullptr); + field_result_loc->value.special = ConstValSpecialRuntime; + ir_analyze_store_ptr(ira, field_result_loc, field_result_loc, deref); } } - - return result; } - if (is_comptime) { + IrInstruction *result = ir_get_deref(ira, instruction, result_loc, nullptr); + + if (is_comptime && !instr_is_comptime(result)) { ir_add_error_node(ira, first_non_const_instruction->source_node, buf_sprintf("unable to evaluate constant expression")); return ira->codegen->invalid_instruction; } - - ir_assert(old_result_loc != nullptr, instruction); - IrInstruction *result_loc = old_result_loc->child; - if (type_is_invalid(result_loc->value.type)) - return result_loc; - return ir_get_deref(ira, instruction, result_loc, nullptr); + return result; } static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, @@ -19074,8 +19093,11 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, buf_sprintf("expected array type or [_], found slice")); return ira->codegen->invalid_instruction; } else if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) { - return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, - instruction->result_loc); + ir_assert(instruction->result_loc != nullptr, &instruction->base); + IrInstruction *result_loc = instruction->result_loc->child; + if (type_is_invalid(result_loc->value.type)) + return result_loc; + return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, result_loc); } else if (container_type->id == ZigTypeIdArray) { // array is same as slice init but we make a compile error if the length is wrong ZigType *child_type; @@ -19199,8 +19221,13 @@ static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ir if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; + ir_assert(instruction->result_loc != nullptr, &instruction->base); + IrInstruction *result_loc = instruction->result_loc->child; + if (type_is_invalid(result_loc->value.type)) + return result_loc; + return ir_analyze_container_init_fields(ira, &instruction->base, container_type, - instruction->field_count, instruction->fields, instruction->result_loc); + instruction->field_count, instruction->fields, result_loc); } static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira, @@ -24390,17 +24417,7 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; - bool want_resolve_result; - if (instruction->result_loc->written) { - if (instruction->result_loc->scope_elide != nullptr && instr_is_comptime(value)) { - want_resolve_result = true; - instruction->result_loc->scope_elide->activated = true; - } else { - want_resolve_result = false; - } - } else { - want_resolve_result = true; - } + bool want_resolve_result = !instruction->result_loc->written; if (want_resolve_result) { IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, value->value.type, value); -- cgit v1.2.3 From e27da17ff2cc45c93ab95defd937fd8038751b51 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 18 Jun 2019 17:07:27 -0400 Subject: back to many behavioral tests passing --- src/codegen.cpp | 4 +--- src/ir.cpp | 2 +- test/stage1/behavior.zig | 4 ++-- test/stage1/behavior/cast.zig | 36 ++++++++++++++++++------------------ test/stage1/behavior/enum.zig | 32 ++++++++++++++++---------------- test/stage1/behavior/error.zig | 16 ++++++++-------- test/stage1/behavior/struct.zig | 12 ++++++------ 7 files changed, 52 insertions(+), 54 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 547840514a..dc2a4f55df 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2017,11 +2017,9 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { render_const_val_global(g, &instruction->value, ""); ZigType *ptr_type = get_pointer_to_type(g, instruction->value.type, true); instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.global_refs->llvm_global, get_llvm_type(g, ptr_type), ""); - } else if (get_codegen_ptr_type(instruction->value.type) != nullptr) { + } else { instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.global_refs->llvm_value, get_llvm_type(g, instruction->value.type), ""); - } else { - instruction->llvm_value = instruction->value.global_refs->llvm_value; } assert(instruction->llvm_value); } diff --git a/src/ir.cpp b/src/ir.cpp index 90d79995e1..4d2221ab39 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14999,7 +14999,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe return parent_result_loc; } // because is_comptime is false, we mark this a runtime pointer - parent_result_loc->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; + parent_result_loc->value.special = ConstValSpecialRuntime; result_loc->written = true; result_loc->resolved_loc = parent_result_loc; return result_loc->resolved_loc; diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 6aa6ab48cb..ccbec6849a 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -40,12 +40,12 @@ comptime { _ = @import("behavior/bugs/920.zig"); _ = @import("behavior/byval_arg_var.zig"); //_ = @import("behavior/cancel.zig"); - _ = @import("behavior/cast.zig"); + _ = @import("behavior/cast.zig"); // TODO _ = @import("behavior/const_slice_child.zig"); //_ = @import("behavior/coroutine_await_struct.zig"); //_ = @import("behavior/coroutines.zig"); _ = @import("behavior/defer.zig"); - _ = @import("behavior/enum.zig"); + _ = @import("behavior/enum.zig"); // TODO _ = @import("behavior/enum_with_members.zig"); _ = @import("behavior/error.zig"); // TODO _ = @import("behavior/eval.zig"); // TODO diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 0a2ffb6c2f..c148523a72 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -165,10 +165,10 @@ fn castToOptionalSlice() ?[]const u8 { return "hi"; } -test "implicitly cast from [0]T to anyerror![]T" { - testCastZeroArrayToErrSliceMut(); - comptime testCastZeroArrayToErrSliceMut(); -} +//test "implicitly cast from [0]T to anyerror![]T" { +// testCastZeroArrayToErrSliceMut(); +// comptime testCastZeroArrayToErrSliceMut(); +//} fn testCastZeroArrayToErrSliceMut() void { expect((gimmeErrOrSlice() catch unreachable).len == 0); @@ -178,20 +178,20 @@ fn gimmeErrOrSlice() anyerror![]u8 { return [_]u8{}; } -test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { - { - var data = "hi"; - const slice = data[0..]; - expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); - } - comptime { - var data = "hi"; - const slice = data[0..]; - expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); - } -} +//test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { +// { +// var data = "hi"; +// const slice = data[0..]; +// expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); +// expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); +// } +// comptime { +// var data = "hi"; +// const slice = data[0..]; +// expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); +// expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); +// } +//} fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { if (a) { return [_]u8{}; diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index 51f4f0e196..e06a075974 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -1,22 +1,22 @@ const expect = @import("std").testing.expect; const mem = @import("std").mem; -test "enum type" { - const foo1 = Foo{ .One = 13 }; - const foo2 = Foo{ - .Two = Point{ - .x = 1234, - .y = 5678, - }, - }; - const bar = Bar.B; - - expect(bar == Bar.B); - expect(@memberCount(Foo) == 3); - expect(@memberCount(Bar) == 4); - expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); - expect(@sizeOf(Bar) == 1); -} +//test "enum type" { +// const foo1 = Foo{ .One = 13 }; +// const foo2 = Foo{ +// .Two = Point{ +// .x = 1234, +// .y = 5678, +// }, +// }; +// const bar = Bar.B; +// +// expect(bar == Bar.B); +// expect(@memberCount(Foo) == 3); +// expect(@memberCount(Bar) == 4); +// expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); +// expect(@sizeOf(Bar) == 1); +//} test "enum as return value" { switch (returnAnInt(13)) { diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig index 861c500751..1f8f8b36e4 100644 --- a/test/stage1/behavior/error.zig +++ b/test/stage1/behavior/error.zig @@ -130,10 +130,10 @@ fn testExplicitErrorSetCast(set1: Set1) void { expect(y == error.A); } -test "comptime test error for empty error set" { - testComptimeTestErrorEmptySet(1234); - comptime testComptimeTestErrorEmptySet(1234); -} +//test "comptime test error for empty error set" { +// testComptimeTestErrorEmptySet(1234); +// comptime testComptimeTestErrorEmptySet(1234); +//} const EmptyErrorSet = error{}; @@ -204,10 +204,10 @@ fn foo2(f: fn () anyerror!void) void { fn bar2() (error{}!void) {} -test "error: Zero sized error set returned with value payload crash" { - _ = foo3(0) catch {}; - _ = comptime foo3(0) catch {}; -} +//test "error: Zero sized error set returned with value payload crash" { +// _ = foo3(0) catch {}; +// _ = comptime foo3(0) catch {}; +//} const Error = error{}; fn foo3(b: usize) Error!usize { diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index ccdff3503e..a08dec5359 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -522,12 +522,12 @@ const S0 = struct { } }; -var g_foo: S0 = S0.init(); - -test "access to global struct fields" { - g_foo.bar.value = 42; - expect(g_foo.bar.value == 42); -} +//var g_foo: S0 = S0.init(); +// +//test "access to global struct fields" { +// g_foo.bar.value = 42; +// expect(g_foo.bar.value == 42); +//} //test "packed struct with fp fields" { // const S = packed struct { -- cgit v1.2.3 From fce2d2d18be279359dcd75254506d46085c59aaf Mon Sep 17 00:00:00 2001 From: Shawn Landden Date: Tue, 18 Jun 2019 17:28:49 -0500 Subject: stage1: add support for @mulAdd fused-multiply-add for floats and vectors of floats Not all of the softfloat library is being built.... Vector support is very buggy at the moment, but should work when the bugs are fixed. (as I had the same code working with another vector function, that hasn't been merged yet). --- CMakeLists.txt | 2 + doc/langref.html.in | 7 ++ src/all_types.hpp | 13 +++ src/analyze.cpp | 7 +- src/codegen.cpp | 46 ++++++++++- src/ir.cpp | 171 ++++++++++++++++++++++++++++++++++++++++ src/ir_print.cpp | 19 +++++ test/stage1/behavior/muladd.zig | 34 ++++++++ 8 files changed, 292 insertions(+), 7 deletions(-) create mode 100644 test/stage1/behavior/muladd.zig (limited to 'src/codegen.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index d6f8176e40..6a06afc9fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -389,6 +389,8 @@ set(EMBEDDED_SOFTFLOAT_SOURCES "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF32.c" "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF64.c" "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c" + "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mulAdd.c" + "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_mulAdd.c" "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/softfloat_state.c" "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_f128M.c" "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_f128M.c" diff --git a/doc/langref.html.in b/doc/langref.html.in index 5ddd572e51..9b95946256 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6259,6 +6259,13 @@ comptime { This function is only valid within function scope.

+ {#header_close#} + {#header_open|@mulAdd#} +
{#syntax#}@mulAdd(comptime T: type, a: T, b: T, c: T) T{#endsyntax#}
+

+ Fused multiply add (for floats), similar to {#syntax#}(a * b) + c{#endsyntax#}, except + only rounds once, and is thus more accurate. +

{#header_close#} {#header_open|@byteSwap#} diff --git a/src/all_types.hpp b/src/all_types.hpp index 5aa1c78ea1..83df71b95f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1406,6 +1406,7 @@ enum BuiltinFnId { BuiltinFnIdSubWithOverflow, BuiltinFnIdMulWithOverflow, BuiltinFnIdShlWithOverflow, + BuiltinFnIdMulAdd, BuiltinFnIdCInclude, BuiltinFnIdCDefine, BuiltinFnIdCUndef, @@ -1554,6 +1555,7 @@ enum ZigLLVMFnId { ZigLLVMFnIdClz, ZigLLVMFnIdPopCount, ZigLLVMFnIdOverflowArithmetic, + ZigLLVMFnIdFMA, ZigLLVMFnIdFloor, ZigLLVMFnIdCeil, ZigLLVMFnIdSqrt, @@ -1584,6 +1586,7 @@ struct ZigLLVMFnKey { } pop_count; struct { uint32_t bit_count; + uint32_t vector_len; // 0 means not a vector } floating; struct { AddSubMul add_sub_mul; @@ -2235,6 +2238,7 @@ enum IrInstructionId { IrInstructionIdHandle, IrInstructionIdAlignOf, IrInstructionIdOverflowOp, + IrInstructionIdMulAdd, IrInstructionIdTestErr, IrInstructionIdUnwrapErrCode, IrInstructionIdUnwrapErrPayload, @@ -3038,6 +3042,15 @@ struct IrInstructionOverflowOp { ZigType *result_ptr_type; }; +struct IrInstructionMulAdd { + IrInstruction base; + + IrInstruction *type_value; + IrInstruction *op1; + IrInstruction *op2; + IrInstruction *op3; +}; + struct IrInstructionAlignOf { IrInstruction base; diff --git a/src/analyze.cpp b/src/analyze.cpp index c7e35367c3..bff740cd52 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5737,11 +5737,11 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { case ZigLLVMFnIdPopCount: return (uint32_t)(x.data.clz.bit_count) * (uint32_t)101195049; case ZigLLVMFnIdFloor: - return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1899859168; case ZigLLVMFnIdCeil: - return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1953839089; case ZigLLVMFnIdSqrt: - return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385; + case ZigLLVMFnIdFMA: + return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + + (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025); case ZigLLVMFnIdBswap: return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; case ZigLLVMFnIdBitReverse: @@ -5772,6 +5772,7 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { case ZigLLVMFnIdFloor: case ZigLLVMFnIdCeil: case ZigLLVMFnIdSqrt: + case ZigLLVMFnIdFMA: return a.data.floating.bit_count == b.data.floating.bit_count; case ZigLLVMFnIdOverflowArithmetic: return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) && diff --git a/src/codegen.cpp b/src/codegen.cpp index 3dd6995c61..6691652a5e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -807,31 +807,51 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *operand_type, AddSu } static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn_id) { - assert(type_entry->id == ZigTypeIdFloat); + assert(type_entry->id == ZigTypeIdFloat || + type_entry->id == ZigTypeIdVector); + + bool is_vector = (type_entry->id == ZigTypeIdVector); + ZigType *float_type = is_vector ? type_entry->data.vector.elem_type : type_entry; ZigLLVMFnKey key = {}; key.id = fn_id; - key.data.floating.bit_count = (uint32_t)type_entry->data.floating.bit_count; + key.data.floating.bit_count = (uint32_t)float_type->data.floating.bit_count; + key.data.floating.vector_len = is_vector ? (uint32_t)type_entry->data.vector.len : 0; auto existing_entry = g->llvm_fn_table.maybe_get(key); if (existing_entry) return existing_entry->value; const char *name; + uint32_t num_args; if (fn_id == ZigLLVMFnIdFloor) { name = "floor"; + num_args = 1; } else if (fn_id == ZigLLVMFnIdCeil) { name = "ceil"; + num_args = 1; } else if (fn_id == ZigLLVMFnIdSqrt) { name = "sqrt"; + num_args = 1; + } else if (fn_id == ZigLLVMFnIdFMA) { + name = "fma"; + num_args = 3; } else { zig_unreachable(); } char fn_name[64]; - sprintf(fn_name, "llvm.%s.f%" ZIG_PRI_usize "", name, type_entry->data.floating.bit_count); + if (is_vector) + sprintf(fn_name, "llvm.%s.v%" PRIu32 "f%" PRIu32, name, key.data.floating.vector_len, key.data.floating.bit_count); + else + sprintf(fn_name, "llvm.%s.f%" PRIu32, name, key.data.floating.bit_count); LLVMTypeRef float_type_ref = get_llvm_type(g, type_entry); - LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, &float_type_ref, 1, false); + LLVMTypeRef return_elem_types[3] = { + float_type_ref, + float_type_ref, + float_type_ref, + }; + LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, return_elem_types, num_args, false); LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); assert(LLVMGetIntrinsicID(fn_val)); @@ -5437,6 +5457,21 @@ static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstr return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); } +static LLVMValueRef ir_render_mul_add(CodeGen *g, IrExecutable *executable, IrInstructionMulAdd *instruction) { + LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); + LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); + LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); + assert(instruction->base.value.type->id == ZigTypeIdFloat || + instruction->base.value.type->id == ZigTypeIdVector); + LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdFMA); + LLVMValueRef args[3] = { + op1, + op2, + op3, + }; + return LLVMBuildCall(g->builder, fn_val, args, 3, ""); +} + static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) { LLVMValueRef op = ir_llvm_value(g, instruction->op); ZigType *int_type = instruction->base.value.type; @@ -5781,6 +5816,8 @@ 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 IrInstructionIdMulAdd: + return ir_render_mul_add(g, executable, (IrInstructionMulAdd *)instruction); case IrInstructionIdArrayToVector: return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction); case IrInstructionIdVectorToArray: @@ -7398,6 +7435,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdRem, "rem", 2); create_builtin_fn(g, BuiltinFnIdMod, "mod", 2); create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2); + create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4); create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX); create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX); create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX); diff --git a/src/ir.cpp b/src/ir.cpp index 5c09e48b2d..c2c6cb6154 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -747,6 +747,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErr *) { return IrInstructionIdTestErr; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionMulAdd *) { + return IrInstructionIdMulAdd; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrCode *) { return IrInstructionIdUnwrapErrCode; } @@ -2308,6 +2312,22 @@ static IrInstruction *ir_build_overflow_op(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } +static IrInstruction *ir_build_mul_add(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *type_value, IrInstruction *op1, IrInstruction *op2, IrInstruction *op3) { + IrInstructionMulAdd *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type_value = type_value; + instruction->op1 = op1; + instruction->op2 = op2; + instruction->op3 = op3; + + ir_ref_instruction(type_value, irb->current_basic_block); + ir_ref_instruction(op1, irb->current_basic_block); + ir_ref_instruction(op2, irb->current_basic_block); + ir_ref_instruction(op3, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) { IrInstructionAlignOf *instruction = ir_build_instruction(irb, scope, source_node); instruction->type_value = type_value; @@ -4028,6 +4048,33 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode * return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr); } +static IrInstruction *ir_gen_mul_add(IrBuilder *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeFnCallExpr); + + AstNode *type_node = node->data.fn_call_expr.params.at(0); + AstNode *op1_node = node->data.fn_call_expr.params.at(1); + AstNode *op2_node = node->data.fn_call_expr.params.at(2); + AstNode *op3_node = node->data.fn_call_expr.params.at(3); + + IrInstruction *type_value = ir_gen_node(irb, type_node, scope); + if (type_value == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + + IrInstruction *op1 = ir_gen_node(irb, op1_node, scope); + if (op1 == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + + IrInstruction *op2 = ir_gen_node(irb, op2_node, scope); + if (op2 == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + + IrInstruction *op3 = ir_gen_node(irb, op3_node, scope); + if (op3 == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + + return ir_build_mul_add(irb, scope, node, type_value, op1, op2, op3); +} + static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *node) { for (Scope *it_scope = orig_scope; it_scope != nullptr; it_scope = it_scope->parent) { if (it_scope->id == ScopeIdDecls) { @@ -4687,6 +4734,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval); case BuiltinFnIdShlWithOverflow: return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval); + case BuiltinFnIdMulAdd: + return ir_lval_wrap(irb, scope, ir_gen_mul_add(irb, scope, node), lval); case BuiltinFnIdTypeName: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -21185,6 +21234,125 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr return result; } +static void ir_eval_mul_add(IrAnalyze *ira, IrInstructionMulAdd *source_instr, ZigType *float_type, + ConstExprValue *op1, ConstExprValue *op2, ConstExprValue *op3, ConstExprValue *out_val) { + if (float_type->id == ZigTypeIdComptimeFloat) { + f128M_mulAdd(&out_val->data.x_bigfloat.value, &op1->data.x_bigfloat.value, &op2->data.x_bigfloat.value, + &op3->data.x_bigfloat.value); + } else if (float_type->id == ZigTypeIdFloat) { + switch (float_type->data.floating.bit_count) { + case 16: + out_val->data.x_f16 = f16_mulAdd(op1->data.x_f16, op2->data.x_f16, op3->data.x_f16); + break; + case 32: + out_val->data.x_f32 = fmaf(op1->data.x_f32, op2->data.x_f32, op3->data.x_f32); + break; + case 64: + out_val->data.x_f64 = fma(op1->data.x_f64, op2->data.x_f64, op3->data.x_f64); + break; + case 128: + f128M_mulAdd(&op1->data.x_f128, &op2->data.x_f128, &op3->data.x_f128, &out_val->data.x_f128); + break; + default: + zig_unreachable(); + } + } else { + zig_unreachable(); + } +} + +static IrInstruction *ir_analyze_instruction_mul_add(IrAnalyze *ira, IrInstructionMulAdd *instruction) { + IrInstruction *type_value = instruction->type_value->child; + if (type_is_invalid(type_value->value.type)) + return ira->codegen->invalid_instruction; + + ZigType *expr_type = ir_resolve_type(ira, type_value); + if (type_is_invalid(expr_type)) + return ira->codegen->invalid_instruction; + + // Only allow float types, and vectors of floats. + ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type; + if (float_type->id != ZigTypeIdFloat) { + ir_add_error(ira, type_value, + buf_sprintf("expected float or vector of float type, found '%s'", buf_ptr(&float_type->name))); + return ira->codegen->invalid_instruction; + } + + IrInstruction *op1 = instruction->op1->child; + if (type_is_invalid(op1->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, expr_type); + if (type_is_invalid(casted_op1->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *op2 = instruction->op2->child; + if (type_is_invalid(op2->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, expr_type); + if (type_is_invalid(casted_op2->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *op3 = instruction->op3->child; + if (type_is_invalid(op3->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *casted_op3 = ir_implicit_cast(ira, op3, expr_type); + if (type_is_invalid(casted_op3->value.type)) + return ira->codegen->invalid_instruction; + + if (instr_is_comptime(casted_op1) && + instr_is_comptime(casted_op2) && + instr_is_comptime(casted_op3)) { + ConstExprValue *op1_const = ir_resolve_const(ira, casted_op1, UndefBad); + if (!op1_const) + return ira->codegen->invalid_instruction; + ConstExprValue *op2_const = ir_resolve_const(ira, casted_op2, UndefBad); + if (!op2_const) + return ira->codegen->invalid_instruction; + ConstExprValue *op3_const = ir_resolve_const(ira, casted_op3, UndefBad); + if (!op3_const) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, &instruction->base, expr_type); + ConstExprValue *out_val = &result->value; + + if (expr_type->id == ZigTypeIdVector) { + expand_undef_array(ira->codegen, op1_const); + expand_undef_array(ira->codegen, op2_const); + expand_undef_array(ira->codegen, op3_const); + out_val->special = ConstValSpecialUndef; + expand_undef_array(ira->codegen, out_val); + size_t len = expr_type->data.vector.len; + for (size_t i = 0; i < len; i += 1) { + ConstExprValue *float_operand_op1 = &op1_const->data.x_array.data.s_none.elements[i]; + ConstExprValue *float_operand_op2 = &op2_const->data.x_array.data.s_none.elements[i]; + ConstExprValue *float_operand_op3 = &op3_const->data.x_array.data.s_none.elements[i]; + ConstExprValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i]; + assert(float_operand_op1->type == float_type); + assert(float_operand_op2->type == float_type); + assert(float_operand_op3->type == float_type); + assert(float_out_val->type == float_type); + ir_eval_mul_add(ira, instruction, float_type, + op1_const, op2_const, op3_const, float_out_val); + float_out_val->type = float_type; + } + out_val->type = expr_type; + out_val->special = ConstValSpecialStatic; + } else { + ir_eval_mul_add(ira, instruction, float_type, op1_const, op2_const, op3_const, out_val); + } + return result; + } + + IrInstruction *result = ir_build_mul_add(&ira->new_irb, + instruction->base.scope, instruction->base.source_node, + type_value, casted_op1, casted_op2, casted_op3); + result->value.type = expr_type; + return result; +} + static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErr *instruction) { IrInstruction *value = instruction->value->child; if (type_is_invalid(value->value.type)) @@ -23596,6 +23764,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction); case IrInstructionIdSqrt: return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); + case IrInstructionIdMulAdd: + return ir_analyze_instruction_mul_add(ira, (IrInstructionMulAdd *)instruction); case IrInstructionIdIntToErr: return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); case IrInstructionIdErrToInt: @@ -23835,6 +24005,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCoroPromise: case IrInstructionIdPromiseResultType: case IrInstructionIdSqrt: + case IrInstructionIdMulAdd: case IrInstructionIdAtomicLoad: case IrInstructionIdIntCast: case IrInstructionIdFloatCast: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index bf9ced89c5..e205c8e067 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1439,6 +1439,22 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) { fprintf(irp->f, ")"); } +static void ir_print_mul_add(IrPrint *irp, IrInstructionMulAdd *instruction) { + fprintf(irp->f, "@mulAdd("); + if (instruction->type_value != nullptr) { + ir_print_other_instruction(irp, instruction->type_value); + } else { + fprintf(irp->f, "null"); + } + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->op1); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->op2); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->op3); + fprintf(irp->f, ")"); +} + static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_var_instruction) { ZigVar *var = decl_var_instruction->var; const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; @@ -1905,6 +1921,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdSqrt: ir_print_sqrt(irp, (IrInstructionSqrt *)instruction); break; + case IrInstructionIdMulAdd: + ir_print_mul_add(irp, (IrInstructionMulAdd *)instruction); + break; case IrInstructionIdAtomicLoad: ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); break; diff --git a/test/stage1/behavior/muladd.zig b/test/stage1/behavior/muladd.zig new file mode 100644 index 0000000000..143e6a93e4 --- /dev/null +++ b/test/stage1/behavior/muladd.zig @@ -0,0 +1,34 @@ +const expect = @import("std").testing.expect; + +test "@mulAdd" { + comptime testMulAdd(); + testMulAdd(); +} + +fn testMulAdd() void { + { + var a: f16 = 5.5; + var b: f16 = 2.5; + var c: f16 = 6.25; + expect(@mulAdd(f16, a, b, c) == 20); + } + { + var a: f32 = 5.5; + var b: f32 = 2.5; + var c: f32 = 6.25; + expect(@mulAdd(f32, a, b, c) == 20); + } + { + var a: f64 = 5.5; + var b: f64 = 2.5; + var c: f64 = 6.25; + expect(@mulAdd(f64, a, b, c) == 20); + } + // Awaits implementation in libm.zig + //{ + // var a: f16 = 5.5; + // var b: f128 = 2.5; + // var c: f128 = 6.25; + // expect(@mulAdd(f128, a, b, c) == 20); + //} +} \ No newline at end of file -- cgit v1.2.3 From b588a803bf4493d2fd1892fe172b9ce8cfb0ca30 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Jun 2019 14:35:59 -0400 Subject: fix comptime modification of const struct field --- src/all_types.hpp | 3 +++ src/analyze.cpp | 2 +- src/codegen.cpp | 2 +- src/ir.cpp | 43 +++++++++++++++++++++++++++---------------- test/stage1/behavior.zig | 2 +- test/stage1/behavior/eval.zig | 16 ++++++++-------- 6 files changed, 41 insertions(+), 27 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 01f084218d..efb74e5ec3 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -334,6 +334,9 @@ struct ConstExprValue { RuntimeHintPtr rh_ptr; RuntimeHintSlice rh_slice; } data; + + ConstExprValue(const ConstExprValue &other) = delete; // plz zero initialize with {} + ConstExprValue& operator= (const ConstExprValue &other) = delete; // use copy_const_val }; enum ReturnKnowledge { diff --git a/src/analyze.cpp b/src/analyze.cpp index b39b1e35ca..d048dd9770 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4711,7 +4711,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { auto entry = g->string_literals_table.maybe_get(str); if (entry != nullptr) { - *const_val = *entry->value; + memcpy(const_val, entry->value, sizeof(ConstExprValue)); return; } diff --git a/src/codegen.cpp b/src/codegen.cpp index dc2a4f55df..8f3a8df451 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6676,7 +6676,7 @@ static void do_code_gen(CodeGen *g) { zig_panic("TODO debug info for var with ptr casted value"); } ZigType *var_type = g->builtin_types.entry_f128; - ConstExprValue coerced_value; + ConstExprValue coerced_value = {}; coerced_value.special = ConstValSpecialStatic; coerced_value.type = var_type; coerced_value.data.x_f128 = bigfloat_to_f128(&const_val->data.x_bigfloat); diff --git a/src/ir.cpp b/src/ir.cpp index 83199fc0cc..3d125da1a1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10624,13 +10624,16 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs) { ConstGlobalRefs *global_refs = dest->global_refs; - assert(!same_global_refs || src->global_refs != nullptr); - *dest = *src; + memcpy(dest, src, sizeof(ConstExprValue)); if (!same_global_refs) { dest->global_refs = global_refs; + if (src->special == ConstValSpecialUndef) + return; if (dest->type->id == ZigTypeIdStruct) { - dest->data.x_struct.fields = allocate_nonzero(dest->type->data.structure.src_field_count); - memcpy(dest->data.x_struct.fields, src->data.x_struct.fields, sizeof(ConstExprValue) * dest->type->data.structure.src_field_count); + dest->data.x_struct.fields = create_const_vals(dest->type->data.structure.src_field_count); + for (size_t i = 0; i < dest->type->data.structure.src_field_count; i += 1) { + copy_const_val(&dest->data.x_struct.fields[i], &src->data.x_struct.fields[i], false); + } } } } @@ -13579,7 +13582,7 @@ static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, IrInstruction *source_in } } else { float_div_trunc(out_val, op1_val, op2_val); - ConstExprValue remainder; + ConstExprValue remainder = {}; float_rem(&remainder, op1_val, op2_val); if (float_cmp_zero(&remainder) != CmpEQ) { return ir_add_error(ira, source_instr, buf_sprintf("exact division had a remainder")); @@ -13954,8 +13957,8 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp // have a remainder function ambiguity problem ok = true; } else { - ConstExprValue rem_result; - ConstExprValue mod_result; + ConstExprValue rem_result = {}; + ConstExprValue mod_result = {}; float_rem(&rem_result, op1_val, op2_val); float_mod(&mod_result, op1_val, op2_val); ok = float_cmp(&rem_result, &mod_result) == CmpEQ; @@ -14178,10 +14181,12 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i size_t next_index = 0; for (size_t i = op1_array_index; i < op1_array_end; i += 1, next_index += 1) { - out_array_val->data.x_array.data.s_none.elements[next_index] = op1_array_val->data.x_array.data.s_none.elements[i]; + copy_const_val(&out_array_val->data.x_array.data.s_none.elements[next_index], + &op1_array_val->data.x_array.data.s_none.elements[i], true); } for (size_t i = op2_array_index; i < op2_array_end; i += 1, next_index += 1) { - out_array_val->data.x_array.data.s_none.elements[next_index] = op2_array_val->data.x_array.data.s_none.elements[i]; + copy_const_val(&out_array_val->data.x_array.data.s_none.elements[next_index], + &op2_array_val->data.x_array.data.s_none.elements[i], true); } if (next_index < new_len) { ConstExprValue *null_byte = &out_array_val->data.x_array.data.s_none.elements[next_index]; @@ -14242,7 +14247,8 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * uint64_t i = 0; for (uint64_t x = 0; x < mult_amt; x += 1) { for (uint64_t y = 0; y < old_array_len; y += 1) { - out_val->data.x_array.data.s_none.elements[i] = array_val->data.x_array.data.s_none.elements[y]; + copy_const_val(&out_val->data.x_array.data.s_none.elements[i], + &array_val->data.x_array.data.s_none.elements[y], true); i += 1; } } @@ -14382,7 +14388,12 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, if (instr_is_comptime(var_ptr) && var_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) { init_val = const_ptr_pointee(ira, ira->codegen, &var_ptr->value, decl_var_instruction->base.source_node); if (is_comptime_var) { - var->const_value = init_val; + if (var->gen_is_const) { + var->const_value = init_val; + } else { + var->const_value = create_const_vals(1); + copy_const_val(var->const_value, init_val, false); + } } } @@ -15291,7 +15302,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod arg_val = create_const_runtime(casted_arg->value.type); } if (arg_part_of_generic_id) { - generic_id->params[generic_id->param_count] = *arg_val; + copy_const_val(&generic_id->params[generic_id->param_count], arg_val, true); generic_id->param_count += 1; } @@ -15476,7 +15487,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source // * "string literal used as comptime slice is memoized" // * "comptime modification of const struct field" - except modified to avoid // ConstPtrMutComptimeVar, thus defeating the logic below. - bool same_global_refs = ptr->value.data.x_ptr.mut != ConstPtrMutComptimeVar; + bool same_global_refs = ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst; copy_const_val(dest_val, &value->value, same_global_refs); if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr; @@ -15877,7 +15888,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, nullptr); IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); - const_instruction->base.value = *align_result; + copy_const_val(&const_instruction->base.value, align_result, true); uint32_t align_bytes = 0; ir_resolve_align(ira, &const_instruction->base, &align_bytes); @@ -21667,7 +21678,7 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio ConstExprValue *byte_val = &casted_byte->value; for (size_t i = start; i < end; i += 1) { - dest_elements[i] = *byte_val; + copy_const_val(&dest_elements[i], byte_val, true); } return ir_const_void(ira, &instruction->base); @@ -21835,7 +21846,7 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio // TODO check for noalias violations - this should be generalized to work for any function for (size_t i = 0; i < count; i += 1) { - dest_elements[dest_start + i] = src_elements[src_start + i]; + copy_const_val(&dest_elements[dest_start + i], &src_elements[src_start + i], true); } return ir_const_void(ira, &instruction->base); diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index ccbec6849a..77fc482ccc 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -48,7 +48,7 @@ comptime { _ = @import("behavior/enum.zig"); // TODO _ = @import("behavior/enum_with_members.zig"); _ = @import("behavior/error.zig"); // TODO - _ = @import("behavior/eval.zig"); // TODO + _ = @import("behavior/eval.zig"); _ = @import("behavior/field_parent_ptr.zig"); _ = @import("behavior/fn.zig"); _ = @import("behavior/fn_in_struct_in_comptime.zig"); diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 62cedbc76f..97d3a269cc 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -583,14 +583,14 @@ pub const Info = struct { pub const diamond_info = Info{ .version = 0 }; -//test "comptime modification of const struct field" { -// comptime { -// var res = diamond_info; -// res.version = 1; -// expect(diamond_info.version == 0); -// expect(res.version == 1); -// } -//} +test "comptime modification of const struct field" { + comptime { + var res = diamond_info; + res.version = 1; + expect(diamond_info.version == 0); + expect(res.version == 1); + } +} test "pointer to type" { comptime { -- cgit v1.2.3 From 974db231a08731f642dbf72d716f669fed2bd2ab Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Jun 2019 16:16:47 -0400 Subject: fix extraneous nested union field instruction --- src/codegen.cpp | 7 ++++++- test/stage1/behavior.zig | 2 +- test/stage1/behavior/enum.zig | 32 ++++++++++++++++---------------- 3 files changed, 23 insertions(+), 18 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 8f3a8df451..bd3bae66fc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3853,6 +3853,9 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable, IrInstructionUnionFieldPtr *instruction) { + if (instruction->base.value.special != ConstValSpecialRuntime) + return nullptr; + ZigType *union_ptr_type = instruction->union_ptr->value.type; assert(union_ptr_type->id == ZigTypeIdPointer); ZigType *union_type = union_ptr_type->data.pointer.child_type; @@ -4077,6 +4080,9 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *executable, IrInstructionOptionalUnwrapPtr *instruction) { + if (instruction->base.value.special != ConstValSpecialRuntime) + return nullptr; + ZigType *ptr_type = instruction->base_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *maybe_type = ptr_type->data.pointer.child_type; @@ -5750,7 +5756,6 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { assert(executable->basic_block_list.length > 0); for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { IrBasicBlock *current_block = executable->basic_block_list.at(block_i); - //assert(current_block->ref_count > 0); assert(current_block->llvm_block); LLVMPositionBuilderAtEnd(g->builder, current_block->llvm_block); for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 5ad6b94f3f..0e93290cc4 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -45,7 +45,7 @@ comptime { //_ = @import("behavior/coroutine_await_struct.zig"); //_ = @import("behavior/coroutines.zig"); _ = @import("behavior/defer.zig"); - _ = @import("behavior/enum.zig"); // TODO + _ = @import("behavior/enum.zig"); _ = @import("behavior/enum_with_members.zig"); _ = @import("behavior/error.zig"); // TODO _ = @import("behavior/eval.zig"); diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index e06a075974..51f4f0e196 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -1,22 +1,22 @@ const expect = @import("std").testing.expect; const mem = @import("std").mem; -//test "enum type" { -// const foo1 = Foo{ .One = 13 }; -// const foo2 = Foo{ -// .Two = Point{ -// .x = 1234, -// .y = 5678, -// }, -// }; -// const bar = Bar.B; -// -// expect(bar == Bar.B); -// expect(@memberCount(Foo) == 3); -// expect(@memberCount(Bar) == 4); -// expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); -// expect(@sizeOf(Bar) == 1); -//} +test "enum type" { + const foo1 = Foo{ .One = 13 }; + const foo2 = Foo{ + .Two = Point{ + .x = 1234, + .y = 5678, + }, + }; + const bar = Bar.B; + + expect(bar == Bar.B); + expect(@memberCount(Foo) == 3); + expect(@memberCount(Bar) == 4); + expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); + expect(@sizeOf(Bar) == 1); +} test "enum as return value" { switch (returnAnInt(13)) { -- cgit v1.2.3 From 96931228af745b8e69c138b3b83893dafa166cfe Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Jun 2019 16:29:46 -0400 Subject: fix comptime test error for empty error set --- src/all_types.hpp | 1 + src/codegen.cpp | 6 ++++++ src/ir.cpp | 26 ++++++++++++++++++++------ test/stage1/behavior/error.zig | 16 ++++++++-------- 4 files changed, 35 insertions(+), 14 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index efb74e5ec3..e376c4d4e8 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3085,6 +3085,7 @@ struct IrInstructionAlignOf { struct IrInstructionTestErrSrc { IrInstruction base; + bool resolve_err_set; IrInstruction *base_ptr; }; diff --git a/src/codegen.cpp b/src/codegen.cpp index bd3bae66fc..05bdf92555 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4913,6 +4913,9 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) { + if (instruction->base.value.special != ConstValSpecialRuntime) + return nullptr; + ZigType *ptr_type = instruction->err_union_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *err_union_type = ptr_type->data.pointer.child_type; @@ -4930,6 +4933,9 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) { + if (instruction->base.value.special != ConstValSpecialRuntime) + return nullptr; + bool want_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base) && g->errors_by_index.length > 1; if (!want_safety && !type_has_bits(instruction->base.value.type)) diff --git a/src/ir.cpp b/src/ir.cpp index 6dfaa168ec..6de4202c5f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2446,10 +2446,11 @@ static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *s } static IrInstruction *ir_build_test_err_src(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *base_ptr) + IrInstruction *base_ptr, bool resolve_err_set) { IrInstructionTestErrSrc *instruction = ir_build_instruction(irb, scope, source_node); instruction->base_ptr = base_ptr; + instruction->resolve_err_set = resolve_err_set; ir_ref_instruction(base_ptr, irb->current_basic_block); @@ -3593,7 +3594,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *ret_ptr = ir_build_result_ptr(irb, scope, node, &result_loc_ret->base, return_value); - IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, ret_ptr); + IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, ret_ptr, false); bool should_inline = ir_should_inline(irb->exec, scope); IrInstruction *is_comptime; @@ -3639,7 +3640,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr); + IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr, true); IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn"); IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue"); @@ -5987,7 +5988,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n LValPtr, nullptr); if (err_val_ptr == irb->codegen->invalid_instruction) return err_val_ptr; - IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr); + IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr, true); 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)); IrInstruction *cond_br_inst; @@ -6771,7 +6772,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * return err_val_ptr; IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); - IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr); + IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr, true); IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk"); IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse"); @@ -7381,7 +7382,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr); + IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr, true); IrInstruction *is_comptime; if (ir_should_inline(irb->exec, parent_scope)) { @@ -22512,6 +22513,19 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct } } + if (instruction->resolve_err_set) { + ZigType *err_set_type = type_entry->data.error_union.err_set_type; + if (!resolve_inferred_error_set(ira->codegen, err_set_type, instruction->base.source_node)) { + return ira->codegen->invalid_instruction; + } + if (!type_is_global_error_set(err_set_type) && + err_set_type->data.error_set.err_count == 0) + { + assert(err_set_type->data.error_set.infer_fn == nullptr); + return ir_const_bool(ira, &instruction->base, false); + } + } + return ir_build_test_err_gen(ira, &instruction->base, value); } else if (type_entry->id == ZigTypeIdErrorSet) { return ir_const_bool(ira, &instruction->base, true); diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig index 1f8f8b36e4..861c500751 100644 --- a/test/stage1/behavior/error.zig +++ b/test/stage1/behavior/error.zig @@ -130,10 +130,10 @@ fn testExplicitErrorSetCast(set1: Set1) void { expect(y == error.A); } -//test "comptime test error for empty error set" { -// testComptimeTestErrorEmptySet(1234); -// comptime testComptimeTestErrorEmptySet(1234); -//} +test "comptime test error for empty error set" { + testComptimeTestErrorEmptySet(1234); + comptime testComptimeTestErrorEmptySet(1234); +} const EmptyErrorSet = error{}; @@ -204,10 +204,10 @@ fn foo2(f: fn () anyerror!void) void { fn bar2() (error{}!void) {} -//test "error: Zero sized error set returned with value payload crash" { -// _ = foo3(0) catch {}; -// _ = comptime foo3(0) catch {}; -//} +test "error: Zero sized error set returned with value payload crash" { + _ = foo3(0) catch {}; + _ = comptime foo3(0) catch {}; +} const Error = error{}; fn foo3(b: usize) Error!usize { -- cgit v1.2.3 From 4ffab5b85f03f63a7e724698482f8497cacc7212 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Jun 2019 18:47:02 -0400 Subject: fix optional pointer to size zero struct --- src/codegen.cpp | 15 ++++++++++++--- src/ir.cpp | 15 ++++++++++----- test/stage1/behavior.zig | 4 ++-- test/stage1/behavior/optional.zig | 10 +++++----- test/stage1/behavior/ptrcast.zig | 14 +++++++------- 5 files changed, 36 insertions(+), 22 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 05bdf92555..b55b8a1094 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4983,7 +4983,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu } } -static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionOptionalWrap *instruction) { +static LLVMValueRef ir_render_optional_wrap(CodeGen *g, IrExecutable *executable, IrInstructionOptionalWrap *instruction) { ZigType *wanted_type = instruction->base.value.type; assert(wanted_type->id == ZigTypeIdOptional); @@ -4991,11 +4991,20 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I ZigType *child_type = wanted_type->data.maybe.child_type; if (!type_has_bits(child_type)) { - return LLVMConstInt(LLVMInt1Type(), 1, false); + LLVMValueRef result = LLVMConstAllOnes(LLVMInt1Type()); + if (instruction->result_loc != nullptr) { + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); + gen_store_untyped(g, result, result_loc, 0, false); + } + return result; } LLVMValueRef payload_val = ir_llvm_value(g, instruction->operand); if (!handle_is_ptr(wanted_type)) { + if (instruction->result_loc != nullptr) { + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); + gen_store_untyped(g, payload_val, result_loc, 0, false); + } return payload_val; } @@ -5666,7 +5675,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdUnwrapErrPayload: return ir_render_unwrap_err_payload(g, executable, (IrInstructionUnwrapErrPayload *)instruction); case IrInstructionIdOptionalWrap: - return ir_render_maybe_wrap(g, executable, (IrInstructionOptionalWrap *)instruction); + return ir_render_optional_wrap(g, executable, (IrInstructionOptionalWrap *)instruction); case IrInstructionIdErrWrapCode: return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction); case IrInstructionIdErrWrapPayload: diff --git a/src/ir.cpp b/src/ir.cpp index 356a1a8cc8..0a920c0974 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1826,7 +1826,7 @@ static IrInstruction *ir_build_optional_wrap(IrAnalyze *ira, IrInstruction *sour instruction->result_loc = result_loc; ir_ref_instruction(operand, ira->new_irb.current_basic_block); - ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -11277,10 +11277,15 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so return &const_instruction->base; } - if (result_loc == nullptr) result_loc = no_result_loc(); - IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); - if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { - return result_loc_inst; + if (result_loc == nullptr && handle_is_ptr(wanted_type)) { + result_loc = no_result_loc(); + } + IrInstruction *result_loc_inst = nullptr; + if (result_loc != nullptr) { + result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } } IrInstruction *result = ir_build_optional_wrap(ira, source_instr, wanted_type, value, result_loc_inst); result->value.data.rh_maybe = RuntimeHintOptionalNonNull; diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 5824f9380f..0387f3c045 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -66,10 +66,10 @@ comptime { _ = @import("behavior/namespace_depends_on_compile_var.zig"); _ = @import("behavior/new_stack_call.zig"); _ = @import("behavior/null.zig"); - _ = @import("behavior/optional.zig"); // TODO + _ = @import("behavior/optional.zig"); _ = @import("behavior/pointers.zig"); _ = @import("behavior/popcount.zig"); - _ = @import("behavior/ptrcast.zig"); // TODO + _ = @import("behavior/ptrcast.zig"); _ = @import("behavior/pub_enum.zig"); _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); _ = @import("behavior/reflection.zig"); diff --git a/test/stage1/behavior/optional.zig b/test/stage1/behavior/optional.zig index 09260c4778..b33e250383 100644 --- a/test/stage1/behavior/optional.zig +++ b/test/stage1/behavior/optional.zig @@ -2,11 +2,11 @@ const expect = @import("std").testing.expect; pub const EmptyStruct = struct {}; -//test "optional pointer to size zero struct" { -// var e = EmptyStruct{}; -// var o: ?*EmptyStruct = &e; -// expect(o != null); -//} +test "optional pointer to size zero struct" { + var e = EmptyStruct{}; + var o: ?*EmptyStruct = &e; + expect(o != null); +} test "equality compare nullable pointers" { testNullPtrsEql(); diff --git a/test/stage1/behavior/ptrcast.zig b/test/stage1/behavior/ptrcast.zig index 004ae4dd83..bf92888214 100644 --- a/test/stage1/behavior/ptrcast.zig +++ b/test/stage1/behavior/ptrcast.zig @@ -59,10 +59,10 @@ test "comptime ptrcast keeps larger alignment" { } } -//test "implicit optional pointer to optional c_void pointer" { -// var buf: [4]u8 = "aoeu"; -// var x: ?[*]u8 = &buf; -// var y: ?*c_void = x; -// var z = @ptrCast(*[4]u8, y); -// expect(std.mem.eql(u8, z, "aoeu")); -//} +test "implicit optional pointer to optional c_void pointer" { + var buf: [4]u8 = "aoeu"; + var x: ?[*]u8 = &buf; + var y: ?*c_void = x; + var z = @ptrCast(*[4]u8, y); + expect(std.mem.eql(u8, z, "aoeu")); +} -- cgit v1.2.3 From 78eeb6e9aea9c280513faaa83f9df959b7ac6f59 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Jun 2019 22:29:39 -0400 Subject: fix double getelementptr of runtime global --- src/codegen.cpp | 3 + src/ir.cpp | 186 +++++++++++++++------------------------- test/stage1/behavior/struct.zig | 12 +-- 3 files changed, 76 insertions(+), 125 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 6830007f32..5cb65b38f3 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3832,6 +3832,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStructFieldPtr *instruction) { + if (instruction->base.value.special != ConstValSpecialRuntime) + return nullptr; + LLVMValueRef struct_ptr = ir_llvm_value(g, instruction->struct_ptr); // not necessarily a pointer. could be ZigTypeIdStruct ZigType *struct_ptr_type = instruction->struct_ptr->value.type; diff --git a/src/ir.cpp b/src/ir.cpp index b2ff8f5896..9ac83443ab 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -187,9 +187,9 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *dest_type); static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type, IrInstruction *value); + ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool non_null_comptime); static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime); + ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime, bool non_null_comptime); static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *base_ptr, bool safety_check_on, bool initializing); static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr, @@ -10844,7 +10844,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc } if (result_loc == nullptr) result_loc = no_result_loc(); - IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -11282,7 +11282,7 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so } IrInstruction *result_loc_inst = nullptr; if (result_loc != nullptr) { - result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); + result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -11325,7 +11325,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction IrInstruction *result_loc_inst; if (handle_is_ptr(wanted_type)) { if (result_loc == nullptr) result_loc = no_result_loc(); - result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); + result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -11410,7 +11410,7 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so IrInstruction *result_loc_inst; if (handle_is_ptr(wanted_type)) { if (result_loc == nullptr) result_loc = no_result_loc(); - result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); + result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -11483,7 +11483,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi IrInstruction *result_loc; if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) { - result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true); + result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true, false); } else { result_loc = nullptr; } @@ -11527,7 +11527,7 @@ 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); if (result_loc == nullptr) result_loc = no_result_loc(); - IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -12180,7 +12180,7 @@ static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction * result->value.type = array_type; return result; } - IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, array_type, nullptr, true); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, array_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -12761,7 +12761,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc IrInstruction *result_loc_inst; if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) { if (result_loc == nullptr) result_loc = no_result_loc(); - result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr, true); + result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -14910,7 +14910,7 @@ static void set_up_result_loc_for_inferred_comptime(IrInstruction *ptr) { // when calling this function, at the callsite must check for result type noreturn and propagate it up static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type, IrInstruction *value) + ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool non_null_comptime) { Error err; if (result_loc->resolved_loc != nullptr) { @@ -14984,9 +14984,11 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe return result_loc->resolved_loc; } case ResultLocIdReturn: { - bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime; - if (is_comptime) - return nullptr; + if (!non_null_comptime) { + bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime; + if (is_comptime) + return nullptr; + } if (!type_has_bits(ira->explicit_return_type) || !handle_is_ptr(ira->explicit_return_type)) return nullptr; @@ -15005,6 +15007,10 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe return ira->codegen->invalid_instruction; peer_parent->skipped = is_comptime; if (peer_parent->skipped) { + if (non_null_comptime) { + return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, + value_type, value, false, non_null_comptime); + } return nullptr; } @@ -15016,7 +15022,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe } IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, - peer_parent->resolved_type, nullptr, false); + peer_parent->resolved_type, nullptr, false, non_null_comptime); if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || parent_result_loc->value.type->id == ZigTypeIdUnreachable) { @@ -15066,7 +15072,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe } IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_bit_cast->parent, - dest_type, bitcasted_value, false); + dest_type, bitcasted_value, false, non_null_comptime); if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || parent_result_loc->value.type->id == ZigTypeIdUnreachable) { @@ -15094,10 +15100,11 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe } static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr, - ResultLoc *result_loc_pass1, ZigType *value_type, IrInstruction *value, bool force_runtime) + ResultLoc *result_loc_pass1, ZigType *value_type, IrInstruction *value, bool force_runtime, + bool non_null_comptime) { IrInstruction *result_loc = ir_resolve_result_raw(ira, suspend_source_instr, result_loc_pass1, value_type, - value); + value, non_null_comptime); if (result_loc == nullptr || (instr_is_unreachable(result_loc) || type_is_invalid(result_loc->value.type))) return result_loc; @@ -15144,23 +15151,16 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn ZigType *implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); if (type_is_invalid(implicit_elem_type)) return ira->codegen->invalid_instruction; - ResultLoc *old_result_loc = instruction->result_loc; - for (;;) { - IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, old_result_loc, - implicit_elem_type, nullptr, false); - if (result_loc != nullptr) - return result_loc; + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + implicit_elem_type, nullptr, false, true); + if (result_loc != nullptr) + return result_loc; - if (instruction->result_loc->id == ResultLocIdPeer) { - old_result_loc = reinterpret_cast(instruction->result_loc)->parent->parent; - continue; - } - IrInstruction *result = ir_const(ira, &instruction->base, implicit_elem_type); - result->value.special = ConstValSpecialUndef; - IrInstruction *ptr = ir_get_ref(ira, &instruction->base, result, false, false); - ptr->value.data.x_ptr.mut = ConstPtrMutComptimeVar; - return ptr; - } + IrInstruction *result = ir_const(ira, &instruction->base, implicit_elem_type); + result->value.special = ConstValSpecialUndef; + IrInstruction *ptr = ir_get_ref(ira, &instruction->base, result, false, false); + ptr->value.data.x_ptr.mut = ConstPtrMutComptimeVar; + return ptr; } static void ir_reset_result(ResultLoc *result_loc) { @@ -15500,7 +15500,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source // * "string literal used as comptime slice is memoized" // * "comptime modification of const struct field" - except modified to avoid // ConstPtrMutComptimeVar, thus defeating the logic below. - bool same_global_refs = ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst; + bool same_global_refs = ptr->value.data.x_ptr.mut != ConstPtrMutComptimeVar; copy_const_val(dest_val, &value->value, same_global_refs); if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr; @@ -15986,7 +15986,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c IrInstruction *result_loc; if (handle_is_ptr(impl_fn_type_id->return_type)) { result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, - impl_fn_type_id->return_type, nullptr, true); + impl_fn_type_id->return_type, nullptr, true, false); if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { return result_loc; } @@ -16106,7 +16106,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c IrInstruction *result_loc; if (handle_is_ptr(return_type)) { result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, - return_type, nullptr, true); + return_type, nullptr, true, false); if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { return result_loc; } @@ -16198,7 +16198,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source if (dst_size <= src_size) { if (src_size == dst_size && types_have_same_zig_comptime_repr(pointee->type, out_val->type)) { - copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut == ConstPtrMutComptimeConst); + copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut != ConstPtrMutComptimeVar); return ErrorNone; } Buf buf = BUF_INIT; @@ -16600,7 +16600,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh // In case resolving the parent activates a suspend, do it now IrInstruction *parent_result_loc = ir_resolve_result(ira, &phi_instruction->base, peer_parent->parent, - peer_parent->resolved_type, nullptr, false); + peer_parent->resolved_type, nullptr, false, false); if (parent_result_loc != nullptr && (type_is_invalid(parent_result_loc->value.type) || instr_is_unreachable(parent_result_loc))) { @@ -17246,11 +17246,10 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction field_val->special = ConstValSpecialUndef; field_val->type = struct_type->data.structure.fields[i].type_entry; ConstParent *parent = get_const_val_parent(ira->codegen, field_val); - if (parent != nullptr) { - parent->id = ConstParentIdStruct; - parent->data.p_struct.struct_val = struct_val; - parent->data.p_struct.field_index = i; - } + assert(parent != nullptr); + parent->id = ConstParentIdStruct; + parent->data.p_struct.struct_val = struct_val; + parent->data.p_struct.field_index = i; } } IrInstruction *result; @@ -17264,7 +17263,7 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction } ConstExprValue *const_val = &result->value; const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct; - const_val->data.x_ptr.mut = struct_ptr->value.data.x_ptr.mut; + const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut; const_val->data.x_ptr.data.base_struct.struct_val = struct_val; const_val->data.x_ptr.data.base_struct.field_index = field->src_index; return result; @@ -17414,6 +17413,11 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, link_lib->symbols.append(symbol_name); } +static IrInstruction *ir_error_dependency_loop(IrAnalyze *ira, IrInstruction *source_instr) { + ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected")); + emit_error_notes_for_ref_stack(ira->codegen, msg); + return ira->codegen->invalid_instruction; +} static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) { resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node); @@ -17428,6 +17432,9 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_ { TldVar *tld_var = (TldVar *)tld; ZigVar *var = tld_var->var; + if (var == nullptr) { + return ir_error_dependency_loop(ira, source_instruction); + } if (tld_var->extern_lib_name != nullptr) { add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, source_instruction->source_node); } @@ -17443,23 +17450,13 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_ if (type_is_invalid(fn_entry->type_entry)) return ira->codegen->invalid_instruction; - // TODO instead of allocating this every time, put it in the tld value and we can reference - // the same one every time - ConstExprValue *const_val = create_const_vals(1); - const_val->special = ConstValSpecialStatic; - const_val->type = fn_entry->type_entry; - const_val->data.x_ptr.data.fn.fn_entry = fn_entry; - const_val->data.x_ptr.special = ConstPtrSpecialFunction; - const_val->data.x_ptr.mut = ConstPtrMutComptimeConst; - if (tld_fn->extern_lib_name != nullptr) { add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, source_instruction->source_node); } - bool ptr_is_const = true; - bool ptr_is_volatile = false; - return ir_get_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry, - ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); + IrInstruction *fn_inst = ir_create_const_fn(&ira->new_irb, source_instruction->scope, + source_instruction->source_node, fn_entry); + return ir_get_ref(ira, source_instruction, fn_inst, true, false); } } zig_unreachable(); @@ -19673,12 +19670,6 @@ static IrInstruction *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira, return ir_const_unsigned(ira, &instruction->base, bit_offset); } -static IrInstruction *ir_error_dependency_loop(IrAnalyze *ira, IrInstruction *source_instr) { - ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected")); - emit_error_notes_for_ref_stack(ira->codegen, msg); - return ira->codegen->invalid_instruction; -} - static void ensure_field_index(ZigType *type, const char *field_name, size_t index) { Buf *field_name_buf; @@ -21088,7 +21079,7 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi IrInstruction *result_loc; if (handle_is_ptr(result_type)) { result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - result_type, nullptr, true); + result_type, nullptr, true, false); if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { return result_loc; } @@ -21345,7 +21336,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru } IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - dest_slice_type, nullptr, true); + dest_slice_type, nullptr, true, false); if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { return result_loc; } @@ -21422,7 +21413,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct } IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - dest_slice_type, nullptr, true); + dest_slice_type, nullptr, true, false); if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { return result_loc; } @@ -22164,7 +22155,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction } IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - return_type, nullptr, true); + return_type, nullptr, true, false); if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { return result_loc; } @@ -23729,58 +23720,15 @@ static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstru static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, IrInstructionDeclRef *instruction) { - Tld *tld = instruction->tld; - LVal lval = instruction->lval; - - resolve_top_level_decl(ira->codegen, tld, instruction->base.source_node); - if (tld->resolution == TldResolutionInvalid) + IrInstruction *ref_instruction = ir_analyze_decl_ref(ira, &instruction->base, instruction->tld); + if (type_is_invalid(ref_instruction->value.type)) return ira->codegen->invalid_instruction; - switch (tld->id) { - case TldIdContainer: - case TldIdCompTime: - zig_unreachable(); - case TldIdVar: { - TldVar *tld_var = (TldVar *)tld; - ZigVar *var = tld_var->var; - - if (var == nullptr) { - return ir_error_dependency_loop(ira, &instruction->base); - } - - IrInstruction *var_ptr = ir_get_var_ptr(ira, &instruction->base, var); - if (type_is_invalid(var_ptr->value.type)) - return ira->codegen->invalid_instruction; - - if (tld_var->extern_lib_name != nullptr) { - add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, instruction->base.source_node); - } - - if (lval == LValPtr) { - return var_ptr; - } else { - return ir_get_deref(ira, &instruction->base, var_ptr, nullptr); - } - } - case TldIdFn: { - TldFn *tld_fn = (TldFn *)tld; - ZigFn *fn_entry = tld_fn->fn_entry; - ir_assert(fn_entry->type_entry, &instruction->base); - - if (tld_fn->extern_lib_name != nullptr) { - add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, instruction->base.source_node); - } - - IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope, - instruction->base.source_node, fn_entry); - if (lval == LValPtr) { - return ir_get_ref(ira, &instruction->base, ref_instruction, true, false); - } else { - return ref_instruction; - } - } + if (instruction->lval == LValPtr) { + return ref_instruction; + } else { + return ir_get_deref(ira, &instruction->base, ref_instruction, nullptr); } - zig_unreachable(); } static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstructionPtrToInt *instruction) { @@ -24655,7 +24603,7 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct bool was_written = instruction->result_loc->written; IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - value->value.type, value, false); + value->value.type, value, false, false); if (result_loc != nullptr) { if (type_is_invalid(result_loc->value.type)) return ira->codegen->invalid_instruction; @@ -24684,7 +24632,7 @@ static IrInstruction *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, IrInst return operand; IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, - &instruction->result_loc_bit_cast->base, operand->value.type, operand, false); + &instruction->result_loc_bit_cast->base, operand->value.type, operand, false, false); if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) return result_loc; diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index a08dec5359..ccdff3503e 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -522,12 +522,12 @@ const S0 = struct { } }; -//var g_foo: S0 = S0.init(); -// -//test "access to global struct fields" { -// g_foo.bar.value = 42; -// expect(g_foo.bar.value == 42); -//} +var g_foo: S0 = S0.init(); + +test "access to global struct fields" { + g_foo.bar.value = 42; + expect(g_foo.bar.value == 42); +} //test "packed struct with fp fields" { // const S = packed struct { -- cgit v1.2.3 From 237233b04bdbbb82a5ce881a074fdd4ca55fe58f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Jun 2019 18:15:27 -0400 Subject: fix coroutines --- src/codegen.cpp | 2 +- src/ir.cpp | 8 +++++++- test/stage1/behavior.zig | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 5cb65b38f3..79c92964f6 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3755,7 +3755,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr 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; ZigList gen_param_values = {}; - LLVMValueRef result_loc = first_arg_ret ? ir_llvm_value(g, instruction->result_loc) : nullptr; + LLVMValueRef result_loc = (first_arg_ret || instruction->is_async) ? ir_llvm_value(g, instruction->result_loc) : nullptr; if (first_arg_ret) { gen_param_values.append(result_loc); } diff --git a/src/ir.cpp b/src/ir.cpp index 4dbc20cf48..c3ed14770f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15252,8 +15252,14 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc 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); + IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, no_result_loc(), + async_return_type, nullptr, true, true); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + return ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, - casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, nullptr, + casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, result_loc, async_return_type); } diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 8fcd9b86b8..f477bb64ed 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -39,11 +39,11 @@ comptime { _ = @import("behavior/bugs/828.zig"); _ = @import("behavior/bugs/920.zig"); _ = @import("behavior/byval_arg_var.zig"); - //_ = @import("behavior/cancel.zig"); + _ = @import("behavior/cancel.zig"); _ = @import("behavior/cast.zig"); _ = @import("behavior/const_slice_child.zig"); - //_ = @import("behavior/coroutine_await_struct.zig"); - //_ = @import("behavior/coroutines.zig"); + _ = @import("behavior/coroutine_await_struct.zig"); + _ = @import("behavior/coroutines.zig"); _ = @import("behavior/defer.zig"); _ = @import("behavior/enum.zig"); _ = @import("behavior/enum_with_members.zig"); -- cgit v1.2.3 From 142e77abbb8a88c2c6473921d0c600faf3d34a62 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 21 Jun 2019 14:44:49 -0400 Subject: fix extern functions returning byval structs --- src/codegen.cpp | 48 +++++++++++++++++++++++++---------------- test/stage1/behavior/struct.zig | 21 ++++++++++++++++++ 2 files changed, 50 insertions(+), 19 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 79c92964f6..5b7169f312 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2394,24 +2394,31 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut } static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { - if (return_instruction->value == nullptr) { - LLVMBuildRetVoid(g->builder); - return nullptr; - } - - ZigType *return_type = return_instruction->value->value.type; - if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) { + if (return_instruction->value == nullptr) { + LLVMBuildRetVoid(g->builder); + return nullptr; + } assert(g->cur_ret_ptr); src_assert(return_instruction->value->value.special != ConstValSpecialRuntime, return_instruction->base.source_node); LLVMValueRef value = ir_llvm_value(g, return_instruction->value); + ZigType *return_type = return_instruction->value->value.type; gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); LLVMBuildRetVoid(g->builder); - } else if (handle_is_ptr(return_type)) { - LLVMValueRef value = ir_llvm_value(g, return_instruction->value); - LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, ""); - LLVMBuildRet(g->builder, by_val_value); + } else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync && + handle_is_ptr(g->cur_fn->type_entry->data.fn.fn_type_id.return_type)) + { + if (return_instruction->value == nullptr) { + LLVMValueRef by_val_value = gen_load_untyped(g, g->cur_ret_ptr, 0, false, ""); + LLVMBuildRet(g->builder, by_val_value); + } else { + LLVMValueRef value = ir_llvm_value(g, return_instruction->value); + LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, ""); + LLVMBuildRet(g->builder, by_val_value); + } + } else if (return_instruction->value == nullptr) { + LLVMBuildRetVoid(g->builder); } else { LLVMValueRef value = ir_llvm_value(g, return_instruction->value); LLVMBuildRet(g->builder, value); @@ -3755,7 +3762,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr 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; ZigList gen_param_values = {}; - LLVMValueRef result_loc = (first_arg_ret || instruction->is_async) ? ir_llvm_value(g, instruction->result_loc) : nullptr; + LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr; if (first_arg_ret) { gen_param_values.append(result_loc); } @@ -6804,20 +6811,24 @@ static void do_code_gen(CodeGen *g) { FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; CallingConvention cc = fn_type_id->cc; bool is_c_abi = cc == CallingConventionC; + bool want_sret = want_first_arg_sret(g, fn_type_id); LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); g->cur_fn = fn_table_entry; g->cur_fn_val = fn; - ZigType *return_type = fn_type_id->return_type; - if (handle_is_ptr(return_type)) { + + build_all_basic_blocks(g, fn_table_entry); + clear_debug_source_node(g); + + if (want_sret) { g->cur_ret_ptr = LLVMGetParam(fn, 0); + } else if (handle_is_ptr(fn_type_id->return_type)) { + g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0); + // TODO add debug info variable for this } else { g->cur_ret_ptr = nullptr; } - build_all_basic_blocks(g, fn_table_entry); - clear_debug_source_node(g); - uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX; if (have_err_ret_trace_arg) { @@ -6863,8 +6874,7 @@ static void do_code_gen(CodeGen *g) { } ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base); - - unsigned gen_i_init = want_first_arg_sret(g, fn_type_id) ? 1 : 0; + unsigned gen_i_init = want_sret ? 1 : 0; // create debug variable declarations for variables and allocate all local variables FnWalk fn_walk_var = {}; diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 0ebd0654d0..b86b171daf 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -578,3 +578,24 @@ test "default struct initialization fields" { }; expectEqual(1239, x.a + x.b); } + +test "extern fn returns struct by value" { + const S = struct { + fn entry() void { + var x = makeBar(10); + expectEqual(i32(10), x.handle); + } + + const ExternBar = extern struct { + handle: i32, + }; + + extern fn makeBar(t: i32) ExternBar { + return ExternBar{ + .handle = t, + }; + } + }; + S.entry(); + comptime S.entry(); +} -- cgit v1.2.3 From 71e014caecaa54fdd8a0516710d2d9597da41398 Mon Sep 17 00:00:00 2001 From: Shawn Landden Date: Fri, 21 Jun 2019 16:18:59 -0500 Subject: stage1: add @sin @cos @exp @exp2 @ln @log2 @log10 @fabs @floor @ceil @trunc @round and expand @sqrt This revealed that the accuracy of ln is not as good as the current algorithm in musl and glibc, and should be ported again. v2: actually include tests v3: fix reversal of in and out arguments on f128M_sqrt() add test for @sqrt on comptime_float do not include @nearbyInt() until it works on all targets. --- doc/langref.html.in | 85 +++++++++- src/all_types.hpp | 26 ++- src/analyze.cpp | 15 +- src/codegen.cpp | 68 ++++---- src/ir.cpp | 355 ++++++++++++++++++++++++++++++++------- src/ir.hpp | 1 + src/ir_print.cpp | 11 +- src/util.cpp | 1 + std/special/c.zig | 44 +++-- test/stage1/behavior.zig | 1 + test/stage1/behavior/floatop.zig | 243 +++++++++++++++++++++++++++ 11 files changed, 719 insertions(+), 131 deletions(-) create mode 100644 test/stage1/behavior/floatop.zig (limited to 'src/codegen.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index 9b95946256..30fe9a3648 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -7354,10 +7354,91 @@ test "@setRuntimeSafety" {
{#syntax#}@sqrt(comptime T: type, value: T) T{#endsyntax#}

Performs the square root of a floating point number. Uses a dedicated hardware instruction - when available. Currently only supports f32 and f64 at runtime. f128 at runtime is TODO. + when available. Supports f16, f32, f64, and f128, as well as vectors.

+ {#header_close#} + {#header_open|@sin#} +
{#syntax#}@sin(comptime T: type, value: T) T{#endsyntax#}
+

+ Sine trigometric function on a floating point number. Uses a dedicated hardware instruction + when available. Currently supports f32 and f64. +

+ {#header_close#} + {#header_open|@cos#} +
{#syntax#}@cos(comptime T: type, value: T) T{#endsyntax#}
+

+ Cosine trigometric function on a floating point number. Uses a dedicated hardware instruction + when available. Currently supports f32 and f64. +

+ {#header_close#} + {#header_open|@exp#} +
{#syntax#}@exp(comptime T: type, value: T) T{#endsyntax#}
+

+ Base-e exponential function on a floating point number. Uses a dedicated hardware instruction + when available. Currently supports f32 and f64. +

+ {#header_close#} + {#header_open|@exp2#} +
{#syntax#}@exp2(comptime T: type, value: T) T{#endsyntax#}
+

+ Base-2 exponential function on a floating point number. Uses a dedicated hardware instruction + when available. Currently supports f32 and f64. +

+ {#header_close#} + {#header_open|@ln#} +
{#syntax#}@ln(comptime T: type, value: T) T{#endsyntax#}
+

+ Returns the natural logarithm of a floating point number. Uses a dedicated hardware instruction + when available. Currently supports f32 and f64. +

+ {#header_close#} + {#header_open|@log2#} +
{#syntax#}@log2(comptime T: type, value: T) T{#endsyntax#}
+

+ Returns the logarithm to the base 2 of a floating point number. Uses a dedicated hardware instruction + when available. Currently supports f32 and f64. +

+ {#header_close#} + {#header_open|@log10#} +
{#syntax#}@log10(comptime T: type, value: T) T{#endsyntax#}
+

+ Returns the logarithm to the base 10 of a floating point number. Uses a dedicated hardware instruction + when available. Currently supports f32 and f64. +

+ {#header_close#} + {#header_open|@fabs#} +
{#syntax#}@fabs(comptime T: type, value: T) T{#endsyntax#}
+

+ Returns the absolute value of a floating point number. Uses a dedicated hardware instruction + when available. Currently supports f32 and f64. +

+ {#header_close#} + {#header_open|@floor#} +
{#syntax#}@floor(comptime T: type, value: T) T{#endsyntax#}
+

+ Returns the largest integral value not greater than the given floating point number. Uses a dedicated hardware instruction + when available. Currently supports f32 and f64. +

+ {#header_close#} + {#header_open|@ceil#} +
{#syntax#}@ceil(comptime T: type, value: T) T{#endsyntax#}
+

+ Returns the largest integral value not less than the given floating point number. Uses a dedicated hardware instruction + when available. Currently supports f32 and f64. +

+ {#header_close#} + {#header_open|@trunc#} +
{#syntax#}@trunc(comptime T: type, value: T) T{#endsyntax#}
+

+ Rounds the given floating point number to an integer, towards zero. Uses a dedicated hardware instruction + when available. Currently supports f32 and f64. +

+ {#header_close#} + {#header_open|@round#} +
{#syntax#}@round(comptime T: type, value: T) T{#endsyntax#}

- This is a low-level intrinsic. Most code can use {#syntax#}std.math.sqrt{#endsyntax#} instead. + Rounds the given floating point number to an integer, away from zero. Uses a dedicated hardware instruction + when available. Currently supports f32 and f64.

{#header_close#} diff --git a/src/all_types.hpp b/src/all_types.hpp index 83df71b95f..6595218bcf 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1434,6 +1434,19 @@ enum BuiltinFnId { BuiltinFnIdRem, BuiltinFnIdMod, BuiltinFnIdSqrt, + BuiltinFnIdSin, + BuiltinFnIdCos, + BuiltinFnIdExp, + BuiltinFnIdExp2, + BuiltinFnIdLn, + BuiltinFnIdLog2, + BuiltinFnIdLog10, + BuiltinFnIdFabs, + BuiltinFnIdFloor, + BuiltinFnIdCeil, + BuiltinFnIdTrunc, + BuiltinFnIdNearbyInt, + BuiltinFnIdRound, BuiltinFnIdTruncate, BuiltinFnIdIntCast, BuiltinFnIdFloatCast, @@ -1556,9 +1569,7 @@ enum ZigLLVMFnId { ZigLLVMFnIdPopCount, ZigLLVMFnIdOverflowArithmetic, ZigLLVMFnIdFMA, - ZigLLVMFnIdFloor, - ZigLLVMFnIdCeil, - ZigLLVMFnIdSqrt, + ZigLLVMFnIdFloatOp, ZigLLVMFnIdBswap, ZigLLVMFnIdBitReverse, }; @@ -1585,6 +1596,7 @@ struct ZigLLVMFnKey { uint32_t bit_count; } pop_count; struct { + BuiltinFnId op; uint32_t bit_count; uint32_t vector_len; // 0 means not a vector } floating; @@ -2239,6 +2251,7 @@ enum IrInstructionId { IrInstructionIdAlignOf, IrInstructionIdOverflowOp, IrInstructionIdMulAdd, + IrInstructionIdFloatOp, IrInstructionIdTestErr, IrInstructionIdUnwrapErrCode, IrInstructionIdUnwrapErrPayload, @@ -2300,7 +2313,6 @@ enum IrInstructionId { IrInstructionIdAddImplicitReturnType, IrInstructionIdMergeErrRetTraces, IrInstructionIdMarkErrRetTracePtr, - IrInstructionIdSqrt, IrInstructionIdErrSetCast, IrInstructionIdToBytes, IrInstructionIdFromBytes, @@ -3474,11 +3486,13 @@ struct IrInstructionMarkErrRetTracePtr { IrInstruction *err_ret_trace_ptr; }; -struct IrInstructionSqrt { +// For float ops which take a single argument +struct IrInstructionFloatOp { IrInstruction base; + BuiltinFnId op; IrInstruction *type; - IrInstruction *op; + IrInstruction *op1; }; struct IrInstructionCheckRuntimeScope { diff --git a/src/analyze.cpp b/src/analyze.cpp index 15b42c7f9d..13b35e0aff 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5736,9 +5736,10 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { return (uint32_t)(x.data.clz.bit_count) * (uint32_t)2428952817; case ZigLLVMFnIdPopCount: return (uint32_t)(x.data.clz.bit_count) * (uint32_t)101195049; - case ZigLLVMFnIdFloor: - case ZigLLVMFnIdCeil: - case ZigLLVMFnIdSqrt: + case ZigLLVMFnIdFloatOp: + return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + + (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025) + + (uint32_t)(x.data.floating.op) * (uint32_t)43789879; case ZigLLVMFnIdFMA: return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025); @@ -5769,10 +5770,10 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { return a.data.bswap.bit_count == b.data.bswap.bit_count; case ZigLLVMFnIdBitReverse: return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; - case ZigLLVMFnIdFloor: - case ZigLLVMFnIdCeil: - case ZigLLVMFnIdSqrt: - return a.data.floating.bit_count == b.data.floating.bit_count; + case ZigLLVMFnIdFloatOp: + return a.data.floating.bit_count == b.data.floating.bit_count && + a.data.floating.vector_len == b.data.floating.vector_len && + a.data.floating.op == b.data.floating.op; case ZigLLVMFnIdFMA: return a.data.floating.bit_count == b.data.floating.bit_count && a.data.floating.vector_len == b.data.floating.vector_len; diff --git a/src/codegen.cpp b/src/codegen.cpp index 6691652a5e..41caa29dbd 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -806,7 +806,7 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *operand_type, AddSu return fn_val; } -static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn_id) { +static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn_id, BuiltinFnId op) { assert(type_entry->id == ZigTypeIdFloat || type_entry->id == ZigTypeIdVector); @@ -817,6 +817,7 @@ static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn key.id = fn_id; key.data.floating.bit_count = (uint32_t)float_type->data.floating.bit_count; key.data.floating.vector_len = is_vector ? (uint32_t)type_entry->data.vector.len : 0; + key.data.floating.op = op; auto existing_entry = g->llvm_fn_table.maybe_get(key); if (existing_entry) @@ -824,18 +825,12 @@ static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn const char *name; uint32_t num_args; - if (fn_id == ZigLLVMFnIdFloor) { - name = "floor"; - num_args = 1; - } else if (fn_id == ZigLLVMFnIdCeil) { - name = "ceil"; - num_args = 1; - } else if (fn_id == ZigLLVMFnIdSqrt) { - name = "sqrt"; - num_args = 1; - } else if (fn_id == ZigLLVMFnIdFMA) { + if (fn_id == ZigLLVMFnIdFMA) { name = "fma"; num_args = 3; + } else if (fn_id == ZigLLVMFnIdFloatOp) { + name = float_op_to_name(op, true); + num_args = 1; } else { zig_unreachable(); } @@ -2480,22 +2475,17 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry, return result; } -static LLVMValueRef gen_floor(CodeGen *g, LLVMValueRef val, ZigType *type_entry) { - if (type_entry->id == ZigTypeIdInt) +static LLVMValueRef gen_float_op(CodeGen *g, LLVMValueRef val, ZigType *type_entry, BuiltinFnId op) { + if ((op == BuiltinFnIdCeil || + op == BuiltinFnIdFloor) && + type_entry->id == ZigTypeIdInt) return val; + assert(type_entry->id == ZigTypeIdFloat); - LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloor); + LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloatOp, op); return LLVMBuildCall(g->builder, floor_fn, &val, 1, ""); } -static LLVMValueRef gen_ceil(CodeGen *g, LLVMValueRef val, ZigType *type_entry) { - if (type_entry->id == ZigTypeIdInt) - return val; - - LLVMValueRef ceil_fn = get_float_fn(g, type_entry, ZigLLVMFnIdCeil); - return LLVMBuildCall(g->builder, ceil_fn, &val, 1, ""); -} - enum DivKind { DivKindFloat, DivKindTrunc, @@ -2571,7 +2561,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast return result; case DivKindExact: if (want_runtime_safety) { - LLVMValueRef floored = gen_floor(g, result, type_entry); + LLVMValueRef floored = gen_float_op(g, result, type_entry, BuiltinFnIdFloor); LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, ""); @@ -2593,12 +2583,12 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block); LLVMPositionBuilderAtEnd(g->builder, ltz_block); - LLVMValueRef ceiled = gen_ceil(g, result, type_entry); + LLVMValueRef ceiled = gen_float_op(g, result, type_entry, BuiltinFnIdCeil); LLVMBasicBlockRef ceiled_end_block = LLVMGetInsertBlock(g->builder); LLVMBuildBr(g->builder, end_block); LLVMPositionBuilderAtEnd(g->builder, gez_block); - LLVMValueRef floored = gen_floor(g, result, type_entry); + LLVMValueRef floored = gen_float_op(g, result, type_entry, BuiltinFnIdFloor); LLVMBasicBlockRef floored_end_block = LLVMGetInsertBlock(g->builder); LLVMBuildBr(g->builder, end_block); @@ -2610,7 +2600,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast return phi; } case DivKindFloor: - return gen_floor(g, result, type_entry); + return gen_float_op(g, result, type_entry, BuiltinFnIdFloor); } zig_unreachable(); } @@ -5450,10 +5440,10 @@ static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *e return nullptr; } -static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstructionSqrt *instruction) { - LLVMValueRef op = ir_llvm_value(g, instruction->op); +static LLVMValueRef ir_render_float_op(CodeGen *g, IrExecutable *executable, IrInstructionFloatOp *instruction) { + LLVMValueRef op = ir_llvm_value(g, instruction->op1); assert(instruction->base.value.type->id == ZigTypeIdFloat); - LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdSqrt); + LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdFloatOp, instruction->op); return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); } @@ -5463,7 +5453,7 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, IrExecutable *executable, IrIn LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); assert(instruction->base.value.type->id == ZigTypeIdFloat || instruction->base.value.type->id == ZigTypeIdVector); - LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdFMA); + LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdFMA, BuiltinFnIdMulAdd); LLVMValueRef args[3] = { op1, op2, @@ -5814,8 +5804,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction); case IrInstructionIdMarkErrRetTracePtr: return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction); - case IrInstructionIdSqrt: - return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction); + case IrInstructionIdFloatOp: + return ir_render_float_op(g, executable, (IrInstructionFloatOp *)instruction); case IrInstructionIdMulAdd: return ir_render_mul_add(g, executable, (IrInstructionMulAdd *)instruction); case IrInstructionIdArrayToVector: @@ -7435,6 +7425,20 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdRem, "rem", 2); create_builtin_fn(g, BuiltinFnIdMod, "mod", 2); create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2); + create_builtin_fn(g, BuiltinFnIdSin, "sin", 2); + create_builtin_fn(g, BuiltinFnIdCos, "cos", 2); + create_builtin_fn(g, BuiltinFnIdExp, "exp", 2); + create_builtin_fn(g, BuiltinFnIdExp2, "exp2", 2); + create_builtin_fn(g, BuiltinFnIdLn, "ln", 2); + create_builtin_fn(g, BuiltinFnIdLog2, "log2", 2); + create_builtin_fn(g, BuiltinFnIdLog10, "log10", 2); + create_builtin_fn(g, BuiltinFnIdFabs, "fabs", 2); + create_builtin_fn(g, BuiltinFnIdFloor, "floor", 2); + create_builtin_fn(g, BuiltinFnIdCeil, "ceil", 2); + create_builtin_fn(g, BuiltinFnIdTrunc, "trunc", 2); + //Needs library support on Windows + //create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2); + create_builtin_fn(g, BuiltinFnIdRound, "round", 2); create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4); create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX); create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX); diff --git a/src/ir.cpp b/src/ir.cpp index c2c6cb6154..50d2a06868 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -991,8 +991,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTraceP return IrInstructionIdMarkErrRetTracePtr; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) { - return IrInstructionIdSqrt; +static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) { + return IrInstructionIdFloatOp; } static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { @@ -2312,6 +2312,59 @@ static IrInstruction *ir_build_overflow_op(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } + +//TODO Powi, Pow, minnum, maxnum, maximum, minimum, copysign, +// lround, llround, lrint, llrint +// So far this is only non-complicated type functions. +const char *float_op_to_name(BuiltinFnId op, bool llvm_name) { + const bool b = llvm_name; + + switch (op) { + case BuiltinFnIdSqrt: + return "sqrt"; + case BuiltinFnIdSin: + return "sin"; + case BuiltinFnIdCos: + return "cos"; + case BuiltinFnIdExp: + return "exp"; + case BuiltinFnIdExp2: + return "exp2"; + case BuiltinFnIdLn: + return b ? "log" : "ln"; + case BuiltinFnIdLog10: + return "log10"; + case BuiltinFnIdLog2: + return "log2"; + case BuiltinFnIdFabs: + return "fabs"; + case BuiltinFnIdFloor: + return "floor"; + case BuiltinFnIdCeil: + return "ceil"; + case BuiltinFnIdTrunc: + return "trunc"; + case BuiltinFnIdNearbyInt: + return b ? "nearbyint" : "nearbyInt"; + case BuiltinFnIdRound: + return "round"; + default: + zig_unreachable(); + } +} + +static IrInstruction *ir_build_float_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op1, BuiltinFnId op) { + IrInstructionFloatOp *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op1 = op1; + instruction->op = op; + + if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op1, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_mul_add(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value, IrInstruction *op1, IrInstruction *op2, IrInstruction *op3) { IrInstructionMulAdd *instruction = ir_build_instruction(irb, scope, source_node); @@ -3033,17 +3086,6 @@ static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *sco return &instruction->base; } -static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) { - IrInstructionSqrt *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type = type; - instruction->op = op; - - if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); - ir_ref_instruction(op, irb->current_basic_block); - - return &instruction->base; -} - static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *container, IrInstruction *name) { @@ -4400,6 +4442,19 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_lval_wrap(irb, scope, bin_op, lval); } case BuiltinFnIdSqrt: + case BuiltinFnIdSin: + case BuiltinFnIdCos: + case BuiltinFnIdExp: + case BuiltinFnIdExp2: + case BuiltinFnIdLn: + case BuiltinFnIdLog2: + case BuiltinFnIdLog10: + case BuiltinFnIdFabs: + case BuiltinFnIdFloor: + case BuiltinFnIdCeil: + case BuiltinFnIdTrunc: + case BuiltinFnIdNearbyInt: + case BuiltinFnIdRound: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); @@ -4411,7 +4466,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *ir_sqrt = ir_build_sqrt(irb, scope, node, arg0_value, arg1_value); + IrInstruction *ir_sqrt = ir_build_float_op(irb, scope, node, arg0_value, arg1_value, builtin_fn->id); return ir_lval_wrap(irb, scope, ir_sqrt, lval); } case BuiltinFnIdTruncate: @@ -23214,70 +23269,248 @@ static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *i return result; } -static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) { - ZigType *float_type = ir_resolve_type(ira, instruction->type->child); - if (type_is_invalid(float_type)) - return ira->codegen->invalid_instruction; +static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr, ZigType *float_type, + ConstExprValue *op, ConstExprValue *out_val) { + assert(ira && source_instr && float_type && out_val && op); + assert(float_type->id == ZigTypeIdFloat || + float_type->id == ZigTypeIdComptimeFloat); - IrInstruction *op = instruction->op->child; - if (type_is_invalid(op->value.type)) + BuiltinFnId fop = source_instr->op; + unsigned bits; + + if (float_type->id == ZigTypeIdComptimeFloat) { + bits = 128; + } else if (float_type->id == ZigTypeIdFloat) + bits = float_type->data.floating.bit_count; + + switch (bits) { + case 16: { + switch (fop) { + case BuiltinFnIdSqrt: + out_val->data.x_f16 = f16_sqrt(op->data.x_f16); + break; + case BuiltinFnIdSin: + case BuiltinFnIdCos: + case BuiltinFnIdExp: + case BuiltinFnIdExp2: + case BuiltinFnIdLn: + case BuiltinFnIdLog10: + case BuiltinFnIdLog2: + case BuiltinFnIdFabs: + case BuiltinFnIdFloor: + case BuiltinFnIdCeil: + case BuiltinFnIdTrunc: + case BuiltinFnIdNearbyInt: + case BuiltinFnIdRound: + zig_panic("unimplemented f16 builtin"); + default: + zig_unreachable(); + }; + break; + }; + case 32: { + switch (fop) { + case BuiltinFnIdSqrt: + out_val->data.x_f32 = sqrtf(op->data.x_f32); + break; + case BuiltinFnIdSin: + out_val->data.x_f32 = sinf(op->data.x_f32); + break; + case BuiltinFnIdCos: + out_val->data.x_f32 = cosf(op->data.x_f32); + break; + case BuiltinFnIdExp: + out_val->data.x_f32 = expf(op->data.x_f32); + break; + case BuiltinFnIdExp2: + out_val->data.x_f32 = exp2f(op->data.x_f32); + break; + case BuiltinFnIdLn: + out_val->data.x_f32 = logf(op->data.x_f32); + break; + case BuiltinFnIdLog10: + out_val->data.x_f32 = log10f(op->data.x_f32); + break; + case BuiltinFnIdLog2: + out_val->data.x_f32 = log2f(op->data.x_f32); + break; + case BuiltinFnIdFabs: + out_val->data.x_f32 = fabsf(op->data.x_f32); + break; + case BuiltinFnIdFloor: + out_val->data.x_f32 = floorf(op->data.x_f32); + break; + case BuiltinFnIdCeil: + out_val->data.x_f32 = ceilf(op->data.x_f32); + break; + case BuiltinFnIdTrunc: + out_val->data.x_f32 = truncf(op->data.x_f32); + break; + case BuiltinFnIdNearbyInt: + out_val->data.x_f32 = nearbyintf(op->data.x_f32); + break; + case BuiltinFnIdRound: + out_val->data.x_f32 = roundf(op->data.x_f32); + break; + default: + zig_unreachable(); + }; + break; + }; + case 64: { + switch (fop) { + case BuiltinFnIdSqrt: + out_val->data.x_f64 = sqrt(op->data.x_f64); + break; + case BuiltinFnIdSin: + out_val->data.x_f64 = sin(op->data.x_f64); + break; + case BuiltinFnIdCos: + out_val->data.x_f64 = cos(op->data.x_f64); + break; + case BuiltinFnIdExp: + out_val->data.x_f64 = exp(op->data.x_f64); + break; + case BuiltinFnIdExp2: + out_val->data.x_f64 = exp2(op->data.x_f64); + break; + case BuiltinFnIdLn: + out_val->data.x_f64 = log(op->data.x_f64); + break; + case BuiltinFnIdLog10: + out_val->data.x_f64 = log10(op->data.x_f64); + break; + case BuiltinFnIdLog2: + out_val->data.x_f64 = log2(op->data.x_f64); + break; + case BuiltinFnIdFabs: + out_val->data.x_f64 = fabs(op->data.x_f64); + break; + case BuiltinFnIdFloor: + out_val->data.x_f64 = floor(op->data.x_f64); + break; + case BuiltinFnIdCeil: + out_val->data.x_f64 = ceil(op->data.x_f64); + break; + case BuiltinFnIdTrunc: + out_val->data.x_f64 = trunc(op->data.x_f64); + break; + case BuiltinFnIdNearbyInt: + out_val->data.x_f64 = nearbyint(op->data.x_f64); + break; + case BuiltinFnIdRound: + out_val->data.x_f64 = round(op->data.x_f64); + break; + default: + zig_unreachable(); + } + break; + }; + case 128: { + float128_t *out, *in; + if (float_type->id == ZigTypeIdComptimeFloat) { + out = &out_val->data.x_bigfloat.value; + in = &op->data.x_bigfloat.value; + } else { + out = &out_val->data.x_f128; + in = &op->data.x_f128; + } + switch (fop) { + case BuiltinFnIdSqrt: + f128M_sqrt(in, out); + break; + case BuiltinFnIdNearbyInt: + case BuiltinFnIdSin: + case BuiltinFnIdCos: + case BuiltinFnIdExp: + case BuiltinFnIdExp2: + case BuiltinFnIdLn: + case BuiltinFnIdLog10: + case BuiltinFnIdLog2: + case BuiltinFnIdFabs: + case BuiltinFnIdFloor: + case BuiltinFnIdCeil: + case BuiltinFnIdTrunc: + case BuiltinFnIdRound: + zig_panic("unimplemented f128 builtin"); + default: + zig_unreachable(); + } + break; + }; + default: + zig_unreachable(); + } +} + +static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstructionFloatOp *instruction) { + IrInstruction *type = instruction->type->child; + if (type_is_invalid(type->value.type)) + return ira->codegen->invalid_instruction; + + ZigType *expr_type = ir_resolve_type(ira, type); + if (type_is_invalid(expr_type)) return ira->codegen->invalid_instruction; - bool ok_type = float_type->id == ZigTypeIdComptimeFloat || float_type->id == ZigTypeIdFloat; - if (!ok_type) { - ir_add_error(ira, instruction->type, buf_sprintf("@sqrt does not support type '%s'", buf_ptr(&float_type->name))); + // Only allow float types, and vectors of floats. + ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type; + if (float_type->id != ZigTypeIdFloat && float_type->id != ZigTypeIdComptimeFloat) { + ir_add_error(ira, instruction->type, buf_sprintf("@%s does not support type '%s'", float_op_to_name(instruction->op, false), buf_ptr(&float_type->name))); return ira->codegen->invalid_instruction; } - IrInstruction *casted_op = ir_implicit_cast(ira, op, float_type); - if (type_is_invalid(casted_op->value.type)) + IrInstruction *op1 = instruction->op1->child; + if (type_is_invalid(op1->value.type)) return ira->codegen->invalid_instruction; - if (instr_is_comptime(casted_op)) { - ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad); - if (!val) + IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, float_type); + if (type_is_invalid(casted_op1->value.type)) + return ira->codegen->invalid_instruction; + + if (instr_is_comptime(casted_op1)) { + // Our comptime 16-bit and 128-bit support is quite limited. + if ((float_type->id == ZigTypeIdComptimeFloat || + float_type->data.floating.bit_count == 16 || + float_type->data.floating.bit_count == 128) && + instruction->op != BuiltinFnIdSqrt) { + ir_add_error(ira, instruction->type, buf_sprintf("@%s does not support type '%s'", float_op_to_name(instruction->op, false), buf_ptr(&float_type->name))); return ira->codegen->invalid_instruction; + } - IrInstruction *result = ir_const(ira, &instruction->base, float_type); + ConstExprValue *op1_const = ir_resolve_const(ira, casted_op1, UndefBad); + if (!op1_const) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, &instruction->base, expr_type); ConstExprValue *out_val = &result->value; - if (float_type->id == ZigTypeIdComptimeFloat) { - bigfloat_sqrt(&out_val->data.x_bigfloat, &val->data.x_bigfloat); - } else if (float_type->id == ZigTypeIdFloat) { - switch (float_type->data.floating.bit_count) { - case 16: - out_val->data.x_f16 = f16_sqrt(val->data.x_f16); - break; - case 32: - out_val->data.x_f32 = sqrtf(val->data.x_f32); - break; - case 64: - out_val->data.x_f64 = sqrt(val->data.x_f64); - break; - case 128: - f128M_sqrt(&val->data.x_f128, &out_val->data.x_f128); - break; - default: - zig_unreachable(); + if (expr_type->id == ZigTypeIdVector) { + expand_undef_array(ira->codegen, op1_const); + out_val->special = ConstValSpecialUndef; + expand_undef_array(ira->codegen, out_val); + size_t len = expr_type->data.vector.len; + for (size_t i = 0; i < len; i += 1) { + ConstExprValue *float_operand_op1 = &op1_const->data.x_array.data.s_none.elements[i]; + ConstExprValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i]; + assert(float_operand_op1->type == float_type); + assert(float_out_val->type == float_type); + ir_eval_float_op(ira, instruction, float_type, + op1_const, float_out_val); + float_out_val->type = float_type; } + out_val->type = expr_type; + out_val->special = ConstValSpecialStatic; } else { - zig_unreachable(); + ir_eval_float_op(ira, instruction, float_type, op1_const, out_val); } - return result; } ir_assert(float_type->id == ZigTypeIdFloat, &instruction->base); - if (float_type->data.floating.bit_count != 16 && - float_type->data.floating.bit_count != 32 && - float_type->data.floating.bit_count != 64) { - ir_add_error(ira, instruction->type, buf_sprintf("compiler TODO: add implementation of sqrt for '%s'", buf_ptr(&float_type->name))); - return ira->codegen->invalid_instruction; - } - IrInstruction *result = ir_build_sqrt(&ira->new_irb, instruction->base.scope, - instruction->base.source_node, nullptr, casted_op); - result->value.type = float_type; + IrInstruction *result = ir_build_float_op(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr, casted_op1, instruction->op); + result->value.type = expr_type; return result; } @@ -23762,8 +23995,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction); case IrInstructionIdMarkErrRetTracePtr: return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction); - case IrInstructionIdSqrt: - return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); + case IrInstructionIdFloatOp: + return ir_analyze_instruction_float_op(ira, (IrInstructionFloatOp *)instruction); case IrInstructionIdMulAdd: return ir_analyze_instruction_mul_add(ira, (IrInstructionMulAdd *)instruction); case IrInstructionIdIntToErr: @@ -24004,7 +24237,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCoroFree: case IrInstructionIdCoroPromise: case IrInstructionIdPromiseResultType: - case IrInstructionIdSqrt: + case IrInstructionIdFloatOp: case IrInstructionIdMulAdd: case IrInstructionIdAtomicLoad: case IrInstructionIdIntCast: diff --git a/src/ir.hpp b/src/ir.hpp index 4fb7552212..597624e2e6 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -26,5 +26,6 @@ bool ir_has_side_effects(IrInstruction *instruction); struct IrAnalyze; ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprValue *const_val, AstNode *source_node); +const char *float_op_to_name(BuiltinFnId op, bool llvm_name); #endif diff --git a/src/ir_print.cpp b/src/ir_print.cpp index e205c8e067..165d9b4739 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1427,15 +1427,16 @@ static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRe fprintf(irp->f, ")"); } -static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) { - fprintf(irp->f, "@sqrt("); +static void ir_print_float_op(IrPrint *irp, IrInstructionFloatOp *instruction) { + + fprintf(irp->f, "@%s(", float_op_to_name(instruction->op, false)); if (instruction->type != nullptr) { ir_print_other_instruction(irp, instruction->type); } else { fprintf(irp->f, "null"); } fprintf(irp->f, ","); - ir_print_other_instruction(irp, instruction->op); + ir_print_other_instruction(irp, instruction->op1); fprintf(irp->f, ")"); } @@ -1918,8 +1919,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdMarkErrRetTracePtr: ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction); break; - case IrInstructionIdSqrt: - ir_print_sqrt(irp, (IrInstructionSqrt *)instruction); + case IrInstructionIdFloatOp: + ir_print_float_op(irp, (IrInstructionFloatOp *)instruction); break; case IrInstructionIdMulAdd: ir_print_mul_add(irp, (IrInstructionMulAdd *)instruction); diff --git a/src/util.cpp b/src/util.cpp index 9a6a382993..f85565806f 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -13,6 +13,7 @@ #include "userland.h" void zig_panic(const char *format, ...) { + abort(); va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); diff --git a/std/special/c.zig b/std/special/c.zig index b3cf54619f..15cefbd2a0 100644 --- a/std/special/c.zig +++ b/std/special/c.zig @@ -254,24 +254,32 @@ export fn fmod(x: f64, y: f64) f64 { // TODO add intrinsics for these (and probably the double version too) // and have the math stuff use the intrinsic. same as @mod and @rem -export fn floorf(x: f32) f32 { - return math.floor(x); -} -export fn ceilf(x: f32) f32 { - return math.ceil(x); -} -export fn floor(x: f64) f64 { - return math.floor(x); -} -export fn ceil(x: f64) f64 { - return math.ceil(x); -} -export fn fma(a: f64, b: f64, c: f64) f64 { - return math.fma(f64, a, b, c); -} -export fn fmaf(a: f32, b: f32, c: f32) f32 { - return math.fma(f32, a, b, c); -} +export fn floorf(x: f32) f32 {return math.floor(x);} +export fn ceilf(x: f32) f32 {return math.ceil(x);} +export fn floor(x: f64) f64 {return math.floor(x);} +export fn ceil(x: f64) f64 {return math.ceil(x);} +export fn fma(a: f64, b: f64, c: f64) f64 {return math.fma(f64, a, b, c);} +export fn fmaf(a: f32, b: f32, c: f32) f32 {return math.fma(f32, a, b, c);} +export fn sin(a: f64) f64 {return math.sin(a);} +export fn sinf(a: f32) f32 {return math.sin(a);} +export fn cos(a: f64) f64 {return math.cos(a);} +export fn cosf(a: f32) f32 {return math.cos(a);} +export fn exp(a: f64) f64 {return math.exp(a);} +export fn expf(a: f32) f32 {return math.exp(a);} +export fn exp2(a: f64) f64 {return math.exp2(a);} +export fn exp2f(a: f32) f32 {return math.exp2(a);} +export fn log(a: f64) f64 {return math.ln(a);} +export fn logf(a: f32) f32 {return math.ln(a);} +export fn log2(a: f64) f64 {return math.log2(a);} +export fn log2f(a: f32) f32 {return math.log2(a);} +export fn log10(a: f64) f64 {return math.log10(a);} +export fn log10f(a: f32) f32 {return math.log10(a);} +export fn fabs(a: f64) f64 {return math.fabs(a);} +export fn fabsf(a: f32) f32 {return math.fabs(a);} +export fn trunc(a: f64) f64 {return math.trunc(a);} +export fn truncf(a: f32) f32 {return math.trunc(a);} +export fn round(a: f64) f64 {return math.round(a);} +export fn roundf(a: f32) f32 {return math.round(a);} fn generic_fmod(comptime T: type, x: T, y: T) T { @setRuntimeSafety(false); diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 10e7c1a09b..efefed33ba 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -71,6 +71,7 @@ comptime { _ = @import("behavior/pointers.zig"); _ = @import("behavior/popcount.zig"); _ = @import("behavior/muladd.zig"); + _ = @import("behavior/floatop.zig"); _ = @import("behavior/ptrcast.zig"); _ = @import("behavior/pub_enum.zig"); _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); diff --git a/test/stage1/behavior/floatop.zig b/test/stage1/behavior/floatop.zig new file mode 100644 index 0000000000..de2f6815a6 --- /dev/null +++ b/test/stage1/behavior/floatop.zig @@ -0,0 +1,243 @@ +const expect = @import("std").testing.expect; +const pi = @import("std").math.pi; +const e = @import("std").math.e; + +test "@sqrt" { + comptime testSqrt(); + testSqrt(); +} + +fn testSqrt() void { + { + var a: f16 = 4; + expect(@sqrt(f16, a) == 2); + } + { + var a: f32 = 9; + expect(@sqrt(f32, a) == 3); + } + { + var a: f64 = 25; + expect(@sqrt(f64, a) == 5); + } + { + const a: comptime_float = 25.0; + expect(@sqrt(comptime_float, a) == 5.0); + } + // Waiting on a c.zig implementation + //{ + // var a: f128 = 49; + // expect(@sqrt(f128, a) == 7); + //} +} + +test "@sin" { + comptime testSin(); + testSin(); +} + +fn testSin() void { + // TODO - this is actually useful and should be implemented + // (all the trig functions for f16) + // but will probably wait till self-hosted + //{ + // var a: f16 = pi; + // expect(@sin(f16, a/2) == 1); + //} + { + var a: f32 = 0; + expect(@sin(f32, a) == 0); + } + { + var a: f64 = 0; + expect(@sin(f64, a) == 0); + } + // TODO + //{ + // var a: f16 = pi; + // expect(@sqrt(f128, a/2) == 1); + //} +} + +test "@cos" { + comptime testCos(); + testCos(); +} + +fn testCos() void { + { + var a: f32 = 0; + expect(@cos(f32, a) == 1); + } + { + var a: f64 = 0; + expect(@cos(f64, a) == 1); + } +} + +test "@exp" { + comptime testExp(); + testExp(); +} + +fn testExp() void { + { + var a: f32 = 0; + expect(@exp(f32, a) == 1); + } + { + var a: f64 = 0; + expect(@exp(f64, a) == 1); + } +} + +test "@exp2" { + comptime testExp2(); + testExp2(); +} + +fn testExp2() void { + { + var a: f32 = 2; + expect(@exp2(f32, a) == 4); + } + { + var a: f64 = 2; + expect(@exp2(f64, a) == 4); + } +} + +test "@ln" { + // Old musl (and glibc?), and our current math.ln implementation do not return 1 + // so also accept those values. + comptime testLn(); + testLn(); +} + +fn testLn() void { + { + var a: f32 = e; + expect(@ln(f32, a) == 1 or @ln(f32, a) == @bitCast(f32, u32(0x3f7fffff))); + } + { + var a: f64 = e; + expect(@ln(f64, a) == 1 or @ln(f64, a) == @bitCast(f64, u64(0x3ff0000000000000))); + } +} + +test "@log2" { + comptime testLog2(); + testLog2(); +} + +fn testLog2() void { + { + var a: f32 = 4; + expect(@log2(f32, a) == 2); + } + { + var a: f64 = 4; + expect(@log2(f64, a) == 2); + } +} + +test "@log10" { + comptime testLog10(); + testLog10(); +} + +fn testLog10() void { + { + var a: f32 = 100; + expect(@log10(f32, a) == 2); + } + { + var a: f64 = 1000; + expect(@log10(f64, a) == 3); + } +} + +test "@fabs" { + comptime testFabs(); + testFabs(); +} + +fn testFabs() void { + { + var a: f32 = -2.5; + var b: f32 = 2.5; + expect(@fabs(f32, a) == 2.5); + expect(@fabs(f32, b) == 2.5); + } + { + var a: f64 = -2.5; + var b: f64 = 2.5; + expect(@fabs(f64, a) == 2.5); + expect(@fabs(f64, b) == 2.5); + } +} + +test "@floor" { + comptime testFloor(); + testFloor(); +} + +fn testFloor() void { + { + var a: f32 = 2.1; + expect(@floor(f32, a) == 2); + } + { + var a: f64 = 3.5; + expect(@floor(f64, a) == 3); + } +} + +test "@ceil" { + comptime testCeil(); + testCeil(); +} + +fn testCeil() void { + { + var a: f32 = 2.1; + expect(@ceil(f32, a) == 3); + } + { + var a: f64 = 3.5; + expect(@ceil(f64, a) == 4); + } +} + +test "@trunc" { + comptime testTrunc(); + testTrunc(); +} + +fn testTrunc() void { + { + var a: f32 = 2.1; + expect(@trunc(f32, a) == 2); + } + { + var a: f64 = -3.5; + expect(@trunc(f64, a) == -3); + } +} + +// This is waiting on library support for the Windows build (not sure why the other's don't need it) +//test "@nearbyInt" { +// comptime testNearbyInt(); +// testNearbyInt(); +//} + +//fn testNearbyInt() void { +// { +// var a: f32 = 2.1; +// expect(@nearbyInt(f32, a) == 2); +// } +// { +// var a: f64 = -3.75; +// expect(@nearbyInt(f64, a) == -4); +// } +//} -- cgit v1.2.3 From 86f362ce8e878188d40393e6f2feba0c60ddbcf0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 22 Jun 2019 16:18:42 -0400 Subject: elide redundant safety check when switching on tagged unions --- src/all_types.hpp | 1 + src/codegen.cpp | 2 +- src/ir.cpp | 9 +++++---- std/zig/render.zig | 6 +++--- 4 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 213a64dd9d..5b75d9f96a 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2540,6 +2540,7 @@ struct IrInstructionStructFieldPtr { struct IrInstructionUnionFieldPtr { IrInstruction base; + bool safety_check_on; bool initializing; IrInstruction *union_ptr; TypeUnionField *field; diff --git a/src/codegen.cpp b/src/codegen.cpp index 5b7169f312..4eea729dd9 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3890,7 +3890,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab LLVMValueRef tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type), &field->enum_field->value); gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); - } else if (ir_want_runtime_safety(g, &instruction->base)) { + } else if (instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base)) { LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, ""); LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, ""); diff --git a/src/ir.cpp b/src/ir.cpp index e943788f97..823ddb13a3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1384,10 +1384,11 @@ static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, Scope *scope, As } static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *union_ptr, TypeUnionField *field, bool initializing) + IrInstruction *union_ptr, TypeUnionField *field, bool safety_check_on, bool initializing) { IrInstructionUnionFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->initializing = initializing; + instruction->safety_check_on = safety_check_on; instruction->union_ptr = union_ptr; instruction->field = field; @@ -17514,7 +17515,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ IrInstruction *result; if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, - source_instr->source_node, container_ptr, field, initializing); + source_instr->source_node, container_ptr, field, true, initializing); result->value.type = ptr_type; result->value.special = ConstValSpecialStatic; } else { @@ -17529,7 +17530,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ } IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, - source_instr->source_node, container_ptr, field, initializing); + source_instr->source_node, container_ptr, field, true, initializing); result->value.type = ptr_type; return result; } @@ -19005,7 +19006,7 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru } IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, target_value_ptr, field, false); + instruction->base.scope, instruction->base.source_node, target_value_ptr, field, false, false); result->value.type = get_pointer_to_type(ira->codegen, field->type_entry, target_value_ptr->value.type->data.pointer.is_const); return result; diff --git a/std/zig/render.zig b/std/zig/render.zig index ef5c8f2346..2e8e4481be 100644 --- a/std/zig/render.zig +++ b/std/zig/render.zig @@ -939,10 +939,10 @@ fn renderExpression( } switch (container_decl.init_arg_expr) { - ast.Node.ContainerDecl.InitArg.None => { + .None => { try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.Space); // union }, - ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| { + .Enum => |enum_tag_type| { try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.None); // union const lparen = tree.nextToken(container_decl.kind_token); @@ -962,7 +962,7 @@ fn renderExpression( try renderToken(tree, stream, tree.nextToken(enum_token), indent, start_col, Space.Space); // ) } }, - ast.Node.ContainerDecl.InitArg.Type => |type_expr| { + .Type => |type_expr| { try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.None); // union const lparen = tree.nextToken(container_decl.kind_token); -- cgit v1.2.3 From 3021e5ca67acca6cf7420bc5e2400aa6965596f9 Mon Sep 17 00:00:00 2001 From: Michael Dusan Date: Mon, 24 Jun 2019 14:38:22 -0400 Subject: align (vector -> array) store to result location --- src/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 4eea729dd9..e12f89756d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5451,7 +5451,7 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab LLVMValueRef vector = ir_llvm_value(g, instruction->vector); LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc, LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), ""); - gen_store_untyped(g, vector, casted_ptr, 0, false); + gen_store_untyped(g, vector, casted_ptr, get_ptr_align(g, instruction->result_loc->value.type), false); return result_loc; } -- cgit v1.2.3 From c61e0a078cea2a6845ed7b03189409829d2cdf24 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 25 Jun 2019 11:31:38 -0400 Subject: fix union init with void payload all std lib tests passing now --- src/analyze.cpp | 14 +++----------- src/analyze.hpp | 1 - src/codegen.cpp | 14 +++++++++++++- src/ir.cpp | 18 +++++++----------- std/zig/parser_test.zig | 12 +----------- test/stage1/behavior/union.zig | 20 ++++++++++++++++++++ 6 files changed, 44 insertions(+), 35 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 85e390f2e0..d3a9376c5d 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5001,12 +5001,9 @@ void init_const_undefined(CodeGen *g, ConstExprValue *const_val) { field_val->type = wanted_type->data.structure.fields[i].type_entry; assert(field_val->type); init_const_undefined(g, field_val); - ConstParent *parent = get_const_val_parent(g, field_val); - if (parent != nullptr) { - parent->id = ConstParentIdStruct; - parent->data.p_struct.struct_val = const_val; - parent->data.p_struct.field_index = i; - } + field_val->parent.id = ConstParentIdStruct; + field_val->parent.data.p_struct.struct_val = const_val; + field_val->parent.data.p_struct.field_index = i; } } else { const_val->special = ConstValSpecialUndef; @@ -5842,11 +5839,6 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { zig_unreachable(); } -// Deprecated. Reference the parent field directly. -ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { - return &value->parent; -} - static const ZigTypeId all_type_ids[] = { ZigTypeIdMetaType, ZigTypeIdVoid, diff --git a/src/analyze.hpp b/src/analyze.hpp index 8d78ef86e2..a6ad92110e 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -180,7 +180,6 @@ void init_const_undefined(CodeGen *g, ConstExprValue *const_val); ConstExprValue *create_const_vals(size_t count); ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); -ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value); void expand_undef_array(CodeGen *g, ConstExprValue *const_val); void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value); diff --git a/src/codegen.cpp b/src/codegen.cpp index e12f89756d..2e430a60e0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3873,8 +3873,20 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab TypeUnionField *field = instruction->field; - if (!type_has_bits(field->type_entry)) + if (!type_has_bits(field->type_entry)) { + if (union_type->data.unionation.gen_tag_index == SIZE_MAX) { + return nullptr; + } + if (instruction->initializing) { + LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr); + LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, + union_type->data.unionation.gen_tag_index, ""); + LLVMValueRef tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type), + &field->enum_field->value); + gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); + } return nullptr; + } LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr); LLVMTypeRef field_type_ref = LLVMPointerType(get_llvm_type(g, field->type_entry), 0); diff --git a/src/ir.cpp b/src/ir.cpp index 32e3692afd..2991dd5186 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17425,11 +17425,9 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction ConstExprValue *field_val = &struct_val->data.x_struct.fields[i]; field_val->special = ConstValSpecialUndef; field_val->type = struct_type->data.structure.fields[i].type_entry; - ConstParent *parent = get_const_val_parent(ira->codegen, field_val); - assert(parent != nullptr); - parent->id = ConstParentIdStruct; - parent->data.p_struct.struct_val = struct_val; - parent->data.p_struct.field_index = i; + field_val->parent.id = ConstParentIdStruct; + field_val->parent.data.p_struct.struct_val = struct_val; + field_val->parent.data.p_struct.field_index = i; } } IrInstruction *result; @@ -17507,11 +17505,8 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ ConstExprValue *payload_val = create_const_vals(1); payload_val->special = ConstValSpecialUndef; payload_val->type = field->type_entry; - ConstParent *parent = get_const_val_parent(ira->codegen, payload_val); - if (parent != nullptr) { - parent->id = ConstParentIdUnion; - parent->data.p_union.union_val = union_val; - } + payload_val->parent.id = ConstParentIdUnion; + payload_val->parent.data.p_union.union_val = union_val; union_val->special = ConstValSpecialStatic; bigint_init_bigint(&union_val->data.x_union.tag, &field->enum_field->value); @@ -25289,7 +25284,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdReturnPtr: case IrInstructionIdTypeOf: case IrInstructionIdStructFieldPtr: - case IrInstructionIdUnionFieldPtr: case IrInstructionIdArrayType: case IrInstructionIdPromiseType: case IrInstructionIdSliceType: @@ -25389,6 +25383,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { } case IrInstructionIdUnwrapErrCode: return reinterpret_cast(instruction)->initializing; + case IrInstructionIdUnionFieldPtr: + return reinterpret_cast(instruction)->initializing; case IrInstructionIdErrWrapPayload: return reinterpret_cast(instruction)->result_loc != nullptr; case IrInstructionIdErrWrapCode: diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 29b70d0a6e..a004089fec 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -1,4 +1,4 @@ -// TODO remove `use` keyword eventually +// TODO remove `use` keyword eventually: https://github.com/ziglang/zig/issues/2591 test "zig fmt: change use to usingnamespace" { try testTransform( \\use @import("std"); @@ -105,7 +105,6 @@ test "zig fmt: linksection" { } test "zig fmt: correctly move doc comments on struct fields" { - if (true) return error.SkipZigTest; // TODO try testTransform( \\pub const section_64 = extern struct { \\ sectname: [16]u8, /// name of this section @@ -917,7 +916,6 @@ test "zig fmt: statements with empty line between" { } test "zig fmt: ptr deref operator and unwrap optional operator" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\const a = b.*; \\const a = b.?; @@ -1020,7 +1018,6 @@ test "zig fmt: same-line comment after a statement" { } test "zig fmt: same-line comment after var decl in struct" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\pub const vfs_cap_data = extern struct { \\ const Data = struct {}; // when on disk. @@ -1030,7 +1027,6 @@ test "zig fmt: same-line comment after var decl in struct" { } test "zig fmt: same-line comment after field decl" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\pub const dirent = extern struct { \\ d_name: u8, @@ -1106,7 +1102,6 @@ test "zig fmt: line comments in struct initializer" { } test "zig fmt: first line comment in struct initializer" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\pub async fn acquire(self: *Self) HeldLock { \\ return HeldLock{ @@ -1120,7 +1115,6 @@ test "zig fmt: first line comment in struct initializer" { } test "zig fmt: doc comments before struct field" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\pub const Allocator = struct { \\ /// Allocate byte_count bytes and return them in a slice, with the @@ -1218,7 +1212,6 @@ test "zig fmt: comments before switch prong" { } test "zig fmt: comments before var decl in struct" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\pub const vfs_cap_data = extern struct { \\ // All of these are mandated as little endian @@ -1609,7 +1602,6 @@ test "zig fmt: indexing" { } test "zig fmt: struct declaration" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\const S = struct { \\ const Self = @This(); @@ -1641,7 +1633,6 @@ test "zig fmt: struct declaration" { } test "zig fmt: enum declaration" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\const E = enum { \\ Ok, @@ -1670,7 +1661,6 @@ test "zig fmt: enum declaration" { } test "zig fmt: union declaration" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\const U = union { \\ Int: u8, diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index 0e8e9f4eda..410b7e9615 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -402,3 +402,23 @@ test "comptime union field value equality" { expect(a0 != a1); expect(b0 != b1); } + +test "return union init with void payload" { + const S = struct { + fn entry() void { + expect(func().state == State.one); + } + const Outer = union(enum) { + state: State, + }; + const State = union(enum) { + one: void, + two: u32, + }; + fn func() Outer { + return Outer{ .state = State{ .one = {} }}; + } + }; + S.entry(); + comptime S.entry(); +} -- cgit v1.2.3 From 33f996bb163568c9bb10e5044ed9df53599a917f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 26 Jun 2019 14:00:44 -0400 Subject: all tests passing on linux --- doc/langref.html.in | 2 +- src/all_types.hpp | 5 +++-- src/codegen.cpp | 4 +++- src/ir.cpp | 4 +++- std/event/lock.zig | 3 +-- 5 files changed, 11 insertions(+), 7 deletions(-) (limited to 'src/codegen.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index a8673a3d77..92c1aeba8e 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5096,7 +5096,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {

For example, if we were to introduce another function to the above snippet:

- {#code_begin|test_err|values of type 'type' must be comptime known#} + {#code_begin|test_err|cannot store runtime value in type 'type'#} fn max(comptime T: type, a: T, b: T) T { return if (a > b) a else b; } diff --git a/src/all_types.hpp b/src/all_types.hpp index 5b75d9f96a..4be6f57593 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -335,8 +335,9 @@ struct ConstExprValue { RuntimeHintSlice rh_slice; } data; - ConstExprValue(const ConstExprValue &other) = delete; // plz zero initialize with {} - ConstExprValue& operator= (const ConstExprValue &other) = delete; // use copy_const_val + // uncomment these to find bugs. can't leave them uncommented because of a gcc-9 warning + //ConstExprValue(const ConstExprValue &other) = delete; // plz zero initialize with {} + //ConstExprValue& operator= (const ConstExprValue &other) = delete; // use copy_const_val }; enum ReturnKnowledge { diff --git a/src/codegen.cpp b/src/codegen.cpp index 2e430a60e0..0942c671ff 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -691,7 +691,9 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { is_definition, scope_line, flags, is_optimized, nullptr); scope->di_scope = ZigLLVMSubprogramToScope(subprogram); - ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram); + if (!g->strip_debug_symbols) { + ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram); + } return scope->di_scope; } case ScopeIdDecls: diff --git a/src/ir.cpp b/src/ir.cpp index 794d41ce22..480493d2ce 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10726,6 +10726,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT } else if (prev_inst->value.type->id == ZigTypeIdOptional) { return prev_inst->value.type; } else { + if ((err = type_resolve(ira->codegen, prev_inst->value.type, ResolveStatusSizeKnown))) + return ira->codegen->builtin_types.entry_invalid; return get_optional_type(ira->codegen, prev_inst->value.type); } } else { @@ -21547,7 +21549,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, dest_slice_type, nullptr, true, false); - if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) { return result_loc; } diff --git a/std/event/lock.zig b/std/event/lock.zig index 6e7a2bbda7..6c2b29b813 100644 --- a/std/event/lock.zig +++ b/std/event/lock.zig @@ -123,8 +123,7 @@ pub const Lock = struct { }; test "std.event.Lock" { - // https://github.com/ziglang/zig/issues/2377 - //if (true) return error.SkipZigTest; + if (builtin.single_threaded) return error.SkipZigTest; const allocator = std.heap.direct_allocator; -- cgit v1.2.3 From 517bdea7549453d958c31cf2af5dc298ea5508a9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 26 Jun 2019 16:27:24 -0400 Subject: fix incorrectly omitting variable declarations in non-debug modes --- src/codegen.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 7601008e16..8842e161cc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3373,9 +3373,6 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrI if (!type_has_bits(var->var_type)) return nullptr; - if (var->ref_count == 0 && g->build_mode != BuildModeDebug) - return nullptr; - var->value_ref = ir_llvm_value(g, instruction->var_ptr); gen_var_debug_decl(g, var); return nullptr; -- cgit v1.2.3 From 69c7c5de09e16e96a6ea5207ef8b3a21e9d119f9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 27 Jun 2019 19:15:33 -0400 Subject: fixups * better detection for already seen packages * "root" instead of "@root" --- src/all_types.hpp | 2 ++ src/codegen.cpp | 30 ++++++++++++++---------------- std/special/bootstrap.zig | 5 ++--- 3 files changed, 18 insertions(+), 19 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 774a00fdb7..bb5bef04bb 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1110,6 +1110,8 @@ struct ZigPackage { // reminder: hash tables must be initialized before use HashMap package_table; + + bool added_to_cache; }; // Stuff that only applies to a struct which is the implicit root struct of a file diff --git a/src/codegen.cpp b/src/codegen.cpp index 1a01e135d2..6ad779fd24 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -180,7 +180,7 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget g->root_package = new_package(".", "", ""); } - g->root_package->package_table.put(buf_create_from_str("@root"), g->root_package); + g->root_package->package_table.put(buf_create_from_str("root"), g->root_package); g->zig_std_special_dir = buf_alloc(); os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir); @@ -8055,6 +8055,8 @@ static Error define_builtin_compile_vars(CodeGen *g) { g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->std_package->package_table.put(buf_create_from_str("std"), g->std_package); + g->std_package->package_table.put(buf_create_from_str("root"), + g->is_test_build ? g->test_runner_package : g->root_package); g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents, SourceKindPkgMain); @@ -8522,8 +8524,10 @@ static ZigType *add_special_code(CodeGen *g, ZigPackage *package, const char *ba return add_source_file(g, package, resolved_path, import_code, SourceKindPkgMain); } -static ZigPackage *create_bootstrap_pkg(CodeGen *g) { - return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special"); +static ZigPackage *create_bootstrap_pkg(CodeGen *g, ZigPackage *pkg_with_main) { + ZigPackage *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special"); + package->package_table.put(buf_create_from_str("root"), pkg_with_main); + return package; } static ZigPackage *create_test_runner_pkg(CodeGen *g) { @@ -8647,12 +8651,12 @@ static void gen_root_source(CodeGen *g) { !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap.zig"); + g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap.zig"); } if (g->zig_target->os == OsWindows && !g->have_dllmain_crt_startup && g->out_type == OutTypeLib && g->is_dynamic) { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap_lib.zig"); + g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig"); } if (!g->error_during_imports) { @@ -8660,7 +8664,7 @@ static void gen_root_source(CodeGen *g) { } if (g->is_test_build) { create_test_compile_var_and_add_test_runner(g); - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap.zig"); + g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->test_runner_package), "bootstrap.zig"); if (!g->error_during_imports) { semantic_analyze(g); @@ -9375,6 +9379,7 @@ void codegen_add_time_event(CodeGen *g, const char *name) { static void add_cache_pkg(CodeGen *g, CacheHash *ch, ZigPackage *pkg) { if (buf_len(&pkg->root_src_path) == 0) return; + pkg->added_to_cache = true; Buf *rel_full_path = buf_alloc(); os_path_join(&pkg->root_src_dir, &pkg->root_src_path, rel_full_path); @@ -9386,11 +9391,7 @@ static void add_cache_pkg(CodeGen *g, CacheHash *ch, ZigPackage *pkg) { if (!entry) break; - // TODO: I think we need a more sophisticated detection of - // packages we have already seen - if (entry->value != pkg) { - auto root = pkg->package_table.maybe_get(buf_create_from_str("@root")); - if (root != nullptr && entry->value == root->value) continue; + if (!pkg->added_to_cache) { cache_buf(ch, entry->key); add_cache_pkg(g, ch, entry->value); } @@ -9648,11 +9649,8 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c assert(g->compile_var_package != nullptr); pkg->package_table.put(buf_create_from_str("std"), g->std_package); - if (g->is_test_build) { - pkg->package_table.put(buf_create_from_str("@root"), g->test_runner_package); - } else { - pkg->package_table.put(buf_create_from_str("@root"), g->root_package); - } + ZigPackage *main_pkg = g->is_test_build ? g->test_runner_package : g->root_package; + pkg->package_table.put(buf_create_from_str("root"), main_pkg); pkg->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); } diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index f1286bd659..7177f58b8a 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -1,7 +1,6 @@ -// This file is in a package which has the root source file exposed as "@root". -// It is included in the compilation unit when exporting an executable. +// This file is included in the compilation unit when exporting an executable. -const root = @import("@root"); +const root = @import("root"); const std = @import("std"); const builtin = @import("builtin"); const assert = std.debug.assert; -- cgit v1.2.3