LLVM 22.0.0git
ProfileVerify.cpp
Go to the documentation of this file.
1//===- ProfileVerify.cpp - Verify profile info for testing ----------------===//
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
11#include "llvm/ADT/STLExtras.h"
13#include "llvm/IR/Analysis.h"
14#include "llvm/IR/Dominators.h"
15#include "llvm/IR/Function.h"
17#include "llvm/IR/LLVMContext.h"
18#include "llvm/IR/MDBuilder.h"
22
23using namespace llvm;
25 DefaultFunctionEntryCount("profcheck-default-function-entry-count",
26 cl::init(1000));
27static cl::opt<bool>
28 AnnotateSelect("profcheck-annotate-select", cl::init(true),
29 cl::desc("Also inject (if missing) and verify MD_prof for "
30 "`select` instructions"));
32 "profcheck-default-select-true-weight", cl::init(2U),
33 cl::desc("When annotating `select` instructions, this value will be used "
34 "for the first ('true') case."));
36 "profcheck-default-select-false-weight", cl::init(3U),
37 cl::desc("When annotating `select` instructions, this value will be used "
38 "for the second ('false') case."));
39namespace {
40class ProfileInjector {
41 Function &F;
43
44public:
45 static const Instruction *
46 getTerminatorBenefitingFromMDProf(const BasicBlock &BB) {
47 if (succ_size(&BB) < 2)
48 return nullptr;
49 auto *Term = BB.getTerminator();
50 return (isa<BranchInst>(Term) || isa<SwitchInst>(Term) ||
51 isa<IndirectBrInst>(Term) || isa<CallBrInst>(Term))
52 ? Term
53 : nullptr;
54 }
55
56 static Instruction *getTerminatorBenefitingFromMDProf(BasicBlock &BB) {
57 return const_cast<Instruction *>(
58 getTerminatorBenefitingFromMDProf(const_cast<const BasicBlock &>(BB)));
59 }
60
61 ProfileInjector(Function &F, FunctionAnalysisManager &FAM) : F(F), FAM(FAM) {}
62 bool inject();
63};
64} // namespace
65
66// FIXME: currently this injects only for terminators. Select isn't yet
67// supported.
68bool ProfileInjector::inject() {
69 // Get whatever branch probability info can be derived from the given IR -
70 // whether it has or not metadata. The main intention for this pass is to
71 // ensure that other passes don't drop or "forget" to update MD_prof. We do
72 // this as a mode in which lit tests would run. We want to avoid changing the
73 // behavior of those tests. A pass may use BPI (or BFI, which is computed from
74 // BPI). If no metadata is present, BPI is guesstimated by
75 // BranchProbabilityAnalysis. The injector (this pass) only persists whatever
76 // information the analysis provides, in other words, the pass being tested
77 // will get the same BPI it does if the injector wasn't running.
79
80 // Inject a function count if there's none. It's reasonable for a pass to
81 // want to clear the MD_prof of a function with zero entry count. If the
82 // original profile (iFDO or AFDO) is empty for a function, it's simpler to
83 // require assigning it the 0-entry count explicitly than to mark every branch
84 // as cold (we do want some explicit information in the spirit of what this
85 // verifier wants to achieve - make dropping / corrupting MD_prof
86 // unit-testable)
87 if (!F.getEntryCount(/*AllowSynthetic=*/true))
88 F.setEntryCount(DefaultFunctionEntryCount);
89 // If there is an entry count that's 0, then don't bother injecting. We won't
90 // verify these either.
91 if (F.getEntryCount(/*AllowSynthetic=*/true)->getCount() == 0)
92 return false;
93 bool Changed = false;
94 for (auto &BB : F) {
95 if (AnnotateSelect) {
96 for (auto &I : BB) {
97 if (isa<SelectInst>(I) && !I.getMetadata(LLVMContext::MD_prof))
99 /*IsExpected=*/false);
100 }
101 }
102 auto *Term = getTerminatorBenefitingFromMDProf(BB);
103 if (!Term || Term->getMetadata(LLVMContext::MD_prof))
104 continue;
106 Probs.reserve(Term->getNumSuccessors());
107 for (auto I = 0U, E = Term->getNumSuccessors(); I < E; ++I)
108 Probs.emplace_back(BPI.getEdgeProbability(&BB, Term->getSuccessor(I)));
109
110 assert(llvm::find_if(Probs,
111 [](const BranchProbability &P) {
112 return P.isUnknown();
113 }) == Probs.end() &&
114 "All branch probabilities should be valid");
115 const auto *FirstZeroDenominator =
116 find_if(Probs, [](const BranchProbability &P) {
117 return P.getDenominator() == 0;
118 });
119 (void)FirstZeroDenominator;
120 assert(FirstZeroDenominator == Probs.end());
121 const auto *FirstNonZeroNumerator =
122 find_if(Probs, [](const BranchProbability &P) { return !P.isZero(); });
123 assert(FirstNonZeroNumerator != Probs.end());
124 DynamicAPInt LCM(Probs[0].getDenominator());
125 DynamicAPInt GCD(FirstNonZeroNumerator->getNumerator());
126 for (const auto &Prob : drop_begin(Probs)) {
127 if (!Prob.getNumerator())
128 continue;
129 LCM = llvm::lcm(LCM, DynamicAPInt(Prob.getDenominator()));
130 GCD = llvm::gcd(GCD, DynamicAPInt(Prob.getNumerator()));
131 }
132 SmallVector<uint32_t> Weights;
133 Weights.reserve(Term->getNumSuccessors());
134 for (const auto &Prob : Probs) {
136 (Prob.getNumerator() * LCM / GCD) / Prob.getDenominator();
137 Weights.emplace_back(static_cast<uint32_t>((int64_t)W));
138 }
139 setBranchWeights(*Term, Weights, /*IsExpected=*/false);
140 Changed = true;
141 }
142 return Changed;
143}
144
147 ProfileInjector PI(F, FAM);
148 if (!PI.inject())
149 return PreservedAnalyses::all();
150
152}
153
156 const auto EntryCount = F.getEntryCount(/*AllowSynthetic=*/true);
157 if (!EntryCount) {
158 F.getContext().emitError("Profile verification failed: function entry "
159 "count missing (set to 0 if cold)");
160 return PreservedAnalyses::all();
161 }
162 if (EntryCount->getCount() == 0)
163 return PreservedAnalyses::all();
164 for (const auto &BB : F) {
165 if (AnnotateSelect) {
166 for (const auto &I : BB)
167 if (isa<SelectInst>(I) && !I.getMetadata(LLVMContext::MD_prof))
168 F.getContext().emitError(
169 "Profile verification failed: select annotation missing");
170 }
171 if (const auto *Term =
172 ProfileInjector::getTerminatorBenefitingFromMDProf(BB))
173 if (!Term->getMetadata(LLVMContext::MD_prof))
174 F.getContext().emitError(
175 "Profile verification failed: branch annotation missing");
176 }
177 return PreservedAnalyses::all();
178}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
#define P(N)
FunctionAnalysisManager FAM
This file contains the declarations for profiling metadata utility functions.
static cl::opt< uint32_t > SelectFalseWeight("profcheck-default-select-false-weight", cl::init(3U), cl::desc("When annotating `select` instructions, this value will be used " "for the second ('false') case."))
static cl::opt< int64_t > DefaultFunctionEntryCount("profcheck-default-function-entry-count", cl::init(1000))
static cl::opt< bool > AnnotateSelect("profcheck-annotate-select", cl::init(true), cl::desc("Also inject (if missing) and verify MD_prof for " "`select` instructions"))
static cl::opt< uint32_t > SelectTrueWeight("profcheck-default-select-true-weight", cl::init(2U), cl::desc("When annotating `select` instructions, this value will be used " "for the first ('true') case."))
This file contains some templates that are useful if you are working with the STL at all.
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:255
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:412
LLVM Basic Block Representation.
Definition: BasicBlock.h:62
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Definition: BasicBlock.h:233
Analysis pass which computes BranchProbabilityInfo.
This class provides support for dynamic arbitrary-precision arithmetic.
Definition: DynamicAPInt.h:48
A set of analyses that are preserved following a run of a transformation pass.
Definition: Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition: Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: Analysis.h:118
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:938
void reserve(size_type N)
Definition: SmallVector.h:664
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
Pass manager infrastructure for declaring and invalidating analyses.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:444
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:338
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt gcd(const DynamicAPInt &A, const DynamicAPInt &B)
Definition: DynamicAPInt.h:403
LLVM_ABI void setBranchWeights(Instruction &I, ArrayRef< uint32_t > Weights, bool IsExpected)
Create a new branch_weights metadata node and add or overwrite a prof metadata reference to instructi...
auto succ_size(const MachineBasicBlock *BB)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt lcm(const DynamicAPInt &A, const DynamicAPInt &B)
Returns the least common multiple of A and B.
Definition: DynamicAPInt.h:413
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1777