Skip to content

Commit 9d34fae

Browse files
committed
Store GUIDs in metadata
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 3441370 commit 9d34fae

File tree

14 files changed

+131
-83
lines changed

14 files changed

+131
-83
lines changed

llvm/include/llvm/Analysis/CtxProfAnalysis.h

Lines changed: 7 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,9 @@ class PGOContextualProfile {
6764

6865
bool isInSpecializedModule() const;
6966

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

7471
StringRef getFunctionName(GlobalValue::GUID GUID) const {
7572
auto It = FuncInfo.find(GUID);
@@ -80,22 +77,22 @@ class PGOContextualProfile {
8077

8178
uint32_t getNumCounters(const Function &F) const {
8279
assert(isFunctionKnown(F));
83-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex;
80+
return FuncInfo.find(F.getGUID())->second.NextCounterIndex;
8481
}
8582

8683
uint32_t getNumCallsites(const Function &F) const {
8784
assert(isFunctionKnown(F));
88-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex;
85+
return FuncInfo.find(F.getGUID())->second.NextCallsiteIndex;
8986
}
9087

9188
uint32_t allocateNextCounterIndex(const Function &F) {
9289
assert(isFunctionKnown(F));
93-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex++;
90+
return FuncInfo.find(F.getGUID())->second.NextCounterIndex++;
9491
}
9592

9693
uint32_t allocateNextCallsiteIndex(const Function &F) {
9794
assert(isFunctionKnown(F));
98-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex++;
95+
return FuncInfo.find(F.getGUID())->second.NextCallsiteIndex++;
9996
}
10097

10198
using ConstVisitor = function_ref<void(const PGOCtxProfContext &)>;
@@ -157,26 +154,5 @@ class CtxProfAnalysisPrinterPass
157154
const PrintMode Mode;
158155
};
159156

160-
/// Assign a GUID to functions as metadata. GUID calculation takes linkage into
161-
/// account, which may change especially through and after thinlto. By
162-
/// pre-computing and assigning as metadata, this mechanism is resilient to such
163-
/// changes (as well as name changes e.g. suffix ".llvm." additions).
164-
165-
// FIXME(mtrofin): we can generalize this mechanism to calculate a GUID early in
166-
// the pass pipeline, associate it with any Global Value, and then use it for
167-
// PGO and ThinLTO.
168-
// At that point, this should be moved elsewhere.
169-
class AssignGUIDPass : public PassInfoMixin<AssignGUIDPass> {
170-
public:
171-
explicit AssignGUIDPass() = default;
172-
173-
/// Assign a GUID *if* one is not already assign, as a function metadata named
174-
/// `GUIDMetadataName`.
175-
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
176-
static const char *GUIDMetadataName;
177-
// This should become GlobalValue::getGUID
178-
static uint64_t getGUID(const Function &F);
179-
};
180-
181157
} // namespace llvm
182158
#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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -594,11 +594,11 @@ class GlobalValue : public Constant {
594594
/// the GUID computation will assume that the global has external linkage.
595595
static GUID getGUIDAssumingExternalLinkage(StringRef GlobalName);
596596

597+
bool assignGUID();
598+
597599
/// Return a 64-bit global unique ID constructed from global value name
598600
/// (i.e. returned by getGlobalIdentifier()).
599-
GUID getGUID() const {
600-
return getGUIDAssumingExternalLinkage(getGlobalIdentifier());
601-
}
601+
GUID getGUID() const;
602602

603603
/// @name Materialization
604604
/// 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 & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -44,35 +44,6 @@ static cl::opt<bool> ForceIsInSpecializedModule(
4444
cl::desc("Treat the given module as-if it were containing the "
4545
"post-thinlink module containing the root"));
4646

47-
const char *AssignGUIDPass::GUIDMetadataName = "guid";
48-
49-
PreservedAnalyses AssignGUIDPass::run(Module &M, ModuleAnalysisManager &MAM) {
50-
for (auto &F : M.functions()) {
51-
if (F.isDeclaration())
52-
continue;
53-
if (F.getMetadata(GUIDMetadataName))
54-
continue;
55-
const GlobalValue::GUID GUID = F.getGUID();
56-
F.setMetadata(GUIDMetadataName,
57-
MDNode::get(M.getContext(),
58-
{ConstantAsMetadata::get(ConstantInt::get(
59-
Type::getInt64Ty(M.getContext()), GUID))}));
60-
}
61-
return PreservedAnalyses::none();
62-
}
63-
64-
GlobalValue::GUID AssignGUIDPass::getGUID(const Function &F) {
65-
if (F.isDeclaration()) {
66-
assert(GlobalValue::isExternalLinkage(F.getLinkage()));
67-
return F.getGUID();
68-
}
69-
auto *MD = F.getMetadata(GUIDMetadataName);
70-
assert(MD && "guid not found for defined function");
71-
return cast<ConstantInt>(cast<ConstantAsMetadata>(MD->getOperand(0))
72-
->getValue()
73-
->stripPointerCasts())
74-
->getZExtValue();
75-
}
7647
AnalysisKey CtxProfAnalysis::Key;
7748

7849
CtxProfAnalysis::CtxProfAnalysis(std::optional<StringRef> Profile)
@@ -141,7 +112,7 @@ PGOContextualProfile CtxProfAnalysis::run(Module &M,
141112
for (const auto &F : M) {
142113
if (F.isDeclaration())
143114
continue;
144-
auto GUID = AssignGUIDPass::getGUID(F);
115+
auto GUID = F.getGUID();
145116
assert(GUID && "guid not found for defined function");
146117
const auto &Entry = F.begin();
147118
uint32_t MaxCounters = 0; // we expect at least a counter.
@@ -175,13 +146,6 @@ PGOContextualProfile CtxProfAnalysis::run(Module &M,
175146
return Result;
176147
}
177148

178-
GlobalValue::GUID
179-
PGOContextualProfile::getDefinedFunctionGUID(const Function &F) const {
180-
if (auto It = FuncInfo.find(AssignGUIDPass::getGUID(F)); It != FuncInfo.end())
181-
return It->first;
182-
return 0;
183-
}
184-
185149
CtxProfAnalysisPrinterPass::CtxProfAnalysisPrinterPass(raw_ostream &OS)
186150
: OS(OS), Mode(PrintLevel) {}
187151

@@ -291,7 +255,7 @@ bool PGOContextualProfile::isInSpecializedModule() const {
291255

292256
void PGOContextualProfile::update(Visitor V, const Function &F) {
293257
assert(isFunctionKnown(F));
294-
GlobalValue::GUID G = getDefinedFunctionGUID(F);
258+
GlobalValue::GUID G = F.getGUID();
295259
for (auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
296260
Node = Node->Next)
297261
V(*reinterpret_cast<PGOCtxProfContext *>(Node));
@@ -302,7 +266,7 @@ void PGOContextualProfile::visit(ConstVisitor V, const Function *F) const {
302266
return preorderVisit<const PGOCtxProfContext::CallTargetMapTy,
303267
const PGOCtxProfContext>(Profiles.Contexts, V);
304268
assert(isFunctionKnown(*F));
305-
GlobalValue::GUID G = getDefinedFunctionGUID(*F);
269+
GlobalValue::GUID G = F->getGUID();
306270
for (const auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
307271
Node = Node->Next)
308272
V(*reinterpret_cast<const PGOCtxProfContext *>(Node));

llvm/lib/IR/Globals.cpp

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

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

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@
329329
#include "llvm/Transforms/Scalar/TailRecursionElimination.h"
330330
#include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
331331
#include "llvm/Transforms/Utils/AddDiscriminators.h"
332+
#include "llvm/Transforms/Utils/AssignGUID.h"
332333
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
333334
#include "llvm/Transforms/Utils/BreakCriticalEdges.h"
334335
#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
@@ -505,7 +505,7 @@ PreservedAnalyses PGOCtxProfFlatteningPass::run(Module &M,
505505
"Function has unreacheable basic blocks. The expectation was that "
506506
"DCE was run before.");
507507

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

llvm/lib/Transforms/Instrumentation/PGOCtxProfLowering.cpp

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

249249
IRBuilder<> Builder(Mark);
250-
Guid = Builder.getInt64(
251-
AssignGUIDPass::getGUID(cast<Function>(*Mark->getNameValue())));
250+
Guid = Builder.getInt64(cast<Function>(*Mark->getNameValue()).getGUID());
252251
// The type of the context of this function is now knowable since we have
253252
// NumCallsites and NumCounters. We delcare it here because it's more
254253
// convenient - we have the Builder.

0 commit comments

Comments
 (0)