| ... | ... | @@ -4658,51 +4658,197 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4658 | 4658 | assert(node->type == NodeTypeWhileExpr); |
| 4659 | 4659 | |
| 4660 | 4660 | AstNode *continue_expr_node = node->data.while_expr.continue_expr; |
| 4661 | AstNode *else_node = node->data.while_expr.else_node; |
| 4661 | 4662 | |
| 4662 | 4663 | IrBasicBlock *cond_block = ir_build_basic_block(irb, scope, "WhileCond"); |
| 4663 | 4664 | IrBasicBlock *body_block = ir_build_basic_block(irb, scope, "WhileBody"); |
| 4664 | 4665 | IrBasicBlock *continue_block = continue_expr_node ? |
| 4665 | 4666 | ir_build_basic_block(irb, scope, "WhileContinue") : cond_block; |
| 4666 | 4667 | IrBasicBlock *end_block = ir_build_basic_block(irb, scope, "WhileEnd"); |
| 4668 | IrBasicBlock *else_block = else_node ? |
| 4669 | ir_build_basic_block(irb, scope, "WhileElse") : end_block; |
| 4667 | 4670 | |
| 4668 | 4671 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, |
| 4669 | 4672 | ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline); |
| 4670 | 4673 | ir_build_br(irb, scope, node, cond_block, is_comptime); |
| 4671 | 4674 | |
| 4672 | | if (continue_expr_node) { |
| 4673 | | ir_set_cursor_at_end(irb, continue_block); |
| 4674 | | IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, scope); |
| 4675 | | if (expr_result == irb->codegen->invalid_instruction) |
| 4676 | | return expr_result; |
| 4677 | | if (!instr_is_unreachable(expr_result)) |
| 4678 | | ir_mark_gen(ir_build_br(irb, scope, node, cond_block, is_comptime)); |
| 4679 | | } |
| 4675 | Buf *var_symbol = node->data.while_expr.var_symbol; |
| 4676 | Buf *err_symbol = node->data.while_expr.err_symbol; |
| 4677 | if (err_symbol != nullptr) { |
| 4678 | ir_set_cursor_at_end(irb, cond_block); |
| 4679 | |
| 4680 | Scope *payload_scope; |
| 4681 | AstNode *symbol_node = node; // TODO make more accurate |
| 4682 | VariableTableEntry *payload_var; |
| 4683 | if (var_symbol) { |
| 4684 | // TODO make it an error to write to payload variable |
| 4685 | payload_var = ir_create_var(irb, symbol_node, scope, var_symbol, |
| 4686 | true, false, false, is_comptime); |
| 4687 | payload_scope = payload_var->child_scope; |
| 4688 | } else { |
| 4689 | payload_scope = scope; |
| 4690 | } |
| 4691 | IrInstruction *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, scope, LVAL_PTR); |
| 4692 | if (err_val_ptr == irb->codegen->invalid_instruction) |
| 4693 | return err_val_ptr; |
| 4694 | IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr); |
| 4695 | IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val); |
| 4696 | if (!instr_is_unreachable(is_err)) { |
| 4697 | ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err, |
| 4698 | else_block, body_block, is_comptime)); |
| 4699 | } |
| 4700 | |
| 4701 | ir_set_cursor_at_end(irb, body_block); |
| 4702 | if (var_symbol) { |
| 4703 | IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node, |
| 4704 | err_val_ptr, false); |
| 4705 | IrInstruction *var_value = node->data.while_expr.var_is_ptr ? |
| 4706 | var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value); |
| 4707 | ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, var_value); |
| 4708 | } |
| 4709 | LoopStackItem *loop_stack_item = irb->loop_stack.add_one(); |
| 4710 | loop_stack_item->break_block = end_block; |
| 4711 | loop_stack_item->continue_block = continue_block; |
| 4712 | loop_stack_item->is_comptime = is_comptime; |
| 4713 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, payload_scope); |
| 4714 | if (body_result == irb->codegen->invalid_instruction) |
| 4715 | return body_result; |
| 4716 | irb->loop_stack.pop(); |
| 4717 | |
| 4718 | if (!instr_is_unreachable(body_result)) |
| 4719 | ir_mark_gen(ir_build_br(irb, payload_scope, node, continue_block, is_comptime)); |
| 4720 | |
| 4721 | if (continue_expr_node) { |
| 4722 | ir_set_cursor_at_end(irb, continue_block); |
| 4723 | IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, payload_scope); |
| 4724 | if (expr_result == irb->codegen->invalid_instruction) |
| 4725 | return expr_result; |
| 4726 | if (!instr_is_unreachable(expr_result)) |
| 4727 | ir_mark_gen(ir_build_br(irb, payload_scope, node, cond_block, is_comptime)); |
| 4728 | } |
| 4729 | |
| 4730 | if (else_node) { |
| 4731 | ir_set_cursor_at_end(irb, else_block); |
| 4680 | 4732 | |
| 4681 | | ir_set_cursor_at_end(irb, cond_block); |
| 4682 | | IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope); |
| 4683 | | if (cond_val == irb->codegen->invalid_instruction) |
| 4684 | | return cond_val; |
| 4685 | | if (!instr_is_unreachable(cond_val)) { |
| 4686 | | ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val, |
| 4687 | | body_block, end_block, is_comptime)); |
| 4688 | | } |
| 4733 | // TODO make it an error to write to error variable |
| 4734 | AstNode *err_symbol_node = else_node; // TODO make more accurate |
| 4735 | VariableTableEntry *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol, |
| 4736 | true, false, false, is_comptime); |
| 4737 | Scope *err_scope = err_var->child_scope; |
| 4738 | IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); |
| 4739 | ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, err_var_value); |
| 4740 | |
| 4741 | IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope); |
| 4742 | if (else_result == irb->codegen->invalid_instruction) |
| 4743 | return else_result; |
| 4744 | if (!instr_is_unreachable(else_result)) |
| 4745 | ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime)); |
| 4746 | } |
| 4747 | |
| 4748 | ir_set_cursor_at_end(irb, end_block); |
| 4749 | return ir_build_const_void(irb, scope, node); |
| 4750 | } else if (var_symbol != nullptr) { |
| 4751 | ir_set_cursor_at_end(irb, cond_block); |
| 4752 | // TODO make it an error to write to payload variable |
| 4753 | AstNode *symbol_node = node; // TODO make more accurate |
| 4754 | VariableTableEntry *payload_var = ir_create_var(irb, symbol_node, scope, var_symbol, |
| 4755 | true, false, false, is_comptime); |
| 4756 | Scope *child_scope = payload_var->child_scope; |
| 4757 | IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, scope, LVAL_PTR); |
| 4758 | if (maybe_val_ptr == irb->codegen->invalid_instruction) |
| 4759 | return maybe_val_ptr; |
| 4760 | IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr); |
| 4761 | IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val); |
| 4762 | if (!instr_is_unreachable(is_non_null)) { |
| 4763 | ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null, |
| 4764 | body_block, else_block, is_comptime)); |
| 4765 | } |
| 4766 | |
| 4767 | ir_set_cursor_at_end(irb, body_block); |
| 4768 | IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false); |
| 4769 | IrInstruction *var_value = node->data.while_expr.var_is_ptr ? |
| 4770 | var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value); |
| 4771 | ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, var_value); |
| 4772 | LoopStackItem *loop_stack_item = irb->loop_stack.add_one(); |
| 4773 | loop_stack_item->break_block = end_block; |
| 4774 | loop_stack_item->continue_block = continue_block; |
| 4775 | loop_stack_item->is_comptime = is_comptime; |
| 4776 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, child_scope); |
| 4777 | if (body_result == irb->codegen->invalid_instruction) |
| 4778 | return body_result; |
| 4779 | irb->loop_stack.pop(); |
| 4780 | |
| 4781 | if (!instr_is_unreachable(body_result)) |
| 4782 | ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime)); |
| 4783 | |
| 4784 | if (continue_expr_node) { |
| 4785 | ir_set_cursor_at_end(irb, continue_block); |
| 4786 | IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, child_scope); |
| 4787 | if (expr_result == irb->codegen->invalid_instruction) |
| 4788 | return expr_result; |
| 4789 | if (!instr_is_unreachable(expr_result)) |
| 4790 | ir_mark_gen(ir_build_br(irb, child_scope, node, cond_block, is_comptime)); |
| 4791 | } |
| 4792 | |
| 4793 | if (else_node) { |
| 4794 | ir_set_cursor_at_end(irb, else_block); |
| 4689 | 4795 | |
| 4690 | | ir_set_cursor_at_end(irb, body_block); |
| 4796 | IrInstruction *else_result = ir_gen_node(irb, else_node, scope); |
| 4797 | if (else_result == irb->codegen->invalid_instruction) |
| 4798 | return else_result; |
| 4799 | if (!instr_is_unreachable(else_result)) |
| 4800 | ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime)); |
| 4801 | } |
| 4691 | 4802 | |
| 4692 | | LoopStackItem *loop_stack_item = irb->loop_stack.add_one(); |
| 4693 | | loop_stack_item->break_block = end_block; |
| 4694 | | loop_stack_item->continue_block = continue_block; |
| 4695 | | loop_stack_item->is_comptime = is_comptime; |
| 4696 | | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope); |
| 4697 | | if (body_result == irb->codegen->invalid_instruction) |
| 4698 | | return body_result; |
| 4699 | | irb->loop_stack.pop(); |
| 4803 | ir_set_cursor_at_end(irb, end_block); |
| 4804 | return ir_build_const_void(irb, scope, node); |
| 4805 | } else { |
| 4806 | if (continue_expr_node) { |
| 4807 | ir_set_cursor_at_end(irb, continue_block); |
| 4808 | IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, scope); |
| 4809 | if (expr_result == irb->codegen->invalid_instruction) |
| 4810 | return expr_result; |
| 4811 | if (!instr_is_unreachable(expr_result)) |
| 4812 | ir_mark_gen(ir_build_br(irb, scope, node, cond_block, is_comptime)); |
| 4813 | } |
| 4814 | |
| 4815 | ir_set_cursor_at_end(irb, cond_block); |
| 4816 | IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope); |
| 4817 | if (cond_val == irb->codegen->invalid_instruction) |
| 4818 | return cond_val; |
| 4819 | if (!instr_is_unreachable(cond_val)) { |
| 4820 | ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val, |
| 4821 | body_block, else_block, is_comptime)); |
| 4822 | } |
| 4823 | |
| 4824 | ir_set_cursor_at_end(irb, body_block); |
| 4825 | |
| 4826 | LoopStackItem *loop_stack_item = irb->loop_stack.add_one(); |
| 4827 | loop_stack_item->break_block = end_block; |
| 4828 | loop_stack_item->continue_block = continue_block; |
| 4829 | loop_stack_item->is_comptime = is_comptime; |
| 4830 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope); |
| 4831 | if (body_result == irb->codegen->invalid_instruction) |
| 4832 | return body_result; |
| 4833 | irb->loop_stack.pop(); |
| 4834 | |
| 4835 | if (!instr_is_unreachable(body_result)) |
| 4836 | ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime)); |
| 4837 | |
| 4838 | if (else_node) { |
| 4839 | ir_set_cursor_at_end(irb, else_block); |
| 4700 | 4840 | |
| 4701 | | if (!instr_is_unreachable(body_result)) |
| 4702 | | ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime)); |
| 4703 | | ir_set_cursor_at_end(irb, end_block); |
| 4841 | IrInstruction *else_result = ir_gen_node(irb, else_node, scope); |
| 4842 | if (else_result == irb->codegen->invalid_instruction) |
| 4843 | return else_result; |
| 4844 | if (!instr_is_unreachable(else_result)) |
| 4845 | ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime)); |
| 4846 | } |
| 4704 | 4847 | |
| 4705 | | return ir_build_const_void(irb, scope, node); |
| 4848 | ir_set_cursor_at_end(irb, end_block); |
| 4849 | |
| 4850 | return ir_build_const_void(irb, scope, node); |
| 4851 | } |
| 4706 | 4852 | } |
| 4707 | 4853 | |
| 4708 | 4854 | static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |