31#define DEBUG_TYPE "ctx_prof"
39 cl::desc(
"Use the specified contextual profile file"));
42 "ctx-profile-printer-level",
45 "everything",
"print everything - most verbose"),
47 "just the yaml representation of the profile")),
48 cl::desc(
"Verbosity level of the contextual profile printer pass."));
56 std::optional<uint64_t>
Count;
58 explicit EdgeInfo(BBInfo &Src, BBInfo &Dest) : Src(&Src), Dest(&Dest) {}
62 std::optional<uint64_t>
Count;
70 size_t UnknownCountOutEdges = 0;
71 size_t UnknownCountInEdges = 0;
78 bool AssumeAllKnown)
const {
79 std::optional<uint64_t> Sum;
80 for (
const auto *
E : Edges) {
85 *Sum += (AssumeAllKnown ? *
E->Count :
E->Count.value_or(0U));
91 bool computeCountFrom(
const SmallVector<EdgeInfo *> &Edges) {
92 assert(!Count.has_value());
93 Count = getEdgeSum(Edges,
true);
94 return Count.has_value();
97 void setSingleUnknownEdgeCount(SmallVector<EdgeInfo *> &Edges) {
98 uint64_t KnownSum = getEdgeSum(Edges,
false).value_or(0U);
99 uint64_t EdgeVal = *Count > KnownSum ? *Count - KnownSum : 0
U;
100 EdgeInfo *
E =
nullptr;
101 for (
auto *
I : Edges)
102 if (
I && !
I->Count.has_value()) {
108 "Expected exactly one edge to have an unknown count, "
109 "found a second one");
113 assert(
E &&
"Expected exactly one edge to have an unknown count");
116 assert(
E->Src->UnknownCountOutEdges > 0);
117 assert(
E->Dest->UnknownCountInEdges > 0);
118 --
E->Src->UnknownCountOutEdges;
119 --
E->Dest->UnknownCountInEdges;
123 BBInfo(
size_t NumInEdges,
size_t NumOutEdges, std::optional<uint64_t> Count)
130 InEdges.reserve(NumInEdges);
131 OutEdges.resize(NumOutEdges);
134 bool tryTakeCountFromKnownOutEdges(
const BasicBlock &BB) {
135 if (!UnknownCountOutEdges) {
136 return computeCountFrom(OutEdges);
141 bool tryTakeCountFromKnownInEdges(
const BasicBlock &BB) {
142 if (!UnknownCountInEdges) {
143 return computeCountFrom(InEdges);
148 void addInEdge(EdgeInfo &Info) {
149 InEdges.push_back(&Info);
150 ++UnknownCountInEdges;
157 void addOutEdge(
size_t Index, EdgeInfo &Info) {
159 ++UnknownCountOutEdges;
162 bool hasCount()
const {
return Count.has_value(); }
164 uint64_t getCount()
const {
return *Count; }
166 bool trySetSingleUnknownInEdgeCount() {
167 if (UnknownCountInEdges == 1) {
168 setSingleUnknownEdgeCount(InEdges);
174 bool trySetSingleUnknownOutEdgeCount() {
175 if (UnknownCountOutEdges == 1) {
176 setSingleUnknownEdgeCount(OutEdges);
181 size_t getNumOutEdges()
const {
return OutEdges.size(); }
183 uint64_t getEdgeCount(
size_t Index)
const {
184 if (
auto *
E = OutEdges[Index])
191 ArrayRef<uint64_t> Counters;
193 std::map<const BasicBlock *, BBInfo> BBInfos;
194 std::vector<EdgeInfo> EdgeInfos;
198 bool shouldExcludeEdge(
const BasicBlock &Src,
const BasicBlock &Dest)
const {
202 BBInfo &getBBInfo(
const BasicBlock &BB) {
return BBInfos.find(&BB)->second; }
204 const BBInfo &getBBInfo(
const BasicBlock &BB)
const {
205 return BBInfos.find(&BB)->second;
210 bool allCountersAreAssigned()
const {
211 for (
const auto &BBInfo : BBInfos)
212 if (!BBInfo.second.hasCount())
214 for (
const auto &EdgeInfo : EdgeInfos)
215 if (!EdgeInfo.Count.has_value())
222 bool allTakenPathsExit()
const {
223 std::deque<const BasicBlock *> Worklist;
224 DenseSet<const BasicBlock *> Visited;
225 Worklist.push_back(&F.getEntryBlock());
226 bool HitExit =
false;
227 while (!Worklist.empty()) {
228 const auto *BB = Worklist.
front();
229 Worklist.pop_front();
230 if (!Visited.
insert(BB).second)
242 const auto &BBInfo = getBBInfo(*BB);
243 bool HasAWayOut =
false;
246 if (!shouldExcludeEdge(*BB, *Succ)) {
247 if (BBInfo.getEdgeCount(
I) > 0) {
249 Worklist.push_back(Succ);
259 bool allNonColdSelectsHaveProfile()
const {
260 for (
const auto &BB : F) {
261 if (getBBInfo(BB).getCount() > 0) {
262 for (
const auto &
I : BB) {
265 *
const_cast<SelectInst *
>(SI))) {
266 auto Index = Inst->getIndex()->getZExtValue();
267 assert(Index < Counters.size());
268 if (Counters[Index] == 0)
280 void propagateCounterValues() {
281 bool KeepGoing =
true;
284 for (
const auto &BB : F) {
285 auto &
Info = getBBInfo(BB);
286 if (!
Info.hasCount())
287 KeepGoing |=
Info.tryTakeCountFromKnownOutEdges(BB) ||
288 Info.tryTakeCountFromKnownInEdges(BB);
289 if (
Info.hasCount()) {
290 KeepGoing |=
Info.trySetSingleUnknownOutEdgeCount();
291 KeepGoing |=
Info.trySetSingleUnknownInEdgeCount();
295 assert(allCountersAreAssigned() &&
296 "[ctx-prof] Expected all counters have been assigned.");
297 assert(allTakenPathsExit() &&
298 "[ctx-prof] Encountered a BB with more than one successor, where "
299 "all outgoing edges have a 0 count. This occurs in non-exiting "
300 "functions (message pumps, usually) which are not supported in the "
301 "contextual profiling case");
302 assert(allNonColdSelectsHaveProfile() &&
303 "[ctx-prof] All non-cold select instructions were expected to have "
309 : F(F), Counters(Counters) {
310 assert(!F.isDeclaration());
311 assert(!Counters.empty());
313 for (
const auto &BB : F) {
314 std::optional<uint64_t>
Count;
317 auto Index = Ins->getIndex()->getZExtValue();
318 assert(Index < Counters.size() &&
319 "The index must be inside the counters vector by construction - "
320 "tripping this assertion indicates a bug in how the contextual "
321 "profile is managed by IPO transforms");
323 Count = Counters[Ins->getIndex()->getZExtValue()];
331 assert(Ins &&
"We iterate through the function's BBs, no reason to "
332 "insert one more than once");
334 return !shouldExcludeEdge(BB, *Succ);
338 EdgeInfos.reserve(NrEdges);
339 for (
const auto &BB : F) {
340 auto &Info = getBBInfo(BB);
341 for (
auto I = 0U;
I < BB.getTerminator()->getNumSuccessors(); ++
I) {
342 const auto *Succ = BB.getTerminator()->getSuccessor(
I);
343 if (!shouldExcludeEdge(BB, *Succ)) {
344 auto &EI = EdgeInfos.emplace_back(getBBInfo(BB), getBBInfo(*Succ));
345 Info.addOutEdge(
I, EI);
346 getBBInfo(*Succ).addInEdge(EI);
350 assert(EdgeInfos.capacity() == NrEdges &&
351 "The capacity of EdgeInfos should have stayed unchanged it was "
352 "populated, because we need pointers to its contents to be stable");
353 propagateCounterValues();
368 return PImpl->getBBCount(BB);
373 uint64_t &FalseCount)
const {
374 const auto &BBInfo = PImpl->getBBInfo(*
SI.getParent());
375 TrueCount = FalseCount = 0;
376 if (BBInfo.getCount() == 0)
382 auto Index = Step->getIndex()->getZExtValue();
384 "The index of the step instruction must be inside the "
385 "counters vector by "
386 "construction - tripping this assertion indicates a bug in "
387 "how the contextual profile is managed by IPO transforms");
388 auto TotalCount = BBInfo.getCount();
389 TrueCount = PImpl->Counters[Index];
390 FalseCount = (TotalCount > TrueCount ? TotalCount - TrueCount : 0U);
396 uint64_t &MaxCount)
const {
403 Profile.resize(Term->getNumSuccessors());
405 const auto &BBInfo = PImpl->getBBInfo(BB);
407 for (
unsigned SuccIdx = 0,
Size = BBInfo.getNumOutEdges(); SuccIdx <
Size;
409 uint64_t EdgeCount = BBInfo.getEdgeCount(SuccIdx);
410 if (EdgeCount > MaxCount)
411 MaxCount = EdgeCount;
434 M.getContext().emitError(
"could not open contextual profile file: " +
440 if (!MaybeProfiles) {
441 M.getContext().emitError(
"contextual profile file is invalid: " +
442 toString(MaybeProfiles.takeError()));
452 auto ModName = M.getName();
461 ProfileRootsInModule.
insert(
Guid.getZExtValue());
462 return ProfileRootsInModule;
464 const auto ProfileRootsInModule = DetermineRootsInModule();
466 Result.IsInSpecializedModule =
468 !ProfileRootsInModule.empty());
474 if (!ProfileRootsInModule.empty()) {
476 for (
auto &[RootGuid,
_] :
478 if (!ProfileRootsInModule.contains(RootGuid))
479 MaybeProfiles->Contexts.erase(RootGuid);
481 MaybeProfiles->FlatProfiles.clear();
484 for (
const auto &
F : M) {
485 if (
F.isDeclaration())
487 auto GUID =
F.getGUID();
488 assert(GUID &&
"guid not found for defined function");
489 const auto &Entry =
F.begin();
491 for (
const auto &
I : *Entry)
494 static_cast<uint32_t>(
C->getNumCounters()->getZExtValue());
500 for (
const auto &BB :
F)
501 for (
const auto &
I : BB)
504 static_cast<uint32_t>(
C->getNumCounters()->getZExtValue());
507 auto [It, Ins] =
Result.FuncInfo.insert(
508 {GUID, PGOContextualProfile::FunctionInfo(
F.getName())});
511 It->second.NextCallsiteIndex = MaxCallsites;
512 It->second.NextCounterIndex = MaxCounters;
516 Result.Profiles = std::move(*MaybeProfiles);
527 if (
C.contexts().empty()) {
528 OS <<
"No contextual profile was provided.\n";
533 OS <<
"Function Info:\n";
534 for (
const auto &[
Guid, FuncInfo] :
C.FuncInfo)
535 OS <<
Guid <<
" : " << FuncInfo.Name
536 <<
". MaxCounterID: " << FuncInfo.NextCounterIndex
537 <<
". MaxCallsiteID: " << FuncInfo.NextCallsiteIndex <<
"\n";
541 OS <<
"\nCurrent Profile:\n";
547 OS <<
"\nFlat Profile:\n";
548 auto Flat =
C.flatten();
565 "didn't expect to find another call, that's not the callsite "
566 "instrumentation, before an instrumentable callsite");
588template <
class ProfTy>
591 std::function<void(ProfTy &)> Traverser = [&](
auto &Ctx) {
593 for (
auto &[
_, SubCtxSet] : Ctx.callsites())
594 for (
auto &[__, Subctx] : SubCtxSet)
600template <
class ProfilesTy,
class ProfTy>
603 for (
auto &[
_,
P] : Profiles)
607void PGOContextualProfile::initIndex() {
610 DenseMap<GlobalValue::GUID, PGOCtxProfContext *> InsertionPoints;
611 for (
auto &[
Guid, FI] : FuncInfo)
612 InsertionPoints[
Guid] = &FI.Index;
614 Profiles.Contexts, [&](PGOCtxProfContext &Ctx) {
615 auto InsertIt = InsertionPoints.find(Ctx.guid());
616 if (InsertIt == InsertionPoints.end())
622 InsertIt->second->Next = &Ctx;
623 Ctx.Previous = InsertIt->second;
624 InsertIt->second = &Ctx;
629 return IsInSpecializedModule;
635 for (
auto *
Node = FuncInfo.find(
G)->second.Index.Next;
Node;
646 for (
const auto *
Node = FuncInfo.find(
G)->second.Index.Next;
Node;
655 uint64_t SamplingRate) {
659 "All contexts corresponding to a function should have the exact "
660 "same number of counters.");
661 for (
size_t I = 0, E = Into.
size();
I < E; ++
I)
662 Into[
I] += From[
I] * SamplingRate;
665 for (
const auto &[
_, CtxRoot] : Profiles.Contexts) {
666 const uint64_t SamplingFactor = CtxRoot.getTotalRootEntryCount();
669 Accummulate(
Flat[Ctx.guid()], Ctx.counters(), SamplingFactor);
672 for (
const auto &[
G, Unh] : CtxRoot.getUnhandled())
673 Accummulate(
Flat[
G], Unh, SamplingFactor);
676 for (
const auto &[
G, FC] : Profiles.FlatProfiles)
677 Accummulate(
Flat[
G], FC, 1);
684 for (
const auto &[
_, CtxRoot] : Profiles.Contexts) {
688 auto &Targets = Ret[Ctx.guid()];
689 for (
const auto &[ID, SubctxSet] : Ctx.callsites())
690 for (
const auto &Subctx : SubctxSet)
691 Targets[ID][Subctx.first] +=
700 SetVector<std::pair<CallBase *, Function *>> &Candidates) {
705 const uint32_t CallID = Instr->getIndex()->getZExtValue();
708 const auto &Targets = Ctx.callsites().find(CallID);
709 if (Targets == Ctx.callsites().end())
711 for (
const auto &[
Guid,
_] : Targets->second)
712 if (
auto Name = Profile.getFunctionName(
Guid); !Name.empty())
713 if (
auto *
Target = M.getFunction(Name))
714 if (
Target->hasFnAttribute(Attribute::AlwaysInline))
715 Candidates.insert({&IC,
Target});
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
static void preorderVisit(ProfilesTy &Profiles, function_ref< void(ProfTy &)> Visitor)
static void preorderVisitOneRoot(ProfTy &Profile, function_ref< void(ProfTy &)> Visitor)
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
static constexpr StringLiteral Filename
Reader for contextual iFDO profile, which comes in bitstream format.
ModuleAnalysisManager MAM
Class for arbitrary precision integers.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
LLVM Basic Block Representation.
LLVM_ABI const BasicBlock * getUniqueSuccessor() const
Return the successor of this block if it has a unique successor.
const Instruction & front() const
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
LLVM_ABI CtxProfAnalysisPrinterPass(raw_ostream &OS)
LLVM_ABI PGOContextualProfile run(Module &M, ModuleAnalysisManager &MAM)
static LLVM_ABI InstrProfIncrementInst * getBBInstrumentation(BasicBlock &BB)
Get the instruction instrumenting a BB, or nullptr if not present.
static LLVM_ABI InstrProfIncrementInstStep * getSelectInstrumentation(SelectInst &SI)
Get the step instrumentation associated with a select
static LLVM_ABI void collectIndirectCallPromotionList(CallBase &IC, Result &Profile, SetVector< std::pair< CallBase *, Function * > > &Candidates)
static LLVM_ABI InstrProfCallsite * getCallsiteInstrumentation(CallBase &CB)
Get the instruction instrumenting a callsite, or nullptr if that cannot be found.
static LLVM_ABI AnalysisKey Key
PGOContextualProfile Result
LLVM_ABI CtxProfAnalysis(std::optional< StringRef > Profile=std::nullopt)
Implements a dense probed hash-table based set.
Represents either an error or a value T.
std::error_code getError() const
uint64_t GUID
Declare a type to represent a global unique identifier for a global value.
This represents the llvm.instrprof.callsite intrinsic.
static bool canInstrumentCallsite(const CallBase &CB)
This represents the llvm.instrprof.increment.step intrinsic.
This represents the llvm.instrprof.increment intrinsic.
LLVM_ABI BasicBlock * getSuccessor(unsigned Idx) const LLVM_READONLY
Return the specified successor. This instruction must be a terminator.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
A Module instance is used to store all the information related to an LLVM module.
The instrumented contextual profile, produced by the CtxProfAnalysis.
LLVM_ABI void visit(ConstVisitor, const Function *F=nullptr) const
LLVM_ABI const CtxProfFlatProfile flatten() const
LLVM_ABI bool isInSpecializedModule() const
LLVM_ABI void update(Visitor, const Function &F)
function_ref< void(PGOCtxProfContext &)> Visitor
function_ref< void(const PGOCtxProfContext &)> ConstVisitor
LLVM_ABI const CtxProfFlatIndirectCallProfile flattenVirtCalls() const
bool isFunctionKnown(const Function &F) const
A node (context) in the loaded contextual profile, suitable for mutation during IPO passes.
std::map< GlobalValue::GUID, PGOCtxProfContext > CallTargetMapTy
LLVM_ABI Expected< PGOCtxProfile > loadProfiles()
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
uint64_t getBBCount(const BasicBlock &BB)
ProfileAnnotatorImpl(const Function &F, ArrayRef< uint64_t > Counters)
friend class ProfileAnnotator
LLVM_ABI ~ProfileAnnotator()
LLVM_ABI bool getSelectInstrProfile(SelectInst &SI, uint64_t &TrueCount, uint64_t &FalseCount) const
LLVM_ABI bool getOutgoingBranchWeights(BasicBlock &BB, SmallVectorImpl< uint64_t > &Profile, uint64_t &MaxCount) const
LLVM_ABI uint64_t getBBCount(const BasicBlock &BB) const
LLVM_ABI ProfileAnnotator(const Function &F, ArrayRef< uint64_t > RawCounters)
This class represents the LLVM 'select' instruction.
A vector that has set insertion semantics.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Target - Wrapper for Target specific information.
std::pair< iterator, bool > insert(const ValueT &V)
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
This class implements an extremely fast bulk output stream that can only output to a stream.
Pass manager infrastructure for declaring and invalidating analyses.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
std::map< GlobalValue::GUID, SmallVector< uint64_t, 1 > > CtxProfFlatProfile
auto successors(const MachineBasicBlock *BB)
cl::opt< std::string > UseCtxProfile("use-ctx-profile", cl::init(""), cl::Hidden, cl::desc("Use the specified contextual profile file"))
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
auto pred_size(const MachineBasicBlock *BB)
const AnalysisOptions & getAnalysisOptions(const LLVMContext &C)
auto succ_size(const MachineBasicBlock *BB)
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
auto count_if(R &&Range, UnaryPredicate P)
Wrapper function around std::count_if to count the number of times an element satisfying a given pred...
DenseMap< GlobalValue::GUID, DenseMap< uint32_t, FlatIndirectTargets > > CtxProfFlatIndirectCallProfile
LLVM_ABI bool isPresplitCoroSuspendExitEdge(const BasicBlock &Src, const BasicBlock &Dest)
static cl::opt< CtxProfAnalysisPrinterPass::PrintMode > PrintLevel("ctx-profile-printer-level", cl::init(CtxProfAnalysisPrinterPass::PrintMode::YAML), cl::Hidden, cl::values(clEnumValN(CtxProfAnalysisPrinterPass::PrintMode::Everything, "everything", "print everything - most verbose"), clEnumValN(CtxProfAnalysisPrinterPass::PrintMode::YAML, "yaml", "just the yaml representation of the profile")), cl::desc("Verbosity level of the contextual profile printer pass."))
constexpr bool valueOr(BoolOrDefault X, bool Default)
LLVM_ABI void convertCtxProfToYaml(raw_ostream &OS, const PGOCtxProfile &Profile)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Implement std::hash so that hash_code can be used in STL containers.
A special type used by analysis passes to provide an address that identifies that particular analysis...