31#define DEBUG_TYPE "ctx_prof"
39 cl::desc(
"Use the specified contextual profile file"));
47 std::optional<uint64_t>
Count;
49 explicit EdgeInfo(BBInfo &Src, BBInfo &Dest) : Src(&Src), Dest(&Dest) {}
53 std::optional<uint64_t>
Count;
61 size_t UnknownCountOutEdges = 0;
62 size_t UnknownCountInEdges = 0;
69 bool AssumeAllKnown)
const {
70 std::optional<uint64_t> Sum;
71 for (
const auto *
E : Edges) {
76 *Sum += (AssumeAllKnown ? *
E->Count :
E->Count.value_or(0U));
82 bool computeCountFrom(
const SmallVector<EdgeInfo *> &Edges) {
83 assert(!Count.has_value());
84 Count = getEdgeSum(Edges,
true);
85 return Count.has_value();
88 void setSingleUnknownEdgeCount(SmallVector<EdgeInfo *> &Edges) {
89 uint64_t KnownSum = getEdgeSum(Edges,
false).value_or(0U);
90 uint64_t EdgeVal = *Count > KnownSum ? *Count - KnownSum : 0
U;
91 EdgeInfo *
E =
nullptr;
93 if (
I && !
I->Count.has_value()) {
99 "Expected exactly one edge to have an unknown count, "
100 "found a second one");
104 assert(
E &&
"Expected exactly one edge to have an unknown count");
107 assert(
E->Src->UnknownCountOutEdges > 0);
108 assert(
E->Dest->UnknownCountInEdges > 0);
109 --
E->Src->UnknownCountOutEdges;
110 --
E->Dest->UnknownCountInEdges;
114 BBInfo(
size_t NumInEdges,
size_t NumOutEdges, std::optional<uint64_t> Count)
121 InEdges.reserve(NumInEdges);
122 OutEdges.resize(NumOutEdges);
125 bool tryTakeCountFromKnownOutEdges(
const BasicBlock &BB) {
126 if (!UnknownCountOutEdges) {
127 return computeCountFrom(OutEdges);
132 bool tryTakeCountFromKnownInEdges(
const BasicBlock &BB) {
133 if (!UnknownCountInEdges) {
134 return computeCountFrom(InEdges);
139 void addInEdge(EdgeInfo &Info) {
140 InEdges.push_back(&Info);
141 ++UnknownCountInEdges;
148 void addOutEdge(
size_t Index, EdgeInfo &Info) {
150 ++UnknownCountOutEdges;
153 bool hasCount()
const {
return Count.has_value(); }
155 uint64_t getCount()
const {
return *Count; }
157 bool trySetSingleUnknownInEdgeCount() {
158 if (UnknownCountInEdges == 1) {
159 setSingleUnknownEdgeCount(InEdges);
165 bool trySetSingleUnknownOutEdgeCount() {
166 if (UnknownCountOutEdges == 1) {
167 setSingleUnknownEdgeCount(OutEdges);
172 size_t getNumOutEdges()
const {
return OutEdges.size(); }
174 uint64_t getEdgeCount(
size_t Index)
const {
175 if (
auto *
E = OutEdges[Index])
182 ArrayRef<uint64_t> Counters;
184 std::map<const BasicBlock *, BBInfo> BBInfos;
185 std::vector<EdgeInfo> EdgeInfos;
189 bool shouldExcludeEdge(
const BasicBlock &Src,
const BasicBlock &Dest)
const {
193 BBInfo &getBBInfo(
const BasicBlock &BB) {
return BBInfos.find(&BB)->second; }
195 const BBInfo &getBBInfo(
const BasicBlock &BB)
const {
196 return BBInfos.find(&BB)->second;
201 bool allCountersAreAssigned()
const {
202 for (
const auto &BBInfo : BBInfos)
203 if (!BBInfo.second.hasCount())
205 for (
const auto &EdgeInfo : EdgeInfos)
206 if (!EdgeInfo.Count.has_value())
213 bool allTakenPathsExit()
const {
214 std::deque<const BasicBlock *> Worklist;
215 DenseSet<const BasicBlock *> Visited;
216 Worklist.push_back(&F.getEntryBlock());
217 bool HitExit =
false;
218 while (!Worklist.empty()) {
219 const auto *BB = Worklist.
front();
220 Worklist.pop_front();
221 if (!Visited.
insert(BB).second)
233 const auto &BBInfo = getBBInfo(*BB);
234 bool HasAWayOut =
false;
237 if (!shouldExcludeEdge(*BB, *Succ)) {
238 if (BBInfo.getEdgeCount(
I) > 0) {
240 Worklist.push_back(Succ);
250 bool allNonColdSelectsHaveProfile()
const {
251 for (
const auto &BB : F) {
252 if (getBBInfo(BB).getCount() > 0) {
253 for (
const auto &
I : BB) {
256 *
const_cast<SelectInst *
>(SI))) {
257 auto Index = Inst->getIndex()->getZExtValue();
258 assert(Index < Counters.size());
259 if (Counters[Index] == 0)
271 void propagateCounterValues() {
272 bool KeepGoing =
true;
275 for (
const auto &BB : F) {
276 auto &
Info = getBBInfo(BB);
277 if (!
Info.hasCount())
278 KeepGoing |=
Info.tryTakeCountFromKnownOutEdges(BB) ||
279 Info.tryTakeCountFromKnownInEdges(BB);
280 if (
Info.hasCount()) {
281 KeepGoing |=
Info.trySetSingleUnknownOutEdgeCount();
282 KeepGoing |=
Info.trySetSingleUnknownInEdgeCount();
286 assert(allCountersAreAssigned() &&
287 "[ctx-prof] Expected all counters have been assigned.");
288 assert(allTakenPathsExit() &&
289 "[ctx-prof] Encountered a BB with more than one successor, where "
290 "all outgoing edges have a 0 count. This occurs in non-exiting "
291 "functions (message pumps, usually) which are not supported in the "
292 "contextual profiling case");
293 assert(allNonColdSelectsHaveProfile() &&
294 "[ctx-prof] All non-cold select instructions were expected to have "
300 : F(F), Counters(Counters) {
301 assert(!F.isDeclaration());
302 assert(!Counters.empty());
304 for (
const auto &BB : F) {
305 std::optional<uint64_t>
Count;
308 auto Index = Ins->getIndex()->getZExtValue();
309 assert(Index < Counters.size() &&
310 "The index must be inside the counters vector by construction - "
311 "tripping this assertion indicates a bug in how the contextual "
312 "profile is managed by IPO transforms");
314 Count = Counters[Ins->getIndex()->getZExtValue()];
322 assert(Ins &&
"We iterate through the function's BBs, no reason to "
323 "insert one more than once");
325 return !shouldExcludeEdge(BB, *Succ);
329 EdgeInfos.reserve(NrEdges);
330 for (
const auto &BB : F) {
331 auto &Info = getBBInfo(BB);
332 for (
auto I = 0U;
I < BB.getTerminator()->getNumSuccessors(); ++
I) {
333 const auto *Succ = BB.getTerminator()->getSuccessor(
I);
334 if (!shouldExcludeEdge(BB, *Succ)) {
335 auto &EI = EdgeInfos.emplace_back(getBBInfo(BB), getBBInfo(*Succ));
336 Info.addOutEdge(
I, EI);
337 getBBInfo(*Succ).addInEdge(EI);
341 assert(EdgeInfos.capacity() == NrEdges &&
342 "The capacity of EdgeInfos should have stayed unchanged it was "
343 "populated, because we need pointers to its contents to be stable");
344 propagateCounterValues();
359 return PImpl->getBBCount(BB);
364 uint64_t &FalseCount)
const {
365 const auto &BBInfo = PImpl->getBBInfo(*
SI.getParent());
366 TrueCount = FalseCount = 0;
367 if (BBInfo.getCount() == 0)
373 auto Index = Step->getIndex()->getZExtValue();
375 "The index of the step instruction must be inside the "
376 "counters vector by "
377 "construction - tripping this assertion indicates a bug in "
378 "how the contextual profile is managed by IPO transforms");
379 auto TotalCount = BBInfo.getCount();
380 TrueCount = PImpl->Counters[Index];
381 FalseCount = (TotalCount > TrueCount ? TotalCount - TrueCount : 0U);
387 uint64_t &MaxCount)
const {
394 Profile.resize(Term->getNumSuccessors());
396 const auto &BBInfo = PImpl->getBBInfo(BB);
398 for (
unsigned SuccIdx = 0,
Size = BBInfo.getNumOutEdges(); SuccIdx <
Size;
400 uint64_t EdgeCount = BBInfo.getEdgeCount(SuccIdx);
401 if (EdgeCount > MaxCount)
402 MaxCount = EdgeCount;
425 M.getContext().emitError(
"could not open contextual profile file: " +
431 if (!MaybeProfiles) {
432 M.getContext().emitError(
"contextual profile file is invalid: " +
433 toString(MaybeProfiles.takeError()));
443 auto ModName = M.getName();
452 ProfileRootsInModule.
insert(
Guid.getZExtValue());
453 return ProfileRootsInModule;
455 const auto ProfileRootsInModule = DetermineRootsInModule();
457 Result.IsInSpecializedModule =
459 !ProfileRootsInModule.empty());
465 if (!ProfileRootsInModule.empty()) {
467 for (
auto &[RootGuid,
_] :
469 if (!ProfileRootsInModule.contains(RootGuid))
470 MaybeProfiles->Contexts.erase(RootGuid);
472 MaybeProfiles->FlatProfiles.clear();
475 for (
const auto &
F : M) {
476 if (
F.isDeclaration())
478 auto GUID =
F.getGUID();
479 assert(GUID &&
"guid not found for defined function");
480 const auto &Entry =
F.begin();
482 for (
const auto &
I : *Entry)
485 static_cast<uint32_t>(
C->getNumCounters()->getZExtValue());
491 for (
const auto &BB :
F)
492 for (
const auto &
I : BB)
495 static_cast<uint32_t>(
C->getNumCounters()->getZExtValue());
498 auto [It, Ins] =
Result.FuncInfo.insert(
499 {GUID, PGOContextualProfile::FunctionInfo(
F.getName())});
502 It->second.NextCallsiteIndex = MaxCallsites;
503 It->second.NextCounterIndex = MaxCounters;
507 Result.Profiles = std::move(*MaybeProfiles);
518 if (
C.contexts().empty()) {
519 OS <<
"No contextual profile was provided.\n";
525 OS <<
"Function Info:\n";
526 for (
const auto &[
Guid, FuncInfo] :
C.FuncInfo)
527 OS <<
Guid <<
" : " << FuncInfo.Name
528 <<
". MaxCounterID: " << FuncInfo.NextCounterIndex
529 <<
". MaxCallsiteID: " << FuncInfo.NextCallsiteIndex <<
"\n";
533 OS <<
"\nCurrent Profile:\n";
539 OS <<
"\nFlat Profile:\n";
540 auto Flat =
C.flatten();
557 "didn't expect to find another call, that's not the callsite "
558 "instrumentation, before an instrumentable callsite");
580template <
class ProfTy>
583 std::function<void(ProfTy &)> Traverser = [&](
auto &Ctx) {
585 for (
auto &[
_, SubCtxSet] : Ctx.callsites())
586 for (
auto &[__, Subctx] : SubCtxSet)
592template <
class ProfilesTy,
class ProfTy>
595 for (
auto &[
_,
P] : Profiles)
599void PGOContextualProfile::initIndex() {
602 DenseMap<GlobalValue::GUID, PGOCtxProfContext *> InsertionPoints;
603 for (
auto &[
Guid, FI] : FuncInfo)
604 InsertionPoints[
Guid] = &FI.Index;
606 Profiles.Contexts, [&](PGOCtxProfContext &Ctx) {
607 auto InsertIt = InsertionPoints.find(Ctx.guid());
608 if (InsertIt == InsertionPoints.end())
614 InsertIt->second->Next = &Ctx;
615 Ctx.Previous = InsertIt->second;
616 InsertIt->second = &Ctx;
621 return IsInSpecializedModule;
627 for (
auto *
Node = FuncInfo.find(
G)->second.Index.Next;
Node;
638 for (
const auto *
Node = FuncInfo.find(
G)->second.Index.Next;
Node;
647 uint64_t SamplingRate) {
651 "All contexts corresponding to a function should have the exact "
652 "same number of counters.");
653 for (
size_t I = 0, E = Into.
size();
I < E; ++
I)
654 Into[
I] += From[
I] * SamplingRate;
657 for (
const auto &[
_, CtxRoot] : Profiles.Contexts) {
658 const uint64_t SamplingFactor = CtxRoot.getTotalRootEntryCount();
661 Accummulate(
Flat[Ctx.guid()], Ctx.counters(), SamplingFactor);
664 for (
const auto &[
G, Unh] : CtxRoot.getUnhandled())
665 Accummulate(
Flat[
G], Unh, SamplingFactor);
668 for (
const auto &[
G, FC] : Profiles.FlatProfiles)
669 Accummulate(
Flat[
G], FC, 1);
676 for (
const auto &[
_, CtxRoot] : Profiles.Contexts) {
680 auto &Targets = Ret[Ctx.guid()];
681 for (
const auto &[ID, SubctxSet] : Ctx.callsites())
682 for (
const auto &Subctx : SubctxSet)
683 Targets[ID][Subctx.first] +=
692 SetVector<std::pair<CallBase *, Function *>> &Candidates) {
697 const uint32_t CallID = Instr->getIndex()->getZExtValue();
700 const auto &Targets = Ctx.callsites().find(CallID);
701 if (Targets == Ctx.callsites().end())
703 for (
const auto &[
Guid,
_] : Targets->second)
704 if (
auto Name = Profile.getFunctionName(
Guid); !Name.empty())
705 if (
auto *
Target = M.getFunction(Name))
706 if (
Target->hasFnAttribute(Attribute::AlwaysInline))
707 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")
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.
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)
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...