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"));
31static cl::opt<bool>
32 WeightsForTest("profcheck-weights-for-test", cl::init(false),
33 cl::desc("Generate weights with small values for tests."));
34
36 "profcheck-default-select-true-weight", cl::init(2U),
37 cl::desc("When annotating `select` instructions, this value will be used "
38 "for the first ('true') case."));
40 "profcheck-default-select-false-weight", cl::init(3U),
41 cl::desc("When annotating `select` instructions, this value will be used "
42 "for the second ('false') case."));
43namespace {
44class ProfileInjector {
45 Function &F;
47
48public:
49 static const Instruction *
50 getTerminatorBenefitingFromMDProf(const BasicBlock &BB) {
51 if (succ_size(&BB) < 2)
52 return nullptr;
53 auto *Term = BB.getTerminator();
54 return (isa<BranchInst>(Term) || isa<SwitchInst>(Term) ||
56 ? Term
57 : nullptr;
58 }
59
60 static Instruction *getTerminatorBenefitingFromMDProf(BasicBlock &BB) {
61 return const_cast<Instruction *>(
62 getTerminatorBenefitingFromMDProf(const_cast<const BasicBlock &>(BB)));
63 }
64
65 ProfileInjector(Function &F, FunctionAnalysisManager &FAM) : F(F), FAM(FAM) {}
66 bool inject();
67};
68
69bool isAsmOnly(const Function &F) {
70 if (!F.hasFnAttribute(Attribute::AttrKind::Naked))
71 return false;
72 for (const auto &BB : F)
73 for (const auto &I : drop_end(BB.instructionsWithoutDebug())) {
74 const auto *CB = dyn_cast<CallBase>(&I);
75 if (!CB || !CB->isInlineAsm())
76 return false;
77 }
78 return true;
79}
80} // namespace
81
82// FIXME: currently this injects only for terminators. Select isn't yet
83// supported.
84bool ProfileInjector::inject() {
85 // skip purely asm functions
86 if (isAsmOnly(F))
87 return false;
88 // Get whatever branch probability info can be derived from the given IR -
89 // whether it has or not metadata. The main intention for this pass is to
90 // ensure that other passes don't drop or "forget" to update MD_prof. We do
91 // this as a mode in which lit tests would run. We want to avoid changing the
92 // behavior of those tests. A pass may use BPI (or BFI, which is computed from
93 // BPI). If no metadata is present, BPI is guesstimated by
94 // BranchProbabilityAnalysis. The injector (this pass) only persists whatever
95 // information the analysis provides, in other words, the pass being tested
96 // will get the same BPI it does if the injector wasn't running.
97 auto &BPI = FAM.getResult<BranchProbabilityAnalysis>(F);
98
99 // Inject a function count if there's none. It's reasonable for a pass to
100 // want to clear the MD_prof of a function with zero entry count. If the
101 // original profile (iFDO or AFDO) is empty for a function, it's simpler to
102 // require assigning it the 0-entry count explicitly than to mark every branch
103 // as cold (we do want some explicit information in the spirit of what this
104 // verifier wants to achieve - make dropping / corrupting MD_prof
105 // unit-testable)
106 if (!F.getEntryCount(/*AllowSynthetic=*/true))
107 F.setEntryCount(DefaultFunctionEntryCount);
108 // If there is an entry count that's 0, then don't bother injecting. We won't
109 // verify these either.
110 if (F.getEntryCount(/*AllowSynthetic=*/true)->getCount() == 0)
111 return false;
112 bool Changed = false;
113 // Cycle through the weights list. If we didn't, tests with more than (say)
114 // one conditional branch would have the same !prof metadata on all of them,
115 // and numerically that may make for a poor unit test.
116 uint32_t WeightsForTestOffset = 0;
117 for (auto &BB : F) {
118 if (AnnotateSelect) {
119 for (auto &I : BB) {
120 if (auto *SI = dyn_cast<SelectInst>(&I)) {
121 if (SI->getCondition()->getType()->isVectorTy())
122 continue;
123 if (I.getMetadata(LLVMContext::MD_prof))
124 continue;
126 /*IsExpected=*/false);
127 }
128 }
129 }
130 auto *Term = getTerminatorBenefitingFromMDProf(BB);
131 if (!Term || Term->getMetadata(LLVMContext::MD_prof))
132 continue;
133 SmallVector<BranchProbability> Probs;
134
135 SmallVector<uint32_t> Weights;
136 Weights.reserve(Term->getNumSuccessors());
137 if (WeightsForTest) {
138 static const std::array Primes{3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
139 37, 41, 43, 47, 53, 59, 61, 67, 71};
140 for (uint32_t I = 0, E = Term->getNumSuccessors(); I < E; ++I)
141 Weights.emplace_back(
142 Primes[(WeightsForTestOffset + I) % Primes.size()]);
143 ++WeightsForTestOffset;
144 } else {
145 Probs.reserve(Term->getNumSuccessors());
146 for (auto I = 0U, E = Term->getNumSuccessors(); I < E; ++I)
147 Probs.emplace_back(BPI.getEdgeProbability(&BB, Term->getSuccessor(I)));
148
149 assert(llvm::find_if(Probs,
150 [](const BranchProbability &P) {
151 return P.isUnknown();
152 }) == Probs.end() &&
153 "All branch probabilities should be valid");
154 const auto *FirstZeroDenominator =
155 find_if(Probs, [](const BranchProbability &P) {
156 return P.getDenominator() == 0;
157 });
158 (void)FirstZeroDenominator;
159 assert(FirstZeroDenominator == Probs.end());
160 const auto *FirstNonZeroNumerator = find_if(
161 Probs, [](const BranchProbability &P) { return !P.isZero(); });
162 assert(FirstNonZeroNumerator != Probs.end());
163 DynamicAPInt LCM(Probs[0].getDenominator());
164 DynamicAPInt GCD(FirstNonZeroNumerator->getNumerator());
165 for (const auto &Prob : drop_begin(Probs)) {
166 if (!Prob.getNumerator())
167 continue;
168 LCM = llvm::lcm(LCM, DynamicAPInt(Prob.getDenominator()));
169 GCD = llvm::gcd(GCD, DynamicAPInt(Prob.getNumerator()));
170 }
171 for (const auto &Prob : Probs) {
172 DynamicAPInt W =
173 (Prob.getNumerator() * LCM / GCD) / Prob.getDenominator();
174 Weights.emplace_back(static_cast<uint32_t>((int64_t)W));
175 }
176 }
177 setBranchWeights(*Term, Weights, /*IsExpected=*/false);
178 Changed = true;
179 }
180 return Changed;
181}
182
185 ProfileInjector PI(F, FAM);
186 if (!PI.inject())
187 return PreservedAnalyses::all();
188
190}
191
194 // skip purely asm functions
195 if (isAsmOnly(F))
196 return PreservedAnalyses::all();
197
198 const auto EntryCount = F.getEntryCount(/*AllowSynthetic=*/true);
199 if (!EntryCount) {
200 auto *MD = F.getMetadata(LLVMContext::MD_prof);
201 if (!MD || !isExplicitlyUnknownProfileMetadata(*MD)) {
202 F.getContext().emitError("Profile verification failed: function entry "
203 "count missing (set to 0 if cold)");
204 return PreservedAnalyses::all();
205 }
206 } else if (EntryCount->getCount() == 0) {
207 return PreservedAnalyses::all();
208 }
209 for (const auto &BB : F) {
210 if (AnnotateSelect) {
211 for (const auto &I : BB)
212 if (auto *SI = dyn_cast<SelectInst>(&I)) {
213 if (SI->getCondition()->getType()->isVectorTy())
214 continue;
215 if (I.getMetadata(LLVMContext::MD_prof))
216 continue;
217 F.getContext().emitError(
218 "Profile verification failed: select annotation missing");
219 }
220 }
221 if (const auto *Term =
222 ProfileInjector::getTerminatorBenefitingFromMDProf(BB))
223 if (!Term->getMetadata(LLVMContext::MD_prof))
224 F.getContext().emitError(
225 "Profile verification failed: branch annotation missing");
226 }
227 return PreservedAnalyses::all();
228}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define P(N)
FunctionAnalysisManager FAM
This file contains the declarations for profiling metadata utility functions.
static cl::opt< bool > WeightsForTest("profcheck-weights-for-test", cl::init(false), cl::desc("Generate weights with small values for tests."))
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.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
LLVM_ABI iterator_range< filter_iterator< BasicBlock::const_iterator, std::function< bool(const Instruction &)> > > instructionsWithoutDebug(bool SkipPseudoOp=true) const
Return a const iterator range over the instructions in the block, skipping any debug instructions.
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
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)
void reserve(size_type N)
Changed
Pass manager infrastructure for declaring and invalidating analyses.
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:81
initializer< Ty > init(const Ty &Val)
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt gcd(const DynamicAPInt &A, const DynamicAPInt &B)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI bool isExplicitlyUnknownProfileMetadata(const MDNode &MD)
LLVM_ABI void setBranchWeights(Instruction &I, ArrayRef< uint32_t > Weights, bool IsExpected, bool ElideAllZero=false)
Create a new branch_weights metadata node and add or overwrite a prof metadata reference to instructi...
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
auto drop_end(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the last N elements excluded.
Definition STLExtras.h:323
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt lcm(const DynamicAPInt &A, const DynamicAPInt &B)
Returns the least common multiple of A and B.
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:1758
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.