| ... | ... | @@ -19,19 +19,10 @@ struct IrExecContext { |
| 19 | 19 | size_t mem_slot_count; |
| 20 | 20 | }; |
| 21 | 21 | |
| 22 | | struct LoopStackItem { |
| 23 | | IrBasicBlock *break_block; |
| 24 | | IrBasicBlock *continue_block; |
| 25 | | IrInstruction *is_comptime; |
| 26 | | ZigList<IrInstruction *> *incoming_values; |
| 27 | | ZigList<IrBasicBlock *> *incoming_blocks; |
| 28 | | }; |
| 29 | | |
| 30 | 22 | struct IrBuilder { |
| 31 | 23 | CodeGen *codegen; |
| 32 | 24 | IrExecutable *exec; |
| 33 | 25 | IrBasicBlock *current_basic_block; |
| 34 | | ZigList<LoopStackItem> loop_stack; |
| 35 | 26 | }; |
| 36 | 27 | |
| 37 | 28 | struct IrAnalyze { |
| ... | ... | @@ -59,18 +50,6 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc |
| 59 | 50 | static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction); |
| 60 | 51 | static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type); |
| 61 | 52 | |
| 62 | | static LoopStackItem *add_loop_stack_item(IrBuilder *irb, IrBasicBlock *break_block, IrBasicBlock *continue_block, |
| 63 | | IrInstruction *is_comptime, ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values) |
| 64 | | { |
| 65 | | LoopStackItem *loop_stack_item = irb->loop_stack.add_one(); |
| 66 | | loop_stack_item->break_block = break_block; |
| 67 | | loop_stack_item->continue_block = continue_block; |
| 68 | | loop_stack_item->is_comptime = is_comptime; |
| 69 | | loop_stack_item->incoming_blocks = incoming_blocks; |
| 70 | | loop_stack_item->incoming_values = incoming_values; |
| 71 | | return loop_stack_item; |
| 72 | | } |
| 73 | | |
| 74 | 53 | ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) { |
| 75 | 54 | assert(const_val->type->id == TypeTableEntryIdPointer); |
| 76 | 55 | assert(const_val->special == ConstValSpecialStatic); |
| ... | ... | @@ -4748,13 +4727,20 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4748 | 4727 | var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value); |
| 4749 | 4728 | ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, var_value); |
| 4750 | 4729 | } |
| 4730 | |
| 4751 | 4731 | ZigList<IrInstruction *> incoming_values = {0}; |
| 4752 | 4732 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| 4753 | | add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values); |
| 4754 | | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, payload_scope); |
| 4733 | |
| 4734 | ScopeLoop *loop_scope = create_loop_scope(node, payload_scope); |
| 4735 | loop_scope->break_block = end_block; |
| 4736 | loop_scope->continue_block = continue_block; |
| 4737 | loop_scope->is_comptime = is_comptime; |
| 4738 | loop_scope->incoming_blocks = &incoming_blocks; |
| 4739 | loop_scope->incoming_values = &incoming_values; |
| 4740 | |
| 4741 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base); |
| 4755 | 4742 | if (body_result == irb->codegen->invalid_instruction) |
| 4756 | 4743 | return body_result; |
| 4757 | | irb->loop_stack.pop(); |
| 4758 | 4744 | |
| 4759 | 4745 | if (!instr_is_unreachable(body_result)) |
| 4760 | 4746 | ir_mark_gen(ir_build_br(irb, payload_scope, node, continue_block, is_comptime)); |
| ... | ... | @@ -4821,13 +4807,20 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4821 | 4807 | IrInstruction *var_value = node->data.while_expr.var_is_ptr ? |
| 4822 | 4808 | var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value); |
| 4823 | 4809 | ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, var_value); |
| 4810 | |
| 4824 | 4811 | ZigList<IrInstruction *> incoming_values = {0}; |
| 4825 | 4812 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| 4826 | | add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values); |
| 4827 | | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, child_scope); |
| 4813 | |
| 4814 | ScopeLoop *loop_scope = create_loop_scope(node, child_scope); |
| 4815 | loop_scope->break_block = end_block; |
| 4816 | loop_scope->continue_block = continue_block; |
| 4817 | loop_scope->is_comptime = is_comptime; |
| 4818 | loop_scope->incoming_blocks = &incoming_blocks; |
| 4819 | loop_scope->incoming_values = &incoming_values; |
| 4820 | |
| 4821 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base); |
| 4828 | 4822 | if (body_result == irb->codegen->invalid_instruction) |
| 4829 | 4823 | return body_result; |
| 4830 | | irb->loop_stack.pop(); |
| 4831 | 4824 | |
| 4832 | 4825 | if (!instr_is_unreachable(body_result)) |
| 4833 | 4826 | ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime)); |
| ... | ... | @@ -4887,11 +4880,17 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4887 | 4880 | |
| 4888 | 4881 | ZigList<IrInstruction *> incoming_values = {0}; |
| 4889 | 4882 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| 4890 | | add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values); |
| 4891 | | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope); |
| 4883 | |
| 4884 | ScopeLoop *loop_scope = create_loop_scope(node, scope); |
| 4885 | loop_scope->break_block = end_block; |
| 4886 | loop_scope->continue_block = continue_block; |
| 4887 | loop_scope->is_comptime = is_comptime; |
| 4888 | loop_scope->incoming_blocks = &incoming_blocks; |
| 4889 | loop_scope->incoming_values = &incoming_values; |
| 4890 | |
| 4891 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base); |
| 4892 | 4892 | if (body_result == irb->codegen->invalid_instruction) |
| 4893 | 4893 | return body_result; |
| 4894 | | irb->loop_stack.pop(); |
| 4895 | 4894 | |
| 4896 | 4895 | if (!instr_is_unreachable(body_result)) |
| 4897 | 4896 | ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime)); |
| ... | ... | @@ -4952,12 +4951,10 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 4952 | 4951 | IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, |
| 4953 | 4952 | ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); |
| 4954 | 4953 | |
| 4955 | | Scope *child_scope = create_loop_scope(node, parent_scope); |
| 4956 | | |
| 4957 | 4954 | // TODO make it an error to write to element variable or i variable. |
| 4958 | 4955 | Buf *elem_var_name = elem_node->data.symbol_expr.symbol; |
| 4959 | | VariableTableEntry *elem_var = ir_create_var(irb, elem_node, child_scope, elem_var_name, true, false, false, is_comptime); |
| 4960 | | child_scope = elem_var->child_scope; |
| 4956 | VariableTableEntry *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); |
| 4957 | Scope *child_scope = elem_var->child_scope; |
| 4961 | 4958 | |
| 4962 | 4959 | IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node); |
| 4963 | 4960 | ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, undefined_value); |
| ... | ... | @@ -5010,9 +5007,14 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 5010 | 5007 | |
| 5011 | 5008 | ZigList<IrInstruction *> incoming_values = {0}; |
| 5012 | 5009 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| 5013 | | add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values); |
| 5014 | | IrInstruction *body_result = ir_gen_node(irb, body_node, child_scope); |
| 5015 | | irb->loop_stack.pop(); |
| 5010 | ScopeLoop *loop_scope = create_loop_scope(node, child_scope); |
| 5011 | loop_scope->break_block = end_block; |
| 5012 | loop_scope->continue_block = continue_block; |
| 5013 | loop_scope->is_comptime = is_comptime; |
| 5014 | loop_scope->incoming_blocks = &incoming_blocks; |
| 5015 | loop_scope->incoming_values = &incoming_values; |
| 5016 | |
| 5017 | IrInstruction *body_result = ir_gen_node(irb, body_node, &loop_scope->base); |
| 5016 | 5018 | |
| 5017 | 5019 | if (!instr_is_unreachable(body_result)) |
| 5018 | 5020 | ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime)); |
| ... | ... | @@ -5584,62 +5586,88 @@ static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNo |
| 5584 | 5586 | return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval); |
| 5585 | 5587 | } |
| 5586 | 5588 | |
| 5587 | | static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 5589 | static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *node) { |
| 5588 | 5590 | assert(node->type == NodeTypeBreak); |
| 5589 | 5591 | |
| 5590 | | if (irb->loop_stack.length == 0) { |
| 5591 | | add_node_error(irb->codegen, node, |
| 5592 | | buf_sprintf("'break' expression outside loop")); |
| 5593 | | return irb->codegen->invalid_instruction; |
| 5594 | | } |
| 5592 | // Search up the scope. We'll find one of these things first: |
| 5593 | // * function definition scope or global scope => error, break outside loop |
| 5594 | // * defer expression scope => error, cannot break out of defer expression |
| 5595 | // * loop scope => OK |
| 5595 | 5596 | |
| 5596 | | LoopStackItem *loop_stack_item = &irb->loop_stack.last(); |
| 5597 | Scope *search_scope = break_scope; |
| 5598 | ScopeLoop *loop_scope; |
| 5599 | for (;;) { |
| 5600 | if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { |
| 5601 | add_node_error(irb->codegen, node, buf_sprintf("break expression outside loop")); |
| 5602 | return irb->codegen->invalid_instruction; |
| 5603 | } else if (search_scope->id == ScopeIdDeferExpr) { |
| 5604 | add_node_error(irb->codegen, node, buf_sprintf("cannot break out of defer expression")); |
| 5605 | return irb->codegen->invalid_instruction; |
| 5606 | } else if (search_scope->id == ScopeIdLoop) { |
| 5607 | loop_scope = (ScopeLoop *)search_scope; |
| 5608 | break; |
| 5609 | } |
| 5610 | search_scope = search_scope->parent; |
| 5611 | } |
| 5597 | 5612 | |
| 5598 | 5613 | IrInstruction *is_comptime; |
| 5599 | | if (ir_should_inline(irb->exec, scope)) { |
| 5600 | | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 5614 | if (ir_should_inline(irb->exec, break_scope)) { |
| 5615 | is_comptime = ir_build_const_bool(irb, break_scope, node, true); |
| 5601 | 5616 | } else { |
| 5602 | | is_comptime = loop_stack_item->is_comptime; |
| 5617 | is_comptime = loop_scope->is_comptime; |
| 5603 | 5618 | } |
| 5604 | 5619 | |
| 5605 | 5620 | IrInstruction *result_value; |
| 5606 | 5621 | if (node->data.break_expr.expr) { |
| 5607 | | result_value = ir_gen_node(irb, node->data.break_expr.expr, scope); |
| 5622 | result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope); |
| 5608 | 5623 | if (result_value == irb->codegen->invalid_instruction) |
| 5609 | 5624 | return irb->codegen->invalid_instruction; |
| 5610 | 5625 | } else { |
| 5611 | | result_value = ir_build_const_void(irb, scope, node); |
| 5626 | result_value = ir_build_const_void(irb, break_scope, node); |
| 5612 | 5627 | } |
| 5613 | 5628 | |
| 5614 | | IrBasicBlock *dest_block = loop_stack_item->break_block; |
| 5615 | | ir_gen_defers_for_block(irb, scope, dest_block->scope, false); |
| 5629 | IrBasicBlock *dest_block = loop_scope->break_block; |
| 5630 | ir_gen_defers_for_block(irb, break_scope, dest_block->scope, false); |
| 5616 | 5631 | |
| 5617 | | loop_stack_item->incoming_blocks->append(irb->current_basic_block); |
| 5618 | | loop_stack_item->incoming_values->append(result_value); |
| 5619 | | return ir_build_br(irb, scope, node, dest_block, is_comptime); |
| 5632 | loop_scope->incoming_blocks->append(irb->current_basic_block); |
| 5633 | loop_scope->incoming_values->append(result_value); |
| 5634 | return ir_build_br(irb, break_scope, node, dest_block, is_comptime); |
| 5620 | 5635 | } |
| 5621 | 5636 | |
| 5622 | | static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 5637 | static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, AstNode *node) { |
| 5623 | 5638 | assert(node->type == NodeTypeContinue); |
| 5624 | 5639 | |
| 5625 | | if (irb->loop_stack.length == 0) { |
| 5626 | | add_node_error(irb->codegen, node, |
| 5627 | | buf_sprintf("'continue' expression outside loop")); |
| 5628 | | return irb->codegen->invalid_instruction; |
| 5629 | | } |
| 5640 | // Search up the scope. We'll find one of these things first: |
| 5641 | // * function definition scope or global scope => error, break outside loop |
| 5642 | // * defer expression scope => error, cannot break out of defer expression |
| 5643 | // * loop scope => OK |
| 5630 | 5644 | |
| 5631 | | LoopStackItem *loop_stack_item = &irb->loop_stack.last(); |
| 5645 | Scope *search_scope = continue_scope; |
| 5646 | ScopeLoop *loop_scope; |
| 5647 | for (;;) { |
| 5648 | if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { |
| 5649 | add_node_error(irb->codegen, node, buf_sprintf("continue expression outside loop")); |
| 5650 | return irb->codegen->invalid_instruction; |
| 5651 | } else if (search_scope->id == ScopeIdDeferExpr) { |
| 5652 | add_node_error(irb->codegen, node, buf_sprintf("cannot continue out of defer expression")); |
| 5653 | return irb->codegen->invalid_instruction; |
| 5654 | } else if (search_scope->id == ScopeIdLoop) { |
| 5655 | loop_scope = (ScopeLoop *)search_scope; |
| 5656 | break; |
| 5657 | } |
| 5658 | search_scope = search_scope->parent; |
| 5659 | } |
| 5632 | 5660 | |
| 5633 | 5661 | IrInstruction *is_comptime; |
| 5634 | | if (ir_should_inline(irb->exec, scope)) { |
| 5635 | | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 5662 | if (ir_should_inline(irb->exec, continue_scope)) { |
| 5663 | is_comptime = ir_build_const_bool(irb, continue_scope, node, true); |
| 5636 | 5664 | } else { |
| 5637 | | is_comptime = loop_stack_item->is_comptime; |
| 5665 | is_comptime = loop_scope->is_comptime; |
| 5638 | 5666 | } |
| 5639 | 5667 | |
| 5640 | | IrBasicBlock *dest_block = loop_stack_item->continue_block; |
| 5641 | | ir_gen_defers_for_block(irb, scope, dest_block->scope, false); |
| 5642 | | return ir_build_br(irb, scope, node, dest_block, is_comptime); |
| 5668 | IrBasicBlock *dest_block = loop_scope->continue_block; |
| 5669 | ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false); |
| 5670 | return ir_build_br(irb, continue_scope, node, dest_block, is_comptime); |
| 5643 | 5671 | } |
| 5644 | 5672 | |
| 5645 | 5673 | static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) { |