| ... | @@ -691,6 +691,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) { | ... | @@ -691,6 +691,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) { |
| 691 | return IrInstructionIdCoroResume; | 691 | return IrInstructionIdCoroResume; |
| 692 | } | 692 | } |
| 693 | | 693 | |
| | 694 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSave *) { |
| | 695 | return IrInstructionIdCoroSave; |
| | 696 | } |
| | 697 | |
| 694 | template<typename T> | 698 | template<typename T> |
| 695 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 699 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 696 | T *special_instruction = allocate<T>(1); | 700 | T *special_instruction = allocate<T>(1); |
| ... | @@ -2585,6 +2589,17 @@ static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -2585,6 +2589,17 @@ static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode |
| 2585 | return &instruction->base; | 2589 | return &instruction->base; |
| 2586 | } | 2590 | } |
| 2587 | | 2591 | |
| | 2592 | static IrInstruction *ir_build_coro_save(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| | 2593 | IrInstruction *coro_handle) |
| | 2594 | { |
| | 2595 | IrInstructionCoroSave *instruction = ir_build_instruction<IrInstructionCoroSave>(irb, scope, source_node); |
| | 2596 | instruction->coro_handle = coro_handle; |
| | 2597 | |
| | 2598 | ir_ref_instruction(coro_handle, irb->current_basic_block); |
| | 2599 | |
| | 2600 | return &instruction->base; |
| | 2601 | } |
| | 2602 | |
| 2588 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { | 2603 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2589 | results[ReturnKindUnconditional] = 0; | 2604 | results[ReturnKindUnconditional] = 0; |
| 2590 | results[ReturnKindError] = 0; | 2605 | results[ReturnKindError] = 0; |
| ... | @@ -5847,7 +5862,67 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast | ... | @@ -5847,7 +5862,67 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast |
| 5847 | static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) { | 5862 | static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| 5848 | assert(node->type == NodeTypeSuspend); | 5863 | assert(node->type == NodeTypeSuspend); |
| 5849 | | 5864 | |
| 5850 | zig_panic("TODO: generate suspend"); | 5865 | FnTableEntry *fn_entry = exec_fn_entry(irb->exec); |
| | 5866 | if (!fn_entry) { |
| | 5867 | add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition")); |
| | 5868 | return irb->codegen->invalid_instruction; |
| | 5869 | } |
| | 5870 | if (fn_entry->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync) { |
| | 5871 | add_node_error(irb->codegen, node, buf_sprintf("suspend in non-async function")); |
| | 5872 | return irb->codegen->invalid_instruction; |
| | 5873 | } |
| | 5874 | |
| | 5875 | ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope); |
| | 5876 | if (scope_defer_expr) { |
| | 5877 | if (!scope_defer_expr->reported_err) { |
| | 5878 | add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside defer expression")); |
| | 5879 | scope_defer_expr->reported_err = true; |
| | 5880 | } |
| | 5881 | return irb->codegen->invalid_instruction; |
| | 5882 | } |
| | 5883 | |
| | 5884 | Scope *outer_scope = irb->exec->begin_scope; |
| | 5885 | |
| | 5886 | |
| | 5887 | IrInstruction *suspend_code; |
| | 5888 | IrInstruction *const_bool_false = ir_build_const_bool(irb, parent_scope, node, false); |
| | 5889 | if (node->data.suspend.block == nullptr) { |
| | 5890 | suspend_code = ir_build_coro_suspend(irb, parent_scope, node, nullptr, const_bool_false); |
| | 5891 | } else { |
| | 5892 | assert(node->data.suspend.promise_symbol != nullptr); |
| | 5893 | assert(node->data.suspend.promise_symbol->type == NodeTypeSymbol); |
| | 5894 | Buf *promise_symbol_name = node->data.suspend.promise_symbol->data.symbol_expr.symbol; |
| | 5895 | Scope *child_scope; |
| | 5896 | if (!buf_eql_str(promise_symbol_name, "_")) { |
| | 5897 | VariableTableEntry *promise_var = ir_create_var(irb, node, parent_scope, promise_symbol_name, |
| | 5898 | true, true, false, const_bool_false); |
| | 5899 | ir_build_var_decl(irb, parent_scope, node, promise_var, nullptr, nullptr, irb->exec->coro_handle); |
| | 5900 | child_scope = promise_var->child_scope; |
| | 5901 | } else { |
| | 5902 | child_scope = parent_scope; |
| | 5903 | } |
| | 5904 | IrInstruction *save_token = ir_build_coro_save(irb, child_scope, node, irb->exec->coro_handle); |
| | 5905 | ir_gen_node(irb, node->data.suspend.block, child_scope); |
| | 5906 | suspend_code = ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false); |
| | 5907 | } |
| | 5908 | |
| | 5909 | IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup"); |
| | 5910 | IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume"); |
| | 5911 | |
| | 5912 | IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2); |
| | 5913 | cases[0].value = ir_build_const_u8(irb, parent_scope, node, 0); |
| | 5914 | cases[0].block = resume_block; |
| | 5915 | cases[1].value = ir_build_const_u8(irb, parent_scope, node, 1); |
| | 5916 | cases[1].block = cleanup_block; |
| | 5917 | ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block, |
| | 5918 | 2, cases, const_bool_false); |
| | 5919 | |
| | 5920 | ir_set_cursor_at_end_and_append_block(irb, cleanup_block); |
| | 5921 | ir_gen_defers_for_block(irb, parent_scope, outer_scope, true); |
| | 5922 | ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false); |
| | 5923 | |
| | 5924 | ir_set_cursor_at_end_and_append_block(irb, resume_block); |
| | 5925 | return ir_build_const_void(irb, parent_scope, node); |
| 5851 | } | 5926 | } |
| 5852 | | 5927 | |
| 5853 | static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, | 5928 | static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, |
| ... | @@ -6099,6 +6174,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -6099,6 +6174,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6099 | | 6174 | |
| 6100 | irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal"); | 6175 | irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal"); |
| 6101 | irb->exec->coro_normal_final = ir_create_basic_block(irb, scope, "CoroNormalFinal"); | 6176 | irb->exec->coro_normal_final = ir_create_basic_block(irb, scope, "CoroNormalFinal"); |
| | 6177 | irb->exec->coro_suspend_block = ir_create_basic_block(irb, scope, "Suspend"); |
| | 6178 | irb->exec->coro_final_cleanup_block = ir_create_basic_block(irb, scope, "FinalCleanup"); |
| 6102 | } | 6179 | } |
| 6103 | | 6180 | |
| 6104 | IrInstruction *result = ir_gen_node_extra(irb, node, scope, LVAL_NONE); | 6181 | IrInstruction *result = ir_gen_node_extra(irb, node, scope, LVAL_NONE); |
| ... | @@ -6112,8 +6189,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -6112,8 +6189,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6112 | | 6189 | |
| 6113 | if (is_async) { | 6190 | if (is_async) { |
| 6114 | IrBasicBlock *invalid_resume_block = ir_create_basic_block(irb, scope, "InvalidResume"); | 6191 | IrBasicBlock *invalid_resume_block = ir_create_basic_block(irb, scope, "InvalidResume"); |
| 6115 | IrBasicBlock *final_cleanup_block = ir_create_basic_block(irb, scope, "FinalCleanup"); | | |
| 6116 | IrBasicBlock *suspend_block = ir_create_basic_block(irb, scope, "Suspend"); | | |
| 6117 | IrBasicBlock *check_free_block = ir_create_basic_block(irb, scope, "CheckFree"); | 6192 | IrBasicBlock *check_free_block = ir_create_basic_block(irb, scope, "CheckFree"); |
| 6118 | | 6193 | |
| 6119 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_early_final); | 6194 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_early_final); |
| ... | @@ -6123,10 +6198,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -6123,10 +6198,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6123 | cases[0].value = ir_build_const_u8(irb, scope, node, 0); | 6198 | cases[0].value = ir_build_const_u8(irb, scope, node, 0); |
| 6124 | cases[0].block = invalid_resume_block; | 6199 | cases[0].block = invalid_resume_block; |
| 6125 | cases[1].value = ir_build_const_u8(irb, scope, node, 1); | 6200 | cases[1].value = ir_build_const_u8(irb, scope, node, 1); |
| 6126 | cases[1].block = final_cleanup_block; | 6201 | cases[1].block = irb->exec->coro_final_cleanup_block; |
| 6127 | ir_build_switch_br(irb, scope, node, suspend_code, suspend_block, 2, cases, const_bool_false); | 6202 | ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false); |
| 6128 | | 6203 | |
| 6129 | ir_set_cursor_at_end_and_append_block(irb, suspend_block); | 6204 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_suspend_block); |
| 6130 | ir_build_coro_end(irb, scope, node); | 6205 | ir_build_coro_end(irb, scope, node); |
| 6131 | ir_build_return(irb, scope, node, irb->exec->coro_handle); | 6206 | ir_build_return(irb, scope, node, irb->exec->coro_handle); |
| 6132 | | 6207 | |
| ... | @@ -6136,7 +6211,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -6136,7 +6211,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6136 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_normal_final); | 6211 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_normal_final); |
| 6137 | ir_build_br(irb, scope, node, check_free_block, const_bool_false); | 6212 | ir_build_br(irb, scope, node, check_free_block, const_bool_false); |
| 6138 | | 6213 | |
| 6139 | ir_set_cursor_at_end_and_append_block(irb, final_cleanup_block); | 6214 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block); |
| 6140 | if (type_has_bits(return_type)) { | 6215 | if (type_has_bits(return_type)) { |
| 6141 | IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); | 6216 | IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); |
| 6142 | IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, result_ptr); | 6217 | IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, result_ptr); |
| ... | @@ -6152,7 +6227,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -6152,7 +6227,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6152 | ir_set_cursor_at_end_and_append_block(irb, check_free_block); | 6227 | ir_set_cursor_at_end_and_append_block(irb, check_free_block); |
| 6153 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); | 6228 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); |
| 6154 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); | 6229 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); |
| 6155 | incoming_blocks[0] = final_cleanup_block; | 6230 | incoming_blocks[0] = irb->exec->coro_final_cleanup_block; |
| 6156 | incoming_values[0] = const_bool_false; | 6231 | incoming_values[0] = const_bool_false; |
| 6157 | incoming_blocks[1] = irb->exec->coro_normal_final; | 6232 | incoming_blocks[1] = irb->exec->coro_normal_final; |
| 6158 | incoming_values[1] = const_bool_true; | 6233 | incoming_values[1] = const_bool_true; |
| ... | @@ -17219,6 +17294,18 @@ static TypeTableEntry *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInst | ... | @@ -17219,6 +17294,18 @@ static TypeTableEntry *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInst |
| 17219 | return result->value.type; | 17294 | return result->value.type; |
| 17220 | } | 17295 | } |
| 17221 | | 17296 | |
| | 17297 | static TypeTableEntry *ir_analyze_instruction_coro_save(IrAnalyze *ira, IrInstructionCoroSave *instruction) { |
| | 17298 | IrInstruction *coro_handle = instruction->coro_handle->other; |
| | 17299 | if (type_is_invalid(coro_handle->value.type)) |
| | 17300 | return ira->codegen->builtin_types.entry_invalid; |
| | 17301 | |
| | 17302 | IrInstruction *result = ir_build_coro_save(&ira->new_irb, instruction->base.scope, |
| | 17303 | instruction->base.source_node, coro_handle); |
| | 17304 | ir_link_new_instruction(result, &instruction->base); |
| | 17305 | result->value.type = ira->codegen->builtin_types.entry_usize; |
| | 17306 | return result->value.type; |
| | 17307 | } |
| | 17308 | |
| 17222 | | 17309 | |
| 17223 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { | 17310 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 17224 | switch (instruction->id) { | 17311 | switch (instruction->id) { |
| ... | @@ -17444,6 +17531,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -17444,6 +17531,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 17444 | return ir_analyze_instruction_coro_free(ira, (IrInstructionCoroFree *)instruction); | 17531 | return ir_analyze_instruction_coro_free(ira, (IrInstructionCoroFree *)instruction); |
| 17445 | case IrInstructionIdCoroResume: | 17532 | case IrInstructionIdCoroResume: |
| 17446 | return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction); | 17533 | return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction); |
| | 17534 | case IrInstructionIdCoroSave: |
| | 17535 | return ir_analyze_instruction_coro_save(ira, (IrInstructionCoroSave *)instruction); |
| 17447 | } | 17536 | } |
| 17448 | zig_unreachable(); | 17537 | zig_unreachable(); |
| 17449 | } | 17538 | } |
| ... | @@ -17566,6 +17655,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -17566,6 +17655,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 17566 | case IrInstructionIdCoroAllocFail: | 17655 | case IrInstructionIdCoroAllocFail: |
| 17567 | case IrInstructionIdCoroEnd: | 17656 | case IrInstructionIdCoroEnd: |
| 17568 | case IrInstructionIdCoroResume: | 17657 | case IrInstructionIdCoroResume: |
| | 17658 | case IrInstructionIdCoroSave: |
| 17569 | return true; | 17659 | return true; |
| 17570 | | 17660 | |
| 17571 | case IrInstructionIdPhi: | 17661 | case IrInstructionIdPhi: |