summaryrefslogtreecommitdiff
path: root/lib/Transforms/Coroutines
diff options
context:
space:
mode:
authorGor Nishanov <GorNishanov@gmail.com>2016-09-30 19:24:19 +0000
committerGor Nishanov <GorNishanov@gmail.com>2016-09-30 19:24:19 +0000
commit40fec41b24f64888fac7df90e7bf920019cc2da9 (patch)
treee7131ba9400d2f90908ca01fe8a81fa59efa239a /lib/Transforms/Coroutines
parent32d667e940bcc9af0168f01ba5594c2640790cc1 (diff)
[Coroutines] Part15c: Fix coro-split to correctly handle definitions between coro.save and coro.suspend
Summary: In the case below, %Result.i19 is defined between coro.save and coro.suspend and used after coro.suspend. We need to correctly place such a value into the coroutine frame. ``` %save = call token @llvm.coro.save(i8* null) %Result.i19 = getelementptr inbounds %"struct.lean_future<int>::Awaiter", %"struct.lean_future<int>::Awaiter"* %ref.tmp7, i64 0, i32 0 %suspend = call i8 @llvm.coro.suspend(token %save, i1 false) switch i8 %suspend, label %exit [ i8 0, label %await.ready i8 1, label %exit ] await.ready: %val = load i32, i32* %Result.i19 ``` Reviewers: majnemer Subscribers: llvm-commits, mehdi_amini Differential Revision: https://reviews.llvm.org/D24418 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@282902 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/Coroutines')
-rw-r--r--lib/Transforms/Coroutines/CoroFrame.cpp48
1 files changed, 26 insertions, 22 deletions
diff --git a/lib/Transforms/Coroutines/CoroFrame.cpp b/lib/Transforms/Coroutines/CoroFrame.cpp
index 2b4e725fd0e..c3aab28f4fb 100644
--- a/lib/Transforms/Coroutines/CoroFrame.cpp
+++ b/lib/Transforms/Coroutines/CoroFrame.cpp
@@ -171,19 +171,22 @@ SuspendCrossingInfo::SuspendCrossingInfo(Function &F, coro::Shape &Shape)
for (auto *CE : Shape.CoroEnds)
getBlockData(CE->getParent()).End = true;
- // Mark all suspend blocks and indicate that kill everything they consume.
- // Note, that crossing coro.save is used to indicate suspend, as any code
+ // Mark all suspend blocks and indicate that they kill everything they
+ // consume. Note, that crossing coro.save also requires a spill, as any code
// between coro.save and coro.suspend may resume the coroutine and all of the
// state needs to be saved by that time.
- for (CoroSuspendInst *CSI : Shape.CoroSuspends) {
- CoroSaveInst *const CoroSave = CSI->getCoroSave();
- BasicBlock *const CoroSaveBB = CoroSave->getParent();
- auto &B = getBlockData(CoroSaveBB);
+ auto markSuspendBlock = [&](IntrinsicInst* BarrierInst) {
+ BasicBlock *SuspendBlock = BarrierInst->getParent();
+ auto &B = getBlockData(SuspendBlock);
B.Suspend = true;
B.Kills |= B.Consumes;
+ };
+ for (CoroSuspendInst *CSI : Shape.CoroSuspends) {
+ markSuspendBlock(CSI);
+ markSuspendBlock(CSI->getCoroSave());
}
- // Iterate propagating consumes and kills until they stop changing
+ // Iterate propagating consumes and kills until they stop changing.
int Iteration = 0;
(void)Iteration;
@@ -533,6 +536,13 @@ static bool materializable(Instruction &V) {
isa<BinaryOperator>(&V) || isa<CmpInst>(&V) || isa<SelectInst>(&V);
}
+// Check for structural coroutine intrinsics that should not be spilled into
+// the coroutine frame.
+static bool isCoroutineStructureIntrinsic(Instruction &I) {
+ return isa<CoroIdInst>(&I) || isa<CoroBeginInst>(&I) ||
+ isa<CoroSaveInst>(&I) || isa<CoroSuspendInst>(&I);
+}
+
// For every use of the value that is across suspend point, recreate that value
// after a suspend point.
static void rewriteMaterializableInstructions(IRBuilder<> &IRB,
@@ -647,10 +657,13 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) {
Shape.CoroBegin->getId()->clearPromise();
}
- // Make sure that all coro.saves and the fallthrough coro.end are in their
- // own block to simplify the logic of building up SuspendCrossing data.
- for (CoroSuspendInst *CSI : Shape.CoroSuspends)
+ // Make sure that all coro.save, coro.suspend and the fallthrough coro.end
+ // intrinsics are in their own blocks to simplify the logic of building up
+ // SuspendCrossing data.
+ for (CoroSuspendInst *CSI : Shape.CoroSuspends) {
splitAround(CSI->getCoroSave(), "CoroSave");
+ splitAround(CSI, "CoroSuspend");
+ }
// Put fallthrough CoroEnd into its own block. Note: Shape::buildFrom places
// the fallthrough coro.end as the first element of CoroEnds array.
@@ -686,18 +699,9 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) {
Spills.emplace_back(&A, U);
for (Instruction &I : instructions(F)) {
- // token returned by CoroSave is an artifact of how we build save/suspend
- // pairs and should not be part of the Coroutine Frame
- if (isa<CoroSaveInst>(&I))
- continue;
- // CoroBeginInst returns a handle to a coroutine which is passed as a sole
- // parameter to .resume and .cleanup parts and should not go into coroutine
- // frame.
- if (isa<CoroBeginInst>(&I))
- continue;
- // A token returned CoroIdInst is used to tie together structural intrinsics
- // in a coroutine. It should not be saved to the coroutine frame.
- if (isa<CoroIdInst>(&I))
+ // Values returned from coroutine structure intrinsics should not be part
+ // of the Coroutine Frame.
+ if (isCoroutineStructureIntrinsic(I))
continue;
// The Coroutine Promise always included into coroutine frame, no need to
// check for suspend crossing.