| ... | ... | @@ -643,8 +643,8 @@ static IrInstruction *ir_build_phi_from(IrBuilder *irb, IrInstruction *old_instr |
| 643 | 643 | return new_instruction; |
| 644 | 644 | } |
| 645 | 645 | |
| 646 | | static IrInstruction *ir_build_br(IrBuilder *irb, AstNode *source_node, IrBasicBlock *dest_block, bool is_inline) { |
| 647 | | IrInstructionBr *br_instruction = ir_build_instruction<IrInstructionBr>(irb, source_node); |
| 646 | static IrInstruction *ir_create_br(IrBuilder *irb, AstNode *source_node, IrBasicBlock *dest_block, bool is_inline) { |
| 647 | IrInstructionBr *br_instruction = ir_create_instruction<IrInstructionBr>(irb->exec, source_node); |
| 648 | 648 | br_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable; |
| 649 | 649 | br_instruction->base.static_value.special = ConstValSpecialStatic; |
| 650 | 650 | br_instruction->dest_block = dest_block; |
| ... | ... | @@ -655,6 +655,12 @@ static IrInstruction *ir_build_br(IrBuilder *irb, AstNode *source_node, IrBasicB |
| 655 | 655 | return &br_instruction->base; |
| 656 | 656 | } |
| 657 | 657 | |
| 658 | static IrInstruction *ir_build_br(IrBuilder *irb, AstNode *source_node, IrBasicBlock *dest_block, bool is_inline) { |
| 659 | IrInstruction *instruction = ir_create_br(irb, source_node, dest_block, is_inline); |
| 660 | ir_instruction_append(irb->current_basic_block, instruction); |
| 661 | return instruction; |
| 662 | } |
| 663 | |
| 658 | 664 | static IrInstruction *ir_build_br_from(IrBuilder *irb, IrInstruction *old_instruction, IrBasicBlock *dest_block) { |
| 659 | 665 | IrInstruction *new_instruction = ir_build_br(irb, old_instruction->source_node, dest_block, false); |
| 660 | 666 | ir_link_new_instruction(new_instruction, old_instruction); |
| ... | ... | @@ -2438,6 +2444,55 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) { |
| 2438 | 2444 | return ir_build_phi(irb, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); |
| 2439 | 2445 | } |
| 2440 | 2446 | |
| 2447 | static LabelTableEntry *find_label(IrExecutable *exec, BlockContext *orig_context, Buf *name) { |
| 2448 | BlockContext *context = orig_context; |
| 2449 | while (context) { |
| 2450 | auto entry = context->label_table.maybe_get(name); |
| 2451 | if (entry) { |
| 2452 | return entry->value; |
| 2453 | } |
| 2454 | context = context->parent; |
| 2455 | } |
| 2456 | return nullptr; |
| 2457 | } |
| 2458 | |
| 2459 | static IrInstruction *ir_gen_label(IrBuilder *irb, AstNode *node) { |
| 2460 | assert(node->type == NodeTypeLabel); |
| 2461 | |
| 2462 | Buf *label_name = node->data.label.name; |
| 2463 | IrBasicBlock *label_block = ir_build_basic_block(irb, buf_ptr(label_name)); |
| 2464 | LabelTableEntry *label = allocate<LabelTableEntry>(1); |
| 2465 | label->decl_node = node; |
| 2466 | label->bb = label_block; |
| 2467 | irb->exec->all_labels.append(label); |
| 2468 | |
| 2469 | LabelTableEntry *existing_label = find_label(irb->exec, node->block_context, label_name); |
| 2470 | if (existing_label) { |
| 2471 | ErrorMsg *msg = add_node_error(irb->codegen, node, |
| 2472 | buf_sprintf("duplicate label name '%s'", buf_ptr(label_name))); |
| 2473 | add_error_note(irb->codegen, msg, existing_label->decl_node, buf_sprintf("other label here")); |
| 2474 | return irb->codegen->invalid_instruction; |
| 2475 | } else { |
| 2476 | node->block_context->label_table.put(label_name, label); |
| 2477 | } |
| 2478 | |
| 2479 | bool is_inline = (node->block_context->fn_entry == nullptr); |
| 2480 | ir_build_br(irb, node, label_block, is_inline); |
| 2481 | ir_set_cursor_at_end(irb, label_block); |
| 2482 | return ir_build_const_void(irb, node); |
| 2483 | } |
| 2484 | |
| 2485 | static IrInstruction *ir_gen_goto(IrBuilder *irb, AstNode *node) { |
| 2486 | assert(node->type == NodeTypeGoto); |
| 2487 | |
| 2488 | // make a placeholder unreachable statement and a note to come back and |
| 2489 | // replace the instruction with a branch instruction |
| 2490 | node->data.goto_expr.bb = irb->current_basic_block; |
| 2491 | node->data.goto_expr.instruction_index = irb->current_basic_block->instruction_list.length; |
| 2492 | irb->exec->goto_list.append(node); |
| 2493 | return ir_build_unreachable(irb, node); |
| 2494 | } |
| 2495 | |
| 2441 | 2496 | static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContext *block_context, |
| 2442 | 2497 | LValPurpose lval) |
| 2443 | 2498 | { |
| ... | ... | @@ -2491,13 +2546,15 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex |
| 2491 | 2546 | return ir_gen_if_var_expr(irb, node); |
| 2492 | 2547 | case NodeTypeSwitchExpr: |
| 2493 | 2548 | return ir_gen_switch_expr(irb, node); |
| 2549 | case NodeTypeLabel: |
| 2550 | return ir_gen_label(irb, node); |
| 2551 | case NodeTypeGoto: |
| 2552 | return ir_gen_goto(irb, node); |
| 2494 | 2553 | case NodeTypeUnwrapErrorExpr: |
| 2495 | 2554 | case NodeTypeDefer: |
| 2496 | 2555 | case NodeTypeSliceExpr: |
| 2497 | | case NodeTypeGoto: |
| 2498 | 2556 | case NodeTypeBreak: |
| 2499 | 2557 | case NodeTypeContinue: |
| 2500 | | case NodeTypeLabel: |
| 2501 | 2558 | case NodeTypeCharLiteral: |
| 2502 | 2559 | case NodeTypeZeroesLiteral: |
| 2503 | 2560 | case NodeTypeErrorType: |
| ... | ... | @@ -2533,11 +2590,46 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *s |
| 2533 | 2590 | return ir_gen_node_extra(irb, node, scope, LValPurposeNone); |
| 2534 | 2591 | } |
| 2535 | 2592 | |
| 2593 | static bool ir_goto_pass2(IrBuilder *irb) { |
| 2594 | for (size_t i = 0; i < irb->exec->goto_list.length; i += 1) { |
| 2595 | AstNode *goto_node = irb->exec->goto_list.at(i); |
| 2596 | size_t instruction_index = goto_node->data.goto_expr.instruction_index; |
| 2597 | IrInstruction **slot = &goto_node->data.goto_expr.bb->instruction_list.at(instruction_index); |
| 2598 | IrInstruction *old_instruction = *slot; |
| 2599 | |
| 2600 | Buf *label_name = goto_node->data.goto_expr.name; |
| 2601 | LabelTableEntry *label = find_label(irb->exec, goto_node->block_context, label_name); |
| 2602 | if (!label) { |
| 2603 | add_node_error(irb->codegen, goto_node, |
| 2604 | buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); |
| 2605 | return false; |
| 2606 | } |
| 2607 | label->used = true; |
| 2608 | |
| 2609 | bool is_inline = goto_node->data.goto_expr.is_inline || (goto_node->block_context->fn_entry == nullptr); |
| 2610 | IrInstruction *new_instruction = ir_create_br(irb, goto_node, label->bb, is_inline); |
| 2611 | new_instruction->ref_count = old_instruction->ref_count; |
| 2612 | *slot = new_instruction; |
| 2613 | } |
| 2614 | |
| 2615 | for (size_t i = 0; i < irb->exec->all_labels.length; i += 1) { |
| 2616 | LabelTableEntry *label = irb->exec->all_labels.at(i); |
| 2617 | if (!label->used) { |
| 2618 | add_node_error(irb->codegen, label->decl_node, |
| 2619 | buf_sprintf("label '%s' defined but not used", |
| 2620 | buf_ptr(label->decl_node->data.label.name))); |
| 2621 | return false; |
| 2622 | } |
| 2623 | } |
| 2624 | |
| 2625 | return true; |
| 2626 | } |
| 2627 | |
| 2536 | 2628 | IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) { |
| 2537 | 2629 | assert(node->owner); |
| 2538 | 2630 | |
| 2539 | | IrBuilder ir_gen = {0}; |
| 2540 | | IrBuilder *irb = &ir_gen; |
| 2631 | IrBuilder ir_builder = {0}; |
| 2632 | IrBuilder *irb = &ir_builder; |
| 2541 | 2633 | |
| 2542 | 2634 | irb->codegen = codegen; |
| 2543 | 2635 | irb->exec = ir_executable; |
| ... | ... | @@ -2549,10 +2641,16 @@ IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrEx |
| 2549 | 2641 | IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValPurposeNone); |
| 2550 | 2642 | assert(result); |
| 2551 | 2643 | |
| 2644 | IrInstruction *return_instruction = ir_build_return(irb, result->source_node, result); |
| 2645 | assert(return_instruction); |
| 2646 | |
| 2552 | 2647 | if (result == codegen->invalid_instruction) |
| 2553 | | return result; |
| 2648 | return codegen->invalid_instruction; |
| 2554 | 2649 | |
| 2555 | | return ir_build_return(irb, result->source_node, result); |
| 2650 | if (!ir_goto_pass2(irb)) |
| 2651 | return codegen->invalid_instruction; |
| 2652 | |
| 2653 | return return_instruction; |
| 2556 | 2654 | } |
| 2557 | 2655 | |
| 2558 | 2656 | IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) { |
| ... | ... | @@ -7241,19 +7339,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { |
| 7241 | 7339 | // } |
| 7242 | 7340 | // zig_unreachable(); |
| 7243 | 7341 | //} |
| 7244 | | //static TypeTableEntry *analyze_goto_pass1(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 7245 | | // TypeTableEntry *expected_type, AstNode *node) |
| 7246 | | //{ |
| 7247 | | // assert(node->type == NodeTypeGoto); |
| 7248 | | // |
| 7249 | | // FnTableEntry *fn_table_entry = context->fn_entry; |
| 7250 | | // assert(fn_table_entry); |
| 7251 | | // |
| 7252 | | // fn_table_entry->goto_list.append(node); |
| 7253 | | // |
| 7254 | | // return g->builtin_types.entry_unreachable; |
| 7255 | | //} |
| 7256 | | // |
| 7257 | 7342 | //static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 7258 | 7343 | // AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name, |
| 7259 | 7344 | // AstNode *out_node) |
| ... | ... | @@ -7710,69 +7795,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { |
| 7710 | 7795 | // return g->builtin_types.entry_void; |
| 7711 | 7796 | //} |
| 7712 | 7797 | // |
| 7713 | | //static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, |
| 7714 | | // TypeTableEntry *expected_type, AstNode *node) |
| 7715 | | //{ |
| 7716 | | // BlockContext *child_context = new_block_context(node, parent_context); |
| 7717 | | // node->data.block.child_block = child_context; |
| 7718 | | // TypeTableEntry *return_type = g->builtin_types.entry_void; |
| 7719 | | // |
| 7720 | | // for (size_t i = 0; i < node->data.block.statements.length; i += 1) { |
| 7721 | | // AstNode *child = node->data.block.statements.at(i); |
| 7722 | | // if (child->type == NodeTypeLabel) { |
| 7723 | | // FnTableEntry *fn_table_entry = child_context->fn_entry; |
| 7724 | | // assert(fn_table_entry); |
| 7725 | | // |
| 7726 | | // LabelTableEntry *label = allocate<LabelTableEntry>(1); |
| 7727 | | // label->decl_node = child; |
| 7728 | | // label->entered_from_fallthrough = (return_type->id != TypeTableEntryIdUnreachable); |
| 7729 | | // |
| 7730 | | // child->block_context = child_context; |
| 7731 | | // child->data.label.label_entry = label; |
| 7732 | | // fn_table_entry->all_labels.append(label); |
| 7733 | | // |
| 7734 | | // child_context->label_table.put(child->data.label.name, label); |
| 7735 | | // |
| 7736 | | // return_type = g->builtin_types.entry_void; |
| 7737 | | // continue; |
| 7738 | | // } |
| 7739 | | // if (return_type->id == TypeTableEntryIdUnreachable) { |
| 7740 | | // if (is_node_void_expr(child)) { |
| 7741 | | // // {unreachable;void;void} is allowed. |
| 7742 | | // // ignore void statements once we enter unreachable land. |
| 7743 | | // analyze_expression(g, import, child_context, g->builtin_types.entry_void, child); |
| 7744 | | // continue; |
| 7745 | | // } |
| 7746 | | // add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code")); |
| 7747 | | // break; |
| 7748 | | // } |
| 7749 | | // bool is_last = (i == node->data.block.statements.length - 1); |
| 7750 | | // TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr; |
| 7751 | | // return_type = analyze_expression(g, import, child_context, passed_expected_type, child); |
| 7752 | | // if (child->type == NodeTypeDefer && return_type->id != TypeTableEntryIdInvalid) { |
| 7753 | | // // defer starts a new block context |
| 7754 | | // child_context = child->data.defer.child_block; |
| 7755 | | // assert(child_context); |
| 7756 | | // } |
| 7757 | | // if (!is_last) { |
| 7758 | | // validate_voided_expr(g, child, return_type); |
| 7759 | | // } |
| 7760 | | // } |
| 7761 | | // node->data.block.nested_block = child_context; |
| 7762 | | // |
| 7763 | | // ConstExprValue *const_val = &node->data.block.resolved_expr.const_val; |
| 7764 | | // if (node->data.block.statements.length == 0) { |
| 7765 | | // const_val->ok = true; |
| 7766 | | // } else if (node->data.block.statements.length == 1) { |
| 7767 | | // AstNode *only_node = node->data.block.statements.at(0); |
| 7768 | | // ConstExprValue *other_const_val = &get_resolved_expr(only_node)->const_val; |
| 7769 | | // if (other_const_val->ok) { |
| 7770 | | // *const_val = *other_const_val; |
| 7771 | | // } |
| 7772 | | // } |
| 7773 | | // |
| 7774 | | // return return_type; |
| 7775 | | //} |
| 7776 | 7798 | // |
| 7777 | 7799 | //static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import, |
| 7778 | 7800 | // BlockContext *context, AstNode *node, Buf *err_name) |
| ... | ... | @@ -7841,51 +7863,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { |
| 7841 | 7863 | // |
| 7842 | 7864 | // return ir_build_return(irb, source_node, value); |
| 7843 | 7865 | //} |
| 7844 | | /* |
| 7845 | | static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 7846 | | assert(node->type == NodeTypeGoto); |
| 7847 | | Buf *label_name = node->data.goto_expr.name; |
| 7848 | | BlockContext *context = node->block_context; |
| 7849 | | assert(context); |
| 7850 | | LabelTableEntry *label = find_label(g, context, label_name); |
| 7851 | | |
| 7852 | | if (!label) { |
| 7853 | | add_node_error(g, node, buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); |
| 7854 | | return; |
| 7855 | | } |
| 7856 | | |
| 7857 | | label->used = true; |
| 7858 | | node->data.goto_expr.label_entry = label; |
| 7859 | | } |
| 7860 | | |
| 7861 | | for (size_t i = 0; i < fn_table_entry->goto_list.length; i += 1) { |
| 7862 | | AstNode *goto_node = fn_table_entry->goto_list.at(i); |
| 7863 | | assert(goto_node->type == NodeTypeGoto); |
| 7864 | | analyze_goto_pass2(g, import, goto_node); |
| 7865 | | } |
| 7866 | | |
| 7867 | | for (size_t i = 0; i < fn_table_entry->all_labels.length; i += 1) { |
| 7868 | | LabelTableEntry *label = fn_table_entry->all_labels.at(i); |
| 7869 | | if (!label->used) { |
| 7870 | | add_node_error(g, label->decl_node, |
| 7871 | | buf_sprintf("label '%s' defined but not used", |
| 7872 | | buf_ptr(label->decl_node->data.label.name))); |
| 7873 | | } |
| 7874 | | } |
| 7875 | | */ |
| 7876 | | |
| 7877 | | //static LabelTableEntry *find_label(CodeGen *g, BlockContext *orig_context, Buf *name) { |
| 7878 | | // BlockContext *context = orig_context; |
| 7879 | | // while (context && context->fn_entry) { |
| 7880 | | // auto entry = context->label_table.maybe_get(name); |
| 7881 | | // if (entry) { |
| 7882 | | // return entry->value; |
| 7883 | | // } |
| 7884 | | // context = context->parent; |
| 7885 | | // } |
| 7886 | | // return nullptr; |
| 7887 | | //} |
| 7888 | | |
| 7889 | 7866 | // |
| 7890 | 7867 | //static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) { |
| 7891 | 7868 | // assert(node->type == NodeTypeFnCallExpr); |
| ... | ... | @@ -9180,20 +9157,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no |
| 9180 | 9157 | // return nullptr; |
| 9181 | 9158 | //} |
| 9182 | 9159 | // |
| 9183 | | //static LLVMValueRef gen_goto(CodeGen *g, AstNode *node) { |
| 9184 | | // assert(node->type == NodeTypeGoto); |
| 9185 | | // |
| 9186 | | // // generate defers for blocks that we exit |
| 9187 | | // LabelTableEntry *label = node->data.goto_expr.label_entry; |
| 9188 | | // BlockContext *this_context = node->block_context; |
| 9189 | | // BlockContext *target_context = label->decl_node->block_context; |
| 9190 | | // gen_defers_for_block(g, this_context, target_context, false, false); |
| 9191 | | // |
| 9192 | | // set_debug_source_node(g, node); |
| 9193 | | // LLVMBuildBr(g->builder, node->data.goto_expr.label_entry->basic_block); |
| 9194 | | // return nullptr; |
| 9195 | | //} |
| 9196 | | // |
| 9197 | 9160 | //static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { |
| 9198 | 9161 | // AstNode *init_expr = node->data.variable_declaration.expr; |
| 9199 | 9162 | // if (node->data.variable_declaration.is_const && init_expr) { |
| ... | ... | @@ -9249,18 +9212,3 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no |
| 9249 | 9212 | // } |
| 9250 | 9213 | // return result; |
| 9251 | 9214 | //} |
| 9252 | | // |
| 9253 | | //static LLVMValueRef gen_label(CodeGen *g, AstNode *node) { |
| 9254 | | // assert(node->type == NodeTypeLabel); |
| 9255 | | // |
| 9256 | | // LabelTableEntry *label = node->data.label.label_entry; |
| 9257 | | // assert(label); |
| 9258 | | // |
| 9259 | | // LLVMBasicBlockRef basic_block = label->basic_block; |
| 9260 | | // if (label->entered_from_fallthrough) { |
| 9261 | | // set_debug_source_node(g, node); |
| 9262 | | // LLVMBuildBr(g->builder, basic_block); |
| 9263 | | // } |
| 9264 | | // LLVMPositionBuilderAtEnd(g->builder, basic_block); |
| 9265 | | // return nullptr; |
| 9266 | | //} |