| ... | @@ -19,19 +19,10 @@ struct IrExecContext { | ... | @@ -19,19 +19,10 @@ struct IrExecContext { |
| 19 | size_t mem_slot_count; | 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 | struct IrBuilder { | 22 | struct IrBuilder { |
| 31 | CodeGen *codegen; | 23 | CodeGen *codegen; |
| 32 | IrExecutable *exec; | 24 | IrExecutable *exec; |
| 33 | IrBasicBlock *current_basic_block; | 25 | IrBasicBlock *current_basic_block; |
| 34 | ZigList<LoopStackItem> loop_stack; | | |
| 35 | }; | 26 | }; |
| 36 | | 27 | |
| 37 | struct IrAnalyze { | 28 | struct IrAnalyze { |
| ... | @@ -59,18 +50,6 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc | ... | @@ -59,18 +50,6 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc |
| 59 | static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction); | 50 | static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction); |
| 60 | static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type); | 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 | ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) { | 53 | ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) { |
| 75 | assert(const_val->type->id == TypeTableEntryIdPointer); | 54 | assert(const_val->type->id == TypeTableEntryIdPointer); |
| 76 | assert(const_val->special == ConstValSpecialStatic); | 55 | assert(const_val->special == ConstValSpecialStatic); |
| ... | @@ -4748,13 +4727,20 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n | ... | @@ -4748,13 +4727,20 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4748 | var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value); | 4727 | var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value); |
| 4749 | ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, var_value); | 4728 | ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, var_value); |
| 4750 | } | 4729 | } |
| | 4730 | |
| 4751 | ZigList<IrInstruction *> incoming_values = {0}; | 4731 | ZigList<IrInstruction *> incoming_values = {0}; |
| 4752 | ZigList<IrBasicBlock *> incoming_blocks = {0}; | 4732 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| 4753 | add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values); | 4733 | |
| 4754 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, payload_scope); | 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 | if (body_result == irb->codegen->invalid_instruction) | 4742 | if (body_result == irb->codegen->invalid_instruction) |
| 4756 | return body_result; | 4743 | return body_result; |
| 4757 | irb->loop_stack.pop(); | | |
| 4758 | | 4744 | |
| 4759 | if (!instr_is_unreachable(body_result)) | 4745 | if (!instr_is_unreachable(body_result)) |
| 4760 | ir_mark_gen(ir_build_br(irb, payload_scope, node, continue_block, is_comptime)); | 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,13 +4807,20 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4821 | IrInstruction *var_value = node->data.while_expr.var_is_ptr ? | 4807 | IrInstruction *var_value = node->data.while_expr.var_is_ptr ? |
| 4822 | var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value); | 4808 | var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value); |
| 4823 | ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, var_value); | 4809 | ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, var_value); |
| | 4810 | |
| 4824 | ZigList<IrInstruction *> incoming_values = {0}; | 4811 | ZigList<IrInstruction *> incoming_values = {0}; |
| 4825 | ZigList<IrBasicBlock *> incoming_blocks = {0}; | 4812 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| 4826 | add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values); | 4813 | |
| 4827 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, child_scope); | 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 | if (body_result == irb->codegen->invalid_instruction) | 4822 | if (body_result == irb->codegen->invalid_instruction) |
| 4829 | return body_result; | 4823 | return body_result; |
| 4830 | irb->loop_stack.pop(); | | |
| 4831 | | 4824 | |
| 4832 | if (!instr_is_unreachable(body_result)) | 4825 | if (!instr_is_unreachable(body_result)) |
| 4833 | ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime)); | 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,11 +4880,17 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4887 | | 4880 | |
| 4888 | ZigList<IrInstruction *> incoming_values = {0}; | 4881 | ZigList<IrInstruction *> incoming_values = {0}; |
| 4889 | ZigList<IrBasicBlock *> incoming_blocks = {0}; | 4882 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| 4890 | add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values); | 4883 | |
| 4891 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope); | 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 | if (body_result == irb->codegen->invalid_instruction) | 4892 | if (body_result == irb->codegen->invalid_instruction) |
| 4893 | return body_result; | 4893 | return body_result; |
| 4894 | irb->loop_stack.pop(); | | |
| 4895 | | 4894 | |
| 4896 | if (!instr_is_unreachable(body_result)) | 4895 | if (!instr_is_unreachable(body_result)) |
| 4897 | ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime)); | 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,12 +4951,10 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 4952 | IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, | 4951 | IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, |
| 4953 | ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); | 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 | // TODO make it an error to write to element variable or i variable. | 4954 | // TODO make it an error to write to element variable or i variable. |
| 4958 | Buf *elem_var_name = elem_node->data.symbol_expr.symbol; | 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); | 4956 | VariableTableEntry *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); |
| 4960 | child_scope = elem_var->child_scope; | 4957 | Scope *child_scope = elem_var->child_scope; |
| 4961 | | 4958 | |
| 4962 | IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node); | 4959 | IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node); |
| 4963 | ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, undefined_value); | 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,9 +5007,14 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 5010 | | 5007 | |
| 5011 | ZigList<IrInstruction *> incoming_values = {0}; | 5008 | ZigList<IrInstruction *> incoming_values = {0}; |
| 5012 | ZigList<IrBasicBlock *> incoming_blocks = {0}; | 5009 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| 5013 | add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values); | 5010 | ScopeLoop *loop_scope = create_loop_scope(node, child_scope); |
| 5014 | IrInstruction *body_result = ir_gen_node(irb, body_node, child_scope); | 5011 | loop_scope->break_block = end_block; |
| 5015 | irb->loop_stack.pop(); | 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 | if (!instr_is_unreachable(body_result)) | 5019 | if (!instr_is_unreachable(body_result)) |
| 5018 | ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime)); | 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,62 +5586,88 @@ static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNo |
| 5584 | return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval); | 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 | assert(node->type == NodeTypeBreak); | 5590 | assert(node->type == NodeTypeBreak); |
| 5589 | | 5591 | |
| 5590 | if (irb->loop_stack.length == 0) { | 5592 | // Search up the scope. We'll find one of these things first: |
| 5591 | add_node_error(irb->codegen, node, | 5593 | // * function definition scope or global scope => error, break outside loop |
| 5592 | buf_sprintf("'break' expression outside loop")); | 5594 | // * defer expression scope => error, cannot break out of defer expression |
| 5593 | return irb->codegen->invalid_instruction; | 5595 | // * loop scope => OK |
| 5594 | } | | |
| 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 | IrInstruction *is_comptime; | 5613 | IrInstruction *is_comptime; |
| 5599 | if (ir_should_inline(irb->exec, scope)) { | 5614 | if (ir_should_inline(irb->exec, break_scope)) { |
| 5600 | is_comptime = ir_build_const_bool(irb, scope, node, true); | 5615 | is_comptime = ir_build_const_bool(irb, break_scope, node, true); |
| 5601 | } else { | 5616 | } else { |
| 5602 | is_comptime = loop_stack_item->is_comptime; | 5617 | is_comptime = loop_scope->is_comptime; |
| 5603 | } | 5618 | } |
| 5604 | | 5619 | |
| 5605 | IrInstruction *result_value; | 5620 | IrInstruction *result_value; |
| 5606 | if (node->data.break_expr.expr) { | 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 | if (result_value == irb->codegen->invalid_instruction) | 5623 | if (result_value == irb->codegen->invalid_instruction) |
| 5609 | return irb->codegen->invalid_instruction; | 5624 | return irb->codegen->invalid_instruction; |
| 5610 | } else { | 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; | 5629 | IrBasicBlock *dest_block = loop_scope->break_block; |
| 5615 | ir_gen_defers_for_block(irb, scope, dest_block->scope, false); | 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); | 5632 | loop_scope->incoming_blocks->append(irb->current_basic_block); |
| 5618 | loop_stack_item->incoming_values->append(result_value); | 5633 | loop_scope->incoming_values->append(result_value); |
| 5619 | return ir_build_br(irb, scope, node, dest_block, is_comptime); | 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 | assert(node->type == NodeTypeContinue); | 5638 | assert(node->type == NodeTypeContinue); |
| 5624 | | 5639 | |
| 5625 | if (irb->loop_stack.length == 0) { | 5640 | // Search up the scope. We'll find one of these things first: |
| 5626 | add_node_error(irb->codegen, node, | 5641 | // * function definition scope or global scope => error, break outside loop |
| 5627 | buf_sprintf("'continue' expression outside loop")); | 5642 | // * defer expression scope => error, cannot break out of defer expression |
| 5628 | return irb->codegen->invalid_instruction; | 5643 | // * loop scope => OK |
| 5629 | } | | |
| 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 | IrInstruction *is_comptime; | 5661 | IrInstruction *is_comptime; |
| 5634 | if (ir_should_inline(irb->exec, scope)) { | 5662 | if (ir_should_inline(irb->exec, continue_scope)) { |
| 5635 | is_comptime = ir_build_const_bool(irb, scope, node, true); | 5663 | is_comptime = ir_build_const_bool(irb, continue_scope, node, true); |
| 5636 | } else { | 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; | 5668 | IrBasicBlock *dest_block = loop_scope->continue_block; |
| 5641 | ir_gen_defers_for_block(irb, scope, dest_block->scope, false); | 5669 | ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false); |
| 5642 | return ir_build_br(irb, scope, node, dest_block, is_comptime); | 5670 | return ir_build_br(irb, continue_scope, node, dest_block, is_comptime); |
| 5643 | } | 5671 | } |
| 5644 | | 5672 | |
| 5645 | static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) { | 5673 | static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) { |