Skip to content

Commit c7c5b41

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 3441370 commit c7c5b41

File tree

14 files changed

+129
-83
lines changed

14 files changed

+129
-83
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 &)>;
@@ -157,26 +152,5 @@ class CtxProfAnalysisPrinterPass
157152
const PrintMode Mode;
158153
};
159154

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-
181155
} // namespace llvm
182156
#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)