diff options
author | Gor Nishanov <GorNishanov@gmail.com> | 2016-09-30 19:24:19 +0000 |
---|---|---|
committer | Gor Nishanov <GorNishanov@gmail.com> | 2016-09-30 19:24:19 +0000 |
commit | 40fec41b24f64888fac7df90e7bf920019cc2da9 (patch) | |
tree | e7131ba9400d2f90908ca01fe8a81fa59efa239a /lib/Transforms/Coroutines | |
parent | 32d667e940bcc9af0168f01ba5594c2640790cc1 (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.cpp | 48 |
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. |