| ... | ... | @@ -691,6 +691,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) { |
| 691 | 691 | return IrInstructionIdCoroResume; |
| 692 | 692 | } |
| 693 | 693 | |
| 694 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSave *) { |
| 695 | return IrInstructionIdCoroSave; |
| 696 | } |
| 697 | |
| 694 | 698 | template<typename T> |
| 695 | 699 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 696 | 700 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -2585,6 +2589,17 @@ static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode |
| 2585 | 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 | 2603 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2589 | 2604 | results[ReturnKindUnconditional] = 0; |
| 2590 | 2605 | results[ReturnKindError] = 0; |
| ... | ... | @@ -5847,7 +5862,67 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast |
| 5847 | 5862 | static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| 5848 | 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 | 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 | 6174 | |
| 6100 | 6175 | irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal"); |
| 6101 | 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 | 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 | 6189 | |
| 6113 | 6190 | if (is_async) { |
| 6114 | 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 | 6192 | IrBasicBlock *check_free_block = ir_create_basic_block(irb, scope, "CheckFree"); |
| 6118 | 6193 | |
| 6119 | 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 | 6198 | cases[0].value = ir_build_const_u8(irb, scope, node, 0); |
| 6124 | 6199 | cases[0].block = invalid_resume_block; |
| 6125 | 6200 | cases[1].value = ir_build_const_u8(irb, scope, node, 1); |
| 6126 | | cases[1].block = final_cleanup_block; |
| 6127 | | ir_build_switch_br(irb, scope, node, suspend_code, suspend_block, 2, cases, const_bool_false); |
| 6201 | cases[1].block = irb->exec->coro_final_cleanup_block; |
| 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 | 6205 | ir_build_coro_end(irb, scope, node); |
| 6131 | 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 | 6211 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_normal_final); |
| 6137 | 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 | 6215 | if (type_has_bits(return_type)) { |
| 6141 | 6216 | IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); |
| 6142 | 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 | 6227 | ir_set_cursor_at_end_and_append_block(irb, check_free_block); |
| 6153 | 6228 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); |
| 6154 | 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 | 6231 | incoming_values[0] = const_bool_false; |
| 6157 | 6232 | incoming_blocks[1] = irb->exec->coro_normal_final; |
| 6158 | 6233 | incoming_values[1] = const_bool_true; |
| ... | ... | @@ -17219,6 +17294,18 @@ static TypeTableEntry *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInst |
| 17219 | 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 | 17310 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 17224 | 17311 | switch (instruction->id) { |
| ... | ... | @@ -17444,6 +17531,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 17444 | 17531 | return ir_analyze_instruction_coro_free(ira, (IrInstructionCoroFree *)instruction); |
| 17445 | 17532 | case IrInstructionIdCoroResume: |
| 17446 | 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 | 17537 | zig_unreachable(); |
| 17449 | 17538 | } |
| ... | ... | @@ -17566,6 +17655,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 17566 | 17655 | case IrInstructionIdCoroAllocFail: |
| 17567 | 17656 | case IrInstructionIdCoroEnd: |
| 17568 | 17657 | case IrInstructionIdCoroResume: |
| 17658 | case IrInstructionIdCoroSave: |
| 17569 | 17659 | return true; |
| 17570 | 17660 | |
| 17571 | 17661 | case IrInstructionIdPhi: |