diff --git a/llvm/lib/Transforms/Coroutines/CoroCloner.h b/llvm/lib/Transforms/Coroutines/CoroCloner.h index d1887980fb3bc..b817e55cad9fc 100644 --- a/llvm/lib/Transforms/Coroutines/CoroCloner.h +++ b/llvm/lib/Transforms/Coroutines/CoroCloner.h @@ -48,6 +48,9 @@ class BaseCloner { CloneKind FKind; IRBuilder<> Builder; TargetTransformInfo &TTI; + // Common module-level metadata that's shared between all coroutine clones and + // doesn't need to be cloned itself. + const MetadataSetTy &CommonDebugInfo; ValueToValueMapTy VMap; Function *NewF = nullptr; @@ -60,12 +63,12 @@ class BaseCloner { /// Create a cloner for a continuation lowering. BaseCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape, Function *NewF, AnyCoroSuspendInst *ActiveSuspend, - TargetTransformInfo &TTI) + TargetTransformInfo &TTI, const MetadataSetTy &CommonDebugInfo) : OrigF(OrigF), Suffix(Suffix), Shape(Shape), FKind(Shape.ABI == ABI::Async ? CloneKind::Async : CloneKind::Continuation), - Builder(OrigF.getContext()), TTI(TTI), NewF(NewF), - ActiveSuspend(ActiveSuspend) { + Builder(OrigF.getContext()), TTI(TTI), CommonDebugInfo(CommonDebugInfo), + NewF(NewF), ActiveSuspend(ActiveSuspend) { assert(Shape.ABI == ABI::Retcon || Shape.ABI == ABI::RetconOnce || Shape.ABI == ABI::Async); assert(NewF && "need existing function for continuation"); @@ -74,9 +77,11 @@ class BaseCloner { public: BaseCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape, - CloneKind FKind, TargetTransformInfo &TTI) + CloneKind FKind, TargetTransformInfo &TTI, + const MetadataSetTy &CommonDebugInfo) : OrigF(OrigF), Suffix(Suffix), Shape(Shape), FKind(FKind), - Builder(OrigF.getContext()), TTI(TTI) {} + Builder(OrigF.getContext()), TTI(TTI), + CommonDebugInfo(CommonDebugInfo) {} virtual ~BaseCloner() {} @@ -84,12 +89,14 @@ class BaseCloner { static Function *createClone(Function &OrigF, const Twine &Suffix, coro::Shape &Shape, Function *NewF, AnyCoroSuspendInst *ActiveSuspend, - TargetTransformInfo &TTI) { + TargetTransformInfo &TTI, + const MetadataSetTy &CommonDebugInfo) { assert(Shape.ABI == ABI::Retcon || Shape.ABI == ABI::RetconOnce || Shape.ABI == ABI::Async); TimeTraceScope FunctionScope("BaseCloner"); - BaseCloner Cloner(OrigF, Suffix, Shape, NewF, ActiveSuspend, TTI); + BaseCloner Cloner(OrigF, Suffix, Shape, NewF, ActiveSuspend, TTI, + CommonDebugInfo); Cloner.create(); return Cloner.getFunction(); } @@ -129,8 +136,9 @@ class SwitchCloner : public BaseCloner { protected: /// Create a cloner for a switch lowering. SwitchCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape, - CloneKind FKind, TargetTransformInfo &TTI) - : BaseCloner(OrigF, Suffix, Shape, FKind, TTI) {} + CloneKind FKind, TargetTransformInfo &TTI, + const MetadataSetTy &CommonDebugInfo) + : BaseCloner(OrigF, Suffix, Shape, FKind, TTI, CommonDebugInfo) {} void create() override; @@ -138,11 +146,12 @@ class SwitchCloner : public BaseCloner { /// Create a clone for a switch lowering. static Function *createClone(Function &OrigF, const Twine &Suffix, coro::Shape &Shape, CloneKind FKind, - TargetTransformInfo &TTI) { + TargetTransformInfo &TTI, + const MetadataSetTy &CommonDebugInfo) { assert(Shape.ABI == ABI::Switch); TimeTraceScope FunctionScope("SwitchCloner"); - SwitchCloner Cloner(OrigF, Suffix, Shape, FKind, TTI); + SwitchCloner Cloner(OrigF, Suffix, Shape, FKind, TTI, CommonDebugInfo); Cloner.create(); return Cloner.getFunction(); } diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp index 23ac55e8ce0cd..ff5df12c398c5 100644 --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -43,6 +43,7 @@ #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/GlobalValue.h" @@ -77,6 +78,24 @@ using namespace llvm; #define DEBUG_TYPE "coro-split" +namespace { +/// Collect (a known) subset of global debug info metadata potentially used by +/// the function \p F. +/// +/// This metadata set can be used to avoid cloning debug info not owned by \p F +/// and is shared among all potential clones \p F. +MetadataSetTy collectCommonDebugInfo(Function &F) { + TimeTraceScope FunctionScope("CollectCommonDebugInfo"); + + DebugInfoFinder DIFinder; + DISubprogram *SPClonedWithinModule = CollectDebugInfoForCloning( + F, CloneFunctionChangeType::LocalChangesOnly, DIFinder); + + return FindDebugInfoToIdentityMap(CloneFunctionChangeType::LocalChangesOnly, + DIFinder, SPClonedWithinModule); +} +} // end anonymous namespace + // FIXME: // Lower the intrinisc in CoroEarly phase if coroutine frame doesn't escape // and it is known that other transformations, for example, sanitizers @@ -891,8 +910,11 @@ void coro::BaseCloner::create() { auto savedLinkage = NewF->getLinkage(); NewF->setLinkage(llvm::GlobalValue::ExternalLinkage); - CloneFunctionInto(NewF, &OrigF, VMap, - CloneFunctionChangeType::LocalChangesOnly, Returns); + CloneFunctionAttributesInto(NewF, &OrigF, VMap, false); + CloneFunctionMetadataInto(*NewF, OrigF, VMap, RF_None, nullptr, nullptr, + &CommonDebugInfo); + CloneFunctionBodyInto(*NewF, OrigF, VMap, RF_None, Returns, "", nullptr, + nullptr, nullptr, &CommonDebugInfo); auto &Context = NewF->getContext(); @@ -1374,16 +1396,21 @@ struct SwitchCoroutineSplitter { TargetTransformInfo &TTI) { assert(Shape.ABI == coro::ABI::Switch); + MetadataSetTy CommonDebugInfo{collectCommonDebugInfo(F)}; + // Create a resume clone by cloning the body of the original function, // setting new entry block and replacing coro.suspend an appropriate value // to force resume or cleanup pass for every suspend point. createResumeEntryBlock(F, Shape); auto *ResumeClone = coro::SwitchCloner::createClone( - F, ".resume", Shape, coro::CloneKind::SwitchResume, TTI); + F, ".resume", Shape, coro::CloneKind::SwitchResume, TTI, + CommonDebugInfo); auto *DestroyClone = coro::SwitchCloner::createClone( - F, ".destroy", Shape, coro::CloneKind::SwitchUnwind, TTI); + F, ".destroy", Shape, coro::CloneKind::SwitchUnwind, TTI, + CommonDebugInfo); auto *CleanupClone = coro::SwitchCloner::createClone( - F, ".cleanup", Shape, coro::CloneKind::SwitchCleanup, TTI); + F, ".cleanup", Shape, coro::CloneKind::SwitchCleanup, TTI, + CommonDebugInfo); postSplitCleanup(*ResumeClone); postSplitCleanup(*DestroyClone); @@ -1768,12 +1795,15 @@ void coro::AsyncABI::splitCoroutine(Function &F, coro::Shape &Shape, } assert(Clones.size() == Shape.CoroSuspends.size()); + + MetadataSetTy CommonDebugInfo{collectCommonDebugInfo(F)}; + for (auto [Idx, CS] : llvm::enumerate(Shape.CoroSuspends)) { auto *Suspend = CS; auto *Clone = Clones[Idx]; coro::BaseCloner::createClone(F, "resume." + Twine(Idx), Shape, Clone, - Suspend, TTI); + Suspend, TTI, CommonDebugInfo); } } @@ -1899,12 +1929,15 @@ void coro::AnyRetconABI::splitCoroutine(Function &F, coro::Shape &Shape, } assert(Clones.size() == Shape.CoroSuspends.size()); + + MetadataSetTy CommonDebugInfo{collectCommonDebugInfo(F)}; + for (auto [Idx, CS] : llvm::enumerate(Shape.CoroSuspends)) { auto Suspend = CS; auto Clone = Clones[Idx]; coro::BaseCloner::createClone(F, "resume." + Twine(Idx), Shape, Clone, - Suspend, TTI); + Suspend, TTI, CommonDebugInfo); } }