authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-26 23:16:38-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-26 23:16:38-05:00
loga52ede6494d44865fcf05591eaf5715d8bd1dc4a
tree54d336044dce404d17283f01c4643f83afa0572f
parenta3db60b5d726004cbb5d7235893a3e148b493096

IR: support goto and labels


4 files changed, 143 insertions(+), 172 deletions(-)

src/all_types.hpp+6-12
...@@ -37,6 +37,8 @@ struct IrExecutable {...@@ -37,6 +37,8 @@ struct IrExecutable {
37 size_t mem_slot_count;37 size_t mem_slot_count;
38 size_t next_debug_id;38 size_t next_debug_id;
39 bool invalid;39 bool invalid;
40 ZigList<LabelTableEntry *> all_labels;
41 ZigList<AstNode *> goto_list;
40};42};
4143
42enum OutType {44enum OutType {
...@@ -554,16 +556,15 @@ struct AstNodeSwitchRange {...@@ -554,16 +556,15 @@ struct AstNodeSwitchRange {
554556
555struct AstNodeLabel {557struct AstNodeLabel {
556 Buf *name;558 Buf *name;
557
558 // populated by semantic analyzer
559 LabelTableEntry *label_entry;
560};559};
561560
562struct AstNodeGoto {561struct AstNodeGoto {
563 Buf *name;562 Buf *name;
563 bool is_inline;
564564
565 // populated by semantic analyzer565 // populated by semantic analyzer
566 LabelTableEntry *label_entry;566 IrBasicBlock *bb;
567 size_t instruction_index;
567};568};
568569
569struct AsmOutput {570struct AsmOutput {
...@@ -1059,7 +1060,6 @@ struct FnTableEntry {...@@ -1059,7 +1060,6 @@ struct FnTableEntry {
1059 ImportTableEntry *import_entry;1060 ImportTableEntry *import_entry;
1060 // Required to be a pre-order traversal of the AST. (parents must come before children)1061 // Required to be a pre-order traversal of the AST. (parents must come before children)
1061 ZigList<BlockContext *> all_block_contexts;1062 ZigList<BlockContext *> all_block_contexts;
1062 ZigList<LabelTableEntry *> all_labels;
1063 Buf symbol_name;1063 Buf symbol_name;
1064 TypeTableEntry *type_entry; // function type1064 TypeTableEntry *type_entry; // function type
1065 bool internal_linkage;1065 bool internal_linkage;
...@@ -1082,7 +1082,6 @@ struct FnTableEntry {...@@ -1082,7 +1082,6 @@ struct FnTableEntry {
1082 ZigList<IrInstructionCast *> cast_alloca_list;1082 ZigList<IrInstructionCast *> cast_alloca_list;
1083 ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;1083 ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
1084 ZigList<VariableTableEntry *> variable_list;1084 ZigList<VariableTableEntry *> variable_list;
1085 ZigList<AstNode *> goto_list;
1086};1085};
10871086
1088enum BuiltinFnId {1087enum BuiltinFnId {
...@@ -1319,9 +1318,8 @@ struct ErrorTableEntry {...@@ -1319,9 +1318,8 @@ struct ErrorTableEntry {
13191318
1320struct LabelTableEntry {1319struct LabelTableEntry {
1321 AstNode *decl_node;1320 AstNode *decl_node;
1322 LLVMBasicBlockRef basic_block;1321 IrBasicBlock *bb;
1323 bool used;1322 bool used;
1324 bool entered_from_fallthrough;
1325};1323};
13261324
1327struct BlockContext {1325struct BlockContext {
...@@ -1427,10 +1425,6 @@ struct IrInstruction {...@@ -1427,10 +1425,6 @@ struct IrInstruction {
1427 size_t ref_count;1425 size_t ref_count;
1428 IrInstruction *other;1426 IrInstruction *other;
1429 ReturnKnowledge return_knowledge;1427 ReturnKnowledge return_knowledge;
1430 // if this is true, this instruction should not cause compile errors.
1431 // for example, we can write to a variable with src_is_const true but
1432 // gen_is_const false.
1433 bool gen_only;
1434};1428};
14351429
1436struct IrInstructionCondBr {1430struct IrInstructionCondBr {
src/ast_render.cpp+13-2
...@@ -356,6 +356,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -356,6 +356,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
356 switch (node->type) {356 switch (node->type) {
357 case NodeTypeSwitchProng:357 case NodeTypeSwitchProng:
358 case NodeTypeSwitchRange:358 case NodeTypeSwitchRange:
359 case NodeTypeLabel:
359 zig_unreachable();360 zig_unreachable();
360 case NodeTypeRoot:361 case NodeTypeRoot:
361 for (size_t i = 0; i < node->data.root.top_level_decls.length; i += 1) {362 for (size_t i = 0; i < node->data.root.top_level_decls.length; i += 1) {
...@@ -426,6 +427,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -426,6 +427,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
426 ar->indent += ar->indent_size;427 ar->indent += ar->indent_size;
427 for (size_t i = 0; i < node->data.block.statements.length; i += 1) {428 for (size_t i = 0; i < node->data.block.statements.length; i += 1) {
428 AstNode *statement = node->data.block.statements.at(i);429 AstNode *statement = node->data.block.statements.at(i);
430 if (statement->type == NodeTypeLabel) {
431 ar->indent -= ar->indent_size;
432 print_indent(ar);
433 fprintf(ar->f, "%s:\n", buf_ptr(statement->data.label.name));
434 ar->indent += ar->indent_size;
435 continue;
436 }
429 print_indent(ar);437 print_indent(ar);
430 render_node_grouped(ar, statement);438 render_node_grouped(ar, statement);
431 if (i != node->data.block.statements.length - 1)439 if (i != node->data.block.statements.length - 1)
...@@ -771,6 +779,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -771,6 +779,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
771 fprintf(ar->f, "}");779 fprintf(ar->f, "}");
772 break;780 break;
773 }781 }
782 case NodeTypeGoto:
783 {
784 fprintf(ar->f, "goto %s", buf_ptr(node->data.goto_expr.name));
785 break;
786 }
774 case NodeTypeFnDecl:787 case NodeTypeFnDecl:
775 case NodeTypeParamDecl:788 case NodeTypeParamDecl:
776 case NodeTypeErrorValueDecl:789 case NodeTypeErrorValueDecl:
...@@ -781,8 +794,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -781,8 +794,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
781 case NodeTypeUse:794 case NodeTypeUse:
782 case NodeTypeZeroesLiteral:795 case NodeTypeZeroesLiteral:
783 case NodeTypeForExpr:796 case NodeTypeForExpr:
784 case NodeTypeLabel:
785 case NodeTypeGoto:
786 case NodeTypeBreak:797 case NodeTypeBreak:
787 case NodeTypeContinue:798 case NodeTypeContinue:
788 zig_panic("TODO more ast rendering");799 zig_panic("TODO more ast rendering");
src/ir.cpp+106-158
...@@ -643,8 +643,8 @@ static IrInstruction *ir_build_phi_from(IrBuilder *irb, IrInstruction *old_instr...@@ -643,8 +643,8 @@ static IrInstruction *ir_build_phi_from(IrBuilder *irb, IrInstruction *old_instr
643 return new_instruction;643 return new_instruction;
644}644}
645645
646static IrInstruction *ir_build_br(IrBuilder *irb, AstNode *source_node, IrBasicBlock *dest_block, bool is_inline) {646static IrInstruction *ir_create_br(IrBuilder *irb, AstNode *source_node, IrBasicBlock *dest_block, bool is_inline) {
647 IrInstructionBr *br_instruction = ir_build_instruction<IrInstructionBr>(irb, source_node);647 IrInstructionBr *br_instruction = ir_create_instruction<IrInstructionBr>(irb->exec, source_node);
648 br_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable;648 br_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable;
649 br_instruction->base.static_value.special = ConstValSpecialStatic;649 br_instruction->base.static_value.special = ConstValSpecialStatic;
650 br_instruction->dest_block = dest_block;650 br_instruction->dest_block = dest_block;
...@@ -655,6 +655,12 @@ static IrInstruction *ir_build_br(IrBuilder *irb, AstNode *source_node, IrBasicB...@@ -655,6 +655,12 @@ static IrInstruction *ir_build_br(IrBuilder *irb, AstNode *source_node, IrBasicB
655 return &br_instruction->base;655 return &br_instruction->base;
656}656}
657657
658static 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
658static IrInstruction *ir_build_br_from(IrBuilder *irb, IrInstruction *old_instruction, IrBasicBlock *dest_block) {664static IrInstruction *ir_build_br_from(IrBuilder *irb, IrInstruction *old_instruction, IrBasicBlock *dest_block) {
659 IrInstruction *new_instruction = ir_build_br(irb, old_instruction->source_node, dest_block, false);665 IrInstruction *new_instruction = ir_build_br(irb, old_instruction->source_node, dest_block, false);
660 ir_link_new_instruction(new_instruction, old_instruction);666 ir_link_new_instruction(new_instruction, old_instruction);
...@@ -2438,6 +2444,55 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {...@@ -2438,6 +2444,55 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {
2438 return ir_build_phi(irb, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);2444 return ir_build_phi(irb, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
2439}2445}
24402446
2447static 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
2459static 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
2485static 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
2441static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContext *block_context,2496static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContext *block_context,
2442 LValPurpose lval)2497 LValPurpose lval)
2443{2498{
...@@ -2491,13 +2546,15 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex...@@ -2491,13 +2546,15 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex
2491 return ir_gen_if_var_expr(irb, node);2546 return ir_gen_if_var_expr(irb, node);
2492 case NodeTypeSwitchExpr:2547 case NodeTypeSwitchExpr:
2493 return ir_gen_switch_expr(irb, node);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 case NodeTypeUnwrapErrorExpr:2553 case NodeTypeUnwrapErrorExpr:
2495 case NodeTypeDefer:2554 case NodeTypeDefer:
2496 case NodeTypeSliceExpr:2555 case NodeTypeSliceExpr:
2497 case NodeTypeGoto:
2498 case NodeTypeBreak:2556 case NodeTypeBreak:
2499 case NodeTypeContinue:2557 case NodeTypeContinue:
2500 case NodeTypeLabel:
2501 case NodeTypeCharLiteral:2558 case NodeTypeCharLiteral:
2502 case NodeTypeZeroesLiteral:2559 case NodeTypeZeroesLiteral:
2503 case NodeTypeErrorType:2560 case NodeTypeErrorType:
...@@ -2533,11 +2590,46 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *s...@@ -2533,11 +2590,46 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *s
2533 return ir_gen_node_extra(irb, node, scope, LValPurposeNone);2590 return ir_gen_node_extra(irb, node, scope, LValPurposeNone);
2534}2591}
25352592
2593static 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
2536IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) {2628IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) {
2537 assert(node->owner);2629 assert(node->owner);
25382630
2539 IrBuilder ir_gen = {0};2631 IrBuilder ir_builder = {0};
2540 IrBuilder *irb = &ir_gen;2632 IrBuilder *irb = &ir_builder;
25412633
2542 irb->codegen = codegen;2634 irb->codegen = codegen;
2543 irb->exec = ir_executable;2635 irb->exec = ir_executable;
...@@ -2549,10 +2641,16 @@ IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrEx...@@ -2549,10 +2641,16 @@ IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrEx
2549 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValPurposeNone);2641 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValPurposeNone);
2550 assert(result);2642 assert(result);
25512643
2644 IrInstruction *return_instruction = ir_build_return(irb, result->source_node, result);
2645 assert(return_instruction);
2646
2552 if (result == codegen->invalid_instruction)2647 if (result == codegen->invalid_instruction)
2553 return result;2648 return codegen->invalid_instruction;
25542649
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}
25572655
2558IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) {2656IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) {
...@@ -7241,19 +7339,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {...@@ -7241,19 +7339,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
7241// }7339// }
7242// zig_unreachable();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//static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,7342//static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
7258// AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name,7343// AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name,
7259// AstNode *out_node)7344// AstNode *out_node)
...@@ -7710,69 +7795,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {...@@ -7710,69 +7795,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
7710// return g->builtin_types.entry_void;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//static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,7799//static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
7778// BlockContext *context, AstNode *node, Buf *err_name)7800// BlockContext *context, AstNode *node, Buf *err_name)
...@@ -7841,51 +7863,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {...@@ -7841,51 +7863,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
7841//7863//
7842// return ir_build_return(irb, source_node, value);7864// return ir_build_return(irb, source_node, value);
7843//}7865//}
7844/*
7845static 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//static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) {7867//static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) {
7891// assert(node->type == NodeTypeFnCallExpr);7868// assert(node->type == NodeTypeFnCallExpr);
...@@ -9180,20 +9157,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no...@@ -9180,20 +9157,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
9180// return nullptr;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//static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {9160//static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
9198// AstNode *init_expr = node->data.variable_declaration.expr;9161// AstNode *init_expr = node->data.variable_declaration.expr;
9199// if (node->data.variable_declaration.is_const && init_expr) {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,18 +9212,3 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
9249// }9212// }
9250// return result;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//}
test/self_hosted2.zig+18
...@@ -67,6 +67,23 @@ fn testNamespaceFnCall() {...@@ -67,6 +67,23 @@ fn testNamespaceFnCall() {
67 assert(case_namespace_fn_call.foo() == 1234);67 assert(case_namespace_fn_call.foo() == 1234);
68}68}
6969
70fn gotoAndLabels() {
71 gotoLoop();
72 assert(goto_counter == 10);
73}
74fn gotoLoop() {
75 var i: i32 = 0;
76 goto cond;
77loop:
78 i += 1;
79cond:
80 if (!(i < 10)) goto end;
81 goto_counter += 1;
82 goto loop;
83end:
84}
85var goto_counter: i32 = 0;
86
70fn assert(ok: bool) {87fn assert(ok: bool) {
71 if (!ok)88 if (!ok)
72 @unreachable();89 @unreachable();
...@@ -80,6 +97,7 @@ fn runAllTests() {...@@ -80,6 +97,7 @@ fn runAllTests() {
80 switchWithAllRanges();97 switchWithAllRanges();
81 testInlineSwitch();98 testInlineSwitch();
82 testNamespaceFnCall();99 testNamespaceFnCall();
100 gotoAndLabels();
83}101}
84102
85export nakedcc fn _start() -> unreachable {103export nakedcc fn _start() -> unreachable {