diff --git a/src/all_types.hpp b/src/all_types.hpp index a2b569898c..82d2e2cddb 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2322,6 +2322,7 @@ enum IrInstructionId { IrInstructionIdUnionInitNamedField, IrInstructionIdSuspendBegin, IrInstructionIdSuspendBr, + IrInstructionIdCoroResume, }; struct IrInstruction { @@ -3548,6 +3549,12 @@ struct IrInstructionSuspendBr { IrBasicBlock *resume_block; }; +struct IrInstructionCoroResume { + IrInstruction base; + + IrInstruction *frame; +}; + enum ResultLocId { ResultLocIdInvalid, ResultLocIdNone, diff --git a/src/codegen.cpp b/src/codegen.cpp index 4a9e5fd629..fa5f3ef8ee 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4969,6 +4969,18 @@ static LLVMValueRef ir_render_suspend_br(CodeGen *g, IrExecutable *executable, return nullptr; } +static LLVMValueRef ir_render_coro_resume(CodeGen *g, IrExecutable *executable, + IrInstructionCoroResume *instruction) +{ + LLVMValueRef frame = ir_llvm_value(g, instruction->frame); + ZigType *frame_type = instruction->frame->value.type; + assert(frame_type->id == ZigTypeIdCoroFrame); + ZigFn *fn = frame_type->data.frame.fn; + LLVMValueRef fn_val = fn_llvm_value(g, fn); + LLVMBuildCall(g->builder, fn_val, &frame, 1, ""); + return nullptr; +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5213,6 +5225,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_suspend_begin(g, executable, (IrInstructionSuspendBegin *)instruction); case IrInstructionIdSuspendBr: return ir_render_suspend_br(g, executable, (IrInstructionSuspendBr *)instruction); + case IrInstructionIdCoroResume: + return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction); } zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 2b3462772f..d0a11c2f1e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1035,6 +1035,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendBr *) { return IrInstructionIdSuspendBr; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) { + return IrInstructionIdCoroResume; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -3216,6 +3220,18 @@ static IrInstruction *ir_build_suspend_br(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } +static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *frame) +{ + IrInstructionCoroResume *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base.value.type = irb->codegen->builtin_types.entry_void; + instruction->frame = frame; + + ir_ref_instruction(frame, irb->current_basic_block); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -7675,7 +7691,7 @@ static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) if (target_inst == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - zig_panic("TODO ir_gen_resume"); + return ir_build_coro_resume(irb, scope, node, target_inst); } static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -24134,6 +24150,20 @@ static IrInstruction *ir_analyze_instruction_suspend_br(IrAnalyze *ira, IrInstru return ir_finish_anal(ira, result); } +static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstructionCoroResume *instruction) { + IrInstruction *frame = instruction->frame->child; + if (type_is_invalid(frame->value.type)) + return ira->codegen->invalid_instruction; + + if (frame->value.type->id != ZigTypeIdCoroFrame) { + ir_add_error(ira, instruction->frame, + buf_sprintf("expected frame, found '%s'", buf_ptr(&frame->value.type->name))); + return ira->codegen->invalid_instruction; + } + + return ir_build_coro_resume(&ira->new_irb, instruction->base.scope, instruction->base.source_node, frame); +} + static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -24421,6 +24451,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_suspend_begin(ira, (IrInstructionSuspendBegin *)instruction); case IrInstructionIdSuspendBr: return ir_analyze_instruction_suspend_br(ira, (IrInstructionSuspendBr *)instruction); + case IrInstructionIdCoroResume: + return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction); } zig_unreachable(); } @@ -24555,6 +24587,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdResetResult: case IrInstructionIdSuspendBegin: case IrInstructionIdSuspendBr: + case IrInstructionIdCoroResume: return true; case IrInstructionIdPhi: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 3a77e92bc7..e14647ea82 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1513,6 +1513,12 @@ static void ir_print_suspend_br(IrPrint *irp, IrInstructionSuspendBr *instructio fprintf(irp->f, ")"); } +static void ir_print_coro_resume(IrPrint *irp, IrInstructionCoroResume *instruction) { + fprintf(irp->f, "@coroResume("); + ir_print_other_instruction(irp, instruction->frame); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1977,6 +1983,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdSuspendBr: ir_print_suspend_br(irp, (IrInstructionSuspendBr *)instruction); break; + case IrInstructionIdCoroResume: + ir_print_coro_resume(irp, (IrInstructionCoroResume *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/test/stage1/behavior/coroutines.zig b/test/stage1/behavior/coroutines.zig index cdab411fb1..fd07790e7f 100644 --- a/test/stage1/behavior/coroutines.zig +++ b/test/stage1/behavior/coroutines.zig @@ -4,9 +4,11 @@ const expect = std.testing.expect; var x: i32 = 1; -test "simple coroutine suspend" { +test "simple coroutine suspend and resume" { const p = async simpleAsyncFn(); expect(x == 2); + resume p; + expect(x == 3); } fn simpleAsyncFn() void { x += 1;