Skip to content

Commit 3da1ceb

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 9b195dc commit 3da1ceb

File tree

17 files changed

+183
-87
lines changed

17 files changed

+183
-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
@@ -54,3 +54,4 @@ 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)
5656
LLVM_FIXED_MD_KIND(MD_callee_type, "callee_type", 42)
57+
LLVM_FIXED_MD_KIND(MD_unique_id, "guid", 43)

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: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
#include "llvm/Support/Debug.h"
21+
22+
namespace llvm {
23+
24+
class AssignGUIDPass : public PassInfoMixin<AssignGUIDPass> {
25+
public:
26+
AssignGUIDPass() = default;
27+
28+
static void runOnModule(Module &M);
29+
30+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
31+
AssignGUIDPass::runOnModule(M);
32+
return PreservedAnalyses::none();
33+
}
34+
35+
static bool isRequired() { return true; }
36+
};
37+
38+
} // end namespace llvm
39+
40+
#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: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,34 @@ 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+
if (isDeclaration()) {
95+
return GlobalValue::getGUIDAssumingExternalLinkage(getGlobalIdentifier());
96+
}
97+
if (isa<GlobalAlias>(this)) {
98+
return GlobalValue::getGUIDAssumingExternalLinkage(getGlobalIdentifier());
99+
}
100+
101+
auto *MD = getMetadata(LLVMContext::MD_unique_id);
102+
assert(MD != nullptr && "GUID was not assigned before calling GetGUID()");
103+
return cast<ConstantInt>(cast<ConstantAsMetadata>(MD->getOperand(0))
104+
->getValue()
105+
->stripPointerCasts())
106+
->getZExtValue();
107+
}
108+
81109
void GlobalValue::removeFromParent() {
82110
switch (getValueID()) {
83111
#define HANDLE_GLOBAL_VALUE(NAME) \

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@
338338
#include "llvm/Transforms/Scalar/TailRecursionElimination.h"
339339
#include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
340340
#include "llvm/Transforms/Utils/AddDiscriminators.h"
341+
#include "llvm/Transforms/Utils/AssignGUID.h"
341342
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
342343
#include "llvm/Transforms/Utils/BreakCriticalEdges.h"
343344
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 12 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"
@@ -786,6 +787,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
786787
void PassBuilder::addRequiredLTOPreLinkPasses(ModulePassManager &MPM) {
787788
MPM.addPass(CanonicalizeAliasesPass());
788789
MPM.addPass(NameAnonGlobalPass());
790+
MPM.addPass(AssignGUIDPass());
789791
}
790792

791793
void PassBuilder::addPreInlinerPasses(ModulePassManager &MPM,
@@ -1234,9 +1236,6 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
12341236
// In pre-link, we just want the instrumented IR. We use the contextual
12351237
// profile in the post-thinlink phase.
12361238
// The instrumentation will be removed in post-thinlink after IPO.
1237-
// FIXME(mtrofin): move AssignGUIDPass if there is agreement to use this
1238-
// mechanism for GUIDs.
1239-
MPM.addPass(AssignGUIDPass());
12401239
if (IsCtxProfUse) {
12411240
MPM.addPass(PGOCtxProfFlatteningPass(/*IsPreThinlink=*/true));
12421241
return MPM;
@@ -1640,6 +1639,11 @@ PassBuilder::buildPerModuleDefaultPipeline(OptimizationLevel Level,
16401639

16411640
ModulePassManager MPM;
16421641

1642+
/*
1643+
MPM.addPass(NameAnonGlobalPass());
1644+
MPM.addPass(AssignGUIDPass());
1645+
*/
1646+
16431647
// Convert @llvm.global.annotations to !annotation metadata.
16441648
MPM.addPass(Annotation2MetadataPass());
16451649

@@ -2208,6 +2212,11 @@ PassBuilder::buildO0DefaultPipeline(OptimizationLevel Level,
22082212

22092213
ModulePassManager MPM;
22102214

2215+
/*
2216+
MPM.addPass(NameAnonGlobalPass());
2217+
MPM.addPass(AssignGUIDPass());
2218+
*/
2219+
22112220
// Perform pseudo probe instrumentation in O0 mode. This is for the
22122221
// consistency between different build modes. For example, a LTO build can be
22132222
// mixed with an O0 prelink and an O2 postlink. Loading a sample profile in

llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
#include "llvm/TargetParser/Triple.h"
9292
#include "llvm/Transforms/IPO.h"
9393
#include "llvm/Transforms/IPO/FunctionAttrs.h"
94+
#include "llvm/Transforms/Utils/AssignGUID.h"
9495
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
9596
#include "llvm/Transforms/Utils/CallPromotionUtils.h"
9697
#include "llvm/Transforms/Utils/Evaluator.h"
@@ -860,6 +861,12 @@ void llvm::updateVCallVisibilityInModule(
860861
function_ref<bool(StringRef)> IsVisibleToRegularObj) {
861862
if (!hasWholeProgramVisibility(WholeProgramVisibilityEnabledInLTO))
862863
return;
864+
865+
// Manually assign GUIDs -- updateVCallVisibilityInModule accesses GUIDs, and
866+
// there's no way to specify it in the pass pipeline since this runs before
867+
// any pass given on the command line.
868+
AssignGUIDPass::runOnModule(M);
869+
863870
for (GlobalVariable &GV : M.globals()) {
864871
// Add linkage unit visibility to any variable with type metadata, which are
865872
// the vtable definitions. We won't have an existing vcall_visibility

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);

0 commit comments

Comments
 (0)