Skip to content
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 @@ -54,3 +54,4 @@ 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_callee_type, "callee_type", 42)
LLVM_FIXED_MD_KIND(MD_unique_id, "guid", 43)
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
40 changes: 40 additions & 0 deletions llvm/include/llvm/Transforms/Utils/AssignGUID.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===-- 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"
#include "llvm/Support/Debug.h"

namespace llvm {

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

static void runOnModule(Module &M);

PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
AssignGUIDPass::runOnModule(M);
return PreservedAnalyses::none();
}

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
28 changes: 28 additions & 0 deletions llvm/lib/IR/Globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,34 @@ 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 {
if (isDeclaration()) {
return GlobalValue::getGUIDAssumingExternalLinkage(getGlobalIdentifier());
}
if (isa<GlobalAlias>(this)) {
return GlobalValue::getGUIDAssumingExternalLinkage(getGlobalIdentifier());
}

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 @@ -338,6 +338,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
15 changes: 12 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 @@ -786,6 +787,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
void PassBuilder::addRequiredLTOPreLinkPasses(ModulePassManager &MPM) {
MPM.addPass(CanonicalizeAliasesPass());
MPM.addPass(NameAnonGlobalPass());
MPM.addPass(AssignGUIDPass());
}

void PassBuilder::addPreInlinerPasses(ModulePassManager &MPM,
Expand Down Expand Up @@ -1234,9 +1236,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 +1639,11 @@ 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 @@ -2208,6 +2212,11 @@ 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
7 changes: 7 additions & 0 deletions llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/FunctionAttrs.h"
#include "llvm/Transforms/Utils/AssignGUID.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/CallPromotionUtils.h"
#include "llvm/Transforms/Utils/Evaluator.h"
Expand Down Expand Up @@ -860,6 +861,12 @@ void llvm::updateVCallVisibilityInModule(
function_ref<bool(StringRef)> IsVisibleToRegularObj) {
if (!hasWholeProgramVisibility(WholeProgramVisibilityEnabledInLTO))
return;

// Manually assign GUIDs -- updateVCallVisibilityInModule accesses GUIDs, and
// there's no way to specify it in the pass pipeline since this runs before
// any pass given on the command line.
AssignGUIDPass::runOnModule(M);

for (GlobalVariable &GV : M.globals()) {
// Add linkage unit visibility to any variable with type metadata, which are
// the vtable definitions. We won't have an existing vcall_visibility
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
Loading
Loading