Skip to content

Store GUIDs in metadata #133682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 5 additions & 31 deletions llvm/include/llvm/Analysis/CtxProfAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ class PGOContextualProfile {
// we'll need when we maintain the profiles during IPO transformations.
std::map<GlobalValue::GUID, FunctionInfo> FuncInfo;

/// Get the GUID of this Function if it's defined in this module.
LLVM_ABI GlobalValue::GUID getDefinedFunctionGUID(const Function &F) const;

// This is meant to be constructed from CtxProfAnalysis, which will also set
// its state piecemeal.
PGOContextualProfile() = default;
Expand All @@ -68,9 +65,7 @@ class PGOContextualProfile {

LLVM_ABI bool isInSpecializedModule() const;

bool isFunctionKnown(const Function &F) const {
return getDefinedFunctionGUID(F) != 0;
}
bool isFunctionKnown(const Function &F) const { return !F.isDeclaration(); }

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

uint32_t getNumCounters(const Function &F) const {
assert(isFunctionKnown(F));
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex;
return FuncInfo.find(F.getGUID())->second.NextCounterIndex;
}

uint32_t getNumCallsites(const Function &F) const {
assert(isFunctionKnown(F));
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex;
return FuncInfo.find(F.getGUID())->second.NextCallsiteIndex;
}

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

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

using ConstVisitor = function_ref<void(const PGOCtxProfContext &)>;
Expand Down Expand Up @@ -188,26 +183,5 @@ class ProfileAnnotator {
LLVM_ABI ~ProfileAnnotator();
};

/// Assign a GUID to functions as metadata. GUID calculation takes linkage into
/// account, which may change especially through and after thinlto. By
/// pre-computing and assigning as metadata, this mechanism is resilient to such
/// changes (as well as name changes e.g. suffix ".llvm." additions).

// FIXME(mtrofin): we can generalize this mechanism to calculate a GUID early in
// the pass pipeline, associate it with any Global Value, and then use it for
// PGO and ThinLTO.
// At that point, this should be moved elsewhere.
class AssignGUIDPass : public PassInfoMixin<AssignGUIDPass> {
public:
explicit AssignGUIDPass() = default;

/// Assign a GUID *if* one is not already assign, as a function metadata named
/// `GUIDMetadataName`.
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
LLVM_ABI static const char *GUIDMetadataName;
// This should become GlobalValue::getGUID
LLVM_ABI static uint64_t getGUID(const Function &F);
};

} // namespace llvm
#endif // LLVM_ANALYSIS_CTXPROFANALYSIS_H
1 change: 1 addition & 0 deletions llvm/include/llvm/IR/FixedMetadataKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,4 @@ LLVM_FIXED_MD_KIND(MD_DIAssignID, "DIAssignID", 38)
LLVM_FIXED_MD_KIND(MD_coro_outside_frame, "coro.outside.frame", 39)
LLVM_FIXED_MD_KIND(MD_mmra, "mmra", 40)
LLVM_FIXED_MD_KIND(MD_noalias_addrspace, "noalias.addrspace", 41)
LLVM_FIXED_MD_KIND(MD_unique_id, "unique_id", 42)
26 changes: 21 additions & 5 deletions llvm/include/llvm/IR/GlobalValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -589,17 +589,33 @@ class GlobalValue : public Constant {
/// used as the key for a global lookup (e.g. profile or ThinLTO).
LLVM_ABI std::string getGlobalIdentifier() const;

/// Assign a GUID to this value based on its current name and linkage.
/// This GUID will remain the same even if those change. This method is
/// idempotent -- if a GUID has already been assigned, calling it again
/// will do nothing.
///
/// This is private (exposed only to \c AssignGUIDPass), as users don't need
/// to call it. GUIDs are assigned only by \c AssignGUIDPass. The pass
/// pipeline should be set up such that GUIDs are always available when
/// needed. If not, the GUID assignment pass should be moved (or run again)
/// such that they are.
void assignGUID();

// assignGUID needs to be accessible from AssignGUIDPass, which is called
// early in the pipeline to make GUIDs available to later passes. But we'd
// rather not expose it publicly, as no-one else should call it.
friend class AssignGUIDPass;

public:
/// Return a 64-bit global unique ID constructed from the name of a global
/// symbol. Since this call doesn't supply the linkage or defining filename,
/// the GUID computation will assume that the global has external linkage.
LLVM_ABI static GUID getGUIDAssumingExternalLinkage(StringRef GlobalName);

/// Return a 64-bit global unique ID constructed from global value name
/// (i.e. returned by getGlobalIdentifier()).
GUID getGUID() const {
return getGUIDAssumingExternalLinkage(getGlobalIdentifier());
}
/// Return a 64-bit global unique ID for this value. It is based on the
/// "original" name and linkage of this value (i.e. whenever its GUID was
/// assigned). This might not match the current name and linkage.
GUID getGUID() const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description needs to be updated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done -- does the new description look good?


/// @name Materialization
/// Materialization is used to construct functions only as they're needed.
Expand Down
34 changes: 34 additions & 0 deletions llvm/include/llvm/Transforms/Utils/AssignGUID.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===-- AssignGUID.h - Unique identifier assignment pass --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file provides a pass which assigns a a GUID (globally unique identifier)
// to every GlobalValue in the module, according to its current name, linkage,
// and originating file.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TRANSFORMS_UTILS_ASSIGNGUID_H
#define LLVM_TRANSFORMS_UTILS_ASSIGNGUID_H

#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"

namespace llvm {

class AssignGUIDPass : public PassInfoMixin<AssignGUIDPass> {
public:
AssignGUIDPass() = default;

PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);

static bool isRequired() { return true; }
};

} // end namespace llvm

#endif // LLVM_TRANSFORMS_UTILS_ASSIGNGUID_H
42 changes: 3 additions & 39 deletions llvm/lib/Analysis/CtxProfAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ static cl::opt<bool> ForceIsInSpecializedModule(
cl::desc("Treat the given module as-if it were containing the "
"post-thinlink module containing the root"));

const char *AssignGUIDPass::GUIDMetadataName = "guid";

namespace llvm {
class ProfileAnnotatorImpl final {
friend class ProfileAnnotator;
Expand Down Expand Up @@ -418,33 +416,6 @@ bool ProfileAnnotator::getOutgoingBranchWeights(
return MaxCount > 0;
}

PreservedAnalyses AssignGUIDPass::run(Module &M, ModuleAnalysisManager &MAM) {
for (auto &F : M.functions()) {
if (F.isDeclaration())
continue;
if (F.getMetadata(GUIDMetadataName))
continue;
const GlobalValue::GUID GUID = F.getGUID();
F.setMetadata(GUIDMetadataName,
MDNode::get(M.getContext(),
{ConstantAsMetadata::get(ConstantInt::get(
Type::getInt64Ty(M.getContext()), GUID))}));
}
return PreservedAnalyses::none();
}

GlobalValue::GUID AssignGUIDPass::getGUID(const Function &F) {
if (F.isDeclaration()) {
assert(GlobalValue::isExternalLinkage(F.getLinkage()));
return F.getGUID();
}
auto *MD = F.getMetadata(GUIDMetadataName);
assert(MD && "guid not found for defined function");
return cast<ConstantInt>(cast<ConstantAsMetadata>(MD->getOperand(0))
->getValue()
->stripPointerCasts())
->getZExtValue();
}
AnalysisKey CtxProfAnalysis::Key;

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

GlobalValue::GUID
PGOContextualProfile::getDefinedFunctionGUID(const Function &F) const {
if (auto It = FuncInfo.find(AssignGUIDPass::getGUID(F)); It != FuncInfo.end())
return It->first;
return 0;
}

CtxProfAnalysisPrinterPass::CtxProfAnalysisPrinterPass(raw_ostream &OS)
: OS(OS), Mode(PrintLevel) {}

Expand Down Expand Up @@ -669,7 +633,7 @@ bool PGOContextualProfile::isInSpecializedModule() const {

void PGOContextualProfile::update(Visitor V, const Function &F) {
assert(isFunctionKnown(F));
GlobalValue::GUID G = getDefinedFunctionGUID(F);
GlobalValue::GUID G = F.getGUID();
for (auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
Node = Node->Next)
V(*reinterpret_cast<PGOCtxProfContext *>(Node));
Expand All @@ -680,7 +644,7 @@ void PGOContextualProfile::visit(ConstVisitor V, const Function *F) const {
return preorderVisit<const PGOCtxProfContext::CallTargetMapTy,
const PGOCtxProfContext>(Profiles.Contexts, V);
assert(isFunctionKnown(*F));
GlobalValue::GUID G = getDefinedFunctionGUID(*F);
GlobalValue::GUID G = F->getGUID();
for (const auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
Node = Node->Next)
V(*reinterpret_cast<const PGOCtxProfContext *>(Node));
Expand Down
21 changes: 21 additions & 0 deletions llvm/lib/IR/Globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,27 @@ GlobalValue::getGUIDAssumingExternalLinkage(StringRef GlobalIdentifier) {
return MD5Hash(GlobalIdentifier);
}

void GlobalValue::assignGUID() {
if (getMetadata(LLVMContext::MD_unique_id) != nullptr)
return;

const GUID G =
GlobalValue::getGUIDAssumingExternalLinkage(getGlobalIdentifier());
setMetadata(
LLVMContext::MD_unique_id,
MDNode::get(getContext(), {ConstantAsMetadata::get(ConstantInt::get(
Type::getInt64Ty(getContext()), G))}));
}

GlobalValue::GUID GlobalValue::getGUID() const {
auto *MD = getMetadata(LLVMContext::MD_unique_id);
assert(MD != nullptr && "GUID was not assigned before calling GetGUID()");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like something that would be reachable through opt with an "incorrect" pipeline? If so, this should use reportFatalUsageError instead.

Though generally, requiring that a certain pass runs before another pass and no new globals are introduced in between sounds fragile to me....

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH I don't really get how this works as-implemented. You are assigning GUIDs at the very start of the pipeline, but there's lots of passes that can insert new globals after that...

return cast<ConstantInt>(cast<ConstantAsMetadata>(MD->getOperand(0))
->getValue()
->stripPointerCasts())
->getZExtValue();
}

void GlobalValue::removeFromParent() {
switch (getValueID()) {
#define HANDLE_GLOBAL_VALUE(NAME) \
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@
#include "llvm/Transforms/Scalar/TailRecursionElimination.h"
#include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
#include "llvm/Transforms/Utils/AddDiscriminators.h"
#include "llvm/Transforms/Utils/AssignGUID.h"
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
#include "llvm/Transforms/Utils/BreakCriticalEdges.h"
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
Expand Down
10 changes: 7 additions & 3 deletions llvm/lib/Passes/PassBuilderPipelines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
#include "llvm/Transforms/Scalar/TailRecursionElimination.h"
#include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
#include "llvm/Transforms/Utils/AddDiscriminators.h"
#include "llvm/Transforms/Utils/AssignGUID.h"
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
#include "llvm/Transforms/Utils/CountVisits.h"
Expand Down Expand Up @@ -1239,9 +1240,6 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
// In pre-link, we just want the instrumented IR. We use the contextual
// profile in the post-thinlink phase.
// The instrumentation will be removed in post-thinlink after IPO.
// FIXME(mtrofin): move AssignGUIDPass if there is agreement to use this
// mechanism for GUIDs.
MPM.addPass(AssignGUIDPass());
if (IsCtxProfUse) {
MPM.addPass(PGOCtxProfFlatteningPass(/*IsPreThinlink=*/true));
return MPM;
Expand Down Expand Up @@ -1640,6 +1638,9 @@ PassBuilder::buildPerModuleDefaultPipeline(OptimizationLevel Level,

ModulePassManager MPM;

MPM.addPass(NameAnonGlobalPass());
MPM.addPass(AssignGUIDPass());

// Convert @llvm.global.annotations to !annotation metadata.
MPM.addPass(Annotation2MetadataPass());

Expand Down Expand Up @@ -2207,6 +2208,9 @@ PassBuilder::buildO0DefaultPipeline(OptimizationLevel Level,

ModulePassManager MPM;

MPM.addPass(NameAnonGlobalPass());
MPM.addPass(AssignGUIDPass());

// Perform pseudo probe instrumentation in O0 mode. This is for the
// consistency between different build modes. For example, a LTO build can be
// mixed with an O0 prelink and an O2 postlink. Loading a sample profile in
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Transforms/Instrumentation/PGOCtxProfFlattening.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ void annotateIndirectCalls(Module &M, const CtxProfAnalysis::Result &CtxProf) {
for (auto &F : M) {
if (F.isDeclaration())
continue;
auto FlatProfIter = FlatIndCalls.find(AssignGUIDPass::getGUID(F));
auto FlatProfIter = FlatIndCalls.find(F.getGUID());
if (FlatProfIter == FlatIndCalls.end())
continue;
const auto &FlatProf = FlatProfIter->second;
Expand Down Expand Up @@ -179,7 +179,7 @@ PreservedAnalyses PGOCtxProfFlatteningPass::run(Module &M,
"Function has unreacheable basic blocks. The expectation was that "
"DCE was run before.");

auto It = FlattenedProfile.find(AssignGUIDPass::getGUID(F));
auto It = FlattenedProfile.find(F.getGUID());
// If this function didn't appear in the contextual profile, it's cold.
if (It == FlattenedProfile.end())
clearColdFunctionProfile(F);
Expand Down
3 changes: 1 addition & 2 deletions llvm/lib/Transforms/Instrumentation/PGOCtxProfLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,7 @@ bool CtxInstrumentationLowerer::lowerFunction(Function &F) {
assert(Mark->getIndex()->isZero());

IRBuilder<> Builder(Mark);
Guid = Builder.getInt64(
AssignGUIDPass::getGUID(cast<Function>(*Mark->getNameValue())));
Guid = Builder.getInt64(cast<Function>(*Mark->getNameValue()).getGUID());
// The type of the context of this function is now knowable since we have
// NumCallsites and NumCounters. We delcare it here because it's more
// convenient - we have the Builder.
Expand Down
34 changes: 34 additions & 0 deletions llvm/lib/Transforms/Utils/AssignGUID.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===-- AssignGUID.cpp - Unique identifier assignment pass ------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file provides a pass which assigns a a GUID (globally unique identifier)
// to every GlobalValue in the module, according to its current name, linkage,
// and originating file.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Utils/AssignGUID.h"
#include "llvm/Support/Debug.h"

using namespace llvm;

PreservedAnalyses AssignGUIDPass::run(Module &M, ModuleAnalysisManager &AM) {
for (auto &GV : M.globals()) {
if (GV.isDeclaration())
continue;
GV.assignGUID();
dbgs() << "[Added GUID to GV:] " << GV.getName() << "\n";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be inside LLVM_DEBUG.

}
for (auto &F : M.functions()) {
if (F.isDeclaration())
continue;
F.assignGUID();
dbgs() << "[Added GUID to F:] " << F.getName() << "\n";
}
return PreservedAnalyses::none();
}
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ add_llvm_component_library(LLVMTransformUtils
AddDiscriminators.cpp
AMDGPUEmitPrintf.cpp
ASanStackFrameLayout.cpp
AssignGUID.cpp
AssumeBundleBuilder.cpp
BasicBlockUtils.cpp
BreakCriticalEdges.cpp
Expand Down
Loading
Loading