diff options
| -rw-r--r-- | src/all_types.hpp | 3 | ||||
| -rw-r--r-- | src/analyze.cpp | 2 | ||||
| -rw-r--r-- | src/codegen.cpp | 48 | ||||
| -rw-r--r-- | src/ir.cpp | 236 | ||||
| -rw-r--r-- | src/ir.hpp | 2 | ||||
| -rw-r--r-- | src/ir_print.cpp | 7 |
6 files changed, 210 insertions, 88 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index df0ecff62c..1ec123bc74 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1609,6 +1609,9 @@ struct IrInstructionConst { IrInstruction base; }; +// When an IrExecutable is not in a function, a return instruction means that +// the expression returns with that value, even though a return statement from +// an AST perspective is invalid. struct IrInstructionReturn { IrInstruction base; diff --git a/src/analyze.cpp b/src/analyze.cpp index b21ba07127..13d3267e67 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5314,7 +5314,7 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { } TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable, - &fn_table_entry->analyzed_executable, expected_type); + &fn_table_entry->analyzed_executable, expected_type, fn_proto->return_type); node->data.fn_def.implicit_return_type = block_return_type; if (g->verbose) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 11e4903ded..023a714819 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2864,6 +2864,48 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn return instruction->var->value_ref; } +static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) { + LLVMValueRef fn_val = ir_llvm_value(g, instruction->fn); + TypeTableEntry *fn_type = instruction->fn->type_entry; + TypeTableEntry *src_return_type = fn_type->data.fn.fn_type_id.return_type; + bool ret_has_bits = type_has_bits(src_return_type); + size_t fn_call_param_count = instruction->arg_count; + bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type); + size_t actual_param_count = fn_call_param_count + (first_arg_ret ? 1 : 0); + bool is_var_args = fn_type->data.fn.fn_type_id.is_var_args; + LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count); + size_t gen_param_index = 0; + if (first_arg_ret) { + zig_panic("TODO"); + //gen_param_values[gen_param_index] = node->data.fn_call_expr.tmp_ptr; + //gen_param_index += 1; + } + for (size_t call_i = 0; call_i < fn_call_param_count; call_i += 1) { + IrInstruction *param_instruction = instruction->args[call_i]; + LLVMValueRef param_value = ir_llvm_value(g, param_instruction); + assert(param_value); + TypeTableEntry *param_type = param_instruction->type_entry; + if (is_var_args || type_has_bits(param_type)) { + gen_param_values[gen_param_index] = param_value; + gen_param_index += 1; + } + } + + LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val, + gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, ""); + + if (src_return_type->id == TypeTableEntryIdUnreachable) { + return LLVMBuildUnreachable(g->builder); + } else if (!ret_has_bits) { + return nullptr; + } else if (first_arg_ret) { + zig_panic("TODO"); + //return node->data.fn_call_expr.tmp_ptr; + } else { + return result; + } +} + static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) { set_debug_source_node(g, instruction->source_node); @@ -2891,10 +2933,11 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_load_ptr(g, executable, (IrInstructionLoadPtr *)instruction); case IrInstructionIdVarPtr: return ir_render_var_ptr(g, executable, (IrInstructionVarPtr *)instruction); + case IrInstructionIdCall: + return ir_render_call(g, executable, (IrInstructionCall *)instruction); case IrInstructionIdSwitchBr: case IrInstructionIdPhi: case IrInstructionIdStorePtr: - case IrInstructionIdCall: case IrInstructionIdBuiltinCall: case IrInstructionIdContainerInitList: case IrInstructionIdContainerInitFields: @@ -2911,8 +2954,7 @@ static void ir_render(CodeGen *g, FnTableEntry *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); - if (current_block->ref_count == 0) - continue; + 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/src/ir.cpp b/src/ir.cpp index f0fb2c1d8e..3473d62279 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -21,6 +21,11 @@ struct IrAnalyze { IrBuilder old_irb; IrBuilder new_irb; IrExecContext exec_context; + ZigList<IrBasicBlock *> block_queue; + size_t block_queue_index; + size_t instruction_index; + TypeTableEntry *explicit_return_type; + ZigList<IrInstruction *> implicit_return_type_list; }; static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *scope); @@ -58,11 +63,6 @@ static void ir_ref_bb(IrBasicBlock *bb) { bb->ref_count += 1; } -static void ir_unref_bb(IrBasicBlock *bb) { - bb->ref_count -= 1; - assert(bb->ref_count != SIZE_MAX); -} - static void ir_ref_instruction(IrInstruction *instruction) { instruction->ref_count += 1; } @@ -349,6 +349,14 @@ static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node, return &call_instruction->base; } +static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction, + IrInstruction *fn, size_t arg_count, IrInstruction **args) +{ + IrInstruction *new_instruction = ir_build_call(irb, old_instruction->source_node, fn, arg_count, args); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + static IrInstruction *ir_build_builtin_call(IrBuilder *irb, AstNode *source_node, BuiltinFnEntry *fn, IrInstruction **args) { @@ -396,11 +404,11 @@ static IrInstruction *ir_build_br(IrBuilder *irb, AstNode *source_node, IrBasicB return &br_instruction->base; } -static IrInstruction *ir_build_br_from(IrBuilder *irb, IrInstruction *old_instruction, IrBasicBlock *dest_block) { - IrInstruction *new_instruction = ir_build_br(irb, old_instruction->source_node, dest_block); - ir_link_new_instruction(new_instruction, old_instruction); - return new_instruction; -} +//static IrInstruction *ir_build_br_from(IrBuilder *irb, IrInstruction *old_instruction, IrBasicBlock *dest_block) { +// IrInstruction *new_instruction = ir_build_br(irb, old_instruction->source_node, dest_block); +// ir_link_new_instruction(new_instruction, old_instruction); +// return new_instruction; +//} static IrInstruction *ir_build_un_op(IrBuilder *irb, AstNode *source_node, IrUnOp op_id, IrInstruction *value) { IrInstructionUnOp *br_instruction = ir_build_instruction<IrInstructionUnOp>(irb, source_node); @@ -1273,36 +1281,26 @@ static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext zig_unreachable(); } -static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext *scope, - IrExecutable *ir_executable, bool add_return, LValPurpose lval) -{ +IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) { assert(node->owner); IrBuilder ir_gen = {0}; IrBuilder *irb = &ir_gen; - irb->codegen = g; + irb->codegen = codegen; irb->exec = ir_executable; irb->current_basic_block = ir_build_basic_block(irb, "Entry"); // Entry block gets a reference because we enter it to begin. ir_ref_bb(irb->current_basic_block); - IrInstruction *result = ir_gen_node_extra(irb, node, scope, lval); + IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValPurposeNone); assert(result); - if (result == g->invalid_instruction) + if (result == codegen->invalid_instruction) return result; - if (add_return) - return ir_build_return(irb, result->source_node, result); - - return result; -} - -IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) { - bool add_return_no = false; - return ir_gen_add_return(codegen, node, scope, ir_executable, add_return_no, LValPurposeNone); + return ir_build_return(irb, result->source_node, result); } IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) { @@ -1315,8 +1313,7 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) { AstNode *body_node = fn_def_node->data.fn_def.body; BlockContext *scope = fn_def_node->data.fn_def.block_context; - bool add_return_yes = true; - return ir_gen_add_return(codegn, body_node, scope, ir_executable, add_return_yes, LValPurposeNone); + return ir_gen(codegn, body_node, scope, ir_executable); } /* @@ -1401,7 +1398,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc return false; } -static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, IrInstruction *parent_instruction, +static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) { assert(instruction_count >= 1); @@ -1465,7 +1462,7 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, IrInstruction *pa return ira->codegen->builtin_types.entry_invalid; } } else { - add_node_error(ira->codegen, parent_instruction->source_node, + add_node_error(ira->codegen, source_node, buf_sprintf("incompatible types: '%s' and '%s'", buf_ptr(&prev_type->name), buf_ptr(&cur_type->name))); @@ -1566,10 +1563,10 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, return ImplicitCastMatchResultNo; } -static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, IrInstruction *parent_instruction, +static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) { - return ir_determine_peer_types(ira, parent_instruction, instructions, instruction_count); + return ir_determine_peer_types(ira, source_node, instructions, instruction_count); } static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, @@ -1608,9 +1605,29 @@ static bool is_u8(TypeTableEntry *type) { static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb) { if (old_bb->other) return old_bb->other; - return ir_build_bb_from(&ira->new_irb, old_bb); + IrBasicBlock *new_bb = ir_build_bb_from(&ira->new_irb, old_bb); + ira->block_queue.append(new_bb); + return new_bb; } +static void ir_finish_bb(IrAnalyze *ira) { + ira->block_queue_index += 1; + + if (ira->block_queue_index < ira->block_queue.length) { + IrBasicBlock *old_bb = ira->block_queue.at(ira->block_queue_index); + ira->instruction_index = 0; + ira->new_irb.current_basic_block = ir_get_new_bb(ira, old_bb); + ira->old_irb.current_basic_block = old_bb; + } +} + +static void ir_inline_bb(IrAnalyze *ira, IrBasicBlock *old_bb) { + ira->instruction_index = 0; + + ira->old_irb.current_basic_block = old_bb; +} + + static ConstExprValue *ir_get_out_val(IrInstruction *instruction) { instruction->other = instruction; return &instruction->static_value; @@ -1942,8 +1959,11 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructi if (value == ira->codegen->invalid_instruction) { return ira->codegen->builtin_types.entry_invalid; } + ira->implicit_return_type_list.append(value); - return ir_build_return_from(&ira->new_irb, &return_instruction->base, value)->type_entry; + IrInstruction *new_instruction = ir_build_return_from(&ira->new_irb, &return_instruction->base, value); + ir_finish_bb(ira); + return new_instruction->type_entry; } static TypeTableEntry *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *const_instruction) { @@ -1991,10 +2011,10 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp } static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { - IrInstruction *op1 = bin_op_instruction->op1; - IrInstruction *op2 = bin_op_instruction->op2; + IrInstruction *op1 = bin_op_instruction->op1->other; + IrInstruction *op2 = bin_op_instruction->op2->other; IrInstruction *instructions[] = {op1, op2}; - TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, &bin_op_instruction->base, instructions, 2); + TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2); if (resolved_type->id == TypeTableEntryIdInvalid) return resolved_type; IrBinOp op_id = bin_op_instruction->op_id; @@ -2052,9 +2072,60 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp zig_unreachable(); } - zig_panic("TODO interpret bin_op_cmp"); + IrInstruction *casted_op1 = ir_get_casted_value(ira, op1, resolved_type); + if (casted_op1 == ira->codegen->invalid_instruction) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *casted_op2 = ir_get_casted_value(ira, op2, resolved_type); + if (casted_op2 == ira->codegen->invalid_instruction) + return ira->codegen->builtin_types.entry_invalid; + + ConstExprValue *op1_val = &casted_op1->static_value; + ConstExprValue *op2_val = &casted_op2->static_value; + if (op1_val->ok && op2_val->ok) { + bool type_can_gt_lt_cmp = (resolved_type->id == TypeTableEntryIdNumLitFloat || + resolved_type->id == TypeTableEntryIdNumLitInt || + resolved_type->id == TypeTableEntryIdFloat || + resolved_type->id == TypeTableEntryIdInt); + bool answer; + if (type_can_gt_lt_cmp) { + bool (*bignum_cmp)(BigNum *, BigNum *); + if (op_id == IrBinOpCmpEq) { + bignum_cmp = bignum_cmp_eq; + } else if (op_id == IrBinOpCmpNotEq) { + bignum_cmp = bignum_cmp_neq; + } else if (op_id == IrBinOpCmpLessThan) { + bignum_cmp = bignum_cmp_lt; + } else if (op_id == IrBinOpCmpGreaterThan) { + bignum_cmp = bignum_cmp_gt; + } else if (op_id == IrBinOpCmpLessOrEq) { + bignum_cmp = bignum_cmp_lte; + } else if (op_id == IrBinOpCmpGreaterOrEq) { + bignum_cmp = bignum_cmp_gte; + } else { + zig_unreachable(); + } - ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id, op1->other, op2->other); + answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum); + } else { + bool are_equal = const_values_equal(op1_val, op2_val, resolved_type); + if (op_id == IrBinOpCmpEq) { + answer = are_equal; + } else if (op_id == IrBinOpCmpNotEq) { + answer = !are_equal; + } else { + zig_unreachable(); + } + } + + ConstExprValue *out_val = ir_get_out_val(&bin_op_instruction->base); + out_val->ok = true; + out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; + out_val->data.x_bool = answer; + return ira->codegen->builtin_types.entry_bool; + } + + ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id, casted_op1, casted_op2); return ira->codegen->builtin_types.entry_bool; } @@ -2158,7 +2229,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp IrInstruction *op1 = bin_op_instruction->op1->other; IrInstruction *op2 = bin_op_instruction->op2->other; IrInstruction *instructions[] = {op1, op2}; - TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, &bin_op_instruction->base, instructions, 2); + TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2); if (resolved_type->id == TypeTableEntryIdInvalid) return resolved_type; IrBinOp op_id = bin_op_instruction->op_id; @@ -2393,6 +2464,13 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction ir_link_new_instruction(cast_instruction, &call_instruction->base); return cast_instruction->type_entry; + } else if (fn_ref->type_entry->id == TypeTableEntryIdFn) { + // TODO fully port over the fn call analyze code to IR + FnTableEntry *fn_table_entry = fn_ref->static_value.data.x_fn; + + ir_build_call_from(&ira->new_irb, &call_instruction->base, + call_instruction->fn, call_instruction->arg_count, call_instruction->args); + return fn_table_entry->type_entry; } else { zig_panic("TODO analyze more fn call types"); } @@ -3777,9 +3855,15 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr *br_instruction) { IrBasicBlock *old_dest_block = br_instruction->dest_block; - IrBasicBlock *new_bb = ir_get_new_bb(ira, old_dest_block); - ir_build_br_from(&ira->new_irb, &br_instruction->base, new_bb); + + // TODO detect backward jumps + + ir_inline_bb(ira, old_dest_block); return ira->codegen->builtin_types.entry_unreachable; + + //IrBasicBlock *new_bb = ir_get_new_bb(ira, old_dest_block); + //ir_build_br_from(&ira->new_irb, &br_instruction->base, new_bb); + //return ira->codegen->builtin_types.entry_unreachable; } static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructionCondBr *cond_br_instruction) { @@ -3787,26 +3871,20 @@ static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstruct IrInstruction *condition = ir_get_casted_value(ira, cond_br_instruction->condition->other, bool_type); if (condition == ira->codegen->invalid_instruction) return ira->codegen->builtin_types.entry_invalid; - + + // TODO detect backward jumps if (condition->static_value.ok) { - IrBasicBlock *old_dest_block; - IrBasicBlock *old_ignored_block; - if (condition->static_value.data.x_bool) { - old_dest_block = cond_br_instruction->then_block; - old_ignored_block = cond_br_instruction->else_block; - } else { - old_dest_block = cond_br_instruction->else_block; - old_ignored_block = cond_br_instruction->then_block; - } - ir_unref_bb(old_ignored_block); - IrBasicBlock *new_bb = ir_get_new_bb(ira, old_dest_block); - ir_build_br_from(&ira->new_irb, &cond_br_instruction->base, new_bb); + IrBasicBlock *old_dest_block = condition->static_value.data.x_bool ? + cond_br_instruction->then_block : cond_br_instruction->else_block; + + ir_inline_bb(ira, old_dest_block); return ira->codegen->builtin_types.entry_unreachable; } IrBasicBlock *new_then_block = ir_get_new_bb(ira, cond_br_instruction->then_block); IrBasicBlock *new_else_block = ir_get_new_bb(ira, cond_br_instruction->else_block); ir_build_cond_br_from(&ira->new_irb, &cond_br_instruction->base, condition, new_then_block, new_else_block); + ir_finish_bb(ira); return ira->codegen->builtin_types.entry_unreachable; } @@ -3862,7 +3940,9 @@ static TypeTableEntry *ir_analyze_instruction_builtin_call(IrAnalyze *ira, static TypeTableEntry *ir_analyze_instruction_unreachable(IrAnalyze *ira, IrInstructionUnreachable *unreachable_instruction) { - return ir_build_unreachable_from(&ira->new_irb, &unreachable_instruction->base)->type_entry; + IrInstruction *new_instruction = ir_build_unreachable_from(&ira->new_irb, &unreachable_instruction->base); + ir_finish_bb(ira); + return new_instruction->type_entry; } static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPhi *phi_instruction) { @@ -3889,7 +3969,7 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP return first_value->type_entry; } - TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, &phi_instruction->base, + TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, phi_instruction->base.source_node, new_incoming_values.items, new_incoming_values.length); if (resolved_type->id == TypeTableEntryIdInvalid) return resolved_type; @@ -4014,8 +4094,6 @@ static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *ins { TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction); instruction->type_entry = instruction_type; - if (instruction->other) - instruction->other->type_entry = instruction_type; IrInstruction *casted_instruction = ir_get_casted_value(ira, instruction, expected_type); return casted_instruction->type_entry; @@ -4024,11 +4102,12 @@ static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *ins // 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. TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec, - TypeTableEntry *expected_type) + TypeTableEntry *expected_type, AstNode *expected_type_source_node) { IrAnalyze ir_analyze_data = {}; IrAnalyze *ira = &ir_analyze_data; ira->codegen = codegen; + ira->explicit_return_type = expected_type; ira->old_irb.codegen = codegen; ira->old_irb.exec = old_exec; @@ -4039,34 +4118,27 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl ira->exec_context.mem_slot_count = ira->old_irb.exec->mem_slot_count; ira->exec_context.mem_slot_list = allocate<ConstExprValue>(ira->exec_context.mem_slot_count); - TypeTableEntry *return_type = ira->codegen->builtin_types.entry_void; - for (size_t bb_i = 0; bb_i < ira->old_irb.exec->basic_block_list.length; bb_i += 1) { - ira->old_irb.current_basic_block = ira->old_irb.exec->basic_block_list.at(bb_i); - if (ira->old_irb.current_basic_block->ref_count == 0) - continue; + IrBasicBlock *old_entry_bb = ira->old_irb.exec->basic_block_list.at(0); + IrBasicBlock *new_entry_bb = ir_get_new_bb(ira, old_entry_bb); + ir_ref_bb(new_entry_bb); + ira->old_irb.current_basic_block = old_entry_bb; + ira->new_irb.current_basic_block = new_entry_bb; + ira->block_queue_index = 0; + ira->instruction_index = 0; - ira->new_irb.current_basic_block = ir_get_new_bb(ira, ira->old_irb.current_basic_block); + while (ira->block_queue_index < ira->block_queue.length) { + IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index); + TypeTableEntry *return_type = ir_analyze_instruction(ira, old_instruction, nullptr); - return_type = ira->codegen->builtin_types.entry_void; + // unreachable instructions do their own control flow. + if (return_type->id == TypeTableEntryIdUnreachable) + continue; - for (size_t instr_i = 0; instr_i < ira->old_irb.current_basic_block->instruction_list.length; instr_i += 1) { - IrInstruction *instruction = ira->old_irb.current_basic_block->instruction_list.at(instr_i); - if (return_type->id == TypeTableEntryIdUnreachable) { - // TODO - //add_node_error(ira->codegen, first_executing_node(instruction->source_node), - // buf_sprintf("unreachable code")); - break; - } - bool is_last = (instr_i == ira->old_irb.current_basic_block->instruction_list.length - 1); - TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr; - return_type = ir_analyze_instruction(ira, instruction, passed_expected_type); - } + ira->instruction_index += 1; } - // Give entry block a ref - ir_ref_bb(ira->new_irb.exec->basic_block_list.at(0)); - - return return_type; + return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items, + ira->implicit_return_type_list.length); } static bool ir_builtin_call_has_side_effects(IrInstructionBuiltinCall *call_instruction) { diff --git a/src/ir.hpp b/src/ir.hpp index af1dfe96ec..6c1c9a9fc9 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -14,7 +14,7 @@ IrInstruction *ir_gen(CodeGen *g, AstNode *node, BlockContext *scope, IrExecutab IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry); TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable, - TypeTableEntry *expected_type); + TypeTableEntry *expected_type, AstNode *expected_type_source_node); bool ir_has_side_effects(IrInstruction *instruction); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index ffc06d841d..d1c8bf52e4 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -62,6 +62,12 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const fprintf(irp->f, "&"); ir_print_const_value(irp, type_entry->data.pointer.child_type, const_val->data.x_ptr.ptr[0]); break; + case TypeTableEntryIdFn: + { + FnTableEntry *fn_entry = const_val->data.x_fn; + fprintf(irp->f, "%s", buf_ptr(&fn_entry->symbol_name)); + break; + } case TypeTableEntryIdVar: case TypeTableEntryIdFloat: case TypeTableEntryIdArray: @@ -73,7 +79,6 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const case TypeTableEntryIdPureError: case TypeTableEntryIdEnum: case TypeTableEntryIdUnion: - case TypeTableEntryIdFn: case TypeTableEntryIdTypeDecl: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: |
