Skip to content

[Coro] Prebuild a module-level debug info set and share it between all coroutine clones #118628

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions llvm/lib/Transforms/Coroutines/CoroCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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");
Expand All @@ -74,22 +77,26 @@ 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() {}

/// Create a clone for a continuation lowering.
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();
}
Expand Down Expand Up @@ -129,20 +136,22 @@ 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;

public:
/// 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();
}
Expand Down
47 changes: 40 additions & 7 deletions llvm/lib/Transforms/Coroutines/CoroSplit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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);
}
}

Expand Down
Loading