mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[coroutines] Add handling for unwind coro.ends
Summary: The purpose of coro.end 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. In landing pads coro.end is replaced with an appropriate instruction to unwind to caller. The handling of coro.end differs depending on whether the target is using landingpad or WinEH exception model. For landingpad based exception model, it is expected that frontend uses the `coro.end`_ intrinsic as follows: ``` 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: ``` 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. Reviewers: majnemer Reviewed By: majnemer Subscribers: llvm-commits, mehdi_amini Differential Revision: https://reviews.llvm.org/D25543 llvm-svn: 297223
This commit is contained in:
parent
56489ac797
commit
01cac3014b
@ -110,7 +110,7 @@ The LLVM IR for this coroutine looks like this:
|
||||
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 @@ store the current value produced by a coroutine.
|
||||
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 @@ A frontend should emit exactly one `coro.id` intrinsic per coroutine.
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
::
|
||||
|
||||
declare void @llvm.coro.end(i8* <handle>, i1 <unwind>)
|
||||
declare i1 @llvm.coro.end(i8* <handle>, i1 <unwind>)
|
||||
|
||||
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:
|
||||
|
@ -666,7 +666,7 @@ def int_coro_begin : Intrinsic<[llvm_ptr_ty], [llvm_token_ty, llvm_ptr_ty],
|
||||
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]>;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "CoroInternal.h"
|
||||
#include "llvm/Analysis/CallGraphSCCPass.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/InstIterator.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
@ -144,6 +145,33 @@ static void replaceFallthroughCoroEnd(IntrinsicInst *End,
|
||||
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<IntrinsicInst>(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
|
||||
@ -270,9 +298,7 @@ static Function *createClone(Function &F, Twine Suffix, coro::Shape &Shape,
|
||||
|
||||
// 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.
|
||||
coro::replaceCoroFree(cast<CoroIdInst>(VMap[Shape.CoroBegin->getId()]),
|
||||
@ -284,8 +310,16 @@ static Function *createClone(Function &F, Twine Suffix, coro::Shape &Shape,
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -32,7 +32,7 @@ coro_Cleanup:
|
||||
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 i32 @llvm.coro.size.i32()
|
||||
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*)
|
||||
|
@ -22,7 +22,7 @@ cleanup:
|
||||
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
|
||||
pad:
|
||||
%tok = cleanuppad within none []
|
||||
@ -54,7 +54,7 @@ declare void @llvm.coro.destroy(i8*)
|
||||
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 double @print(double)
|
||||
|
@ -28,7 +28,7 @@ cleanup:
|
||||
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
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ declare void @llvm.coro.destroy(i8*)
|
||||
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)
|
||||
|
@ -26,7 +26,7 @@ cleanup:
|
||||
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 void @llvm.coro.destroy(i8*)
|
||||
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)
|
||||
|
@ -28,7 +28,7 @@ await.ready:
|
||||
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.frame() #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
|
||||
|
||||
|
@ -38,7 +38,7 @@ coro_Cleanup: ; preds = %for.cond
|
||||
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 i8 @llvm.coro.suspend(token, i1) #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
|
||||
|
145
test/Transforms/Coroutines/coro-split-eh.ll
Normal file
145
test/Transforms/Coroutines/coro-split-eh.ll
Normal file
@ -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*)
|
||||
|
@ -24,7 +24,7 @@ cleanup:
|
||||
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.resume(i8*)
|
||||
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)
|
||||
|
@ -20,7 +20,7 @@ cleanup:
|
||||
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 i32 @llvm.coro.size.i32()
|
||||
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*)
|
||||
|
@ -29,7 +29,7 @@ dyn.free:
|
||||
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 i32 @llvm.coro.size.i32()
|
||||
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*)
|
||||
|
@ -26,7 +26,7 @@ cleanup:
|
||||
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 i32 @llvm.coro.size.i32()
|
||||
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*)
|
||||
|
@ -28,7 +28,7 @@ cleanup:
|
||||
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 i32 @llvm.coro.size.i32()
|
||||
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*)
|
||||
|
@ -31,7 +31,7 @@ cleanup:
|
||||
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 i8* @llvm.coro.begin(token, i8*)
|
||||
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() {
|
||||
|
@ -32,7 +32,7 @@ dyn.free:
|
||||
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 @@ cleanup:
|
||||
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 @@ cleanup:
|
||||
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 @@ cleanup:
|
||||
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 i8* @llvm.coro.begin(token, i8*)
|
||||
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*)
|
||||
|
@ -17,7 +17,7 @@ cleanup:
|
||||
|
||||
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 void @llvm.coro.destroy(i8*)
|
||||
|
||||
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)
|
||||
|
@ -25,7 +25,7 @@ cleanup:
|
||||
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 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 void @llvm.coro.end(i8*, i1)
|
||||
declare i1 @llvm.coro.end(i8*, i1)
|
||||
|
||||
declare noalias i8* @malloc(i32)
|
||||
declare void @print(i32)
|
||||
|
Loading…
Reference in New Issue
Block a user