@@ -65,9 +65,60 @@ static cl::opt<uint32_t> MisExpectTolerance(
65
65
cl::desc(" Prevents emitting diagnostics when profile counts are "
66
66
" within N% of the threshold.." ));
67
67
68
+ // Command line option to enable/disable the Remparks when profile data suggests
69
+ // that the llvm.expect intrinsic may be profitable
70
+ static cl::opt<bool >
71
+ PGOMissingAnnotations (" pgo-missing-annotations" , cl::init(false ),
72
+ cl::Hidden,
73
+ cl::desc (" Use this option to turn on/off suggestions "
74
+ " of missing llvm.expect intrinsics." ));
68
75
} // namespace llvm
69
76
70
77
namespace {
78
+ struct ProfDataSummary {
79
+ uint64_t Likely;
80
+ uint64_t Unlikely;
81
+ uint64_t RealTotal;
82
+ uint64_t NumUnlikely;
83
+ };
84
+
85
+ enum class DiagKind {
86
+ MisExpect, // Reports when llvm.expect usage is contradicted by PGO data
87
+ MissingExpect, // Reports when llvm.expect would be profitable
88
+ Unsupported, // An error
89
+ };
90
+
91
+ std::optional<uint64_t > getScaledThreshold (const ProfDataSummary &PDS) {
92
+
93
+ uint64_t TotalBranchWeight = PDS.Likely + (PDS.Unlikely * PDS.NumUnlikely );
94
+
95
+ LLVM_DEBUG (dbgs () << " Total Branch Weight = " << TotalBranchWeight << " \n "
96
+ << " Likely Branch Weight = " << PDS.Likely << " \n " );
97
+
98
+ // FIXME: When we've addressed sample profiling, restore the assertion
99
+ //
100
+ // We cannot calculate branch probability if either of these invariants aren't
101
+ // met. However, MisExpect diagnostics should not prevent code from compiling,
102
+ // so we simply forgo emitting diagnostics here, and return early.
103
+ // assert((TotalBranchWeight >= LikelyBranchWeight) && (TotalBranchWeight > 0)
104
+ // && "TotalBranchWeight is less than the Likely branch weight");
105
+ if ((TotalBranchWeight == 0 ) || (TotalBranchWeight <= PDS.Likely ))
106
+ return std::nullopt;
107
+
108
+ // To determine our threshold value we need to obtain the branch probability
109
+ // for the weights added by llvm.expect and use that proportion to calculate
110
+ // our threshold based on the collected profile data.
111
+ BranchProbability LikelyProbablilty =
112
+ BranchProbability::getBranchProbability (PDS.Likely , TotalBranchWeight);
113
+
114
+ return LikelyProbablilty.scale (PDS.RealTotal );
115
+ }
116
+
117
+ bool isAnnotationDiagEnabled (LLVMContext &Ctx) {
118
+ LLVM_DEBUG (dbgs () << " PGOMissingAnnotations = " << PGOMissingAnnotations
119
+ << " \n " );
120
+ return PGOMissingAnnotations || Ctx.getAnnotationDiagsRequested ();
121
+ }
71
122
72
123
bool isMisExpectDiagEnabled (LLVMContext &Ctx) {
73
124
return PGOWarnMisExpect || Ctx.getMisExpectWarningRequested ();
@@ -112,10 +163,69 @@ void emitMisexpectDiagnostic(Instruction *I, LLVMContext &Ctx,
112
163
Instruction *Cond = getInstCondition (I);
113
164
if (isMisExpectDiagEnabled (Ctx))
114
165
Ctx.diagnose (DiagnosticInfoMisExpect (Cond, Msg));
115
- OptimizationRemarkEmitter ORE (I->getParent ()-> getParent ());
166
+ OptimizationRemarkEmitter ORE (I->getFunction ());
116
167
ORE.emit (OptimizationRemark (DEBUG_TYPE, " misexpect" , Cond) << RemStr.str ());
117
168
}
118
169
170
+
171
+ void emitMissingAnnotationDiag (Instruction *I) {
172
+ const auto *RemStr =
173
+ " Extremely hot condition. Consider adding llvm.expect intrinsic" ;
174
+ Instruction *Cond = getInstCondition (I);
175
+ OptimizationRemarkEmitter ORE (I->getParent ()->getParent ());
176
+ ORE.emit (
177
+ OptimizationRemark (" missing-annotations" , " missing-annotations" , Cond)
178
+ << RemStr);
179
+ }
180
+
181
+ uint64_t totalWeight (const ArrayRef<uint32_t > Weights) {
182
+ return std::accumulate (Weights.begin (), Weights.end (), (uint64_t )0 ,
183
+ std::plus<uint64_t >());
184
+ }
185
+
186
+ void scaleByTollerance (const Instruction &I, uint64_t &ScaledThreshold) {
187
+ // clamp tolerance range to [0, 100)
188
+ uint32_t Tolerance = getMisExpectTolerance (I.getContext ());
189
+ Tolerance = std::clamp (Tolerance, 0u , 99u );
190
+
191
+ // Allow users to relax checking by N% i.e., if they use a 5% tolerance,
192
+ // then we check against 0.95*ScaledThreshold
193
+ if (Tolerance > 0 )
194
+ ScaledThreshold *= (1.0 - Tolerance / 100.0 );
195
+
196
+ LLVM_DEBUG (dbgs () << " Scaled Threshold = " << ScaledThreshold << " \n " );
197
+ }
198
+
199
+ void reportDiagnostics (Instruction &I, const ProfDataSummary &PDS,
200
+ uint32_t ProfiledWeight, DiagKind Kind) {
201
+ std::optional<uint64_t > ScaledOpt = getScaledThreshold (PDS);
202
+ if (!ScaledOpt)
203
+ return ;
204
+ uint64_t ScaledThreshold = ScaledOpt.value ();
205
+ scaleByTollerance (I, ScaledThreshold);
206
+
207
+ LLVM_DEBUG (dbgs () << " Total Branch Weight = " << PDS.RealTotal << " \n "
208
+ << " Scaled Threshold = " << ScaledThreshold << " \n "
209
+ << " Profiled Weight = " << ProfiledWeight << " \n "
210
+ << " Likely Branch Weight = " << PDS.Likely << " \n " );
211
+ // When the profile weight is outside the range, we emit the diagnostic
212
+ switch (Kind) {
213
+ case DiagKind::MisExpect:
214
+ if (ProfiledWeight < ScaledThreshold) {
215
+ emitMisexpectDiagnostic (&I, I.getContext (), ProfiledWeight,
216
+ PDS.RealTotal );
217
+ }
218
+ return ;
219
+ case DiagKind::MissingExpect:
220
+ if (ProfiledWeight > ScaledThreshold) {
221
+ emitMissingAnnotationDiag (&I);
222
+ }
223
+ return ;
224
+ default :
225
+ llvm_unreachable (" Unsupported diagnostic type used in PGO based analysis" );
226
+ };
227
+ }
228
+
119
229
} // namespace
120
230
121
231
namespace llvm {
@@ -143,39 +253,10 @@ void verifyMisExpect(Instruction &I, ArrayRef<uint32_t> RealWeights,
143
253
}
144
254
145
255
const uint64_t ProfiledWeight = RealWeights[MaxIndex];
146
- const uint64_t RealWeightsTotal =
147
- std::accumulate (RealWeights.begin (), RealWeights.end (), (uint64_t )0 ,
148
- std::plus<uint64_t >());
149
- const uint64_t NumUnlikelyTargets = RealWeights.size () - 1 ;
150
-
151
- uint64_t TotalBranchWeight =
152
- LikelyBranchWeight + (UnlikelyBranchWeight * NumUnlikelyTargets);
153
-
154
- // Failing this assert means that we have corrupted metadata.
155
- assert ((TotalBranchWeight >= LikelyBranchWeight) && (TotalBranchWeight > 0 ) &&
156
- " TotalBranchWeight is less than the Likely branch weight" );
157
-
158
- // To determine our threshold value we need to obtain the branch probability
159
- // for the weights added by llvm.expect and use that proportion to calculate
160
- // our threshold based on the collected profile data.
161
- auto LikelyProbablilty = BranchProbability::getBranchProbability (
162
- LikelyBranchWeight, TotalBranchWeight);
163
-
164
- uint64_t ScaledThreshold = LikelyProbablilty.scale (RealWeightsTotal);
165
-
166
- // clamp tolerance range to [0, 100)
167
- auto Tolerance = getMisExpectTolerance (I.getContext ());
168
- Tolerance = std::clamp (Tolerance, 0u , 99u );
169
-
170
- // Allow users to relax checking by N% i.e., if they use a 5% tolerance,
171
- // then we check against 0.95*ScaledThreshold
172
- if (Tolerance > 0 )
173
- ScaledThreshold *= (1.0 - Tolerance / 100.0 );
174
-
175
- // When the profile weight is below the threshold, we emit the diagnostic
176
- if (ProfiledWeight < ScaledThreshold)
177
- emitMisexpectDiagnostic (&I, I.getContext (), ProfiledWeight,
178
- RealWeightsTotal);
256
+ const ProfDataSummary PDS = {LikelyBranchWeight, UnlikelyBranchWeight,
257
+ totalWeight (RealWeights),
258
+ RealWeights.size () - 1 };
259
+ reportDiagnostics (I,PDS, ProfiledWeight, DiagKind::MisExpect);
179
260
}
180
261
181
262
void checkBackendInstrumentation (Instruction &I,
@@ -211,6 +292,47 @@ void checkExpectAnnotations(Instruction &I,
211
292
}
212
293
}
213
294
295
+ void verifyMissingAnnotations (Instruction &I, ArrayRef<uint32_t > RealWeights) {
296
+ // To determine if we emit a diagnostic, we need to compare the branch weights
297
+ // from the profile to those that would be added by the llvm.expect intrinsic.
298
+ // And compare it to the real profile to see if it would be profitable.
299
+ uint32_t ProfiledWeight =
300
+ *std::max_element (RealWeights.begin (), RealWeights.end ());
301
+
302
+ const uint64_t LikelyBranchWeight = 2000 ;
303
+ const uint64_t UnlikelyBranchWeight = 1 ;
304
+ const ProfDataSummary PDS = {LikelyBranchWeight, UnlikelyBranchWeight,
305
+ totalWeight (RealWeights),
306
+ RealWeights.size () - 1 };
307
+ reportDiagnostics (I, PDS, ProfiledWeight, DiagKind::MissingExpect);
308
+ }
309
+
310
+ void checkMissingAnnotations (Instruction &I,
311
+ const ArrayRef<uint32_t > ExistingWeights,
312
+ bool IsFrontendInstr) {
313
+
314
+ // TODO: Ironically, this is probably a branch that should be marked UNLIKELY
315
+ // exit early if these diagnostics weren't requested
316
+ if (!isAnnotationDiagEnabled (I.getContext ()))
317
+ return ;
318
+
319
+ if (IsFrontendInstr) {
320
+ // TODO: Fronend checking will have to be thought through, since we need
321
+ // to do the check on branches that don't have expect intrinsics
322
+
323
+ // auto RealWeightsOpt = extractWeights(&I, I.getContext());
324
+ // if (!RealWeightsOpt)
325
+ // return;
326
+ // auto RealWeights = RealWeightsOpt.getValue();
327
+ // verifyMissingAnnotations(I, RealWeights, ExistingWeights);
328
+ } else {
329
+ SmallVector<uint32_t > ExpectedWeights;
330
+ if (extractBranchWeights (I, ExpectedWeights))
331
+ return ;
332
+ verifyMissingAnnotations (I, ExistingWeights);
333
+ }
334
+ }
335
+
214
336
} // namespace misexpect
215
337
} // namespace llvm
216
338
#undef DEBUG_TYPE
0 commit comments