| ... | ... | @@ -22,6 +22,8 @@ struct LoopStackItem { |
| 22 | 22 | IrBasicBlock *break_block; |
| 23 | 23 | IrBasicBlock *continue_block; |
| 24 | 24 | IrInstruction *is_comptime; |
| 25 | ZigList<IrInstruction *> *incoming_values; |
| 26 | ZigList<IrBasicBlock *> *incoming_blocks; |
| 25 | 27 | }; |
| 26 | 28 | |
| 27 | 29 | struct IrBuilder { |
| ... | ... | @@ -56,6 +58,18 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc |
| 56 | 58 | static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction); |
| 57 | 59 | static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type); |
| 58 | 60 | |
| 61 | static LoopStackItem *add_loop_stack_item(IrBuilder *irb, IrBasicBlock *break_block, IrBasicBlock *continue_block, |
| 62 | IrInstruction *is_comptime, ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values) |
| 63 | { |
| 64 | LoopStackItem *loop_stack_item = irb->loop_stack.add_one(); |
| 65 | loop_stack_item->break_block = break_block; |
| 66 | loop_stack_item->continue_block = continue_block; |
| 67 | loop_stack_item->is_comptime = is_comptime; |
| 68 | loop_stack_item->incoming_blocks = incoming_blocks; |
| 69 | loop_stack_item->incoming_values = incoming_values; |
| 70 | return loop_stack_item; |
| 71 | } |
| 72 | |
| 59 | 73 | ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) { |
| 60 | 74 | assert(const_val->type->id == TypeTableEntryIdPointer); |
| 61 | 75 | assert(const_val->special == ConstValSpecialStatic); |
| ... | ... | @@ -4693,6 +4707,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4693 | 4707 | return err_val_ptr; |
| 4694 | 4708 | IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr); |
| 4695 | 4709 | IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val); |
| 4710 | IrBasicBlock *after_cond_block = irb->current_basic_block; |
| 4711 | IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); |
| 4696 | 4712 | if (!instr_is_unreachable(is_err)) { |
| 4697 | 4713 | ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err, |
| 4698 | 4714 | else_block, body_block, is_comptime)); |
| ... | ... | @@ -4706,10 +4722,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4706 | 4722 | var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value); |
| 4707 | 4723 | ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, var_value); |
| 4708 | 4724 | } |
| 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; |
| 4725 | ZigList<IrInstruction *> incoming_values = {0}; |
| 4726 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| 4727 | add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values); |
| 4713 | 4728 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, payload_scope); |
| 4714 | 4729 | if (body_result == irb->codegen->invalid_instruction) |
| 4715 | 4730 | return body_result; |
| ... | ... | @@ -4727,6 +4742,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4727 | 4742 | ir_mark_gen(ir_build_br(irb, payload_scope, node, cond_block, is_comptime)); |
| 4728 | 4743 | } |
| 4729 | 4744 | |
| 4745 | IrInstruction *else_result = nullptr; |
| 4730 | 4746 | if (else_node) { |
| 4731 | 4747 | ir_set_cursor_at_end(irb, else_block); |
| 4732 | 4748 | |
| ... | ... | @@ -4738,15 +4754,23 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4738 | 4754 | IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); |
| 4739 | 4755 | ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, err_var_value); |
| 4740 | 4756 | |
| 4741 | | IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope); |
| 4757 | else_result = ir_gen_node(irb, else_node, err_scope); |
| 4742 | 4758 | if (else_result == irb->codegen->invalid_instruction) |
| 4743 | 4759 | return else_result; |
| 4744 | 4760 | if (!instr_is_unreachable(else_result)) |
| 4745 | 4761 | ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime)); |
| 4746 | 4762 | } |
| 4747 | | |
| 4763 | IrBasicBlock *after_else_block = irb->current_basic_block; |
| 4748 | 4764 | ir_set_cursor_at_end(irb, end_block); |
| 4749 | | return ir_build_const_void(irb, scope, node); |
| 4765 | if (else_result) { |
| 4766 | incoming_blocks.append(after_else_block); |
| 4767 | incoming_values.append(else_result); |
| 4768 | } else { |
| 4769 | incoming_blocks.append(after_cond_block); |
| 4770 | incoming_values.append(void_else_result); |
| 4771 | } |
| 4772 | |
| 4773 | return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); |
| 4750 | 4774 | } else if (var_symbol != nullptr) { |
| 4751 | 4775 | ir_set_cursor_at_end(irb, cond_block); |
| 4752 | 4776 | // TODO make it an error to write to payload variable |
| ... | ... | @@ -4759,6 +4783,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4759 | 4783 | return maybe_val_ptr; |
| 4760 | 4784 | IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr); |
| 4761 | 4785 | IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val); |
| 4786 | IrBasicBlock *after_cond_block = irb->current_basic_block; |
| 4787 | IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); |
| 4762 | 4788 | if (!instr_is_unreachable(is_non_null)) { |
| 4763 | 4789 | ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null, |
| 4764 | 4790 | body_block, else_block, is_comptime)); |
| ... | ... | @@ -4769,10 +4795,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4769 | 4795 | IrInstruction *var_value = node->data.while_expr.var_is_ptr ? |
| 4770 | 4796 | var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value); |
| 4771 | 4797 | 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; |
| 4798 | ZigList<IrInstruction *> incoming_values = {0}; |
| 4799 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| 4800 | add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values); |
| 4776 | 4801 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, child_scope); |
| 4777 | 4802 | if (body_result == irb->codegen->invalid_instruction) |
| 4778 | 4803 | return body_result; |
| ... | ... | @@ -4790,18 +4815,27 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4790 | 4815 | ir_mark_gen(ir_build_br(irb, child_scope, node, cond_block, is_comptime)); |
| 4791 | 4816 | } |
| 4792 | 4817 | |
| 4818 | IrInstruction *else_result = nullptr; |
| 4793 | 4819 | if (else_node) { |
| 4794 | 4820 | ir_set_cursor_at_end(irb, else_block); |
| 4795 | 4821 | |
| 4796 | | IrInstruction *else_result = ir_gen_node(irb, else_node, scope); |
| 4822 | else_result = ir_gen_node(irb, else_node, scope); |
| 4797 | 4823 | if (else_result == irb->codegen->invalid_instruction) |
| 4798 | 4824 | return else_result; |
| 4799 | 4825 | if (!instr_is_unreachable(else_result)) |
| 4800 | 4826 | ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime)); |
| 4801 | 4827 | } |
| 4802 | | |
| 4828 | IrBasicBlock *after_else_block = irb->current_basic_block; |
| 4803 | 4829 | ir_set_cursor_at_end(irb, end_block); |
| 4804 | | return ir_build_const_void(irb, scope, node); |
| 4830 | if (else_result) { |
| 4831 | incoming_blocks.append(after_else_block); |
| 4832 | incoming_values.append(else_result); |
| 4833 | } else { |
| 4834 | incoming_blocks.append(after_cond_block); |
| 4835 | incoming_values.append(void_else_result); |
| 4836 | } |
| 4837 | |
| 4838 | return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); |
| 4805 | 4839 | } else { |
| 4806 | 4840 | if (continue_expr_node) { |
| 4807 | 4841 | ir_set_cursor_at_end(irb, continue_block); |
| ... | ... | @@ -4816,6 +4850,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4816 | 4850 | IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope); |
| 4817 | 4851 | if (cond_val == irb->codegen->invalid_instruction) |
| 4818 | 4852 | return cond_val; |
| 4853 | IrBasicBlock *after_cond_block = irb->current_basic_block; |
| 4854 | IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); |
| 4819 | 4855 | if (!instr_is_unreachable(cond_val)) { |
| 4820 | 4856 | ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val, |
| 4821 | 4857 | body_block, else_block, is_comptime)); |
| ... | ... | @@ -4823,10 +4859,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4823 | 4859 | |
| 4824 | 4860 | ir_set_cursor_at_end(irb, body_block); |
| 4825 | 4861 | |
| 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; |
| 4862 | ZigList<IrInstruction *> incoming_values = {0}; |
| 4863 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| 4864 | add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values); |
| 4830 | 4865 | IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, scope); |
| 4831 | 4866 | if (body_result == irb->codegen->invalid_instruction) |
| 4832 | 4867 | return body_result; |
| ... | ... | @@ -4835,19 +4870,27 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 4835 | 4870 | if (!instr_is_unreachable(body_result)) |
| 4836 | 4871 | ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime)); |
| 4837 | 4872 | |
| 4873 | IrInstruction *else_result = nullptr; |
| 4838 | 4874 | if (else_node) { |
| 4839 | 4875 | ir_set_cursor_at_end(irb, else_block); |
| 4840 | 4876 | |
| 4841 | | IrInstruction *else_result = ir_gen_node(irb, else_node, scope); |
| 4877 | else_result = ir_gen_node(irb, else_node, scope); |
| 4842 | 4878 | if (else_result == irb->codegen->invalid_instruction) |
| 4843 | 4879 | return else_result; |
| 4844 | 4880 | if (!instr_is_unreachable(else_result)) |
| 4845 | 4881 | ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime)); |
| 4846 | 4882 | } |
| 4847 | | |
| 4883 | IrBasicBlock *after_else_block = irb->current_basic_block; |
| 4848 | 4884 | ir_set_cursor_at_end(irb, end_block); |
| 4885 | if (else_result) { |
| 4886 | incoming_blocks.append(after_else_block); |
| 4887 | incoming_values.append(else_result); |
| 4888 | } else { |
| 4889 | incoming_blocks.append(after_cond_block); |
| 4890 | incoming_values.append(void_else_result); |
| 4891 | } |
| 4849 | 4892 | |
| 4850 | | return ir_build_const_void(irb, scope, node); |
| 4893 | return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); |
| 4851 | 4894 | } |
| 4852 | 4895 | } |
| 4853 | 4896 | |
| ... | ... | @@ -4858,6 +4901,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 4858 | 4901 | AstNode *elem_node = node->data.for_expr.elem_node; |
| 4859 | 4902 | AstNode *index_node = node->data.for_expr.index_node; |
| 4860 | 4903 | AstNode *body_node = node->data.for_expr.body; |
| 4904 | AstNode *else_node = node->data.for_expr.else_node; |
| 4861 | 4905 | |
| 4862 | 4906 | if (!elem_node) { |
| 4863 | 4907 | add_node_error(irb->codegen, node, buf_sprintf("for loop expression missing element parameter")); |
| ... | ... | @@ -4915,6 +4959,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 4915 | 4959 | IrBasicBlock *cond_block = ir_build_basic_block(irb, child_scope, "ForCond"); |
| 4916 | 4960 | IrBasicBlock *body_block = ir_build_basic_block(irb, child_scope, "ForBody"); |
| 4917 | 4961 | IrBasicBlock *end_block = ir_build_basic_block(irb, child_scope, "ForEnd"); |
| 4962 | IrBasicBlock *else_block = else_node ? ir_build_basic_block(irb, child_scope, "ForElse") : end_block; |
| 4918 | 4963 | IrBasicBlock *continue_block = ir_build_basic_block(irb, child_scope, "ForContinue"); |
| 4919 | 4964 | |
| 4920 | 4965 | IrInstruction *len_val = ir_build_array_len(irb, child_scope, node, array_val); |
| ... | ... | @@ -4923,7 +4968,9 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 4923 | 4968 | ir_set_cursor_at_end(irb, cond_block); |
| 4924 | 4969 | IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_ptr); |
| 4925 | 4970 | IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false); |
| 4926 | | ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, end_block, is_comptime)); |
| 4971 | IrBasicBlock *after_cond_block = irb->current_basic_block; |
| 4972 | IrInstruction *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node)); |
| 4973 | ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, else_block, is_comptime)); |
| 4927 | 4974 | |
| 4928 | 4975 | ir_set_cursor_at_end(irb, body_block); |
| 4929 | 4976 | IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, false); |
| ... | ... | @@ -4935,10 +4982,9 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 4935 | 4982 | } |
| 4936 | 4983 | ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val)); |
| 4937 | 4984 | |
| 4938 | | LoopStackItem *loop_stack_item = irb->loop_stack.add_one(); |
| 4939 | | loop_stack_item->break_block = end_block; |
| 4940 | | loop_stack_item->continue_block = continue_block; |
| 4941 | | loop_stack_item->is_comptime = is_comptime; |
| 4985 | ZigList<IrInstruction *> incoming_values = {0}; |
| 4986 | ZigList<IrBasicBlock *> incoming_blocks = {0}; |
| 4987 | add_loop_stack_item(irb, end_block, continue_block, is_comptime, &incoming_blocks, &incoming_values); |
| 4942 | 4988 | IrInstruction *body_result = ir_gen_node(irb, body_node, child_scope); |
| 4943 | 4989 | irb->loop_stack.pop(); |
| 4944 | 4990 | |
| ... | ... | @@ -4950,9 +4996,28 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 4950 | 4996 | ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val)); |
| 4951 | 4997 | ir_build_br(irb, child_scope, node, cond_block, is_comptime); |
| 4952 | 4998 | |
| 4999 | IrInstruction *else_result = nullptr; |
| 5000 | if (else_node) { |
| 5001 | ir_set_cursor_at_end(irb, else_block); |
| 5002 | |
| 5003 | else_result = ir_gen_node(irb, else_node, parent_scope); |
| 5004 | if (else_result == irb->codegen->invalid_instruction) |
| 5005 | return else_result; |
| 5006 | if (!instr_is_unreachable(else_result)) |
| 5007 | ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); |
| 5008 | } |
| 5009 | IrBasicBlock *after_else_block = irb->current_basic_block; |
| 4953 | 5010 | ir_set_cursor_at_end(irb, end_block); |
| 4954 | | return ir_build_const_void(irb, child_scope, node); |
| 4955 | 5011 | |
| 5012 | if (else_result) { |
| 5013 | incoming_blocks.append(after_else_block); |
| 5014 | incoming_values.append(else_result); |
| 5015 | } else { |
| 5016 | incoming_blocks.append(after_cond_block); |
| 5017 | incoming_values.append(void_else_value); |
| 5018 | } |
| 5019 | |
| 5020 | return ir_build_phi(irb, parent_scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); |
| 4956 | 5021 | } |
| 4957 | 5022 | |
| 4958 | 5023 | static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode *node) { |
| ... | ... | @@ -5512,8 +5577,20 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node) |
| 5512 | 5577 | is_comptime = loop_stack_item->is_comptime; |
| 5513 | 5578 | } |
| 5514 | 5579 | |
| 5580 | IrInstruction *result_value; |
| 5581 | if (node->data.break_expr.expr) { |
| 5582 | result_value = ir_gen_node(irb, node->data.break_expr.expr, scope); |
| 5583 | if (result_value == irb->codegen->invalid_instruction) |
| 5584 | return irb->codegen->invalid_instruction; |
| 5585 | } else { |
| 5586 | result_value = ir_build_const_void(irb, scope, node); |
| 5587 | } |
| 5588 | |
| 5515 | 5589 | IrBasicBlock *dest_block = loop_stack_item->break_block; |
| 5516 | 5590 | ir_gen_defers_for_block(irb, scope, dest_block->scope, false); |
| 5591 | |
| 5592 | loop_stack_item->incoming_blocks->append(irb->current_basic_block); |
| 5593 | loop_stack_item->incoming_values->append(result_value); |
| 5517 | 5594 | return ir_build_br(irb, scope, node, dest_block, is_comptime); |
| 5518 | 5595 | } |
| 5519 | 5596 | |