| author | |
| committer | |
| log | 11bd50f2b2a74ce25d841a15ba67d042d41b71c2 |
| tree | 8221af0a57e853be09b7dea942ba2f44261f8270 |
| parent | 78e03c466c6641571adef4bb3931d6cc6f425eb4 |
| signature |
5 files changed, 67 insertions(+), 2 deletions(-)
src/all_types.hpp+7| ... | ... | @@ -2322,6 +2322,7 @@ enum IrInstructionId { |
| 2322 | 2322 | IrInstructionIdUnionInitNamedField, |
| 2323 | 2323 | IrInstructionIdSuspendBegin, |
| 2324 | 2324 | IrInstructionIdSuspendBr, |
| 2325 | IrInstructionIdCoroResume, | |
| 2325 | 2326 | }; |
| 2326 | 2327 | |
| 2327 | 2328 | struct IrInstruction { |
| ... | ... | @@ -3548,6 +3549,12 @@ struct IrInstructionSuspendBr { |
| 3548 | 3549 | IrBasicBlock *resume_block; |
| 3549 | 3550 | }; |
| 3550 | 3551 | |
| 3552 | struct IrInstructionCoroResume { | |
| 3553 | IrInstruction base; | |
| 3554 | ||
| 3555 | IrInstruction *frame; | |
| 3556 | }; | |
| 3557 | ||
| 3551 | 3558 | enum ResultLocId { |
| 3552 | 3559 | ResultLocIdInvalid, |
| 3553 | 3560 | ResultLocIdNone, |
src/codegen.cpp+14| ... | ... | @@ -4969,6 +4969,18 @@ static LLVMValueRef ir_render_suspend_br(CodeGen *g, IrExecutable *executable, |
| 4969 | 4969 | return nullptr; |
| 4970 | 4970 | } |
| 4971 | 4971 | |
| 4972 | static LLVMValueRef ir_render_coro_resume(CodeGen *g, IrExecutable *executable, | |
| 4973 | IrInstructionCoroResume *instruction) | |
| 4974 | { | |
| 4975 | LLVMValueRef frame = ir_llvm_value(g, instruction->frame); | |
| 4976 | ZigType *frame_type = instruction->frame->value.type; | |
| 4977 | assert(frame_type->id == ZigTypeIdCoroFrame); | |
| 4978 | ZigFn *fn = frame_type->data.frame.fn; | |
| 4979 | LLVMValueRef fn_val = fn_llvm_value(g, fn); | |
| 4980 | LLVMBuildCall(g->builder, fn_val, &frame, 1, ""); | |
| 4981 | return nullptr; | |
| 4982 | } | |
| 4983 | ||
| 4972 | 4984 | static void set_debug_location(CodeGen *g, IrInstruction *instruction) { |
| 4973 | 4985 | AstNode *source_node = instruction->source_node; |
| 4974 | 4986 | Scope *scope = instruction->scope; |
| ... | ... | @@ -5213,6 +5225,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5213 | 5225 | return ir_render_suspend_begin(g, executable, (IrInstructionSuspendBegin *)instruction); |
| 5214 | 5226 | case IrInstructionIdSuspendBr: |
| 5215 | 5227 | return ir_render_suspend_br(g, executable, (IrInstructionSuspendBr *)instruction); |
| 5228 | case IrInstructionIdCoroResume: | |
| 5229 | return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction); | |
| 5216 | 5230 | } |
| 5217 | 5231 | zig_unreachable(); |
| 5218 | 5232 | } |
src/ir.cpp+34-1| ... | ... | @@ -1035,6 +1035,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendBr *) { |
| 1035 | 1035 | return IrInstructionIdSuspendBr; |
| 1036 | 1036 | } |
| 1037 | 1037 | |
| 1038 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) { | |
| 1039 | return IrInstructionIdCoroResume; | |
| 1040 | } | |
| 1041 | ||
| 1038 | 1042 | template<typename T> |
| 1039 | 1043 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1040 | 1044 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -3216,6 +3220,18 @@ static IrInstruction *ir_build_suspend_br(IrBuilder *irb, Scope *scope, AstNode |
| 3216 | 3220 | return &instruction->base; |
| 3217 | 3221 | } |
| 3218 | 3222 | |
| 3223 | static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 3224 | IrInstruction *frame) | |
| 3225 | { | |
| 3226 | IrInstructionCoroResume *instruction = ir_build_instruction<IrInstructionCoroResume>(irb, scope, source_node); | |
| 3227 | instruction->base.value.type = irb->codegen->builtin_types.entry_void; | |
| 3228 | instruction->frame = frame; | |
| 3229 | ||
| 3230 | ir_ref_instruction(frame, irb->current_basic_block); | |
| 3231 | ||
| 3232 | return &instruction->base; | |
| 3233 | } | |
| 3234 | ||
| 3219 | 3235 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 3220 | 3236 | results[ReturnKindUnconditional] = 0; |
| 3221 | 3237 | results[ReturnKindError] = 0; |
| ... | ... | @@ -7675,7 +7691,7 @@ static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) |
| 7675 | 7691 | if (target_inst == irb->codegen->invalid_instruction) |
| 7676 | 7692 | return irb->codegen->invalid_instruction; |
| 7677 | 7693 | |
| 7678 | zig_panic("TODO ir_gen_resume"); | |
| 7694 | return ir_build_coro_resume(irb, scope, node, target_inst); | |
| 7679 | 7695 | } |
| 7680 | 7696 | |
| 7681 | 7697 | 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 |
| 24134 | 24150 | return ir_finish_anal(ira, result); |
| 24135 | 24151 | } |
| 24136 | 24152 | |
| 24153 | static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstructionCoroResume *instruction) { | |
| 24154 | IrInstruction *frame = instruction->frame->child; | |
| 24155 | if (type_is_invalid(frame->value.type)) | |
| 24156 | return ira->codegen->invalid_instruction; | |
| 24157 | ||
| 24158 | if (frame->value.type->id != ZigTypeIdCoroFrame) { | |
| 24159 | ir_add_error(ira, instruction->frame, | |
| 24160 | buf_sprintf("expected frame, found '%s'", buf_ptr(&frame->value.type->name))); | |
| 24161 | return ira->codegen->invalid_instruction; | |
| 24162 | } | |
| 24163 | ||
| 24164 | return ir_build_coro_resume(&ira->new_irb, instruction->base.scope, instruction->base.source_node, frame); | |
| 24165 | } | |
| 24166 | ||
| 24137 | 24167 | static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { |
| 24138 | 24168 | switch (instruction->id) { |
| 24139 | 24169 | case IrInstructionIdInvalid: |
| ... | ... | @@ -24421,6 +24451,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 24421 | 24451 | return ir_analyze_instruction_suspend_begin(ira, (IrInstructionSuspendBegin *)instruction); |
| 24422 | 24452 | case IrInstructionIdSuspendBr: |
| 24423 | 24453 | return ir_analyze_instruction_suspend_br(ira, (IrInstructionSuspendBr *)instruction); |
| 24454 | case IrInstructionIdCoroResume: | |
| 24455 | return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction); | |
| 24424 | 24456 | } |
| 24425 | 24457 | zig_unreachable(); |
| 24426 | 24458 | } |
| ... | ... | @@ -24555,6 +24587,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 24555 | 24587 | case IrInstructionIdResetResult: |
| 24556 | 24588 | case IrInstructionIdSuspendBegin: |
| 24557 | 24589 | case IrInstructionIdSuspendBr: |
| 24590 | case IrInstructionIdCoroResume: | |
| 24558 | 24591 | return true; |
| 24559 | 24592 | |
| 24560 | 24593 | case IrInstructionIdPhi: |
src/ir_print.cpp+9| ... | ... | @@ -1513,6 +1513,12 @@ static void ir_print_suspend_br(IrPrint *irp, IrInstructionSuspendBr *instructio |
| 1513 | 1513 | fprintf(irp->f, ")"); |
| 1514 | 1514 | } |
| 1515 | 1515 | |
| 1516 | static void ir_print_coro_resume(IrPrint *irp, IrInstructionCoroResume *instruction) { | |
| 1517 | fprintf(irp->f, "@coroResume("); | |
| 1518 | ir_print_other_instruction(irp, instruction->frame); | |
| 1519 | fprintf(irp->f, ")"); | |
| 1520 | } | |
| 1521 | ||
| 1516 | 1522 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1517 | 1523 | ir_print_prefix(irp, instruction); |
| 1518 | 1524 | switch (instruction->id) { |
| ... | ... | @@ -1977,6 +1983,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1977 | 1983 | case IrInstructionIdSuspendBr: |
| 1978 | 1984 | ir_print_suspend_br(irp, (IrInstructionSuspendBr *)instruction); |
| 1979 | 1985 | break; |
| 1986 | case IrInstructionIdCoroResume: | |
| 1987 | ir_print_coro_resume(irp, (IrInstructionCoroResume *)instruction); | |
| 1988 | break; | |
| 1980 | 1989 | } |
| 1981 | 1990 | fprintf(irp->f, "\n"); |
| 1982 | 1991 | } |
test/stage1/behavior/coroutines.zig+3-1| ... | ... | @@ -4,9 +4,11 @@ const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | var x: i32 = 1; |
| 6 | 6 | |
| 7 | test "simple coroutine suspend" { | |
| 7 | test "simple coroutine suspend and resume" { | |
| 8 | 8 | const p = async simpleAsyncFn(); |
| 9 | 9 | expect(x == 2); |
| 10 | resume p; | |
| 11 | expect(x == 3); | |
| 10 | 12 | } |
| 11 | 13 | fn simpleAsyncFn() void { |
| 12 | 14 | x += 1; |