LLVM 24.0.0git
CtxProfAnalysis.cpp
Go to the documentation of this file.
1//===- CtxProfAnalysis.cpp - contextual profile analysis ------------------===//
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// Implementation of the contextual profile analysis, which maintains contextual
10// profiling info through IPO passes.
11//
12//===----------------------------------------------------------------------===//
13
15#include "AnalysisOptions.h"
16#include "llvm/ADT/APInt.h"
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/Analysis/CFG.h"
19#include "llvm/IR/Analysis.h"
20#include "llvm/IR/Dominators.h"
22#include "llvm/IR/Module.h"
23#include "llvm/IR/PassManager.h"
27#include "llvm/Support/Path.h"
28#include <deque>
29#include <memory>
30
31#define DEBUG_TYPE "ctx_prof"
32
33using namespace llvm;
34
35namespace llvm {
36
38 UseCtxProfile("use-ctx-profile", cl::init(""), cl::Hidden,
39 cl::desc("Use the specified contextual profile file"));
40
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."));
49
51 friend class ProfileAnnotator;
52 class BBInfo;
53 struct EdgeInfo {
54 BBInfo *const Src;
55 BBInfo *const Dest;
56 std::optional<uint64_t> Count;
57
58 explicit EdgeInfo(BBInfo &Src, BBInfo &Dest) : Src(&Src), Dest(&Dest) {}
59 };
60
61 class BBInfo {
62 std::optional<uint64_t> Count;
63 // OutEdges is dimensioned to match the number of terminator operands.
64 // Entries in the vector match the index in the terminator operand list. In
65 // some cases - see `shouldExcludeEdge` and its implementation - an entry
66 // will be nullptr.
67 // InEdges doesn't have the above constraint.
70 size_t UnknownCountOutEdges = 0;
71 size_t UnknownCountInEdges = 0;
72
73 // Pass AssumeAllKnown when we try to propagate counts from edges to BBs -
74 // because all the edge counters must be known.
75 // Return std::nullopt if there were no edges to sum. The user can decide
76 // how to interpret that.
77 std::optional<uint64_t> getEdgeSum(const SmallVector<EdgeInfo *> &Edges,
78 bool AssumeAllKnown) const {
79 std::optional<uint64_t> Sum;
80 for (const auto *E : Edges) {
81 // `Edges` may be `OutEdges`, case in which `E` could be nullptr.
82 if (E) {
83 if (!Sum.has_value())
84 Sum = 0;
85 *Sum += (AssumeAllKnown ? *E->Count : E->Count.value_or(0U));
86 }
87 }
88 return Sum;
89 }
90
91 bool computeCountFrom(const SmallVector<EdgeInfo *> &Edges) {
92 assert(!Count.has_value());
93 Count = getEdgeSum(Edges, true);
94 return Count.has_value();
95 }
96
97 void setSingleUnknownEdgeCount(SmallVector<EdgeInfo *> &Edges) {
98 uint64_t KnownSum = getEdgeSum(Edges, false).value_or(0U);
99 uint64_t EdgeVal = *Count > KnownSum ? *Count - KnownSum : 0U;
100 EdgeInfo *E = nullptr;
101 for (auto *I : Edges)
102 if (I && !I->Count.has_value()) {
103 E = I;
104#ifdef NDEBUG
105 break;
106#else
107 assert((!E || E == I) &&
108 "Expected exactly one edge to have an unknown count, "
109 "found a second one");
110 continue;
111#endif
112 }
113 assert(E && "Expected exactly one edge to have an unknown count");
114 assert(!E->Count.has_value());
115 E->Count = EdgeVal;
116 assert(E->Src->UnknownCountOutEdges > 0);
117 assert(E->Dest->UnknownCountInEdges > 0);
118 --E->Src->UnknownCountOutEdges;
119 --E->Dest->UnknownCountInEdges;
120 }
121
122 public:
123 BBInfo(size_t NumInEdges, size_t NumOutEdges, std::optional<uint64_t> Count)
124 : Count(Count) {
125 // For in edges, we just want to pre-allocate enough space, since we know
126 // it at this stage. For out edges, we will insert edges at the indices
127 // corresponding to positions in this BB's terminator instruction, so we
128 // construct a default (nullptr values)-initialized vector. A nullptr edge
129 // corresponds to those that are excluded (see shouldExcludeEdge).
130 InEdges.reserve(NumInEdges);
131 OutEdges.resize(NumOutEdges);
132 }
133
134 bool tryTakeCountFromKnownOutEdges(const BasicBlock &BB) {
135 if (!UnknownCountOutEdges) {
136 return computeCountFrom(OutEdges);
137 }
138 return false;
139 }
140
141 bool tryTakeCountFromKnownInEdges(const BasicBlock &BB) {
142 if (!UnknownCountInEdges) {
143 return computeCountFrom(InEdges);
144 }
145 return false;
146 }
147
148 void addInEdge(EdgeInfo &Info) {
149 InEdges.push_back(&Info);
150 ++UnknownCountInEdges;
151 }
152
153 // For the out edges, we care about the position we place them in, which is
154 // the position in terminator instruction's list (at construction). Later,
155 // we build branch_weights metadata with edge frequency values matching
156 // these positions.
157 void addOutEdge(size_t Index, EdgeInfo &Info) {
158 OutEdges[Index] = &Info;
159 ++UnknownCountOutEdges;
160 }
161
162 bool hasCount() const { return Count.has_value(); }
163
164 uint64_t getCount() const { return *Count; }
165
166 bool trySetSingleUnknownInEdgeCount() {
167 if (UnknownCountInEdges == 1) {
168 setSingleUnknownEdgeCount(InEdges);
169 return true;
170 }
171 return false;
172 }
173
174 bool trySetSingleUnknownOutEdgeCount() {
175 if (UnknownCountOutEdges == 1) {
176 setSingleUnknownEdgeCount(OutEdges);
177 return true;
178 }
179 return false;
180 }
181 size_t getNumOutEdges() const { return OutEdges.size(); }
182
183 uint64_t getEdgeCount(size_t Index) const {
184 if (auto *E = OutEdges[Index])
185 return *E->Count;
186 return 0U;
187 }
188 };
189
190 const Function &F;
191 ArrayRef<uint64_t> Counters;
192 // To be accessed through getBBInfo() after construction.
193 std::map<const BasicBlock *, BBInfo> BBInfos;
194 std::vector<EdgeInfo> EdgeInfos;
195
196 // The only criteria for exclusion is faux suspend -> exit edges in presplit
197 // coroutines. The API serves for readability, currently.
198 bool shouldExcludeEdge(const BasicBlock &Src, const BasicBlock &Dest) const {
199 return llvm::isPresplitCoroSuspendExitEdge(Src, Dest);
200 }
201
202 BBInfo &getBBInfo(const BasicBlock &BB) { return BBInfos.find(&BB)->second; }
203
204 const BBInfo &getBBInfo(const BasicBlock &BB) const {
205 return BBInfos.find(&BB)->second;
206 }
207
208 // validation function after we propagate the counters: all BBs and edges'
209 // counters must have a value.
210 bool allCountersAreAssigned() const {
211 for (const auto &BBInfo : BBInfos)
212 if (!BBInfo.second.hasCount())
213 return false;
214 for (const auto &EdgeInfo : EdgeInfos)
215 if (!EdgeInfo.Count.has_value())
216 return false;
217 return true;
218 }
219
220 /// Check that all paths from the entry basic block that use edges with
221 /// non-zero counts arrive at a basic block with no successors (i.e. "exit")
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)
231 continue;
232 if (succ_size(BB) == 0) {
234 return false;
235 HitExit = true;
236 continue;
237 }
238 if (succ_size(BB) == 1) {
239 Worklist.push_back(BB->getUniqueSuccessor());
240 continue;
241 }
242 const auto &BBInfo = getBBInfo(*BB);
243 bool HasAWayOut = false;
244 for (auto I = 0U; I < BB->getTerminator()->getNumSuccessors(); ++I) {
245 const auto *Succ = BB->getTerminator()->getSuccessor(I);
246 if (!shouldExcludeEdge(*BB, *Succ)) {
247 if (BBInfo.getEdgeCount(I) > 0) {
248 HasAWayOut = true;
249 Worklist.push_back(Succ);
250 }
251 }
252 }
253 if (!HasAWayOut)
254 return false;
255 }
256 return HitExit;
257 }
258
259 bool allNonColdSelectsHaveProfile() const {
260 for (const auto &BB : F) {
261 if (getBBInfo(BB).getCount() > 0) {
262 for (const auto &I : BB) {
263 if (const auto *SI = dyn_cast<SelectInst>(&I)) {
264 if (const auto *Inst = CtxProfAnalysis::getSelectInstrumentation(
265 *const_cast<SelectInst *>(SI))) {
266 auto Index = Inst->getIndex()->getZExtValue();
267 assert(Index < Counters.size());
268 if (Counters[Index] == 0)
269 return false;
270 }
271 }
272 }
273 }
274 }
275 return true;
276 }
277
278 // This is an adaptation of PGOUseFunc::populateCounters.
279 // FIXME(mtrofin): look into factoring the code to share one implementation.
280 void propagateCounterValues() {
281 bool KeepGoing = true;
282 while (KeepGoing) {
283 KeepGoing = false;
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();
292 }
293 }
294 }
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 "
304 "a profile.");
305 }
306
307public:
309 : F(F), Counters(Counters) {
310 assert(!F.isDeclaration());
311 assert(!Counters.empty());
312 size_t NrEdges = 0;
313 for (const auto &BB : F) {
314 std::optional<uint64_t> Count;
316 const_cast<BasicBlock &>(BB))) {
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");
322 (void)Index;
323 Count = Counters[Ins->getIndex()->getZExtValue()];
324 } else if (isa<UnreachableInst>(BB.getTerminator())) {
325 // The program presumably didn't crash.
326 Count = 0;
327 }
328 auto [It, Ins] =
329 BBInfos.insert({&BB, {pred_size(&BB), succ_size(&BB), Count}});
330 (void)Ins;
331 assert(Ins && "We iterate through the function's BBs, no reason to "
332 "insert one more than once");
333 NrEdges += llvm::count_if(successors(&BB), [&](const auto *Succ) {
334 return !shouldExcludeEdge(BB, *Succ);
335 });
336 }
337 // Pre-allocate the vector, we want references to its contents to be stable.
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);
347 }
348 }
349 }
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();
354 }
355
356 uint64_t getBBCount(const BasicBlock &BB) { return getBBInfo(BB).getCount(); }
357};
358
359} // namespace llvm
360
362 ArrayRef<uint64_t> RawCounters)
363 : PImpl(std::make_unique<ProfileAnnotatorImpl>(F, RawCounters)) {}
364
366
367uint64_t ProfileAnnotator::getBBCount(const BasicBlock &BB) const {
368 return PImpl->getBBCount(BB);
369}
370
372 uint64_t &TrueCount,
373 uint64_t &FalseCount) const {
374 const auto &BBInfo = PImpl->getBBInfo(*SI.getParent());
375 TrueCount = FalseCount = 0;
376 if (BBInfo.getCount() == 0)
377 return false;
378
380 if (!Step)
381 return false;
382 auto Index = Step->getIndex()->getZExtValue();
383 assert(Index < PImpl->Counters.size() &&
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);
391 return true;
392}
393
396 uint64_t &MaxCount) const {
397 Profile.clear();
398
399 if (succ_size(&BB) < 2)
400 return false;
401
402 auto *Term = BB.getTerminator();
403 Profile.resize(Term->getNumSuccessors());
404
405 const auto &BBInfo = PImpl->getBBInfo(BB);
406 MaxCount = 0;
407 for (unsigned SuccIdx = 0, Size = BBInfo.getNumOutEdges(); SuccIdx < Size;
408 ++SuccIdx) {
409 uint64_t EdgeCount = BBInfo.getEdgeCount(SuccIdx);
410 if (EdgeCount > MaxCount)
411 MaxCount = EdgeCount;
412 Profile[SuccIdx] = EdgeCount;
413 }
414 return MaxCount > 0;
415}
416
418
419CtxProfAnalysis::CtxProfAnalysis(std::optional<StringRef> Profile)
420 : Profile([&]() -> std::optional<StringRef> {
421 if (Profile)
422 return *Profile;
423 if (UseCtxProfile.getNumOccurrences())
424 return UseCtxProfile;
425 return std::nullopt;
426 }()) {}
427
430 if (!Profile)
431 return {};
433 if (auto EC = MB.getError()) {
434 M.getContext().emitError("could not open contextual profile file: " +
435 EC.message());
436 return {};
437 }
438 PGOCtxProfileReader Reader(MB.get()->getBuffer());
439 auto MaybeProfiles = Reader.loadProfiles();
440 if (!MaybeProfiles) {
441 M.getContext().emitError("contextual profile file is invalid: " +
442 toString(MaybeProfiles.takeError()));
443 return {};
444 }
445
446 // FIXME: We should drive this from ThinLTO, but for the time being, use the
447 // module name as indicator.
448 // We want to *only* keep the contextual profiles in modules that capture
449 // context trees. That allows us to compute specific PSIs, for example.
450 auto DetermineRootsInModule = [&M]() -> const DenseSet<GlobalValue::GUID> {
451 DenseSet<GlobalValue::GUID> ProfileRootsInModule;
452 auto ModName = M.getName();
453 auto Filename = sys::path::filename(ModName);
454 // Drop the file extension.
455 Filename = Filename.substr(0, Filename.find_last_of('.'));
456 // See if it parses
457 APInt Guid;
458 // getAsInteger returns true if there are more chars to read other than the
459 // integer. So the "false" test is what we want.
460 if (!Filename.getAsInteger(0, Guid))
461 ProfileRootsInModule.insert(Guid.getZExtValue());
462 return ProfileRootsInModule;
463 };
464 const auto ProfileRootsInModule = DetermineRootsInModule();
466 Result.IsInSpecializedModule =
467 valueOr(getAnalysisOptions(M).ctx_profile_force_is_specialized,
468 !ProfileRootsInModule.empty());
469
470 // the logic from here on allows for modules that contain - by design - more
471 // than one root. We currently don't support that, because the determination
472 // happens based on the module name matching the root guid, but the logic can
473 // avoid assuming that.
474 if (!ProfileRootsInModule.empty()) {
475 // Trim first the roots that aren't in this module.
476 for (auto &[RootGuid, _] :
477 llvm::make_early_inc_range(MaybeProfiles->Contexts))
478 if (!ProfileRootsInModule.contains(RootGuid))
479 MaybeProfiles->Contexts.erase(RootGuid);
480 // we can also drop the flat profiles
481 MaybeProfiles->FlatProfiles.clear();
482 }
483
484 for (const auto &F : M) {
485 if (F.isDeclaration())
486 continue;
487 auto GUID = F.getGUID();
488 assert(GUID && "guid not found for defined function");
489 const auto &Entry = F.begin();
490 uint32_t MaxCounters = 0; // we expect at least a counter.
491 for (const auto &I : *Entry)
492 if (auto *C = dyn_cast<InstrProfIncrementInst>(&I)) {
493 MaxCounters =
494 static_cast<uint32_t>(C->getNumCounters()->getZExtValue());
495 break;
496 }
497 if (!MaxCounters)
498 continue;
499 uint32_t MaxCallsites = 0;
500 for (const auto &BB : F)
501 for (const auto &I : BB)
502 if (auto *C = dyn_cast<InstrProfCallsite>(&I)) {
503 MaxCallsites =
504 static_cast<uint32_t>(C->getNumCounters()->getZExtValue());
505 break;
506 }
507 auto [It, Ins] = Result.FuncInfo.insert(
508 {GUID, PGOContextualProfile::FunctionInfo(F.getName())});
509 (void)Ins;
510 assert(Ins);
511 It->second.NextCallsiteIndex = MaxCallsites;
512 It->second.NextCounterIndex = MaxCounters;
513 }
514 // If we made it this far, the Result is valid - which we mark by setting
515 // .Profiles.
516 Result.Profiles = std::move(*MaybeProfiles);
517 Result.initIndex();
518 return Result;
519}
520
523
527 if (C.contexts().empty()) {
528 OS << "No contextual profile was provided.\n";
529 return PreservedAnalyses::all();
530 }
531
532 if (Mode == PrintMode::Everything) {
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";
538 }
539
540 if (Mode == PrintMode::Everything)
541 OS << "\nCurrent Profile:\n";
542 convertCtxProfToYaml(OS, C.profiles());
543 OS << "\n";
544 if (Mode == PrintMode::YAML)
545 return PreservedAnalyses::all();
546
547 OS << "\nFlat Profile:\n";
548 auto Flat = C.flatten();
549 for (const auto &[Guid, Counters] : Flat) {
550 OS << Guid << " : ";
551 for (auto V : Counters)
552 OS << V << " ";
553 OS << "\n";
554 }
555 return PreservedAnalyses::all();
556}
557
560 return nullptr;
561 for (auto *Prev = CB.getPrevNode(); Prev; Prev = Prev->getPrevNode()) {
562 if (auto *IPC = dyn_cast<InstrProfCallsite>(Prev))
563 return IPC;
564 assert(!isa<CallBase>(Prev) &&
565 "didn't expect to find another call, that's not the callsite "
566 "instrumentation, before an instrumentable callsite");
567 }
568 return nullptr;
569}
570
572 for (auto &I : BB)
573 if (auto *Incr = dyn_cast<InstrProfIncrementInst>(&I))
575 return Incr;
576 return nullptr;
577}
578
581 Instruction *Prev = &SI;
582 while ((Prev = Prev->getPrevNode()))
583 if (auto *Step = dyn_cast<InstrProfIncrementInstStep>(Prev))
584 return Step;
585 return nullptr;
586}
587
588template <class ProfTy>
589static void preorderVisitOneRoot(ProfTy &Profile,
590 function_ref<void(ProfTy &)> Visitor) {
591 std::function<void(ProfTy &)> Traverser = [&](auto &Ctx) {
592 Visitor(Ctx);
593 for (auto &[_, SubCtxSet] : Ctx.callsites())
594 for (auto &[__, Subctx] : SubCtxSet)
595 Traverser(Subctx);
596 };
597 Traverser(Profile);
598}
599
600template <class ProfilesTy, class ProfTy>
601static void preorderVisit(ProfilesTy &Profiles,
602 function_ref<void(ProfTy &)> Visitor) {
603 for (auto &[_, P] : Profiles)
605}
606
607void PGOContextualProfile::initIndex() {
608 // Initialize the head of the index list for each function. We don't need it
609 // after this point.
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())
617 return;
618 // Insert at the end of the list. Since we traverse in preorder, it
619 // means that when we iterate the list from the beginning, we'd
620 // encounter the contexts in the order we would have, should we have
621 // performed a full preorder traversal.
622 InsertIt->second->Next = &Ctx;
623 Ctx.Previous = InsertIt->second;
624 InsertIt->second = &Ctx;
625 });
626}
627
629 return IsInSpecializedModule;
630}
631
634 GlobalValue::GUID G = F.getGUID();
635 for (auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
636 Node = Node->Next)
637 V(*reinterpret_cast<PGOCtxProfContext *>(Node));
638}
639
641 if (!F)
643 const PGOCtxProfContext>(Profiles.Contexts, V);
645 GlobalValue::GUID G = F->getGUID();
646 for (const auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
647 Node = Node->Next)
648 V(*reinterpret_cast<const PGOCtxProfContext *>(Node));
649}
650
653 auto Accummulate = [](SmallVectorImpl<uint64_t> &Into,
654 const SmallVectorImpl<uint64_t> &From,
655 uint64_t SamplingRate) {
656 if (Into.empty())
657 Into.resize(From.size());
658 assert(Into.size() == From.size() &&
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;
663 };
664
665 for (const auto &[_, CtxRoot] : Profiles.Contexts) {
666 const uint64_t SamplingFactor = CtxRoot.getTotalRootEntryCount();
668 CtxRoot, [&](const PGOCtxProfContext &Ctx) {
669 Accummulate(Flat[Ctx.guid()], Ctx.counters(), SamplingFactor);
670 });
671
672 for (const auto &[G, Unh] : CtxRoot.getUnhandled())
673 Accummulate(Flat[G], Unh, SamplingFactor);
674 }
675 // We don't sample "Flat" currently, so sampling rate is 1.
676 for (const auto &[G, FC] : Profiles.FlatProfiles)
677 Accummulate(Flat[G], FC, /*SamplingRate=*/1);
678 return Flat;
679}
680
684 for (const auto &[_, CtxRoot] : Profiles.Contexts) {
685 const uint64_t TotalRootEntryCount = CtxRoot.getTotalRootEntryCount();
687 CtxRoot, [&](const PGOCtxProfContext &Ctx) {
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] +=
692 Subctx.second.getEntrycount() * TotalRootEntryCount;
693 });
694 }
695 return Ret;
696}
697
699 CallBase &IC, Result &Profile,
700 SetVector<std::pair<CallBase *, Function *>> &Candidates) {
701 const auto *Instr = CtxProfAnalysis::getCallsiteInstrumentation(IC);
702 if (!Instr)
703 return;
704 Module &M = *IC.getParent()->getModule();
705 const uint32_t CallID = Instr->getIndex()->getZExtValue();
706 Profile.visit(
707 [&](const PGOCtxProfContext &Ctx) {
708 const auto &Targets = Ctx.callsites().find(CallID);
709 if (Targets == Ctx.callsites().end())
710 return;
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});
716 },
717 IC.getCaller());
718}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
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)
#define _
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
Load MIR Sample Profile
static constexpr StringLiteral Filename
#define P(N)
Reader for contextual iFDO profile, which comes in bitstream format.
ModuleAnalysisManager MAM
This file contains some templates that are useful if you are working with the STL at all.
Class for arbitrary precision integers.
Definition APInt.h:78
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
LLVM Basic Block Representation.
Definition BasicBlock.h:62
LLVM_ABI const BasicBlock * getUniqueSuccessor() const
Return the successor of this block if it has a unique successor.
const Instruction & front() const
Definition BasicBlock.h:463
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Definition BasicBlock.h:237
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.
Definition DenseSet.h:281
Represents either an error or a value T.
Definition ErrorOr.h:56
reference get()
Definition ErrorOr.h:149
std::error_code getError() const
Definition ErrorOr.h:152
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.
Definition Module.h:68
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.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
uint64_t getBBCount(const BasicBlock &BB)
ProfileAnnotatorImpl(const Function &F, ArrayRef< uint64_t > Counters)
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.
Definition SetVector.h:57
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void resize(size_type N)
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.
Definition StringRef.h:56
Target - Wrapper for Target specific information.
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition ilist_node.h:34
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
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.
Definition Path.cpp:594
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.
Definition Casting.h:643
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...
Definition STLExtras.h:649
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...
Definition Casting.h:547
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
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...
Definition STLExtras.h:2035
DenseMap< GlobalValue::GUID, DenseMap< uint32_t, FlatIndirectTargets > > CtxProfFlatIndirectCallProfile
LLVM_ABI bool isPresplitCoroSuspendExitEdge(const BasicBlock &Src, const BasicBlock &Dest)
Definition CFG.cpp:424
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)
@ TotalRootEntryCount
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition Analysis.h:29