Index: docs/Coroutines.rst =================================================================== --- docs/Coroutines.rst +++ docs/Coroutines.rst @@ -110,7 +110,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 false) + %unused = call i1 @llvm.coro.end(i8* %hdl, i1 false) ret i8* %hdl } @@ -440,7 +440,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 false) + %unused = call i1 @llvm.coro.end(i8* %hdl, i1 false) ret i8* %hdl } @@ -955,41 +955,90 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare void @llvm.coro.end(i8* , i1 ) + declare i1 @llvm.coro.end(i8* , i1 ) Overview: """"""""" The '``llvm.coro.end``' marks the point where execution of the resume part of -the coroutine should end and control returns back to the caller. +the coroutine should end and control should return to the caller. Arguments: """""""""" -The first argument should refer to the coroutine handle of the enclosing coroutine. +The first argument should refer to the coroutine handle of the enclosing +coroutine. A frontend is allowed to supply null as the first parameter, in this +case `coro-early` pass will replace the null with an appropriate coroutine +handle value. The second argument should be `true` if this coro.end is in the block that is -part of the unwind sequence leaving the coroutine body due to exception prior to -the first reaching any suspend points, and `false` otherwise. +part of the unwind sequence leaving the coroutine body due to an exception and +`false` otherwise. Semantics: """""""""" -The `coro.end`_ intrinsic is a no-op during an initial invocation of the -coroutine. When the coroutine resumes, the intrinsic marks the point when -coroutine need to return control back to the caller. +The purpose of this intrinsic is to allow frontends to mark the cleanup and +other code that is only relevant during the initial invocation of the coroutine +and should not be present in resume and destroy parts. -This intrinsic is removed by the CoroSplit pass when a coroutine is split into -the start, resume and destroy parts. In start part, the intrinsic is removed, -in resume and destroy parts, it is replaced with `ret void` instructions and +This intrinsic is lowered when a coroutine is split into +the start, resume and destroy parts. In the start part, it is a no-op, +in resume and destroy parts, it is replaced with `ret void` instruction and the rest of the block containing `coro.end` instruction is discarded. - In landing pads it is replaced with an appropriate instruction to unwind to -caller. +caller. The handling of coro.end differs depending on whether the target is +using landingpad or WinEH exception model. -A frontend is allowed to supply null as the first parameter, in this case -`coro-early` pass will replace the null with an appropriate coroutine handle -value. +For landingpad based exception model, it is expected that frontend uses the +`coro.end`_ intrinsic as follows: + +.. code-block:: llvm + + ehcleanup: + %InResumePart = call i1 @llvm.coro.end(i8* null, i1 true) + br i1 %InResumePart, label %eh.resume, label %cleanup.cont + + cleanup.cont: + ; rest of the cleanup + + eh.resume: + %exn = load i8*, i8** %exn.slot, align 8 + %sel = load i32, i32* %ehselector.slot, align 4 + %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0 + %lpad.val29 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1 + resume { i8*, i32 } %lpad.val29 + +The `CoroSpit` pass replaces `coro.end` with ``True`` in the resume functions, +thus leading to immediate unwind to the caller, whereas in start function it +is replaced with ``False``, thus allowing to proceed to the rest of the cleanup +code that is only needed during initial invocation of the coroutine. + +For Windows Exception handling model, a frontend should attach a funclet bundle +referring to an enclosing cleanuppad as follows: + +.. code-block:: text + + ehcleanup: + %tok = cleanuppad within none [] + %unused = call i1 @llvm.coro.end(i8* null, i1 true) [ "funclet"(token %tok) ] + cleanupret from %tok unwind label %RestOfTheCleanup + +The `CoroSplit` pass, if the funclet bundle is present, will insert +``cleanupret from %tok unwind to caller`` before +the `coro.end`_ intrinsic and will remove the rest of the block. + +The following table summarizes the handling of `coro.end`_ intrinsic. + ++--------------------------+-------------------+-------------------------------+ +| | In Start Function | In Resume/Destroy Functions | ++--------------------------+-------------------+-------------------------------+ +|unwind=false | nothing |``ret void`` | ++------------+-------------+-------------------+-------------------------------+ +| | WinEH | nothing |``cleanupret unwind to caller``| +|unwind=true +-------------+-------------------+-------------------------------+ +| | Landingpad | nothing | nothing | ++------------+-------------+-------------------+-------------------------------+ .. _coro.suspend: .. _suspend points: Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -619,7 +619,7 @@ def int_coro_free : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly, ReadOnly<1>, NoCapture<1>]>; -def int_coro_end : Intrinsic<[], [llvm_ptr_ty, llvm_i1_ty], []>; +def int_coro_end : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_i1_ty], []>; def int_coro_frame : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>; def int_coro_size : Intrinsic<[llvm_anyint_ty], [], [IntrNoMem]>; Index: lib/Transforms/Coroutines/CoroSplit.cpp =================================================================== --- lib/Transforms/Coroutines/CoroSplit.cpp +++ lib/Transforms/Coroutines/CoroSplit.cpp @@ -145,6 +145,33 @@ BB->getTerminator()->eraseFromParent(); } +// In Resumers, we replace unwind coro.end with True to force the immediate +// unwind to caller. +static void replaceUnwindCoroEnds(coro::Shape &Shape, ValueToValueMapTy &VMap) { + if (Shape.CoroEnds.empty()) + return; + + LLVMContext &Context = Shape.CoroEnds.front()->getContext(); + auto *True = ConstantInt::getTrue(Context); + for (CoroEndInst *CE : Shape.CoroEnds) { + if (!CE->isUnwind()) + continue; + + auto *NewCE = cast(VMap[CE]); + + // If coro.end has an associated bundle, add cleanupret instruction. + if (auto Bundle = NewCE->getOperandBundle(LLVMContext::OB_funclet)) { + Value *FromPad = Bundle->Inputs[0]; + auto *CleanupRet = CleanupReturnInst::Create(FromPad, nullptr, NewCE); + NewCE->getParent()->splitBasicBlock(NewCE); + CleanupRet->getParent()->getTerminator()->eraseFromParent(); + } + + NewCE->replaceAllUsesWith(True); + NewCE->eraseFromParent(); + } +} + // Rewrite final suspend point handling. We do not use suspend index to // represent the final suspend point. Instead we zero-out ResumeFnAddr in the // coroutine frame, since it is undefined behavior to resume a coroutine @@ -271,8 +298,7 @@ // Remove coro.end intrinsics. replaceFallthroughCoroEnd(Shape.CoroEnds.front(), VMap); - // FIXME: coming in upcoming patches: - // replaceUnwindCoroEnds(Shape.CoroEnds, VMap); + replaceUnwindCoroEnds(Shape, VMap); // Eliminate coro.free from the clones, replacing it with 'null' in cleanup, // to suppress deallocation code. @@ -285,8 +311,16 @@ } static void removeCoroEnds(coro::Shape &Shape) { - for (CoroEndInst *CE : Shape.CoroEnds) + if (Shape.CoroEnds.empty()) + return; + + LLVMContext &Context = Shape.CoroEnds.front()->getContext(); + auto *False = ConstantInt::getFalse(Context); + + for (CoroEndInst *CE : Shape.CoroEnds) { + CE->replaceAllUsesWith(False); CE->eraseFromParent(); + } } static void replaceFrameSize(coro::Shape &Shape) { @@ -510,16 +544,6 @@ return; } - // If there are no suspend points, no split required, just remove - // the allocation and deallocation blocks, they are not needed. - if (Shape.CoroSuspends.empty()) { - handleNoSuspendCoroutine(Shape.CoroBegin, Shape.FrameTy); - removeCoroEnds(Shape); - postSplitCleanup(F); - coro::updateCallGraph(F, {}, CG, SCC); - return; - } - auto *ResumeEntry = createResumeEntryBlock(F, Shape); auto ResumeClone = createClone(F, ".resume", Shape, ResumeEntry, 0); auto DestroyClone = createClone(F, ".destroy", Shape, ResumeEntry, 1); Index: test/Transforms/Coroutines/ArgAddr.ll =================================================================== --- test/Transforms/Coroutines/ArgAddr.ll +++ test/Transforms/Coroutines/ArgAddr.ll @@ -32,7 +32,7 @@ br label %coro_Suspend coro_Suspend: - call void @llvm.coro.end(i8* null, i1 false) + call i1 @llvm.coro.end(i8* null, i1 false) ret i8* %1 } @@ -61,7 +61,7 @@ declare i8* @llvm.coro.begin(token, i8*) declare i8 @llvm.coro.suspend(token, i1) declare i8* @llvm.coro.free(token, i8*) -declare void @llvm.coro.end(i8*, i1) +declare i1 @llvm.coro.end(i8*, i1) declare void @llvm.coro.resume(i8*) declare void @llvm.coro.destroy(i8*) Index: test/Transforms/Coroutines/coro-split-00.ll =================================================================== --- test/Transforms/Coroutines/coro-split-00.ll +++ test/Transforms/Coroutines/coro-split-00.ll @@ -20,7 +20,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 0) + call i1 @llvm.coro.end(i8* %hdl, i1 0) ret i8* %hdl } @@ -54,7 +54,7 @@ declare token @llvm.coro.id(i32, i8*, i8*, i8*) declare i8* @llvm.coro.alloc(token) declare i8* @llvm.coro.begin(token, i8*) -declare void @llvm.coro.end(i8*, i1) +declare i1 @llvm.coro.end(i8*, i1) declare noalias i8* @malloc(i32) declare void @print(i32) Index: test/Transforms/Coroutines/coro-split-01.ll =================================================================== --- test/Transforms/Coroutines/coro-split-01.ll +++ test/Transforms/Coroutines/coro-split-01.ll @@ -26,7 +26,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 0) + call i1 @llvm.coro.end(i8* %hdl, i1 0) ret i8* %hdl } define i32 @main() { @@ -49,7 +49,7 @@ declare token @llvm.coro.id(i32, i8*, i8*, i8*) declare i1 @llvm.coro.alloc(token) declare i8* @llvm.coro.begin(token, i8*) -declare void @llvm.coro.end(i8*, i1) +declare i1 @llvm.coro.end(i8*, i1) declare noalias i8* @malloc(i32) declare void @print(i32) Index: test/Transforms/Coroutines/coro-split-02.ll =================================================================== --- test/Transforms/Coroutines/coro-split-02.ll +++ test/Transforms/Coroutines/coro-split-02.ll @@ -28,7 +28,7 @@ call void @print(i32 %val) br label %exit exit: - call void @llvm.coro.end(i8* null, i1 false) + call i1 @llvm.coro.end(i8* null, i1 false) ret void } @@ -50,5 +50,5 @@ declare i8 @llvm.coro.suspend(token, i1) #3 declare void @"\01??3@YAXPEAX@Z"(i8*) local_unnamed_addr #10 declare i8* @llvm.coro.free(token, i8* nocapture readonly) #2 -declare void @llvm.coro.end(i8*, i1) #3 +declare i1 @llvm.coro.end(i8*, i1) #3 Index: test/Transforms/Coroutines/coro-split-dbg.ll =================================================================== --- test/Transforms/Coroutines/coro-split-dbg.ll +++ test/Transforms/Coroutines/coro-split-dbg.ll @@ -38,7 +38,7 @@ br label %coro_Suspend, !dbg !36 coro_Suspend: ; preds = %for.cond, %if.then, %coro_Cleanup - tail call void @llvm.coro.end(i8* null, i1 false) #9, !dbg !38 + tail call i1 @llvm.coro.end(i8* null, i1 false) #9, !dbg !38 ret i8* %2, !dbg !39 } @@ -57,7 +57,7 @@ declare void @llvm.lifetime.end(i64, i8* nocapture) #4 declare i8* @llvm.coro.free(token, i8* nocapture readonly) #5 declare void @free(i8* nocapture) local_unnamed_addr #6 -declare void @llvm.coro.end(i8*, i1) #7 +declare i1 @llvm.coro.end(i8*, i1) #7 declare i8* @llvm.coro.subfn.addr(i8* nocapture readonly, i8) #5 declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1 Index: test/Transforms/Coroutines/coro-split-eh.ll =================================================================== --- /dev/null +++ test/Transforms/Coroutines/coro-split-eh.ll @@ -0,0 +1,145 @@ +; Tests that coro-split removes cleanup code after coro.end in resume functions +; and retains it in the start function. +; RUN: opt < %s -coro-split -S | FileCheck %s + +define i8* @f(i1 %val) "coroutine.presplit"="1" personality i32 3 { +entry: + %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) + %hdl = call i8* @llvm.coro.begin(token %id, i8* null) + call void @print(i32 0) + br i1 %val, label %resume, label %susp + +susp: + %0 = call i8 @llvm.coro.suspend(token none, i1 false) + switch i8 %0, label %suspend [i8 0, label %resume + i8 1, label %suspend] +resume: + invoke void @print(i32 1) to label %suspend unwind label %lpad + +suspend: + call i1 @llvm.coro.end(i8* %hdl, i1 0) + call void @print(i32 0) ; should not be present in f.resume + ret i8* %hdl + +lpad: + %lpval = landingpad { i8*, i32 } + cleanup + + call void @print(i32 2) + %need.resume = call i1 @llvm.coro.end(i8* null, i1 true) + br i1 %need.resume, label %eh.resume, label %cleanup.cont + +cleanup.cont: + call void @print(i32 3) ; should not be present in f.resume + br label %eh.resume + +eh.resume: + resume { i8*, i32 } %lpval +} + +; Verify that start function contains both print calls the one before and after coro.end +; CHECK-LABEL: define i8* @f( +; CHECK: invoke void @print(i32 1) +; CHECK: to label %AfterCoroEnd unwind label %lpad + +; CHECK: AfterCoroEnd: +; CHECK: call void @print(i32 0) +; CHECK: ret i8* %hdl + +; CHECK: lpad: +; CHECK-NEXT: %lpval = landingpad { i8*, i32 } +; CHECK-NEXT: cleanup +; CHECK-NEXT: call void @print(i32 2) +; CHECK-NEXT: call void @print(i32 3) +; CHECK-NEXT: resume { i8*, i32 } %lpval + +define i8* @f2(i1 %val) "coroutine.presplit"="1" personality i32 4 { +entry: + %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) + %hdl = call i8* @llvm.coro.begin(token %id, i8* null) + call void @print(i32 0) + br i1 %val, label %resume, label %susp + +susp: + %0 = call i8 @llvm.coro.suspend(token none, i1 false) + switch i8 %0, label %suspend [i8 0, label %resume + i8 1, label %suspend] +resume: + invoke void @print(i32 1) to label %suspend unwind label %lpad + +suspend: + call i1 @llvm.coro.end(i8* %hdl, i1 0) + call void @print(i32 0) ; should not be present in f.resume + ret i8* %hdl + +lpad: + %tok = cleanuppad within none [] + call void @print(i32 2) + %unused = call i1 @llvm.coro.end(i8* null, i1 true) [ "funclet"(token %tok) ] + cleanupret from %tok unwind label %cleanup.cont + +cleanup.cont: + %tok2 = cleanuppad within none [] + call void @print(i32 3) ; should not be present in f.resume + cleanupret from %tok2 unwind to caller +} + +; Verify that start function contains both print calls the one before and after coro.end +; CHECK-LABEL: define i8* @f2( +; CHECK: invoke void @print(i32 1) +; CHECK: to label %AfterCoroEnd unwind label %lpad + +; CHECK: AfterCoroEnd: +; CHECK: call void @print(i32 0) +; CHECK: ret i8* %hdl + +; CHECK: lpad: +; CHECK-NEXT: %tok = cleanuppad within none [] +; CHECK-NEXT: call void @print(i32 2) +; CHECK-NEXT: call void @print(i32 3) +; CHECK-NEXT: cleanupret from %tok unwind to caller + +; VERIFY Resume Parts + +; Verify that resume function does not contains both print calls appearing after coro.end +; CHECK-LABEL: define internal fastcc void @f.resume +; CHECK: invoke void @print(i32 1) +; CHECK: to label %CoroEnd unwind label %lpad + +; CHECK: CoroEnd: +; CHECK-NEXT: ret void + +; CHECK: lpad: +; CHECK-NEXT: %lpval = landingpad { i8*, i32 } +; CHECK-NEXT: cleanup +; CHECK-NEXT: call void @print(i32 2) +; CHECK-NEXT: resume { i8*, i32 } %lpval + +; Verify that resume function does not contains both print calls appearing after coro.end +; CHECK-LABEL: define internal fastcc void @f2.resume +; CHECK: invoke void @print(i32 1) +; CHECK: to label %CoroEnd unwind label %lpad + +; CHECK: CoroEnd: +; CHECK-NEXT: ret void + +; CHECK: lpad: +; CHECK-NEXT: %tok = cleanuppad within none [] +; CHECK-NEXT: call void @print(i32 2) +; CHECK-NEXT: cleanupret from %tok unwind to caller + +declare i8* @llvm.coro.free(token, i8*) +declare i32 @llvm.coro.size.i32() +declare i8 @llvm.coro.suspend(token, i1) +declare void @llvm.coro.resume(i8*) +declare void @llvm.coro.destroy(i8*) + +declare token @llvm.coro.id(i32, i8*, i8*, i8*) +declare i8* @llvm.coro.alloc(token) +declare i8* @llvm.coro.begin(token, i8*) +declare i1 @llvm.coro.end(i8*, i1) + +declare noalias i8* @malloc(i32) +declare void @print(i32) +declare void @free(i8*) + Index: test/Transforms/Coroutines/ex0.ll =================================================================== --- test/Transforms/Coroutines/ex0.ll +++ test/Transforms/Coroutines/ex0.ll @@ -24,7 +24,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 0) + call i1 @llvm.coro.end(i8* %hdl, i1 0) ret i8* %hdl } @@ -52,7 +52,7 @@ declare void @llvm.coro.destroy(i8*) declare i8* @llvm.coro.begin(token, i8*) -declare void @llvm.coro.end(i8*, i1) +declare i1 @llvm.coro.end(i8*, i1) declare noalias i8* @malloc(i32) declare void @print(i32) Index: test/Transforms/Coroutines/ex1.ll =================================================================== --- test/Transforms/Coroutines/ex1.ll +++ test/Transforms/Coroutines/ex1.ll @@ -20,7 +20,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 false) + call i1 @llvm.coro.end(i8* %hdl, i1 false) ret i8* %hdl } @@ -48,7 +48,7 @@ declare i8* @llvm.coro.begin(token, i8*) declare i8 @llvm.coro.suspend(token, i1) declare i8* @llvm.coro.free(token, i8*) -declare void @llvm.coro.end(i8*, i1) +declare i1 @llvm.coro.end(i8*, i1) declare void @llvm.coro.resume(i8*) declare void @llvm.coro.destroy(i8*) Index: test/Transforms/Coroutines/ex2.ll =================================================================== --- test/Transforms/Coroutines/ex2.ll +++ test/Transforms/Coroutines/ex2.ll @@ -29,7 +29,7 @@ call void @CustomFree(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 false) + call i1 @llvm.coro.end(i8* %hdl, i1 false) ret i8* %hdl } @@ -57,7 +57,7 @@ declare i8* @llvm.coro.begin(token, i8*) declare i8 @llvm.coro.suspend(token, i1) declare i8* @llvm.coro.free(token, i8*) -declare void @llvm.coro.end(i8*, i1) +declare i1 @llvm.coro.end(i8*, i1) declare void @llvm.coro.resume(i8*) declare void @llvm.coro.destroy(i8*) Index: test/Transforms/Coroutines/ex3.ll =================================================================== --- test/Transforms/Coroutines/ex3.ll +++ test/Transforms/Coroutines/ex3.ll @@ -26,7 +26,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 false) + call i1 @llvm.coro.end(i8* %hdl, i1 false) ret i8* %hdl } @@ -54,7 +54,7 @@ declare i8* @llvm.coro.begin(token, i8*) declare i8 @llvm.coro.suspend(token, i1) declare i8* @llvm.coro.free(token, i8*) -declare void @llvm.coro.end(i8*, i1) +declare i1 @llvm.coro.end(i8*, i1) declare void @llvm.coro.resume(i8*) declare void @llvm.coro.destroy(i8*) Index: test/Transforms/Coroutines/ex4.ll =================================================================== --- test/Transforms/Coroutines/ex4.ll +++ test/Transforms/Coroutines/ex4.ll @@ -28,7 +28,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 false) + call i1 @llvm.coro.end(i8* %hdl, i1 false) ret i8* %hdl } @@ -65,7 +65,7 @@ declare i8* @llvm.coro.begin(token, i8*) declare i8 @llvm.coro.suspend(token, i1) declare i8* @llvm.coro.free(token, i8*) -declare void @llvm.coro.end(i8*, i1) +declare i1 @llvm.coro.end(i8*, i1) declare void @llvm.coro.resume(i8*) declare void @llvm.coro.destroy(i8*) Index: test/Transforms/Coroutines/ex5.ll =================================================================== --- test/Transforms/Coroutines/ex5.ll +++ test/Transforms/Coroutines/ex5.ll @@ -31,7 +31,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 false) + call i1 @llvm.coro.end(i8* %hdl, i1 false) ret i8* %hdl } @@ -46,7 +46,7 @@ declare token @llvm.coro.save(i8*) declare i8 @llvm.coro.suspend(token, i1) declare i8* @llvm.coro.free(token, i8*) -declare void @llvm.coro.end(i8*, i1) +declare i1 @llvm.coro.end(i8*, i1) ; CHECK-LABEL: @main define i32 @main() { Index: test/Transforms/Coroutines/no-suspend.ll =================================================================== --- test/Transforms/Coroutines/no-suspend.ll +++ test/Transforms/Coroutines/no-suspend.ll @@ -32,7 +32,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 false) + call i1 @llvm.coro.end(i8* %hdl, i1 false) ret void } @@ -77,7 +77,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 false) + call i1 @llvm.coro.end(i8* %hdl, i1 false) ret void } @@ -122,7 +122,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 false) + call i1 @llvm.coro.end(i8* %hdl, i1 false) ret void } @@ -167,7 +167,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 false) + call i1 @llvm.coro.end(i8* %hdl, i1 false) ret void } @@ -183,7 +183,7 @@ declare token @llvm.coro.save(i8* %hdl) declare i8 @llvm.coro.suspend(token, i1) declare i8* @llvm.coro.free(token, i8*) -declare void @llvm.coro.end(i8*, i1) +declare i1 @llvm.coro.end(i8*, i1) declare void @llvm.coro.resume(i8*) declare void @llvm.coro.destroy(i8*) Index: test/Transforms/Coroutines/phi-coro-end.ll =================================================================== --- test/Transforms/Coroutines/phi-coro-end.ll +++ test/Transforms/Coroutines/phi-coro-end.ll @@ -17,7 +17,7 @@ suspend: %r = phi i32 [%n, %entry], [1, %cleanup] - call void @llvm.coro.end(i8* %hdl, i1 false) + call i1 @llvm.coro.end(i8* %hdl, i1 false) call void @print(i32 %r) ret i8* %hdl } @@ -41,7 +41,7 @@ declare token @llvm.coro.id(i32, i8*, i8*, i8*) declare i8* @llvm.coro.begin(token, i8*) -declare void @llvm.coro.end(i8*, i1) +declare i1 @llvm.coro.end(i8*, i1) declare noalias i8* @malloc(i32) declare void @print(i32) Index: test/Transforms/Coroutines/restart-trigger.ll =================================================================== --- test/Transforms/Coroutines/restart-trigger.ll +++ test/Transforms/Coroutines/restart-trigger.ll @@ -25,7 +25,7 @@ call void @free(i8* %mem) br label %suspend suspend: - call void @llvm.coro.end(i8* %hdl, i1 0) + call i1 @llvm.coro.end(i8* %hdl, i1 0) ret void } @@ -36,7 +36,7 @@ declare i8 @llvm.coro.suspend(token, i1) declare void @llvm.coro.resume(i8*) declare void @llvm.coro.destroy(i8*) -declare void @llvm.coro.end(i8*, i1) +declare i1 @llvm.coro.end(i8*, i1) declare noalias i8* @malloc(i32) declare void @print(i32)