Commit 11bd50f2b2

Andrew Kelley <andrew@ziglang.org>
2019-07-22 02:54:08
implement coroutine resume
1 parent 78e03c4
Changed files (5)
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,
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();
 }
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<typename T>
 static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
     T *special_instruction = allocate<T>(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<IrInstructionCoroResume>(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:
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");
 }
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;