diff options
Diffstat (limited to 'llvm/lib/Transforms/Coroutines')
-rw-r--r-- | llvm/lib/Transforms/Coroutines/CoroInstr.h | 7 | ||||
-rw-r--r-- | llvm/lib/Transforms/Coroutines/CoroSplit.cpp | 45 |
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); } |