From 85b6d1463792a321832ff79b81d5ba51c324d7fa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 18 Dec 2016 00:09:43 -0500 Subject: [PATCH] IR: support var type args and fix phi peer type resolution --- src/analyze.cpp | 143 ++++++++++++++-------- src/analyze.hpp | 1 + src/ir.cpp | 306 ++++++++++++++++++++++++++---------------------- 3 files changed, 260 insertions(+), 190 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 8bc861c879..6c4d05be17 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -723,6 +723,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { fn_type->data.fn.calling_convention = LLVMFastCallConv; } + bool skip_debug_info = false; + // populate the name of the type buf_resize(&fn_type->name, 0); const char *extern_str = fn_type_id->is_extern ? "extern " : ""; @@ -736,6 +738,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { const char *comma = (i == 0) ? "" : ", "; const char *noalias_str = param_info->is_noalias ? "noalias " : ""; buf_appendf(&fn_type->name, "%s%s%s", comma, noalias_str, buf_ptr(¶m_type->name)); + + skip_debug_info = skip_debug_info || !param_type->di_type; } if (fn_type_id->is_var_args) { @@ -746,67 +750,70 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { if (fn_type_id->return_type->id != TypeTableEntryIdVoid) { buf_appendf(&fn_type->name, " -> %s", buf_ptr(&fn_type_id->return_type->name)); } + skip_debug_info = skip_debug_info || !fn_type_id->return_type->di_type; // next, loop over the parameters again and compute debug information // and codegen information - bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type); - // +1 for maybe making the first argument the return value - LLVMTypeRef *gen_param_types = allocate(1 + fn_type_id->param_count); - // +1 because 0 is the return type and +1 for maybe making first arg ret val - ZigLLVMDIType **param_di_types = allocate(2 + fn_type_id->param_count); - param_di_types[0] = fn_type_id->return_type->di_type; - size_t gen_param_index = 0; - TypeTableEntry *gen_return_type; - if (!type_has_bits(fn_type_id->return_type)) { - gen_return_type = g->builtin_types.entry_void; - } else if (first_arg_return) { - TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); - gen_param_types[gen_param_index] = gen_type->type_ref; - gen_param_index += 1; - // after the gen_param_index += 1 because 0 is the return type - param_di_types[gen_param_index] = gen_type->di_type; - gen_return_type = g->builtin_types.entry_void; - } else { - gen_return_type = fn_type_id->return_type; - } - fn_type->data.fn.gen_return_type = gen_return_type; - - fn_type->data.fn.gen_param_info = allocate(fn_type_id->param_count); - for (size_t i = 0; i < fn_type_id->param_count; i += 1) { - FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i]; - TypeTableEntry *type_entry = src_param_info->type; - FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i]; - - gen_param_info->src_index = i; - gen_param_info->gen_index = SIZE_MAX; - - assert(type_is_complete(type_entry)); - if (type_has_bits(type_entry)) { - TypeTableEntry *gen_type; - if (handle_is_ptr(type_entry)) { - gen_type = get_pointer_to_type(g, type_entry, true); - gen_param_info->is_byval = true; - } else { - gen_type = type_entry; - } + if (!skip_debug_info) { + bool first_arg_return = !fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type); + // +1 for maybe making the first argument the return value + LLVMTypeRef *gen_param_types = allocate(1 + fn_type_id->param_count); + // +1 because 0 is the return type and +1 for maybe making first arg ret val + ZigLLVMDIType **param_di_types = allocate(2 + fn_type_id->param_count); + param_di_types[0] = fn_type_id->return_type->di_type; + size_t gen_param_index = 0; + TypeTableEntry *gen_return_type; + if (!type_has_bits(fn_type_id->return_type)) { + gen_return_type = g->builtin_types.entry_void; + } else if (first_arg_return) { + TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); gen_param_types[gen_param_index] = gen_type->type_ref; - gen_param_info->gen_index = gen_param_index; - gen_param_info->type = gen_type; - gen_param_index += 1; - // after the gen_param_index += 1 because 0 is the return type param_di_types[gen_param_index] = gen_type->di_type; + gen_return_type = g->builtin_types.entry_void; + } else { + gen_return_type = fn_type_id->return_type; } + fn_type->data.fn.gen_return_type = gen_return_type; + + fn_type->data.fn.gen_param_info = allocate(fn_type_id->param_count); + for (size_t i = 0; i < fn_type_id->param_count; i += 1) { + FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i]; + TypeTableEntry *type_entry = src_param_info->type; + FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i]; + + gen_param_info->src_index = i; + gen_param_info->gen_index = SIZE_MAX; + + assert(type_is_complete(type_entry)); + if (type_has_bits(type_entry)) { + TypeTableEntry *gen_type; + if (handle_is_ptr(type_entry)) { + gen_type = get_pointer_to_type(g, type_entry, true); + gen_param_info->is_byval = true; + } else { + gen_type = type_entry; + } + gen_param_types[gen_param_index] = gen_type->type_ref; + gen_param_info->gen_index = gen_param_index; + gen_param_info->type = gen_type; + + gen_param_index += 1; + + // after the gen_param_index += 1 because 0 is the return type + param_di_types[gen_param_index] = gen_type->di_type; + } + } + + fn_type->data.fn.gen_param_count = gen_param_index; + + fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, + gen_param_types, gen_param_index, fn_type_id->is_var_args); + fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); + fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types, gen_param_index + 1, 0); } - fn_type->data.fn.gen_param_count = gen_param_index; - - fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, - gen_param_types, gen_param_index, fn_type_id->is_var_args); - fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); - fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types, gen_param_index + 1, 0); - g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type); return fn_type; @@ -2765,6 +2772,40 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) zig_unreachable(); } +bool type_requires_comptime(TypeTableEntry *type_entry) { + switch (type_entry->id) { + case TypeTableEntryIdInvalid: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdVar: + zig_unreachable(); + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdMetaType: + case TypeTableEntryIdVoid: + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBlock: + case TypeTableEntryIdBoundFn: + return true; + case TypeTableEntryIdArray: + case TypeTableEntryIdStruct: + case TypeTableEntryIdUnion: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdTypeDecl: + case TypeTableEntryIdEnum: + case TypeTableEntryIdPureError: + case TypeTableEntryIdFn: + case TypeTableEntryIdBool: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdPointer: + return false; + } + zig_unreachable(); +} + uint64_t get_memcpy_align(CodeGen *g, TypeTableEntry *type_entry) { TypeTableEntry *first_type_in_mem = type_of_first_thing_in_memory(type_entry); return LLVMABISizeOfType(g->target_data_ref, first_type_in_mem->type_ref); diff --git a/src/analyze.hpp b/src/analyze.hpp index 16261036d4..6bb0818251 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -75,6 +75,7 @@ FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage); void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node); AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index); FnTableEntry *scope_get_fn_if_root(Scope *scope); +bool type_requires_comptime(TypeTableEntry *type_entry); ScopeBlock *create_block_scope(AstNode *node, Scope *parent); ScopeDefer *create_defer_scope(AstNode *node, Scope *parent); diff --git a/src/ir.cpp b/src/ir.cpp index cadd5adf2d..b26b896949 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2307,6 +2307,12 @@ static IrInstruction *ir_gen_null_literal(IrBuilder *irb, Scope *scope, AstNode return ir_build_const_null(irb, scope, node); } +static IrInstruction *ir_gen_var_literal(IrBuilder *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeVarLiteral); + + return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_var); +} + static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, Tld *tld, LValPurpose lval, Scope *scope) { @@ -3927,6 +3933,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_asm_expr(irb, scope, node), lval); case NodeTypeNullLiteral: return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval); + case NodeTypeVarLiteral: + return ir_lval_wrap(irb, scope, ir_gen_var_literal(irb, scope, node), lval); case NodeTypeIfVarExpr: return ir_lval_wrap(irb, scope, ir_gen_if_var_expr(irb, scope, node), lval); case NodeTypeSwitchExpr: @@ -3949,8 +3957,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval); case NodeTypeUnwrapErrorExpr: return ir_lval_wrap(irb, scope, ir_gen_err_ok_or(irb, scope, node), lval); - case NodeTypeZeroesLiteral: - case NodeTypeVarLiteral: case NodeTypeFnProto: case NodeTypeFnDef: case NodeTypeFnDecl: @@ -3959,6 +3965,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeErrorValueDecl: case NodeTypeTypeDecl: zig_panic("TODO more IR gen for node types"); + case NodeTypeZeroesLiteral: + zig_panic("TODO zeroes is deprecated"); } zig_unreachable(); } @@ -4065,17 +4073,18 @@ static IrInstruction *ir_exec_const_result(IrExecutable *exec) { return nullptr; IrBasicBlock *bb = exec->basic_block_list.at(0); - if (bb->instruction_list.length != 1) - return nullptr; - - IrInstruction *only_inst = bb->instruction_list.at(0); - if (only_inst->id != IrInstructionIdReturn) - return nullptr; - - IrInstructionReturn *ret_inst = (IrInstructionReturn *)only_inst; - IrInstruction *value = ret_inst->value; - assert(value->static_value.special != ConstValSpecialRuntime); - return value; + for (size_t i = 0; i < bb->instruction_list.length; i += 1) { + IrInstruction *instruction = bb->instruction_list.at(i); + if (instruction->id == IrInstructionIdReturn) { + IrInstructionReturn *ret_inst = (IrInstructionReturn *)instruction; + IrInstruction *value = ret_inst->value; + assert(value->static_value.special != ConstValSpecialRuntime); + return value; + } else if (ir_has_side_effects(instruction)) { + return nullptr; + } + } + return nullptr; } static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) { @@ -4123,9 +4132,109 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc return false; } -static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_node, - IrInstruction **instructions, size_t instruction_count) +enum ImplicitCastMatchResult { + ImplicitCastMatchResultNo, + ImplicitCastMatchResultYes, + ImplicitCastMatchResultReportedError, +}; + +static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *expected_type, + TypeTableEntry *actual_type, IrInstruction *value) { + if (types_match_const_cast_only(expected_type, actual_type)) { + return ImplicitCastMatchResultYes; + } + + // implicit conversion from anything to var + if (expected_type->id == TypeTableEntryIdVar) { + return ImplicitCastMatchResultYes; + } + + // implicit conversion from non maybe type to maybe type + if (expected_type->id == TypeTableEntryIdMaybe && + ir_types_match_with_implicit_cast(ira, expected_type->data.maybe.child_type, actual_type, value)) + { + return ImplicitCastMatchResultYes; + } + + // implicit conversion from null literal to maybe type + if (expected_type->id == TypeTableEntryIdMaybe && + actual_type->id == TypeTableEntryIdNullLit) + { + return ImplicitCastMatchResultYes; + } + + // implicit conversion from error child type to error type + if (expected_type->id == TypeTableEntryIdErrorUnion && + ir_types_match_with_implicit_cast(ira, expected_type->data.error.child_type, actual_type, value)) + { + return ImplicitCastMatchResultYes; + } + + // implicit conversion from pure error to error union type + if (expected_type->id == TypeTableEntryIdErrorUnion && + actual_type->id == TypeTableEntryIdPureError) + { + return ImplicitCastMatchResultYes; + } + + // implicit widening conversion + if (expected_type->id == TypeTableEntryIdInt && + actual_type->id == TypeTableEntryIdInt && + expected_type->data.integral.is_signed == actual_type->data.integral.is_signed && + expected_type->data.integral.bit_count >= actual_type->data.integral.bit_count) + { + return ImplicitCastMatchResultYes; + } + + // small enough unsigned ints can get casted to large enough signed ints + if (expected_type->id == TypeTableEntryIdInt && expected_type->data.integral.is_signed && + actual_type->id == TypeTableEntryIdInt && !actual_type->data.integral.is_signed && + expected_type->data.integral.bit_count > actual_type->data.integral.bit_count) + { + return ImplicitCastMatchResultYes; + } + + // implicit float widening conversion + if (expected_type->id == TypeTableEntryIdFloat && + actual_type->id == TypeTableEntryIdFloat && + expected_type->data.floating.bit_count >= actual_type->data.floating.bit_count) + { + return ImplicitCastMatchResultYes; + } + + // implicit array to slice conversion + if (expected_type->id == TypeTableEntryIdStruct && + expected_type->data.structure.is_slice && + actual_type->id == TypeTableEntryIdArray && + types_match_const_cast_only( + expected_type->data.structure.fields[0].type_entry->data.pointer.child_type, + actual_type->data.array.child_type)) + { + return ImplicitCastMatchResultYes; + } + + // implicit number literal to typed number + if ((actual_type->id == TypeTableEntryIdNumLitFloat || + actual_type->id == TypeTableEntryIdNumLitInt)) + { + if (ir_num_lit_fits_in_other_type(ira, value, expected_type)) { + return ImplicitCastMatchResultYes; + } else { + return ImplicitCastMatchResultReportedError; + } + } + + // implicit undefined literal to anything + if (actual_type->id == TypeTableEntryIdUndefLit) { + return ImplicitCastMatchResultYes; + } + + + return ImplicitCastMatchResultNo; +} + +static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) { assert(instruction_count >= 1); IrInstruction *prev_inst = instructions[0]; if (prev_inst->type_entry->id == TypeTableEntryIdInvalid) { @@ -4241,109 +4350,6 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_n } } -enum ImplicitCastMatchResult { - ImplicitCastMatchResultNo, - ImplicitCastMatchResultYes, - ImplicitCastMatchResultReportedError, -}; - -static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *expected_type, - TypeTableEntry *actual_type, IrInstruction *value) -{ - if (types_match_const_cast_only(expected_type, actual_type)) { - return ImplicitCastMatchResultYes; - } - - // implicit conversion from non maybe type to maybe type - if (expected_type->id == TypeTableEntryIdMaybe && - ir_types_match_with_implicit_cast(ira, expected_type->data.maybe.child_type, actual_type, value)) - { - return ImplicitCastMatchResultYes; - } - - // implicit conversion from null literal to maybe type - if (expected_type->id == TypeTableEntryIdMaybe && - actual_type->id == TypeTableEntryIdNullLit) - { - return ImplicitCastMatchResultYes; - } - - // implicit conversion from error child type to error type - if (expected_type->id == TypeTableEntryIdErrorUnion && - ir_types_match_with_implicit_cast(ira, expected_type->data.error.child_type, actual_type, value)) - { - return ImplicitCastMatchResultYes; - } - - // implicit conversion from pure error to error union type - if (expected_type->id == TypeTableEntryIdErrorUnion && - actual_type->id == TypeTableEntryIdPureError) - { - return ImplicitCastMatchResultYes; - } - - // implicit widening conversion - if (expected_type->id == TypeTableEntryIdInt && - actual_type->id == TypeTableEntryIdInt && - expected_type->data.integral.is_signed == actual_type->data.integral.is_signed && - expected_type->data.integral.bit_count >= actual_type->data.integral.bit_count) - { - return ImplicitCastMatchResultYes; - } - - // small enough unsigned ints can get casted to large enough signed ints - if (expected_type->id == TypeTableEntryIdInt && expected_type->data.integral.is_signed && - actual_type->id == TypeTableEntryIdInt && !actual_type->data.integral.is_signed && - expected_type->data.integral.bit_count > actual_type->data.integral.bit_count) - { - return ImplicitCastMatchResultYes; - } - - // implicit float widening conversion - if (expected_type->id == TypeTableEntryIdFloat && - actual_type->id == TypeTableEntryIdFloat && - expected_type->data.floating.bit_count >= actual_type->data.floating.bit_count) - { - return ImplicitCastMatchResultYes; - } - - // implicit array to slice conversion - if (expected_type->id == TypeTableEntryIdStruct && - expected_type->data.structure.is_slice && - actual_type->id == TypeTableEntryIdArray && - types_match_const_cast_only( - expected_type->data.structure.fields[0].type_entry->data.pointer.child_type, - actual_type->data.array.child_type)) - { - return ImplicitCastMatchResultYes; - } - - // implicit number literal to typed number - if ((actual_type->id == TypeTableEntryIdNumLitFloat || - actual_type->id == TypeTableEntryIdNumLitInt)) - { - if (ir_num_lit_fits_in_other_type(ira, value, expected_type)) { - return ImplicitCastMatchResultYes; - } else { - return ImplicitCastMatchResultReportedError; - } - } - - // implicit undefined literal to anything - if (actual_type->id == TypeTableEntryIdUndefLit) { - return ImplicitCastMatchResultYes; - } - - - return ImplicitCastMatchResultNo; -} - -static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, - IrInstruction **instructions, size_t instruction_count) -{ - return ir_determine_peer_types(ira, source_node, instructions, instruction_count); -} - static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *type_entry) { if (type_has_bits(type_entry) && handle_is_ptr(type_entry)) { FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); @@ -4746,6 +4752,9 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ira->codegen->invalid_instruction; } + if (wanted_type->id == TypeTableEntryIdVar) + return value; + // explicit match or non-const to const if (types_match_const_cast_only(wanted_type, actual_type)) { return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false); @@ -5833,7 +5842,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node Buf *param_name = param_decl_node->data.param_decl.name; VariableTableEntry *var = add_variable(ira->codegen, param_decl_node, - *exec_scope, param_name, param_type, true, first_arg_val); + *exec_scope, param_name, casted_arg->type_entry, true, first_arg_val); *exec_scope = var->child_scope; *next_proto_i += 1; @@ -5852,38 +5861,49 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod if (param_type->id == TypeTableEntryIdInvalid) return false; - bool is_var_type = (param_type->id == TypeTableEntryIdVar); - IrInstruction *casted_arg; - if (is_var_type) { - casted_arg = arg; - } else { - casted_arg = ir_implicit_cast(ira, arg, param_type); - if (casted_arg->type_entry->id == TypeTableEntryIdInvalid) - return false; - } + IrInstruction *casted_arg = ir_implicit_cast(ira, arg, param_type); + if (casted_arg->type_entry->id == TypeTableEntryIdInvalid) + return false; bool inline_arg = param_decl_node->data.param_decl.is_inline; - if (inline_arg || is_var_type) { - ConstExprValue *arg_val = ir_resolve_const(ira, casted_arg, UndefBad); + bool is_var_type = (param_type->id == TypeTableEntryIdVar); + + ConstExprValue *arg_val; + + if (inline_arg) { + arg_val = ir_resolve_const(ira, casted_arg, UndefBad); if (!arg_val) return false; - - Buf *param_name = param_decl_node->data.param_decl.name; - VariableTableEntry *var = add_variable(ira->codegen, param_decl_node, - *child_scope, param_name, param_type, true, arg_val); - *child_scope = var->child_scope; // This generic function instance could be called with anything, so when this variable is read it // needs to know that it depends on compile time variable data. - var->value->depends_on_compile_var = true; + arg_val->depends_on_compile_var = true; + } else { + arg_val = nullptr; + } + Buf *param_name = param_decl_node->data.param_decl.name; + VariableTableEntry *var = add_variable(ira->codegen, param_decl_node, + *child_scope, param_name, casted_arg->type_entry, true, arg_val); + *child_scope = var->child_scope; + + if (inline_arg || is_var_type) { GenericParamValue *generic_param = &generic_id->params[generic_id->param_count]; generic_param->type = casted_arg->type_entry; generic_param->value = arg_val; generic_id->param_count += 1; - } else { + } + if (!inline_arg) { + if (type_requires_comptime(var->type)) { + ir_add_error(ira, arg, + buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&var->type->name))); + return false; + } + + var->shadowable = true; + casted_args[fn_type_id->param_count] = casted_arg; FnTypeParamInfo *param_info = &fn_type_id->param_info[fn_type_id->param_count]; - param_info->type = param_type; + param_info->type = casted_arg->type_entry; param_info->is_noalias = param_decl_node->data.param_decl.is_noalias; impl_fn->param_source_nodes[fn_type_id->param_count] = param_decl_node; fn_type_id->param_count += 1; @@ -6475,12 +6495,20 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP return ira->codegen->builtin_types.entry_invalid; } - // cast all literal values to the resolved type + // cast all values to the resolved type. however we can't put cast instructions in front of the phi instruction. + // so we go back and insert the casts as the last instruction in the corresponding predecessor blocks, and + // then make sure the branch instruction is preserved. + IrBasicBlock *cur_bb = ira->new_irb.current_basic_block; for (size_t i = 0; i < new_incoming_values.length; i += 1) { IrInstruction *new_value = new_incoming_values.at(i); + IrBasicBlock *predecessor = new_incoming_blocks.at(i); + IrInstruction *branch_instruction = predecessor->instruction_list.pop(); + ir_set_cursor_at_end(&ira->new_irb, predecessor); IrInstruction *casted_value = ir_implicit_cast(ira, new_value, resolved_type); new_incoming_values.items[i] = casted_value; + predecessor->instruction_list.append(branch_instruction); } + ir_set_cursor_at_end(&ira->new_irb, cur_bb); ir_build_phi_from(&ira->new_irb, &phi_instruction->base, new_incoming_blocks.length, new_incoming_blocks.items, new_incoming_values.items);