Skip to content

Commit 5457365

Browse files
committed
Compute GUIDs once and store in metadata
This allows us to keep GUIDs consistent across compilation phases which may change the name or linkage type. See https://discourse.llvm.org/t/rfc-keep-globalvalue-guids-stable/84801
1 parent 0ca8324 commit 5457365

87 files changed

Lines changed: 605 additions & 296 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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/Bitcode/BitcodeReader.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "llvm/ADT/StringRef.h"
1818
#include "llvm/Bitstream/BitCodeEnums.h"
1919
#include "llvm/IR/GlobalValue.h"
20+
#include "llvm/IR/ModuleSummaryIndex.h"
2021
#include "llvm/Support/Compiler.h"
2122
#include "llvm/Support/Endian.h"
2223
#include "llvm/Support/Error.h"
@@ -165,7 +166,8 @@ struct ParserCallbacks {
165166
/// into CombinedIndex.
166167
LLVM_ABI Error
167168
readSummary(ModuleSummaryIndex &CombinedIndex, StringRef ModulePath,
168-
std::function<bool(GlobalValue::GUID)> IsPrevailing = nullptr);
169+
std::function<bool(StringRef)> IsPrevailing = nullptr,
170+
std::function<void(ValueInfo)> OnValueInfo = nullptr);
169171
};
170172

171173
struct BitcodeFileContents {

llvm/include/llvm/Bitcode/LLVMBitCodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ enum ModuleCodes {
120120

121121
// IFUNC: [ifunc value type, addrspace, resolver val#, linkage, visibility]
122122
MODULE_CODE_IFUNC = 18,
123+
124+
// GUIDLIST: [n x i64]
125+
MODULE_CODE_GUIDLIST = 19,
123126
};
124127

125128
/// PARAMATTR blocks have code for defining a parameter attribute set.

llvm/include/llvm/IR/FixedMetadataKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,4 @@ LLVM_FIXED_MD_KIND(MD_alloc_token, "alloc_token", 45)
6060
LLVM_FIXED_MD_KIND(MD_implicit_ref, "implicit.ref", 46)
6161
LLVM_FIXED_MD_KIND(MD_nofpclass, "nofpclass", 47)
6262
LLVM_FIXED_MD_KIND(MD_call_target, "call_target", 48)
63+
LLVM_FIXED_MD_KIND(MD_unique_id, "guid", 49)

llvm/include/llvm/IR/GlobalValue.h

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -589,17 +589,40 @@ 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;
619+
620+
/// Return the GUID for this value if it has been assigned, nullopt
621+
/// otherwise. This should only need to be used in some exceptional
622+
/// situations. If possible whatever code needs access to a GUID should
623+
/// be set up to run after AssignGUIDPass, in which case it will always
624+
/// be available.
625+
std::optional<GUID> getGUIDIfAssigned() const;
603626

604627
/// @name Materialization
605628
/// Materialization is used to construct functions only as they're needed.

llvm/include/llvm/IR/Module.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "llvm/Support/CBindingWrapping.h"
3333
#include "llvm/Support/CodeGen.h"
3434
#include "llvm/Support/Compiler.h"
35+
#include "llvm/Support/Debug.h"
3536
#include "llvm/TargetParser/Triple.h"
3637
#include <cstddef>
3738
#include <cstdint>
@@ -576,7 +577,22 @@ class LLVM_ABI Module {
576577
// Use global_size() to get the total number of global variables.
577578
// Use globals() to get the range of all global variables.
578579

580+
std::optional<GlobalValue::GUID> getGUID(const Value* V) const {
581+
const auto It = ValueToGUIDMap.find(V);
582+
if (It == ValueToGUIDMap.end()) {
583+
return {};
584+
}
585+
586+
return It->getSecond();
587+
}
588+
589+
void insertGUID(const Value* V, GlobalValue::GUID GUID) {
590+
ValueToGUIDMap[V] = GUID;
591+
}
592+
579593
private:
594+
DenseMap<const Value*, GlobalValue::GUID> ValueToGUIDMap;
595+
580596
/// @}
581597
/// @name Direct access to the globals list, functions list, and symbol table
582598
/// @{

llvm/include/llvm/IR/ModuleSummaryIndex.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "llvm/IR/Module.h"
3030
#include "llvm/Support/Allocator.h"
3131
#include "llvm/Support/Compiler.h"
32+
#include "llvm/Support/Debug.h"
3233
#include "llvm/Support/InterleavedRange.h"
3334
#include "llvm/Support/ScaledNumber.h"
3435
#include "llvm/Support/StringSaver.h"
@@ -599,8 +600,8 @@ class GlobalValueSummary {
599600
bool wasPromoted() const { return Flags.Promoted; }
600601

601602
void promote() {
602-
assert(GlobalValue::isLocalLinkage(linkage()) &&
603-
"unexpected (re-)promotion of non-local symbol");
603+
assert(!GlobalValue::isExternalLinkage(linkage()) &&
604+
"unexpected (re-)promotion of external symbol");
604605
assert(!Flags.Promoted);
605606
Flags.Promoted = true;
606607
Flags.Linkage = GlobalValue::LinkageTypes::ExternalLinkage;
@@ -1769,14 +1770,19 @@ class ModuleSummaryIndex {
17691770
return ValueInfo(HaveGVs, VP);
17701771
}
17711772

1772-
/// Return a ValueInfo for \p GV and mark it as belonging to GV.
1773-
ValueInfo getOrInsertValueInfo(const GlobalValue *GV) {
1773+
/// Return a ValueInfo for \p GV with GUID \p GUID and mark it as belonging to GV.
1774+
ValueInfo getOrInsertValueInfo(const GlobalValue *GV, GlobalValue::GUID GUID) {
17741775
assert(HaveGVs);
1775-
auto VP = getOrInsertValuePtr(GV->getGUID());
1776+
auto VP = getOrInsertValuePtr(GUID);
17761777
VP->second.U.GV = GV;
17771778
return ValueInfo(HaveGVs, VP);
17781779
}
17791780

1781+
/// Return a ValueInfo for \p GV and mark it as belonging to GV.
1782+
ValueInfo getOrInsertValueInfo(const GlobalValue *GV) {
1783+
return getOrInsertValueInfo(GV, GV->getGUID());
1784+
}
1785+
17801786
/// Return the GUID for \p OriginalId in the OidGuidMap.
17811787
GlobalValue::GUID getGUIDFromOriginalID(GlobalValue::GUID OriginalID) const {
17821788
const auto I = OidGuidMap.find(OriginalID);

llvm/include/llvm/LTO/LTO.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,23 @@ class LTO {
572572
/// LTO backend.
573573
unsigned Partition = Unknown;
574574

575+
// FIXME: make private, and also make GlobalResolution a class, it has been
576+
// becoming more than just a data bag.
577+
GlobalValue::GUID GUID = 0;
578+
579+
void setGUID(GlobalValue::GUID G) {
580+
assert(G);
581+
assert(!GUID || GUID == G);
582+
GUID = G;
583+
}
584+
585+
GlobalValue::GUID getGUID() const {
586+
return GUID ? GUID
587+
: GlobalValue::getGUIDAssumingExternalLinkage(
588+
GlobalValue::getGlobalIdentifier(
589+
IRName, GlobalValue::LinkageTypes::ExternalLinkage,
590+
""));
591+
}
575592
/// Special partition numbers.
576593
enum : unsigned {
577594
/// A partition number has not yet been assigned to this global.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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. This way we have a consistent identifier even when
12+
// these inputs to the GUID change (for instance, after externalising a global
13+
// in ThinLTO).
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef LLVM_TRANSFORMS_UTILS_ASSIGNGUID_H
18+
#define LLVM_TRANSFORMS_UTILS_ASSIGNGUID_H
19+
20+
#include "llvm/IR/Module.h"
21+
#include "llvm/IR/PassManager.h"
22+
#include "llvm/Support/Debug.h"
23+
24+
namespace llvm {
25+
26+
class AssignGUIDPass : public PassInfoMixin<AssignGUIDPass> {
27+
public:
28+
AssignGUIDPass() = default;
29+
30+
static void runOnModule(Module &M);
31+
32+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
33+
AssignGUIDPass::runOnModule(M);
34+
return PreservedAnalyses::all();
35+
}
36+
37+
static bool isRequired() { return true; }
38+
};
39+
40+
} // end namespace llvm
41+
42+
#endif // LLVM_TRANSFORMS_UTILS_ASSIGNGUID_H

llvm/lib/Analysis/CtxProfAnalysis.cpp

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,7 @@ static cl::opt<bool> ForceIsInSpecializedModule(
5050
"ctx-profile-force-is-specialized", cl::init(false),
5151
cl::desc("Treat the given module as-if it were containing the "
5252
"post-thinlink module containing the root"));
53-
54-
const char *AssignGUIDPass::GUIDMetadataName = "guid";
55-
53+
5654
class ProfileAnnotatorImpl final {
5755
friend class ProfileAnnotator;
5856
class BBInfo;
@@ -420,33 +418,6 @@ bool ProfileAnnotator::getOutgoingBranchWeights(
420418
return MaxCount > 0;
421419
}
422420

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

452423
CtxProfAnalysis::CtxProfAnalysis(std::optional<StringRef> Profile)
@@ -515,7 +486,7 @@ PGOContextualProfile CtxProfAnalysis::run(Module &M,
515486
for (const auto &F : M) {
516487
if (F.isDeclaration())
517488
continue;
518-
auto GUID = AssignGUIDPass::getGUID(F);
489+
auto GUID = F.getGUID();
519490
assert(GUID && "guid not found for defined function");
520491
const auto &Entry = F.begin();
521492
uint32_t MaxCounters = 0; // we expect at least a counter.
@@ -549,13 +520,6 @@ PGOContextualProfile CtxProfAnalysis::run(Module &M,
549520
return Result;
550521
}
551522

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

@@ -671,7 +635,7 @@ bool PGOContextualProfile::isInSpecializedModule() const {
671635

672636
void PGOContextualProfile::update(Visitor V, const Function &F) {
673637
assert(isFunctionKnown(F));
674-
GlobalValue::GUID G = getDefinedFunctionGUID(F);
638+
GlobalValue::GUID G = F.getGUID();
675639
for (auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
676640
Node = Node->Next)
677641
V(*reinterpret_cast<PGOCtxProfContext *>(Node));
@@ -682,7 +646,7 @@ void PGOContextualProfile::visit(ConstVisitor V, const Function *F) const {
682646
return preorderVisit<const PGOCtxProfContext::CallTargetMapTy,
683647
const PGOCtxProfContext>(Profiles.Contexts, V);
684648
assert(isFunctionKnown(*F));
685-
GlobalValue::GUID G = getDefinedFunctionGUID(*F);
649+
GlobalValue::GUID G = F->getGUID();
686650
for (const auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
687651
Node = Node->Next)
688652
V(*reinterpret_cast<const PGOCtxProfContext *>(Node));

0 commit comments

Comments
 (0)