Skip to content

Commit e40c56f

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 bb51c5d commit e40c56f

File tree

15 files changed

+153
-87
lines changed

15 files changed

+153
-87
lines changed

llvm/include/llvm/Analysis/CtxProfAnalysis.h

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

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

6966
LLVM_ABI bool isInSpecializedModule() const;
7067

71-
bool isFunctionKnown(const Function &F) const {
72-
return getDefinedFunctionGUID(F) != 0;
73-
}
68+
bool isFunctionKnown(const Function &F) const { return !F.isDeclaration(); }
7469

7570
StringRef getFunctionName(GlobalValue::GUID GUID) const {
7671
auto It = FuncInfo.find(GUID);
@@ -81,22 +76,22 @@ class PGOContextualProfile {
8176

8277
uint32_t getNumCounters(const Function &F) const {
8378
assert(isFunctionKnown(F));
84-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex;
79+
return FuncInfo.find(F.getGUID())->second.NextCounterIndex;
8580
}
8681

8782
uint32_t getNumCallsites(const Function &F) const {
8883
assert(isFunctionKnown(F));
89-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex;
84+
return FuncInfo.find(F.getGUID())->second.NextCallsiteIndex;
9085
}
9186

9287
uint32_t allocateNextCounterIndex(const Function &F) {
9388
assert(isFunctionKnown(F));
94-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex++;
89+
return FuncInfo.find(F.getGUID())->second.NextCounterIndex++;
9590
}
9691

9792
uint32_t allocateNextCallsiteIndex(const Function &F) {
9893
assert(isFunctionKnown(F));
99-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex++;
94+
return FuncInfo.find(F.getGUID())->second.NextCallsiteIndex++;
10095
}
10196

10297
using ConstVisitor = function_ref<void(const PGOCtxProfContext &)>;
@@ -188,26 +183,5 @@ class ProfileAnnotator {
188183
LLVM_ABI ~ProfileAnnotator();
189184
};
190185

191-
/// Assign a GUID to functions as metadata. GUID calculation takes linkage into
192-
/// account, which may change especially through and after thinlto. By
193-
/// pre-computing and assigning as metadata, this mechanism is resilient to such
194-
/// changes (as well as name changes e.g. suffix ".llvm." additions).
195-
196-
// FIXME(mtrofin): we can generalize this mechanism to calculate a GUID early in
197-
// the pass pipeline, associate it with any Global Value, and then use it for
198-
// PGO and ThinLTO.
199-
// At that point, this should be moved elsewhere.
200-
class AssignGUIDPass : public PassInfoMixin<AssignGUIDPass> {
201-
public:
202-
explicit AssignGUIDPass() = default;
203-
204-
/// Assign a GUID *if* one is not already assign, as a function metadata named
205-
/// `GUIDMetadataName`.
206-
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
207-
LLVM_ABI static const char *GUIDMetadataName;
208-
// This should become GlobalValue::getGUID
209-
LLVM_ABI static uint64_t getGUID(const Function &F);
210-
};
211-
212186
} // namespace llvm
213187
#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: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -589,17 +589,33 @@ class GlobalValue : public Constant {
589589
/// used as the key for a global lookup (e.g. profile or ThinLTO).
590590
LLVM_ABI std::string getGlobalIdentifier() const;
591591

592+
/// Assign a GUID to this value based on its current name and linkage.
593+
/// This GUID will remain the same even if those change. This method is
594+
/// idempotent -- if a GUID has already been assigned, calling it again
595+
/// will do nothing.
596+
///
597+
/// This is private (exposed only to \c AssignGUIDPass), as users don't need
598+
/// to call it. GUIDs are assigned only by \c AssignGUIDPass. The pass
599+
/// pipeline should be set up such that GUIDs are always available when
600+
/// needed. If not, the GUID assignment pass should be moved (or run again)
601+
/// such that they are.
602+
void assignGUID();
603+
604+
// assignGUID needs to be accessible from AssignGUIDPass, which is called
605+
// early in the pipeline to make GUIDs available to later passes. But we'd
606+
// rather not expose it publicly, as no-one else should call it.
607+
friend class AssignGUIDPass;
608+
592609
public:
593610
/// Return a 64-bit global unique ID constructed from the name of a global
594611
/// symbol. Since this call doesn't supply the linkage or defining filename,
595612
/// the GUID computation will assume that the global has external linkage.
596613
LLVM_ABI static GUID getGUIDAssumingExternalLinkage(StringRef GlobalName);
597614

598-
/// Return a 64-bit global unique ID constructed from global value name
599-
/// (i.e. returned by getGlobalIdentifier()).
600-
GUID getGUID() const {
601-
return getGUIDAssumingExternalLinkage(getGlobalIdentifier());
602-
}
615+
/// Return a 64-bit global unique ID for this value. It is based on the
616+
/// "original" name and linkage of this value (i.e. whenever its GUID was
617+
/// assigned). This might not match the current name and linkage.
618+
GUID getGUID() const;
603619

604620
/// @name Materialization
605621
/// 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
@@ -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;
@@ -418,33 +416,6 @@ bool ProfileAnnotator::getOutgoingBranchWeights(
418416
return MaxCount > 0;
419417
}
420418

421-
PreservedAnalyses AssignGUIDPass::run(Module &M, ModuleAnalysisManager &MAM) {
422-
for (auto &F : M.functions()) {
423-
if (F.isDeclaration())
424-
continue;
425-
if (F.getMetadata(GUIDMetadataName))
426-
continue;
427-
const GlobalValue::GUID GUID = F.getGUID();
428-
F.setMetadata(GUIDMetadataName,
429-
MDNode::get(M.getContext(),
430-
{ConstantAsMetadata::get(ConstantInt::get(
431-
Type::getInt64Ty(M.getContext()), GUID))}));
432-
}
433-
return PreservedAnalyses::none();
434-
}
435-
436-
GlobalValue::GUID AssignGUIDPass::getGUID(const Function &F) {
437-
if (F.isDeclaration()) {
438-
assert(GlobalValue::isExternalLinkage(F.getLinkage()));
439-
return F.getGUID();
440-
}
441-
auto *MD = F.getMetadata(GUIDMetadataName);
442-
assert(MD && "guid not found for defined function");
443-
return cast<ConstantInt>(cast<ConstantAsMetadata>(MD->getOperand(0))
444-
->getValue()
445-
->stripPointerCasts())
446-
->getZExtValue();
447-
}
448419
AnalysisKey CtxProfAnalysis::Key;
449420

450421
CtxProfAnalysis::CtxProfAnalysis(std::optional<StringRef> Profile)
@@ -513,7 +484,7 @@ PGOContextualProfile CtxProfAnalysis::run(Module &M,
513484
for (const auto &F : M) {
514485
if (F.isDeclaration())
515486
continue;
516-
auto GUID = AssignGUIDPass::getGUID(F);
487+
auto GUID = F.getGUID();
517488
assert(GUID && "guid not found for defined function");
518489
const auto &Entry = F.begin();
519490
uint32_t MaxCounters = 0; // we expect at least a counter.
@@ -547,13 +518,6 @@ PGOContextualProfile CtxProfAnalysis::run(Module &M,
547518
return Result;
548519
}
549520

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-
557521
CtxProfAnalysisPrinterPass::CtxProfAnalysisPrinterPass(raw_ostream &OS)
558522
: OS(OS), Mode(PrintLevel) {}
559523

@@ -669,7 +633,7 @@ bool PGOContextualProfile::isInSpecializedModule() const {
669633

670634
void PGOContextualProfile::update(Visitor V, const Function &F) {
671635
assert(isFunctionKnown(F));
672-
GlobalValue::GUID G = getDefinedFunctionGUID(F);
636+
GlobalValue::GUID G = F.getGUID();
673637
for (auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
674638
Node = Node->Next)
675639
V(*reinterpret_cast<PGOCtxProfContext *>(Node));
@@ -680,7 +644,7 @@ void PGOContextualProfile::visit(ConstVisitor V, const Function *F) const {
680644
return preorderVisit<const PGOCtxProfContext::CallTargetMapTy,
681645
const PGOCtxProfContext>(Profiles.Contexts, V);
682646
assert(isFunctionKnown(*F));
683-
GlobalValue::GUID G = getDefinedFunctionGUID(*F);
647+
GlobalValue::GUID G = F->getGUID();
684648
for (const auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
685649
Node = Node->Next)
686650
V(*reinterpret_cast<const PGOCtxProfContext *>(Node));

llvm/lib/IR/Globals.cpp

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

81+
void GlobalValue::assignGUID() {
82+
if (getMetadata(LLVMContext::MD_unique_id) != nullptr)
83+
return;
84+
85+
const GUID G =
86+
GlobalValue::getGUIDAssumingExternalLinkage(getGlobalIdentifier());
87+
setMetadata(
88+
LLVMContext::MD_unique_id,
89+
MDNode::get(getContext(), {ConstantAsMetadata::get(ConstantInt::get(
90+
Type::getInt64Ty(getContext()), G))}));
91+
}
92+
93+
GlobalValue::GUID GlobalValue::getGUID() const {
94+
auto *MD = getMetadata(LLVMContext::MD_unique_id);
95+
assert(MD != nullptr && "GUID was not assigned before calling GetGUID()");
96+
return cast<ConstantInt>(cast<ConstantAsMetadata>(MD->getOperand(0))
97+
->getValue()
98+
->stripPointerCasts())
99+
->getZExtValue();
100+
}
101+
81102
void GlobalValue::removeFromParent() {
82103
switch (getValueID()) {
83104
#define HANDLE_GLOBAL_VALUE(NAME) \

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@
332332
#include "llvm/Transforms/Scalar/TailRecursionElimination.h"
333333
#include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
334334
#include "llvm/Transforms/Utils/AddDiscriminators.h"
335+
#include "llvm/Transforms/Utils/AssignGUID.h"
335336
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
336337
#include "llvm/Transforms/Utils/BreakCriticalEdges.h"
337338
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 7 additions & 3 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"
@@ -1239,9 +1240,6 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
12391240
// In pre-link, we just want the instrumented IR. We use the contextual
12401241
// profile in the post-thinlink phase.
12411242
// 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.
1244-
MPM.addPass(AssignGUIDPass());
12451243
if (IsCtxProfUse) {
12461244
MPM.addPass(PGOCtxProfFlatteningPass(/*IsPreThinlink=*/true));
12471245
return MPM;
@@ -1640,6 +1638,9 @@ PassBuilder::buildPerModuleDefaultPipeline(OptimizationLevel Level,
16401638

16411639
ModulePassManager MPM;
16421640

1641+
MPM.addPass(NameAnonGlobalPass());
1642+
MPM.addPass(AssignGUIDPass());
1643+
16431644
// Convert @llvm.global.annotations to !annotation metadata.
16441645
MPM.addPass(Annotation2MetadataPass());
16451646

@@ -2207,6 +2208,9 @@ PassBuilder::buildO0DefaultPipeline(OptimizationLevel Level,
22072208

22082209
ModulePassManager MPM;
22092210

2211+
MPM.addPass(NameAnonGlobalPass());
2212+
MPM.addPass(AssignGUIDPass());
2213+
22102214
// Perform pseudo probe instrumentation in O0 mode. This is for the
22112215
// consistency between different build modes. For example, a LTO build can be
22122216
// mixed with an O0 prelink and an O2 postlink. Loading a sample profile in

llvm/lib/Transforms/Instrumentation/PGOCtxProfFlattening.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ void annotateIndirectCalls(Module &M, const CtxProfAnalysis::Result &CtxProf) {
126126
for (auto &F : M) {
127127
if (F.isDeclaration())
128128
continue;
129-
auto FlatProfIter = FlatIndCalls.find(AssignGUIDPass::getGUID(F));
129+
auto FlatProfIter = FlatIndCalls.find(F.getGUID());
130130
if (FlatProfIter == FlatIndCalls.end())
131131
continue;
132132
const auto &FlatProf = FlatProfIter->second;
@@ -179,7 +179,7 @@ PreservedAnalyses PGOCtxProfFlatteningPass::run(Module &M,
179179
"Function has unreacheable basic blocks. The expectation was that "
180180
"DCE was run before.");
181181

182-
auto It = FlattenedProfile.find(AssignGUIDPass::getGUID(F));
182+
auto It = FlattenedProfile.find(F.getGUID());
183183
// If this function didn't appear in the contextual profile, it's cold.
184184
if (It == FlattenedProfile.end())
185185
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.

0 commit comments

Comments
 (0)