summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms')
-rw-r--r--llvm/lib/Transforms/Coroutines/CoroInstr.h7
-rw-r--r--llvm/lib/Transforms/Coroutines/CoroSplit.cpp45
2 files changed, 36 insertions, 16 deletions
diff --git a/llvm/lib/Transforms/Coroutines/CoroInstr.h b/llvm/lib/Transforms/Coroutines/CoroInstr.h
index 91d7427c379..e03cef4bfc4 100644
--- a/llvm/lib/Transforms/Coroutines/CoroInstr.h
+++ b/llvm/lib/Transforms/Coroutines/CoroInstr.h
@@ -80,11 +80,10 @@ class LLVM_LIBRARY_VISIBILITY CoroIdInst : public IntrinsicInst {
enum { AlignArg, PromiseArg, CoroutineArg, InfoArg };
public:
- IntrinsicInst *getCoroAlloc() {
+ CoroAllocInst *getCoroAlloc() {
for (User *U : users())
- if (auto *II = dyn_cast<IntrinsicInst>(U))
- if (II->getIntrinsicID() == Intrinsic::coro_alloc)
- return II;
+ if (auto *CA = dyn_cast<CoroAllocInst>(U))
+ return CA;
return nullptr;
}
diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
index 77c4be88a4e..7a3f4f60bae 100644
--- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -273,18 +273,6 @@ static Function *createClone(Function &F, Twine Suffix, coro::Shape &Shape,
// FIXME: coming in upcoming patches:
// replaceUnwindCoroEnds(Shape.CoroEnds, VMap);
- // We only store resume(0) and destroy(1) addresses in the coroutine frame.
- // The cleanup(2) clone is only used during devirtualization when coroutine is
- // eligible for heap elision and thus does not participate in indirect calls
- // and does not need its address to be stored in the coroutine frame.
- if (FnIndex < 2) {
- // Store the address of this clone in the coroutine frame.
- Builder.SetInsertPoint(Shape.FramePtr->getNextNode());
- auto *G = Builder.CreateConstInBoundsGEP2_32(Shape.FrameTy, Shape.FramePtr,
- 0, FnIndex, "fn.addr");
- Builder.CreateStore(NewF, G);
- }
-
// Eliminate coro.free from the clones, replacing it with 'null' in cleanup,
// to suppress deallocation code.
coro::replaceCoroFree(cast<CoroIdInst>(VMap[Shape.CoroBegin->getId()]),
@@ -348,6 +336,31 @@ static void setCoroInfo(Function &F, CoroBeginInst *CoroBegin,
CoroBegin->getId()->setInfo(BC);
}
+// Store addresses of Resume/Destroy/Cleanup functions in the coroutine frame.
+static void updateCoroFrame(coro::Shape &Shape, Function *ResumeFn,
+ Function *DestroyFn, Function *CleanupFn) {
+
+ IRBuilder<> Builder(Shape.FramePtr->getNextNode());
+ auto *ResumeAddr = Builder.CreateConstInBoundsGEP2_32(
+ Shape.FrameTy, Shape.FramePtr, 0, coro::Shape::ResumeField,
+ "resume.addr");
+ Builder.CreateStore(ResumeFn, ResumeAddr);
+
+ Value *DestroyOrCleanupFn = DestroyFn;
+
+ CoroIdInst *CoroId = Shape.CoroBegin->getId();
+ if (CoroAllocInst *CA = CoroId->getCoroAlloc()) {
+ // If there is a CoroAlloc and it returns false (meaning we elide the
+ // allocation, use CleanupFn instead of DestroyFn).
+ DestroyOrCleanupFn = Builder.CreateSelect(CA, DestroyFn, CleanupFn);
+ }
+
+ auto *DestroyAddr = Builder.CreateConstInBoundsGEP2_32(
+ Shape.FrameTy, Shape.FramePtr, 0, coro::Shape::DestroyField,
+ "destroy.addr");
+ Builder.CreateStore(DestroyOrCleanupFn, DestroyAddr);
+}
+
static void postSplitCleanup(Function &F) {
removeUnreachableBlocks(F);
llvm::legacy::FunctionPassManager FPM(F.getParent());
@@ -496,7 +509,15 @@ static void splitCoroutine(Function &F, CallGraph &CG, CallGraphSCC &SCC) {
postSplitCleanup(*DestroyClone);
postSplitCleanup(*CleanupClone);
+ // Store addresses resume/destroy/cleanup functions in the coroutine frame.
+ updateCoroFrame(Shape, ResumeClone, DestroyClone, CleanupClone);
+
+ // Create a constant array referring to resume/destroy/clone functions pointed
+ // by the last argument of @llvm.coro.info, so that CoroElide pass can
+ // determined correct function to call.
setCoroInfo(F, Shape.CoroBegin, {ResumeClone, DestroyClone, CleanupClone});
+
+ // Update call graph and add the functions we created to the SCC.
coro::updateCallGraph(F, {ResumeClone, DestroyClone, CleanupClone}, CG, SCC);
}
OpenPOWER on IntegriCloud