Skip to content

Commit d4948c1

Browse files
committed
Store GUIDs in metadata
See https://discourse.llvm.org/t/rfc-keep-globalvalue-guids-stable/84801 for context. This takes the existing AssignGUID pass from CtxProfAnalysis, and runs it by default, at the appropriate stages of the LTO pipeline. It also changes GlobalValue::getGUID() to retrieve the GUID from the metadata instead of computing it. We don't yet have the supporting downstream changes to make a dedicated GUID table in bitcode, nor do we use the metadata as part of ThinLTO -- it retains its existing mechanisms of recomputing GUIDs from separately saved data. That will be changed later.
1 parent c6cec7b commit d4948c1

14 files changed

+144
-56
lines changed

llvm/include/llvm/Analysis/CtxProfAnalysis.h

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ class PGOContextualProfile {
4646
// we'll need when we maintain the profiles during IPO transformations.
4747
std::map<GlobalValue::GUID, FunctionInfo> FuncInfo;
4848

49-
/// Get the GUID of this Function if it's defined in this module.
50-
GlobalValue::GUID getDefinedFunctionGUID(const Function &F) const;
51-
5249
// This is meant to be constructed from CtxProfAnalysis, which will also set
5350
// its state piecemeal.
5451
PGOContextualProfile() = default;
@@ -67,9 +64,7 @@ class PGOContextualProfile {
6764

6865
bool isInSpecializedModule() const;
6966

70-
bool isFunctionKnown(const Function &F) const {
71-
return getDefinedFunctionGUID(F) != 0;
72-
}
67+
bool isFunctionKnown(const Function &F) const { return F.getGUID() != 0; }
7368

7469
StringRef getFunctionName(GlobalValue::GUID GUID) const {
7570
auto It = FuncInfo.find(GUID);
@@ -80,22 +75,22 @@ class PGOContextualProfile {
8075

8176
uint32_t getNumCounters(const Function &F) const {
8277
assert(isFunctionKnown(F));
83-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex;
78+
return FuncInfo.find(F.getGUID())->second.NextCounterIndex;
8479
}
8580

8681
uint32_t getNumCallsites(const Function &F) const {
8782
assert(isFunctionKnown(F));
88-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex;
83+
return FuncInfo.find(F.getGUID())->second.NextCallsiteIndex;
8984
}
9085

9186
uint32_t allocateNextCounterIndex(const Function &F) {
9287
assert(isFunctionKnown(F));
93-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex++;
88+
return FuncInfo.find(F.getGUID())->second.NextCounterIndex++;
9489
}
9590

9691
uint32_t allocateNextCallsiteIndex(const Function &F) {
9792
assert(isFunctionKnown(F));
98-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex++;
93+
return FuncInfo.find(F.getGUID())->second.NextCallsiteIndex++;
9994
}
10095

10196
using ConstVisitor = function_ref<void(const PGOCtxProfContext &)>;
@@ -185,26 +180,5 @@ class ProfileAnnotator {
185180
~ProfileAnnotator();
186181
};
187182

188-
/// Assign a GUID to functions as metadata. GUID calculation takes linkage into
189-
/// account, which may change especially through and after thinlto. By
190-
/// pre-computing and assigning as metadata, this mechanism is resilient to such
191-
/// changes (as well as name changes e.g. suffix ".llvm." additions).
192-
193-
// FIXME(mtrofin): we can generalize this mechanism to calculate a GUID early in
194-
// the pass pipeline, associate it with any Global Value, and then use it for
195-
// PGO and ThinLTO.
196-
// At that point, this should be moved elsewhere.
197-
class AssignGUIDPass : public PassInfoMixin<AssignGUIDPass> {
198-
public:
199-
explicit AssignGUIDPass() = default;
200-
201-
/// Assign a GUID *if* one is not already assign, as a function metadata named
202-
/// `GUIDMetadataName`.
203-
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
204-
static const char *GUIDMetadataName;
205-
// This should become GlobalValue::getGUID
206-
static uint64_t getGUID(const Function &F);
207-
};
208-
209183
} // namespace llvm
210184
#endif // LLVM_ANALYSIS_CTXPROFANALYSIS_H

llvm/include/llvm/IR/FixedMetadataKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,4 @@ LLVM_FIXED_MD_KIND(MD_DIAssignID, "DIAssignID", 38)
5353
LLVM_FIXED_MD_KIND(MD_coro_outside_frame, "coro.outside.frame", 39)
5454
LLVM_FIXED_MD_KIND(MD_mmra, "mmra", 40)
5555
LLVM_FIXED_MD_KIND(MD_noalias_addrspace, "noalias.addrspace", 41)
56+
LLVM_FIXED_MD_KIND(MD_unique_id, "unique_id", 42)

llvm/include/llvm/IR/GlobalValue.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -594,11 +594,20 @@ class GlobalValue : public Constant {
594594
/// the GUID computation will assume that the global has external linkage.
595595
static GUID getGUIDAssumingExternalLinkage(StringRef GlobalName);
596596

597+
/// Assign a GUID to this value based on its current name and linkage.
598+
/// This GUID will remain the same even if those change. This method is
599+
/// idempotent -- if a GUID has already been assigned, calling it again
600+
/// will do nothing.
601+
///
602+
/// Users don't need to call this method. They are assigned in batch by a
603+
/// dedicated pass. The pass pipeline should be set up such that GUIDs are
604+
/// always available when needed. If not, the GUID assignment pass should
605+
/// be moved such that they are.
606+
void assignGUID();
607+
597608
/// Return a 64-bit global unique ID constructed from global value name
598609
/// (i.e. returned by getGlobalIdentifier()).
599-
GUID getGUID() const {
600-
return getGUIDAssumingExternalLinkage(getGlobalIdentifier());
601-
}
610+
GUID getGUID() const;
602611

603612
/// @name Materialization
604613
/// Materialization is used to construct functions only as they're needed.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===-- AssignGUID.h - Unique identifier assignment pass --------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file provides a pass which assigns a a GUID (globally unique identifier)
10+
// to every GlobalValue in the module, according to its current name, linkage,
11+
// and originating file.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_TRANSFORMS_UTILS_ASSIGNGUID_H
16+
#define LLVM_TRANSFORMS_UTILS_ASSIGNGUID_H
17+
18+
#include "llvm/IR/Module.h"
19+
#include "llvm/IR/PassManager.h"
20+
21+
namespace llvm {
22+
23+
class AssignGUIDPass : public PassInfoMixin<AssignGUIDPass> {
24+
public:
25+
AssignGUIDPass() = default;
26+
27+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
28+
29+
static bool isRequired() { return true; }
30+
};
31+
32+
} // end namespace llvm
33+
34+
#endif // LLVM_TRANSFORMS_UTILS_ASSIGNGUID_H

llvm/lib/Analysis/CtxProfAnalysis.cpp

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ static cl::opt<bool> ForceIsInSpecializedModule(
4848
cl::desc("Treat the given module as-if it were containing the "
4949
"post-thinlink module containing the root"));
5050

51-
const char *AssignGUIDPass::GUIDMetadataName = "guid";
52-
5351
namespace llvm {
5452
class ProfileAnnotatorImpl final {
5553
friend class ProfileAnnotator;
@@ -513,7 +511,7 @@ PGOContextualProfile CtxProfAnalysis::run(Module &M,
513511
for (const auto &F : M) {
514512
if (F.isDeclaration())
515513
continue;
516-
auto GUID = AssignGUIDPass::getGUID(F);
514+
auto GUID = F.getGUID();
517515
assert(GUID && "guid not found for defined function");
518516
const auto &Entry = F.begin();
519517
uint32_t MaxCounters = 0; // we expect at least a counter.
@@ -547,13 +545,6 @@ PGOContextualProfile CtxProfAnalysis::run(Module &M,
547545
return Result;
548546
}
549547

550-
GlobalValue::GUID
551-
PGOContextualProfile::getDefinedFunctionGUID(const Function &F) const {
552-
if (auto It = FuncInfo.find(AssignGUIDPass::getGUID(F)); It != FuncInfo.end())
553-
return It->first;
554-
return 0;
555-
}
556-
557548
CtxProfAnalysisPrinterPass::CtxProfAnalysisPrinterPass(raw_ostream &OS)
558549
: OS(OS), Mode(PrintLevel) {}
559550

@@ -669,7 +660,7 @@ bool PGOContextualProfile::isInSpecializedModule() const {
669660

670661
void PGOContextualProfile::update(Visitor V, const Function &F) {
671662
assert(isFunctionKnown(F));
672-
GlobalValue::GUID G = getDefinedFunctionGUID(F);
663+
GlobalValue::GUID G = F.getGUID();
673664
for (auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
674665
Node = Node->Next)
675666
V(*reinterpret_cast<PGOCtxProfContext *>(Node));
@@ -680,7 +671,7 @@ void PGOContextualProfile::visit(ConstVisitor V, const Function *F) const {
680671
return preorderVisit<const PGOCtxProfContext::CallTargetMapTy,
681672
const PGOCtxProfContext>(Profiles.Contexts, V);
682673
assert(isFunctionKnown(*F));
683-
GlobalValue::GUID G = getDefinedFunctionGUID(*F);
674+
GlobalValue::GUID G = F->getGUID();
684675
for (const auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
685676
Node = Node->Next)
686677
V(*reinterpret_cast<const PGOCtxProfContext *>(Node));

llvm/lib/IR/Globals.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,46 @@ GlobalValue::getGUIDAssumingExternalLinkage(StringRef GlobalIdentifier) {
7878
return MD5Hash(GlobalIdentifier);
7979
}
8080

81+
void GlobalValue::assignGUID() {
82+
if (isDeclaration()) {
83+
// Declarations don't get an assigned GUID. Their definition is in another
84+
// module, and it may have been promoted from local to external linkage
85+
// during LTO. Because of this, we can only determine their GUID once the
86+
// definition is available.
87+
return;
88+
}
89+
if (getMetadata(LLVMContext::MD_unique_id) != nullptr)
90+
return;
91+
92+
const GUID G =
93+
GlobalValue::getGUIDAssumingExternalLinkage(getGlobalIdentifier());
94+
setMetadata(
95+
LLVMContext::MD_unique_id,
96+
MDNode::get(getContext(), {ConstantAsMetadata::get(ConstantInt::get(
97+
Type::getInt64Ty(getContext()), G))}));
98+
}
99+
100+
GlobalValue::GUID GlobalValue::getGUID() const {
101+
if (isa<GlobalAlias>(this)) {
102+
return GlobalValue::getGUIDAssumingExternalLinkage(getGlobalIdentifier());
103+
}
104+
105+
if (isDeclaration()) {
106+
// Declarations don't get an assigned GUID. Their definition is in another
107+
// module, and it may have been promoted from local to external linkage
108+
// during LTO. Because of this, we can only determine their GUID once the
109+
// definition is available.
110+
return 0;
111+
}
112+
113+
auto *MD = getMetadata(LLVMContext::MD_unique_id);
114+
assert(MD != nullptr && "GUID was not assigned before calling GetGUID()");
115+
return cast<ConstantInt>(cast<ConstantAsMetadata>(MD->getOperand(0))
116+
->getValue()
117+
->stripPointerCasts())
118+
->getZExtValue();
119+
}
120+
81121
void GlobalValue::removeFromParent() {
82122
switch (getValueID()) {
83123
#define HANDLE_GLOBAL_VALUE(NAME) \

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@
334334
#include "llvm/Transforms/Scalar/TailRecursionElimination.h"
335335
#include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
336336
#include "llvm/Transforms/Utils/AddDiscriminators.h"
337+
#include "llvm/Transforms/Utils/AssignGUID.h"
337338
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
338339
#include "llvm/Transforms/Utils/BreakCriticalEdges.h"
339340
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
#include "llvm/Transforms/Scalar/TailRecursionElimination.h"
131131
#include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
132132
#include "llvm/Transforms/Utils/AddDiscriminators.h"
133+
#include "llvm/Transforms/Utils/AssignGUID.h"
133134
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
134135
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
135136
#include "llvm/Transforms/Utils/CountVisits.h"
@@ -791,6 +792,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
791792
void PassBuilder::addRequiredLTOPreLinkPasses(ModulePassManager &MPM) {
792793
MPM.addPass(CanonicalizeAliasesPass());
793794
MPM.addPass(NameAnonGlobalPass());
795+
MPM.addPass(AssignGUIDPass());
794796
}
795797

796798
void PassBuilder::addPreInlinerPasses(ModulePassManager &MPM,
@@ -1076,6 +1078,11 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
10761078

10771079
ModulePassManager MPM;
10781080

1081+
if (Phase != ThinOrFullLTOPhase::ThinLTOPostLink) {
1082+
MPM.addPass(NameAnonGlobalPass());
1083+
MPM.addPass(AssignGUIDPass());
1084+
}
1085+
10791086
// Place pseudo probe instrumentation as the first pass of the pipeline to
10801087
// minimize the impact of optimization changes.
10811088
if (PGOOpt && PGOOpt->PseudoProbeForProfiling &&
@@ -1239,8 +1246,6 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
12391246
// In pre-link, we just want the instrumented IR. We use the contextual
12401247
// profile in the post-thinlink phase.
12411248
// The instrumentation will be removed in post-thinlink after IPO.
1242-
// FIXME(mtrofin): move AssignGUIDPass if there is agreement to use this
1243-
// mechanism for GUIDs.
12441249
MPM.addPass(AssignGUIDPass());
12451250
if (IsCtxProfUse) {
12461251
MPM.addPass(PGOCtxProfFlatteningPass(/*IsPreThinlink=*/true));

llvm/lib/Transforms/Instrumentation/PGOCtxProfFlattening.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ PreservedAnalyses PGOCtxProfFlatteningPass::run(Module &M,
181181
"Function has unreacheable basic blocks. The expectation was that "
182182
"DCE was run before.");
183183

184-
auto It = FlattenedProfile.find(AssignGUIDPass::getGUID(F));
184+
auto It = FlattenedProfile.find(F.getGUID());
185185
// If this function didn't appear in the contextual profile, it's cold.
186186
if (It == FlattenedProfile.end())
187187
clearColdFunctionProfile(F);

llvm/lib/Transforms/Instrumentation/PGOCtxProfLowering.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,7 @@ bool CtxInstrumentationLowerer::lowerFunction(Function &F) {
280280
assert(Mark->getIndex()->isZero());
281281

282282
IRBuilder<> Builder(Mark);
283-
Guid = Builder.getInt64(
284-
AssignGUIDPass::getGUID(cast<Function>(*Mark->getNameValue())));
283+
Guid = Builder.getInt64(cast<Function>(*Mark->getNameValue()).getGUID());
285284
// The type of the context of this function is now knowable since we have
286285
// NumCallsites and NumCounters. We delcare it here because it's more
287286
// convenient - we have the Builder.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===-- AssignGUID.cpp - Unique identifier assignment pass ------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file provides a pass which assigns a a GUID (globally unique identifier)
10+
// to every GlobalValue in the module, according to its current name, linkage,
11+
// and originating file.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "llvm/Transforms/Utils/AssignGUID.h"
16+
#include "llvm/Support/Debug.h"
17+
18+
using namespace llvm;
19+
20+
PreservedAnalyses AssignGUIDPass::run(Module &M, ModuleAnalysisManager &AM) {
21+
for (auto &GV : M.globals()) {
22+
if (GV.isDeclaration())
23+
continue;
24+
GV.assignGUID();
25+
dbgs() << "[Added GUID to GV:] " << GV.getName() << "\n";
26+
}
27+
for (auto &F : M.functions()) {
28+
if (F.isDeclaration())
29+
continue;
30+
F.assignGUID();
31+
dbgs() << "[Added GUID to F:] " << F.getName() << "\n";
32+
}
33+
return PreservedAnalyses::none();
34+
}

llvm/lib/Transforms/Utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_llvm_component_library(LLVMTransformUtils
22
AddDiscriminators.cpp
33
AMDGPUEmitPrintf.cpp
44
ASanStackFrameLayout.cpp
5+
AssignGUID.cpp
56
AssumeBundleBuilder.cpp
67
BasicBlockUtils.cpp
78
BreakCriticalEdges.cpp

llvm/lib/Transforms/Utils/CallPromotionUtils.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -616,11 +616,11 @@ CallBase *llvm::promoteCallWithIfThenElse(CallBase &CB, Function &Callee,
616616
IndirectBBIns->setIndex(IndirectID);
617617
IndirectBBIns->insertInto(&IndirectBB, IndirectBB.getFirstInsertionPt());
618618

619-
const GlobalValue::GUID CalleeGUID = AssignGUIDPass::getGUID(Callee);
619+
const GlobalValue::GUID CalleeGUID = Callee.getGUID();
620620
const uint32_t NewCountersSize = IndirectID + 1;
621621

622622
auto ProfileUpdater = [&](PGOCtxProfContext &Ctx) {
623-
assert(Ctx.guid() == AssignGUIDPass::getGUID(Caller));
623+
assert(Ctx.guid() == Caller.getGUID());
624624
assert(NewCountersSize - 2 == Ctx.counters().size());
625625
// All the ctx-es belonging to a function must have the same size counters.
626626
Ctx.resizeCounters(NewCountersSize);
@@ -655,7 +655,6 @@ CallBase *llvm::promoteCallWithIfThenElse(CallBase &CB, Function &Callee,
655655
// times, and the indirect BB, IndirectCount times
656656
Ctx.counters()[DirectID] = DirectCount;
657657
Ctx.counters()[IndirectID] = IndirectCount;
658-
659658
};
660659
CtxProf.update(ProfileUpdater, Caller);
661660
return &DirectCall;

llvm/lib/Transforms/Utils/InlineFunction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2373,7 +2373,7 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
23732373
// Get some preliminary data about the callsite before it might get inlined.
23742374
// Inlining shouldn't delete the callee, but it's cleaner (and low-cost) to
23752375
// get this data upfront and rely less on InlineFunction's behavior.
2376-
const auto CalleeGUID = AssignGUIDPass::getGUID(Callee);
2376+
const auto CalleeGUID = Callee.getGUID();
23772377
auto *CallsiteIDIns = CtxProfAnalysis::getCallsiteInstrumentation(CB);
23782378
const auto CallsiteID =
23792379
static_cast<uint32_t>(CallsiteIDIns->getIndex()->getZExtValue());
@@ -2398,7 +2398,7 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI,
23982398
const uint32_t NewCountersSize = CtxProf.getNumCounters(Caller);
23992399

24002400
auto Updater = [&](PGOCtxProfContext &Ctx) {
2401-
assert(Ctx.guid() == AssignGUIDPass::getGUID(Caller));
2401+
assert(Ctx.guid() == Caller.getGUID());
24022402
const auto &[CalleeCounterMap, CalleeCallsiteMap] = IndicesMaps;
24032403
assert(
24042404
(Ctx.counters().size() +

0 commit comments

Comments
 (0)