llvm.org GIT mirror llvm / 4a50a94
clang-misexpect: Profile Guided Validation of Performance Annotations in LLVM This patch contains the basic functionality for reporting potentially incorrect usage of __builtin_expect() by comparing the developer's annotation against a collected PGO profile. A more detailed proposal and discussion appears on the CFE-dev mailing list (http://lists.llvm.org/pipermail/cfe-dev/2019-July/062971.html) and a prototype of the initial frontend changes appear here in D65300 We revised the work in D65300 by moving the misexpect check into the LLVM backend, and adding support for IR and sampling based profiles, in addition to frontend instrumentation. We add new misexpect metadata tags to those instructions directly influenced by the llvm.expect intrinsic (branch, switch, and select) when lowering the intrinsics. The misexpect metadata contains information about the expected target of the intrinsic so that we can check against the correct PGO counter when emitting diagnostics, and the compiler's values for the LikelyBranchWeight and UnlikelyBranchWeight. We use these branch weight values to determine when to emit the diagnostic to the user. A future patch should address the comment at the top of LowerExpectIntrisic.cpp to hoist the LikelyBranchWeight and UnlikelyBranchWeight values into a shared space that can be accessed outside of the LowerExpectIntrinsic pass. Once that is done, the misexpect metadata can be updated to be smaller. In the long term, it is possible to reconstruct portions of the misexpect metadata from the existing profile data. However, we have avoided this to keep the code simple, and because some kind of metadata tag will be required to identify which branch/switch/select instructions are influenced by the use of llvm.expect Patch By: paulkirth Differential Revision: https://reviews.llvm.org/D66324 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@371584 91177308-0d34-0410-b5e6-96231b3b80d8 Petr Hosek a month ago
23 changed file(s) with 1346 addition(s) and 26 deletion(s). Raw diff Collapse all Expand all
7474 DK_MIRParser,
7575 DK_PGOProfile,
7676 DK_Unsupported,
77 DK_FirstPluginKind
77 DK_FirstPluginKind,
78 DK_MisExpect
7879 };
7980
8081 /// Get the next available kind ID for a plugin diagnostic.
10011002 void print(DiagnosticPrinter &DP) const override;
10021003 };
10031004
1005 /// Diagnostic information for MisExpect analysis.
1006 class DiagnosticInfoMisExpect : public DiagnosticInfoWithLocationBase {
1007 public:
1008 DiagnosticInfoMisExpect(const Instruction *Inst, Twine &Msg);
1009
1010 /// \see DiagnosticInfo::print.
1011 void print(DiagnosticPrinter &DP) const override;
1012
1013 static bool classof(const DiagnosticInfo *DI) {
1014 return DI->getKind() == DK_MisExpect;
1015 }
1016
1017 const Twine &getMsg() const { return Msg; }
1018
1019 private:
1020 /// Message to report.
1021 const Twine &Msg;
1022 };
1023
10041024 } // end namespace llvm
10051025
10061026 #endif // LLVM_IR_DIAGNOSTICINFO_H
3838 LLVM_FIXED_MD_KIND(MD_access_group, "llvm.access.group", 25)
3939 LLVM_FIXED_MD_KIND(MD_callback, "callback", 26)
4040 LLVM_FIXED_MD_KIND(MD_preserve_access_index, "llvm.preserve.access.index", 27)
41 LLVM_FIXED_MD_KIND(MD_misexpect, "misexpect", 28)
1515
1616 #include "llvm/ADT/DenseSet.h"
1717 #include "llvm/ADT/StringRef.h"
18 #include "llvm/IR/Constants.h"
1819 #include "llvm/IR/GlobalValue.h"
1920 #include "llvm/Support/DataTypes.h"
2021 #include
7475 /// Return metadata containing the section prefix for a function.
7576 MDNode *createFunctionSectionPrefix(StringRef Prefix);
7677
78 /// return metadata containing expected value
79 MDNode *createMisExpect(uint64_t Index, uint64_t LikelyWeight,
80 uint64_t UnlikelyWeight);
81
7782 //===------------------------------------------------------------------===//
7883 // Range metadata.
7984 //===------------------------------------------------------------------===//
0 //===--- MisExpect.h - Check the use of llvm.expect with PGO data ---------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This contains code to emit warnings for potentially incorrect usage of the
9 // llvm.expect intrinsic. This utility extracts the threshold values from
10 // metadata associated with the instrumented Branch or Switch instruction. The
11 // threshold values are then used to determine if a warning should be emmited.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/IR/Function.h"
17 #include "llvm/IR/Instructions.h"
18 #include "llvm/IR/LLVMContext.h"
19
20 namespace llvm {
21 namespace misexpect {
22
23 /// verifyMisExpect - compares PGO counters to the thresholds used for
24 /// llvm.expect and warns if the PGO counters are outside of the expected
25 /// range.
26 /// \param I The Instruction being checked
27 /// \param Weights A vector of profile weights for each target block
28 /// \param Ctx The current LLVM context
29 void verifyMisExpect(llvm::Instruction *I,
30 const llvm::SmallVector &Weights,
31 llvm::LLVMContext &Ctx);
32
33 /// checkClangInstrumentation - verify if llvm.expect matches PGO profile
34 /// This function checks the frontend instrumentation in the backend when
35 /// lowering llvm.expect intrinsics. It checks for existing metadata, and
36 /// then validates the use of llvm.expect against the assigned branch weights.
37 //
38 /// \param I the Instruction being checked
39 void checkFrontendInstrumentation(Instruction &I);
40
41 } // namespace misexpect
42 } // namespace llvm
369369 return OS.str();
370370 }
371371
372 DiagnosticInfoMisExpect::DiagnosticInfoMisExpect(const Instruction *Inst,
373 Twine &Msg)
374 : DiagnosticInfoWithLocationBase(DK_MisExpect, DS_Warning,
375 *Inst->getParent()->getParent(),
376 Inst->getDebugLoc()),
377 Msg(Msg) {}
378
379 void DiagnosticInfoMisExpect::print(DiagnosticPrinter &DP) const {
380 DP << getLocationStr() << ": " << getMsg();
381 }
382
372383 void OptimizationRemarkAnalysisFPCommute::anchor() {}
373384 void OptimizationRemarkAnalysisAliasing::anchor() {}
308308 };
309309 return MDNode::get(Context, Vals);
310310 }
311
312 MDNode *MDBuilder::createMisExpect(uint64_t Index, uint64_t LikleyWeight,
313 uint64_t UnlikleyWeight) {
314 auto *IntType = Type::getInt64Ty(Context);
315 Metadata *Vals[] = {
316 createString("misexpect"),
317 createConstant(ConstantInt::get(IntType, Index)),
318 createConstant(ConstantInt::get(IntType, LikleyWeight)),
319 createConstant(ConstantInt::get(IntType, UnlikleyWeight)),
320 };
321 return MDNode::get(Context, Vals);
322 }
7171 #include "llvm/Transforms/Instrumentation.h"
7272 #include "llvm/Transforms/Utils/CallPromotionUtils.h"
7373 #include "llvm/Transforms/Utils/Cloning.h"
74 #include "llvm/Transforms/Utils/MisExpect.h"
7475 #include
7576 #include
7677 #include
14451446 }
14461447 }
14471448
1449 misexpect::verifyMisExpect(TI, Weights, TI->getContext());
1450
14481451 uint64_t TempWeight;
14491452 // Only set weights if there is at least one non-zero weight.
14501453 // In any other case, let the analyzer set weights.
107107 #include "llvm/Transforms/Instrumentation.h"
108108 #include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
109109 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
110 #include "llvm/Transforms/Utils/MisExpect.h"
110111 #include
111112 #include
112113 #include
17751776 : Weights) {
17761777 dbgs() << W << " ";
17771778 } dbgs() << "\n";);
1779
1780 misexpect::verifyMisExpect(TI, Weights, TI->getContext());
1781
17781782 TI->setMetadata(LLVMContext::MD_prof, MDB.createBranchWeights(Weights));
17791783 if (EmitBranchProbability) {
17801784 std::string BrCondStr = getBranchCondString(TI);
2525 #include "llvm/Support/CommandLine.h"
2626 #include "llvm/Support/Debug.h"
2727 #include "llvm/Transforms/Scalar.h"
28 #include "llvm/Transforms/Utils/MisExpect.h"
2829
2930 using namespace llvm;
3031
7071 unsigned n = SI.getNumCases(); // +1 for default case.
7172 SmallVector Weights(n + 1, UnlikelyBranchWeight);
7273
73 if (Case == *SI.case_default())
74 Weights[0] = LikelyBranchWeight;
75 else
76 Weights[Case.getCaseIndex() + 1] = LikelyBranchWeight;
74 uint64_t Index = (Case == *SI.case_default()) ? 0 : Case.getCaseIndex() + 1;
75 Weights[Index] = LikelyBranchWeight;
76
77 SI.setMetadata(
78 LLVMContext::MD_misexpect,
79 MDBuilder(CI->getContext())
80 .createMisExpect(Index, LikelyBranchWeight, UnlikelyBranchWeight));
81
82 SI.setCondition(ArgValue);
83 misexpect::checkFrontendInstrumentation(SI);
7784
7885 SI.setMetadata(LLVMContext::MD_prof,
7986 MDBuilder(CI->getContext()).createBranchWeights(Weights));
8087
81 SI.setCondition(ArgValue);
8288 return true;
8389 }
8490
279285
280286 MDBuilder MDB(CI->getContext());
281287 MDNode *Node;
288 MDNode *ExpNode;
282289
283290 if ((ExpectedValue->getZExtValue() == ValueComparedTo) ==
284 (Predicate == CmpInst::ICMP_EQ))
291 (Predicate == CmpInst::ICMP_EQ)) {
285292 Node = MDB.createBranchWeights(LikelyBranchWeight, UnlikelyBranchWeight);
286 else
293 ExpNode = MDB.createMisExpect(0, LikelyBranchWeight, UnlikelyBranchWeight);
294 } else {
287295 Node = MDB.createBranchWeights(UnlikelyBranchWeight, LikelyBranchWeight);
288
289 BSI.setMetadata(LLVMContext::MD_prof, Node);
296 ExpNode = MDB.createMisExpect(1, LikelyBranchWeight, UnlikelyBranchWeight);
297 }
298
299 BSI.setMetadata(LLVMContext::MD_misexpect, ExpNode);
290300
291301 if (CmpI)
292302 CmpI->setOperand(0, ArgValue);
293303 else
294304 BSI.setCondition(ArgValue);
305
306 misexpect::checkFrontendInstrumentation(BSI);
307
308 BSI.setMetadata(LLVMContext::MD_prof, Node);
309
295310 return true;
296311 }
297312
3939 LowerSwitch.cpp
4040 Mem2Reg.cpp
4141 MetaRenamer.cpp
42 MisExpect.cpp
4243 ModuleUtils.cpp
4344 NameAnonGlobals.cpp
4445 PredicateInfo.cpp
0 //===--- MisExpect.cpp - Check the use of llvm.expect with PGO data -------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This contains code to emit warnings for potentially incorrect usage of the
9 // llvm.expect intrinsic. This utility extracts the threshold values from
10 // metadata associated with the instrumented Branch or Switch instruction. The
11 // threshold values are then used to determine if a warning should be emmited.
12 //
13 // MisExpect metadata is generated when llvm.expect intrinsics are lowered see
14 // LowerExpectIntrinsic.cpp
15 //
16 //===----------------------------------------------------------------------===//
17
18 #include "llvm/Transforms/Utils/MisExpect.h"
19 #include "llvm/ADT/Twine.h"
20 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
21 #include "llvm/IR/Constants.h"
22 #include "llvm/IR/DiagnosticInfo.h"
23 #include "llvm/IR/Instruction.h"
24 #include "llvm/IR/Instructions.h"
25 #include "llvm/IR/LLVMContext.h"
26 #include "llvm/Support/BranchProbability.h"
27 #include "llvm/Support/Debug.h"
28 #include "llvm/Support/FormatVariadic.h"
29 #include
30 #include
31 #include
32
33 #define DEBUG_TYPE "misexpect"
34
35 using namespace llvm;
36 using namespace misexpect;
37
38 namespace llvm {
39
40 // Command line option to enable/disable the warning when profile data suggests
41 // a mismatch with the use of the llvm.expect intrinsic
42 static cl::opt PGOWarnMisExpect(
43 "pgo-warn-misexpect", cl::init(false), cl::Hidden,
44 cl::desc("Use this option to turn on/off "
45 "warnings about incorrect usage of llvm.expect intrinsics."));
46
47 } // namespace llvm
48
49 namespace {
50
51 Instruction *getOprndOrInst(Instruction *I) {
52 assert(I != nullptr && "MisExpect target Instruction cannot be nullptr");
53 Instruction *Ret = nullptr;
54 if (auto *B = dyn_cast(I)) {
55 Ret = dyn_cast(B->getCondition());
56 }
57 // TODO: Find a way to resolve condition location for switches
58 // Using the condition of the switch seems to often resolve to an earlier
59 // point in the program, i.e. the calculation of the switch condition, rather
60 // than the switches location in the source code. Thus, we should use the
61 // instruction to get source code locations rather than the condition to
62 // improve diagnostic output, such as the caret. If the same problem exists
63 // for branch instructions, then we should remove this function and directly
64 // use the instruction
65 //
66 // else if (auto S = dyn_cast(I)) {
67 // Ret = I;
68 //}
69 return Ret ? Ret : I;
70 }
71
72 void emitMisexpectDiagnostic(Instruction *I, LLVMContext &Ctx,
73 uint64_t ProfCount, uint64_t TotalCount) {
74 double PercentageCorrect = (double)ProfCount / TotalCount;
75 auto PerString =
76 formatv("{0:P} ({1} / {2})", PercentageCorrect, ProfCount, TotalCount);
77 auto RemStr = formatv(
78 "Potential performance regression from use of the llvm.expect intrinsic: "
79 "Annotation was correct on {0} of profiled executions.",
80 PerString);
81 Twine Msg(PerString);
82 Instruction *Cond = getOprndOrInst(I);
83 if (PGOWarnMisExpect)
84 Ctx.diagnose(DiagnosticInfoMisExpect(Cond, Msg));
85 OptimizationRemarkEmitter ORE(I->getParent()->getParent());
86 ORE.emit(OptimizationRemark(DEBUG_TYPE, "misexpect", Cond) << RemStr.str());
87 }
88
89 } // namespace
90
91 namespace llvm {
92 namespace misexpect {
93
94 void verifyMisExpect(Instruction *I, const SmallVector &Weights,
95 LLVMContext &Ctx) {
96 if (auto *MisExpectData = I->getMetadata(LLVMContext::MD_misexpect)) {
97 auto *MisExpectDataName = dyn_cast(MisExpectData->getOperand(0));
98 if (MisExpectDataName &&
99 MisExpectDataName->getString().equals("misexpect")) {
100 LLVM_DEBUG(llvm::dbgs() << "------------------\n");
101 LLVM_DEBUG(llvm::dbgs()
102 << "Function: " << I->getFunction()->getName() << "\n");
103 LLVM_DEBUG(llvm::dbgs() << "Instruction: " << *I << ":\n");
104 LLVM_DEBUG(for (int Idx = 0, Size = Weights.size(); Idx < Size; ++Idx) {
105 llvm::dbgs() << "Weights[" << Idx << "] = " << Weights[Idx] << "\n";
106 });
107
108 // extract values from misexpect metadata
109 const auto *IndexCint =
110 mdconst::dyn_extract(MisExpectData->getOperand(1));
111 const auto *LikelyCInt =
112 mdconst::dyn_extract(MisExpectData->getOperand(2));
113 const auto *UnlikelyCInt =
114 mdconst::dyn_extract(MisExpectData->getOperand(3));
115
116 if (!IndexCint || !LikelyCInt || !UnlikelyCInt)
117 return;
118
119 const uint64_t Index = IndexCint->getZExtValue();
120 const uint64_t LikelyBranchWeight = LikelyCInt->getZExtValue();
121 const uint64_t UnlikelyBranchWeight = UnlikelyCInt->getZExtValue();
122 const uint64_t ProfileCount = Weights[Index];
123 const uint64_t CaseTotal = std::accumulate(
124 Weights.begin(), Weights.end(), (uint64_t)0, std::plus());
125 const uint64_t NumUnlikelyTargets = Weights.size() - 1;
126
127 const uint64_t TotalBranchWeight =
128 LikelyBranchWeight + (UnlikelyBranchWeight * NumUnlikelyTargets);
129
130 const llvm::BranchProbability LikelyThreshold(LikelyBranchWeight,
131 TotalBranchWeight);
132 uint64_t ScaledThreshold = LikelyThreshold.scale(CaseTotal);
133
134 LLVM_DEBUG(llvm::dbgs()
135 << "Unlikely Targets: " << NumUnlikelyTargets << ":\n");
136 LLVM_DEBUG(llvm::dbgs() << "Profile Count: " << ProfileCount << ":\n");
137 LLVM_DEBUG(llvm::dbgs()
138 << "Scaled Threshold: " << ScaledThreshold << ":\n");
139 LLVM_DEBUG(llvm::dbgs() << "------------------\n");
140 if (ProfileCount < ScaledThreshold)
141 emitMisexpectDiagnostic(I, Ctx, ProfileCount, CaseTotal);
142 }
143 }
144 }
145
146 void checkFrontendInstrumentation(Instruction &I) {
147 if (auto *MD = I.getMetadata(LLVMContext::MD_prof)) {
148 unsigned NOps = MD->getNumOperands();
149
150 // Only emit misexpect diagnostics if at least 2 branch weights are present.
151 // Less than 2 branch weights means that the profiling metadata is:
152 // 1) incorrect/corrupted
153 // 2) not branch weight metadata
154 // 3) completely deterministic
155 // In these cases we should not emit any diagnostic related to misexpect.
156 if (NOps < 3)
157 return;
158
159 // Operand 0 is a string tag "branch_weights"
160 if (MDString *Tag = cast(MD->getOperand(0))) {
161 if (Tag->getString().equals("branch_weights")) {
162 SmallVector RealWeights(NOps - 1);
163 for (unsigned i = 1; i < NOps; i++) {
164 ConstantInt *Value =
165 mdconst::dyn_extract(MD->getOperand(i));
166 RealWeights[i - 1] = Value->getZExtValue();
167 }
168 verifyMisExpect(&I, RealWeights, I.getContext());
169 }
170 }
171 }
172 }
173
174 } // namespace misexpect
175 } // namespace llvm
176 #undef DEBUG_TYPE
99 ; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc \
1010 ; RUN: -o /dev/null -stats \
1111 ; RUN: 2>&1 | FileCheck %s -check-prefix=LAZY
12 ; LAZY: 61 bitcode-reader - Number of Metadata records loaded
12 ; LAZY: 63 bitcode-reader - Number of Metadata records loaded
1313 ; LAZY: 2 bitcode-reader - Number of MDStrings loaded
1414
1515 ; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc \
1616 ; RUN: -o /dev/null -disable-ondemand-mds-loading -stats \
1717 ; RUN: 2>&1 | FileCheck %s -check-prefix=NOTLAZY
18 ; NOTLAZY: 70 bitcode-reader - Number of Metadata records loaded
18 ; NOTLAZY: 72 bitcode-reader - Number of Metadata records loaded
1919 ; NOTLAZY: 7 bitcode-reader - Number of MDStrings loaded
2020
2121
1212 %conv1 = sext i32 %conv to i64
1313 %expval = call i64 @llvm.expect.i64(i64 %conv1, i64 1)
1414 %tobool = icmp ne i64 %expval, 0
15 ; CHECK: !prof !0
15 ; CHECK: !prof !0, !misexpect !1
1616 ; CHECK-NOT: @llvm.expect
1717 br i1 %tobool, label %if.then, label %if.end
1818
4444 %conv = sext i32 %tmp to i64
4545 %expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
4646 %tobool = icmp ne i64 %expval, 0
47 ; CHECK: !prof !0
47 ; CHECK: !prof !0, !misexpect !1
4848 ; CHECK-NOT: @llvm.expect
4949 br i1 %tobool, label %if.then, label %if.end
5050
7575 %conv = sext i32 %lnot.ext to i64
7676 %expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
7777 %tobool1 = icmp ne i64 %expval, 0
78 ; CHECK: !prof !0
78 ; CHECK: !prof !0, !misexpect !1
7979 ; CHECK-NOT: @llvm.expect
8080 br i1 %tobool1, label %if.then, label %if.end
8181
107107 %conv = sext i32 %lnot.ext to i64
108108 %expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
109109 %tobool2 = icmp ne i64 %expval, 0
110 ; CHECK: !prof !0
110 ; CHECK: !prof !0, !misexpect !1
111111 ; CHECK-NOT: @llvm.expect
112112 br i1 %tobool2, label %if.then, label %if.end
113113
137137 %conv1 = sext i32 %conv to i64
138138 %expval = call i64 @llvm.expect.i64(i64 %conv1, i64 0)
139139 %tobool = icmp ne i64 %expval, 0
140 ; CHECK: !prof !1
140 ; CHECK: !prof !2, !misexpect !3
141141 ; CHECK-NOT: @llvm.expect
142142 br i1 %tobool, label %if.then, label %if.end
143143
163163 store i32 %x, i32* %x.addr, align 4
164164 %tmp = load i32, i32* %x.addr, align 4
165165 %conv = sext i32 %tmp to i64
166 %expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
167 ; CHECK: !prof !2
166 %expval = call i64 @llvm.expect.i64(i64 %conv, i64 2)
167 ; CHECK: !prof !4, !misexpect !5
168168 ; CHECK-NOT: @llvm.expect
169169 switch i64 %expval, label %sw.epilog [
170170 i64 1, label %sw.bb
193193 %tmp = load i32, i32* %x.addr, align 4
194194 %conv = sext i32 %tmp to i64
195195 %expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
196 ; CHECK: !prof !3
196 ; CHECK: !prof !6, !misexpect !1
197197 ; CHECK-NOT: @llvm.expect
198198 switch i64 %expval, label %sw.epilog [
199199 i64 2, label %sw.bb
225225 %conv = zext i1 %cmp to i32
226226 %expval = call i32 @llvm.expect.i32(i32 %conv, i32 1)
227227 %tobool = icmp ne i32 %expval, 0
228 ; CHECK: !prof !0
228 ; CHECK: !prof !0, !misexpect !1
229229 ; CHECK-NOT: @llvm.expect
230230 br i1 %tobool, label %if.then, label %if.end
231231
254254 %tmp = load i32, i32* %x.addr, align 4
255255 %cmp = icmp sgt i32 %tmp, 1
256256 %expval = call i1 @llvm.expect.i1(i1 %cmp, i1 1)
257 ; CHECK: !prof !0
257 ; CHECK: !prof !0, !misexpect !1
258258 ; CHECK-NOT: @llvm.expect
259259 br i1 %expval, label %if.then, label %if.end
260260
277277 %t7 = call i64 @llvm.expect.i64(i64 %t6, i64 0)
278278 %t8 = icmp ne i64 %t7, 0
279279 %t9 = select i1 %t8, i32 1, i32 2
280 ; CHECK: select{{.*}}, !prof !1
280 ; CHECK: select{{.*}}, !prof !2, !misexpect !3
281281 ret i32 %t9
282282 }
283283
285285 declare i1 @llvm.expect.i1(i1, i1) nounwind readnone
286286
287287 ; CHECK: !0 = !{!"branch_weights", i32 2000, i32 1}
288 ; CHECK: !1 = !{!"branch_weights", i32 1, i32 2000}
289 ; CHECK: !2 = !{!"branch_weights", i32 1, i32 2000, i32 1}
290 ; CHECK: !3 = !{!"branch_weights", i32 2000, i32 1, i32 1}
288 ; CHECK: !1 = !{!"misexpect", i64 0, i64 2000, i64 1}
289 ; CHECK: !2 = !{!"branch_weights", i32 1, i32 2000}
290 ; CHECK: !3 = !{!"misexpect", i64 1, i64 2000, i64 1}
291 ; CHECK: !4 = !{!"branch_weights", i32 1, i32 1, i32 2000}
292 ; CHECK: !5 = !{!"misexpect", i64 2, i64 2000, i64 1}
293 ; CHECK: !6 = !{!"branch_weights", i32 2000, i32 1, i32 1}
0 # IR level Instrumentation Flag
1 :ir
2 bar
3 # Func Hash:
4 29667547796
5 # Num Counters:
6 2
7 # Counter Values:
8 200000
9 0
10
11 baz
12 # Func Hash:
13 12884901887
14 # Num Counters:
15 1
16 # Counter Values:
17 399668
18
19 foo
20 # Func Hash:
21 29212902728
22 # Num Counters:
23 2
24 # Counter Values:
25 40803991
26 1600332
27
28 main
29 # Func Hash:
30 41605652536
31 # Num Counters:
32 3
33 # Counter Values:
34 2000000
35 2000
36 1
37
0 # IR level Instrumentation Flag
1 :ir
2 bar
3 # Func Hash:
4 29667547796
5 # Num Counters:
6 2
7 # Counter Values:
8 399668
9 1600332
10
11 baz
12 # Func Hash:
13 12884901887
14 # Num Counters:
15 1
16 # Counter Values:
17 399668
18
19 foo
20 # Func Hash:
21 29212902728
22 # Num Counters:
23 2
24 # Counter Values:
25 40803991
26 1600332
27
28 main
29 # Func Hash:
30 41605652536
31 # Num Counters:
32 3
33 # Counter Values:
34 2000000
35 2000
36 1
37
0 # IR level Instrumentation Flag
1 :ir
2 main
3 # Func Hash:
4 74054140268
5 # Num Counters:
6 7
7 # Counter Values:
8 0
9 0
10 20000
11 0
12 0
13 1
14 0
15
0 # IR level Instrumentation Flag
1 :ir
2 main
3 # Func Hash:
4 74054140268
5 # Num Counters:
6 7
7 # Counter Values:
8 3973
9 3970
10 0
11 11889
12 8111
13 1
14 0
15
0 ; RUN: llvm-profdata merge %S/Inputs/misexpect-branch-correct.proftext -o %t.profdata
1
2 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pgo-warn-misexpect -pass-remarks=misexpect 2>&1 | FileCheck %s
3
4 ; New PM
5 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pgo-warn-misexpect -pass-remarks=misexpect -S 2>&1 | FileCheck %s
6
7 ; CHECK-NOT: warning: {{.*}}
8 ; CHECK-NOT: remark: {{.*}}
9 ; CHECK: !{!"misexpect", i64 1, i64 2000, i64 1}
10
11
12 ; ModuleID = 'misexpect-branch-correct.c'
13 source_filename = "misexpect-branch-correct.c"
14 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
15 target triple = "x86_64-unknown-linux-gnu"
16
17 @inner_loop = constant i32 100, align 4
18 @outer_loop = constant i32 2000, align 4
19
20 ; Function Attrs: nounwind
21 define i32 @bar() #0 {
22 entry:
23 %rando = alloca i32, align 4
24 %x = alloca i32, align 4
25 %0 = bitcast i32* %rando to i8*
26 call void @llvm.lifetime.start.p0i8(i64 4, i8* %0) #4
27 %call = call i32 (...) @buzz()
28 store i32 %call, i32* %rando, align 4, !tbaa !3
29 %1 = bitcast i32* %x to i8*
30 call void @llvm.lifetime.start.p0i8(i64 4, i8* %1) #4
31 store i32 0, i32* %x, align 4, !tbaa !3
32 %2 = load i32, i32* %rando, align 4, !tbaa !3
33 %rem = srem i32 %2, 200000
34 %cmp = icmp eq i32 %rem, 0
35 %lnot = xor i1 %cmp, true
36 %lnot1 = xor i1 %lnot, true
37 %lnot.ext = zext i1 %lnot1 to i32
38 %conv = sext i32 %lnot.ext to i64
39 %expval = call i64 @llvm.expect.i64(i64 %conv, i64 0)
40 %tobool = icmp ne i64 %expval, 0
41 br i1 %tobool, label %if.then, label %if.else
42
43 if.then: ; preds = %entry
44 %3 = load i32, i32* %rando, align 4, !tbaa !3
45 %call2 = call i32 @baz(i32 %3)
46 store i32 %call2, i32* %x, align 4, !tbaa !3
47 br label %if.end
48
49 if.else: ; preds = %entry
50 %call3 = call i32 @foo(i32 50)
51 store i32 %call3, i32* %x, align 4, !tbaa !3
52 br label %if.end
53
54 if.end: ; preds = %if.else, %if.then
55 %4 = load i32, i32* %x, align 4, !tbaa !3
56 %5 = bitcast i32* %x to i8*
57 call void @llvm.lifetime.end.p0i8(i64 4, i8* %5) #4
58 %6 = bitcast i32* %rando to i8*
59 call void @llvm.lifetime.end.p0i8(i64 4, i8* %6) #4
60 ret i32 %4
61 }
62
63 ; Function Attrs: argmemonly nounwind willreturn
64 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
65
66 declare i32 @buzz(...) #2
67
68 ; Function Attrs: nounwind readnone willreturn
69 declare i64 @llvm.expect.i64(i64, i64) #3
70
71 declare i32 @baz(i32) #2
72
73 declare i32 @foo(i32) #2
74
75 ; Function Attrs: argmemonly nounwind willreturn
76 declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
77
78 attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
79 attributes #1 = { argmemonly nounwind willreturn }
80 attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
81 attributes #3 = { nounwind readnone willreturn }
82 attributes #4 = { nounwind }
83
84 !llvm.module.flags = !{!0, !1}
85 !llvm.ident = !{!2}
86
87 !0 = !{i32 2, !"Debug Info Version", i32 3}
88 !1 = !{i32 1, !"wchar_size", i32 4}
89 !2 = !{!"clang version 10.0.0 (c20270bfffc9d6965219de339d66c61e9fe7d82d)"}
90 !3 = !{!4, !4, i64 0}
91 !4 = !{!"int", !5, i64 0}
92 !5 = !{!"omnipotent char", !6, i64 0}
93 !6 = !{!"Simple C/C++ TBAA"}
0
1 ; RUN: llvm-profdata merge %S/Inputs/misexpect-branch.proftext -o %t.profdata
2
3
4 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pgo-warn-misexpect 2>&1 | FileCheck %s --check-prefix=WARNING
5 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pass-remarks=misexpect 2>&1 | FileCheck %s --check-prefix=REMARK
6 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pgo-warn-misexpect -pass-remarks=misexpect 2>&1 | FileCheck %s --check-prefix=BOTH
7 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S 2>&1 | FileCheck %s --check-prefix=DISABLED
8
9 ; New PM
10 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pgo-warn-misexpect -S 2>&1 | FileCheck %s --check-prefix=WARNING
11 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pass-remarks=misexpect -S 2>&1 | FileCheck %s --check-prefix=REMARK
12 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pgo-warn-misexpect -pass-remarks=misexpect -S 2>&1 | FileCheck %s --check-prefix=BOTH
13 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -S 2>&1 | FileCheck %s --check-prefix=DISABLED
14
15
16
17 ; WARNING-DAG: warning: :0:0: 19.98%
18 ; WARNING-NOT: remark: :0:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 19.98% (399668 / 2000000) of profiled executions.
19
20 ; REMARK-NOT: warning: :0:0: 19.98%
21 ; REMARK-DAG: remark: :0:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 19.98% (399668 / 2000000) of profiled executions.
22
23 ; BOTH-DAG: warning: :0:0: 19.98%
24 ; BOTH-DAG: remark: :0:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 19.98% (399668 / 2000000) of profiled executions.
25
26 ; DISABLED-NOT: warning: :0:0: 19.98%
27 ; DISABLED-NOT: remark: :0:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 19.98% (399668 / 2000000) of profiled executions.
28
29 ; CHECK-DAG: !{!"misexpect", i64 1, i64 2000, i64 1}
30
31
32
33 ; ModuleID = 'misexpect-branch.c'
34 source_filename = "misexpect-branch.c"
35 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
36 target triple = "x86_64-unknown-linux-gnu"
37
38 @inner_loop = constant i32 100, align 4
39 @outer_loop = constant i32 2000, align 4
40
41 ; Function Attrs: nounwind
42 define i32 @bar() #0 {
43 entry:
44 %rando = alloca i32, align 4
45 %x = alloca i32, align 4
46 %0 = bitcast i32* %rando to i8*
47 call void @llvm.lifetime.start.p0i8(i64 4, i8* %0) #4
48 %call = call i32 (...) @buzz()
49 store i32 %call, i32* %rando, align 4, !tbaa !3
50 %1 = bitcast i32* %x to i8*
51 call void @llvm.lifetime.start.p0i8(i64 4, i8* %1) #4
52 store i32 0, i32* %x, align 4, !tbaa !3
53 %2 = load i32, i32* %rando, align 4, !tbaa !3
54 %rem = srem i32 %2, 200000
55 %cmp = icmp eq i32 %rem, 0
56 %lnot = xor i1 %cmp, true
57 %lnot1 = xor i1 %lnot, true
58 %lnot.ext = zext i1 %lnot1 to i32
59 %conv = sext i32 %lnot.ext to i64
60 %expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
61 %tobool = icmp ne i64 %expval, 0
62 br i1 %tobool, label %if.then, label %if.else
63
64 if.then: ; preds = %entry
65 %3 = load i32, i32* %rando, align 4, !tbaa !3
66 %call2 = call i32 @baz(i32 %3)
67 store i32 %call2, i32* %x, align 4, !tbaa !3
68 br label %if.end
69
70 if.else: ; preds = %entry
71 %call3 = call i32 @foo(i32 50)
72 store i32 %call3, i32* %x, align 4, !tbaa !3
73 br label %if.end
74
75 if.end: ; preds = %if.else, %if.then
76 %4 = load i32, i32* %x, align 4, !tbaa !3
77 %5 = bitcast i32* %x to i8*
78 call void @llvm.lifetime.end.p0i8(i64 4, i8* %5) #4
79 %6 = bitcast i32* %rando to i8*
80 call void @llvm.lifetime.end.p0i8(i64 4, i8* %6) #4
81 ret i32 %4
82 }
83
84 ; Function Attrs: argmemonly nounwind willreturn
85 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
86
87 declare i32 @buzz(...) #2
88
89 ; Function Attrs: nounwind readnone willreturn
90 declare i64 @llvm.expect.i64(i64, i64) #3
91
92 declare i32 @baz(i32) #2
93
94 declare i32 @foo(i32) #2
95
96 ; Function Attrs: argmemonly nounwind willreturn
97 declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
98
99 attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
100 attributes #1 = { argmemonly nounwind willreturn }
101 attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
102 attributes #3 = { nounwind readnone willreturn }
103 attributes #4 = { nounwind }
104
105 !llvm.module.flags = !{!0, !1}
106 !llvm.ident = !{!2}
107
108 !0 = !{i32 2, !"Debug Info Version", i32 3}
109 !1 = !{i32 1, !"wchar_size", i32 4}
110 !2 = !{!"clang version 10.0.0 (trunk c20270bfffc9d6965219de339d66c61e9fe7d82d)"}
111 !3 = !{!4, !4, i64 0}
112 !4 = !{!"int", !5, i64 0}
113 !5 = !{!"omnipotent char", !6, i64 0}
114 !6 = !{!"Simple C/C++ TBAA"}
0 ; RUN: llvm-profdata merge %S/Inputs/misexpect-branch-correct.proftext -o %t.profdata
1
2 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pgo-warn-misexpect -pass-remarks=misexpect 2>&1 | FileCheck %s
3
4 ; New PM
5 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pgo-warn-misexpect -pass-remarks=misexpect -S 2>&1 | FileCheck %s
6
7 ; CHECK-NOT: warning: {{.*}}
8 ; CHECK-NOT: remark: {{.*}}
9 ; CHECK-NOT: !"misexpect"
10
11
12 ; ModuleID = 'misexpect-branch-unpredictable.c'
13 source_filename = "clang/test/Profile/misexpect-branch-unpredictable.c"
14 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
15 target triple = "x86_64-unknown-linux-gnu"
16
17 @inner_loop = constant i32 100, align 4
18 @outer_loop = constant i32 2000, align 4
19
20 ; Function Attrs: nounwind
21 define i32 @bar() #0 {
22 entry:
23 %rando = alloca i32, align 4
24 %x = alloca i32, align 4
25 %0 = bitcast i32* %rando to i8*
26 call void @llvm.lifetime.start.p0i8(i64 4, i8* %0) #3
27 %call = call i32 (...) @buzz()
28 store i32 %call, i32* %rando, align 4, !tbaa !2
29 %1 = bitcast i32* %x to i8*
30 call void @llvm.lifetime.start.p0i8(i64 4, i8* %1) #3
31 store i32 0, i32* %x, align 4, !tbaa !2
32 %2 = load i32, i32* %rando, align 4, !tbaa !2
33 %rem = srem i32 %2, 200000
34 %cmp = icmp eq i32 %rem, 0
35 %lnot = xor i1 %cmp, true
36 %lnot1 = xor i1 %lnot, true
37 %lnot.ext = zext i1 %lnot1 to i32
38 %conv = sext i32 %lnot.ext to i64
39 %tobool = icmp ne i64 %conv, 0
40 br i1 %tobool, label %if.then, label %if.else, !unpredictable !6
41
42 if.then: ; preds = %entry
43 %3 = load i32, i32* %rando, align 4, !tbaa !2
44 %call2 = call i32 @baz(i32 %3)
45 store i32 %call2, i32* %x, align 4, !tbaa !2
46 br label %if.end
47
48 if.else: ; preds = %entry
49 %call3 = call i32 @foo(i32 50)
50 store i32 %call3, i32* %x, align 4, !tbaa !2
51 br label %if.end
52
53 if.end: ; preds = %if.else, %if.then
54 %4 = load i32, i32* %x, align 4, !tbaa !2
55 %5 = bitcast i32* %x to i8*
56 call void @llvm.lifetime.end.p0i8(i64 4, i8* %5) #3
57 %6 = bitcast i32* %rando to i8*
58 call void @llvm.lifetime.end.p0i8(i64 4, i8* %6) #3
59 ret i32 %4
60 }
61
62 ; Function Attrs: argmemonly nounwind willreturn
63 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
64
65 declare i32 @buzz(...) #2
66
67 declare i32 @baz(i32) #2
68
69 declare i32 @foo(i32) #2
70
71 ; Function Attrs: argmemonly nounwind willreturn
72 declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
73
74 attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
75 attributes #1 = { argmemonly nounwind willreturn }
76 attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
77 attributes #3 = { nounwind }
78
79 !llvm.module.flags = !{!0}
80 !llvm.ident = !{!1}
81
82 !0 = !{i32 1, !"wchar_size", i32 4}
83 !1 = !{!"Fuchsia clang version 10.0.0 (153b453014c94291c8c6cf6320b2f46df40f26f3) (based on LLVM 10.0.0svn)"}
84 !2 = !{!3, !3, i64 0}
85 !3 = !{!"int", !4, i64 0}
86 !4 = !{!"omnipotent char", !5, i64 0}
87 !5 = !{!"Simple C/C++ TBAA"}
88 !6 = !{}
0
1 ; RUN: llvm-profdata merge %S/Inputs/misexpect-branch.proftext -o %t.profdata
2
3
4 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pgo-warn-misexpect 2>&1 | FileCheck %s --check-prefix=WARNING
5 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pass-remarks=misexpect 2>&1 | FileCheck %s --check-prefix=REMARK
6 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pgo-warn-misexpect -pass-remarks=misexpect 2>&1 | FileCheck %s --check-prefix=BOTH
7 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S 2>&1 | FileCheck %s --check-prefix=DISABLED
8
9 ; New PM
10 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pgo-warn-misexpect -S 2>&1 | FileCheck %s --check-prefix=WARNING
11 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pass-remarks=misexpect -S 2>&1 | FileCheck %s --check-prefix=REMARK
12 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pgo-warn-misexpect -pass-remarks=misexpect -S 2>&1 | FileCheck %s --check-prefix=BOTH
13 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -S 2>&1 | FileCheck %s --check-prefix=DISABLED
14
15
16
17 ; WARNING-DAG: warning: misexpect-branch.c:22:0: 19.98%
18 ; WARNING-NOT: remark: misexpect-branch.c:22:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 19.98% (399668 / 2000000) of profiled executions.
19
20 ; REMARK-NOT: warning: misexpect-branch.c:22:0: 19.98%
21 ; REMARK-DAG: remark: misexpect-branch.c:22:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 19.98% (399668 / 2000000) of profiled executions.
22
23 ; BOTH-DAG: warning: misexpect-branch.c:22:0: 19.98%
24 ; BOTH-DAG: remark: misexpect-branch.c:22:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 19.98% (399668 / 2000000) of profiled executions.
25
26 ; DISABLED-NOT: warning: misexpect-branch.c:22:0: 19.98%
27 ; DISABLED-NOT: remark: misexpect-branch.c:22:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 19.98% (399668 / 2000000) of profiled executions.
28
29 ; CHECK-DAG: !{!"misexpect", i64 1, i64 2000, i64 1}
30
31
32
33 ; ModuleID = 'misexpect-branch.c'
34 source_filename = "misexpect-branch.c"
35 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
36 target triple = "x86_64-unknown-linux-gnu"
37
38 @inner_loop = constant i32 100, align 4
39 @outer_loop = constant i32 2000, align 4
40
41 ; Function Attrs: nounwind
42 define i32 @bar() #0 !dbg !6 {
43 entry:
44 %rando = alloca i32, align 4
45 %x = alloca i32, align 4
46 %0 = bitcast i32* %rando to i8*, !dbg !9
47 call void @llvm.lifetime.start.p0i8(i64 4, i8* %0) #4, !dbg !9
48 %call = call i32 (...) @buzz(), !dbg !9
49 store i32 %call, i32* %rando, align 4, !dbg !9, !tbaa !10
50 %1 = bitcast i32* %x to i8*, !dbg !14
51 call void @llvm.lifetime.start.p0i8(i64 4, i8* %1) #4, !dbg !14
52 store i32 0, i32* %x, align 4, !dbg !14, !tbaa !10
53 %2 = load i32, i32* %rando, align 4, !dbg !15, !tbaa !10
54 %rem = srem i32 %2, 200000, !dbg !15
55 %cmp = icmp eq i32 %rem, 0, !dbg !15
56 %lnot = xor i1 %cmp, true, !dbg !15
57 %lnot1 = xor i1 %lnot, true, !dbg !15
58 %lnot.ext = zext i1 %lnot1 to i32, !dbg !15
59 %conv = sext i32 %lnot.ext to i64, !dbg !15
60 %expval = call i64 @llvm.expect.i64(i64 %conv, i64 1), !dbg !15
61 %tobool = icmp ne i64 %expval, 0, !dbg !15
62 br i1 %tobool, label %if.then, label %if.else, !dbg !15
63
64 if.then: ; preds = %entry
65 %3 = load i32, i32* %rando, align 4, !dbg !16, !tbaa !10
66 %call2 = call i32 @baz(i32 %3), !dbg !16
67 store i32 %call2, i32* %x, align 4, !dbg !16, !tbaa !10
68 br label %if.end, !dbg !17
69
70 if.else: ; preds = %entry
71 %call3 = call i32 @foo(i32 50), !dbg !18
72 store i32 %call3, i32* %x, align 4, !dbg !18, !tbaa !10
73 br label %if.end
74
75 if.end: ; preds = %if.else, %if.then
76 %4 = load i32, i32* %x, align 4, !dbg !19, !tbaa !10
77 %5 = bitcast i32* %x to i8*, !dbg !20
78 call void @llvm.lifetime.end.p0i8(i64 4, i8* %5) #4, !dbg !20
79 %6 = bitcast i32* %rando to i8*, !dbg !20
80 call void @llvm.lifetime.end.p0i8(i64 4, i8* %6) #4, !dbg !20
81 ret i32 %4, !dbg !19
82 }
83
84 ; Function Attrs: argmemonly nounwind willreturn
85 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
86
87 declare i32 @buzz(...) #2
88
89 ; Function Attrs: nounwind readnone willreturn
90 declare i64 @llvm.expect.i64(i64, i64) #3
91
92 declare i32 @baz(i32) #2
93
94 declare i32 @foo(i32) #2
95
96 ; Function Attrs: argmemonly nounwind willreturn
97 declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
98
99 attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
100 attributes #1 = { argmemonly nounwind willreturn }
101 attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
102 attributes #3 = { nounwind readnone willreturn }
103 attributes #4 = { nounwind }
104
105 !llvm.dbg.cu = !{!0}
106 !llvm.module.flags = !{!3, !4}
107 !llvm.ident = !{!5}
108
109 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk c20270bfffc9d6965219de339d66c61e9fe7d82d)", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2, nameTableKind: None)
110 !1 = !DIFile(filename: "", directory: ".")
111 !2 = !{}
112 !3 = !{i32 2, !"Debug Info Version", i32 3}
113 !4 = !{i32 1, !"wchar_size", i32 4}
114 !5 = !{!"clang version 10.0.0 (trunk c20270bfffc9d6965219de339d66c61e9fe7d82d)"}
115 !6 = distinct !DISubprogram(name: "bar", scope: !7, file: !7, line: 19, type: !8, scopeLine: 19, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
116 !7 = !DIFile(filename: "misexpect-branch.c", directory: ".")
117 !8 = !DISubroutineType(types: !2)
118 !9 = !DILocation(line: 20, scope: !6)
119 !10 = !{!11, !11, i64 0}
120 !11 = !{!"int", !12, i64 0}
121 !12 = !{!"omnipotent char", !13, i64 0}
122 !13 = !{!"Simple C/C++ TBAA"}
123 !14 = !DILocation(line: 21, scope: !6)
124 !15 = !DILocation(line: 22, scope: !6)
125 !16 = !DILocation(line: 23, scope: !6)
126 !17 = !DILocation(line: 24, scope: !6)
127 !18 = !DILocation(line: 25, scope: !6)
128 !19 = !DILocation(line: 27, scope: !6)
129 !20 = !DILocation(line: 28, scope: !6)
0
1 ; RUN: llvm-profdata merge %S/Inputs/misexpect-switch.proftext -o %t.profdata
2
3 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pgo-warn-misexpect 2>&1 | FileCheck %s --check-prefix=WARNING
4 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pass-remarks=misexpect 2>&1 | FileCheck %s --check-prefix=REMARK
5 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pgo-warn-misexpect -pass-remarks=misexpect 2>&1 | FileCheck %s --check-prefix=BOTH
6 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S 2>&1 | FileCheck %s --check-prefix=DISABLED
7
8 ; New PM
9 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pgo-warn-misexpect -S 2>&1 | FileCheck %s --check-prefix=WARNING
10 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pass-remarks=misexpect -S 2>&1 | FileCheck %s --check-prefix=REMARK
11 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pgo-warn-misexpect -pass-remarks=misexpect -S 2>&1 | FileCheck %s --check-prefix=BOTH
12 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -S 2>&1 | FileCheck %s --check-prefix=DISABLED
13
14 ; WARNING-DAG: warning: :0:0: 0.00%
15 ; WARNING-NOT: remark: :0:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 0.00% (0 / 27943) of profiled executions.
16
17 ; REMARK-NOT: warning: :0:0: 0.00%
18 ; REMARK-DAG: remark: :0:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 0.00% (0 / 27943) of profiled executions.
19
20 ; BOTH-DAG: warning: :0:0: 0.00%
21 ; BOTH-DAG: remark: :0:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 0.00% (0 / 27943) of profiled executions.
22
23 ; DISABLED-NOT: warning: :0:0: 0.00%
24 ; DISABLED-NOT: remark: :0:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 0.00% (0 / 27943) of profiled executions.
25
26 ; DISABLED-NOT: warning: :0:0: 0.00%
27 ; DISABLED-NOT: remark: :0:0: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 0.00% (0 / 27943) of profiled executions.
28
29 ; CORRECT-NOT: warning: {{.*}}
30 ; CORRECT-NOT: remark: {{.*}}
31 ; CHECK-DAG: !{!"misexpect", i64 0, i64 2000, i64 1}
32
33
34
35 ; ModuleID = 'misexpect-switch.c'
36 source_filename = "misexpect-switch.c"
37 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
38 target triple = "x86_64-unknown-linux-gnu"
39
40 @inner_loop = dso_local constant i32 1000, align 4
41 @outer_loop = dso_local constant i32 20, align 4
42 @arry_size = dso_local constant i32 25, align 4
43 @arry = dso_local global [25 x i32] zeroinitializer, align 16
44
45 ; Function Attrs: nounwind uwtable
46 define dso_local void @init_arry() #0 {
47 entry:
48 %i = alloca i32, align 4
49 %0 = bitcast i32* %i to i8*
50 call void @llvm.lifetime.start.p0i8(i64 4, i8* %0) #6
51 store i32 0, i32* %i, align 4, !tbaa !4
52 br label %for.cond
53
54 for.cond: ; preds = %for.inc, %entry
55 %1 = load i32, i32* %i, align 4, !tbaa !4
56 %cmp = icmp slt i32 %1, 25
57 br i1 %cmp, label %for.body, label %for.end
58
59 for.body: ; preds = %for.cond
60 %call = call i32 @rand() #6
61 %rem = srem i32 %call, 10
62 %2 = load i32, i32* %i, align 4, !tbaa !4
63 %idxprom = sext i32 %2 to i64
64 %arrayidx = getelementptr inbounds [25 x i32], [25 x i32]* @arry, i64 0, i64 %idxprom
65 store i32 %rem, i32* %arrayidx, align 4, !tbaa !4
66 br label %for.inc
67
68 for.inc: ; preds = %for.body
69 %3 = load i32, i32* %i, align 4, !tbaa !4
70 %inc = add nsw i32 %3, 1
71 store i32 %inc, i32* %i, align 4, !tbaa !4
72 br label %for.cond
73
74 for.end: ; preds = %for.cond
75 %4 = bitcast i32* %i to i8*
76 call void @llvm.lifetime.end.p0i8(i64 4, i8* %4) #6
77 ret void
78 }
79
80 ; Function Attrs: argmemonly nounwind willreturn
81 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
82
83 ; Function Attrs: nounwind readnone speculatable willreturn
84 declare void @llvm.dbg.declare(metadata, metadata, metadata) #2
85
86 ; Function Attrs: nounwind
87 declare dso_local i32 @rand() #3
88
89 ; Function Attrs: argmemonly nounwind willreturn
90 declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
91
92 ; Function Attrs: nounwind uwtable
93 define dso_local i32 @main() #0 {
94 entry:
95 %retval = alloca i32, align 4
96 %val = alloca i32, align 4
97 %j = alloca i32, align 4
98 %condition = alloca i32, align 4
99 store i32 0, i32* %retval, align 4
100 call void @init_arry()
101 %0 = bitcast i32* %val to i8*
102 call void @llvm.lifetime.start.p0i8(i64 4, i8* %0) #6
103 store i32 0, i32* %val, align 4, !tbaa !4
104 %1 = bitcast i32* %j to i8*
105 call void @llvm.lifetime.start.p0i8(i64 4, i8* %1) #6
106 store i32 0, i32* %j, align 4, !tbaa !4
107 br label %for.cond
108
109 for.cond: ; preds = %for.inc, %entry
110 %2 = load i32, i32* %j, align 4, !tbaa !4
111 %cmp = icmp slt i32 %2, 20000
112 br i1 %cmp, label %for.body, label %for.end
113
114 for.body: ; preds = %for.cond
115 %3 = bitcast i32* %condition to i8*
116 call void @llvm.lifetime.start.p0i8(i64 4, i8* %3) #6
117 %call = call i32 @rand() #6
118 %rem = srem i32 %call, 5
119 store i32 %rem, i32* %condition, align 4, !tbaa !4
120 %4 = load i32, i32* %condition, align 4, !tbaa !4
121 %conv = zext i32 %4 to i64
122 %expval = call i64 @llvm.expect.i64(i64 %conv, i64 6)
123 switch i64 %expval, label %sw.default [
124 i64 0, label %sw.bb
125 i64 1, label %sw.bb2
126 i64 2, label %sw.bb2
127 i64 3, label %sw.bb2
128 i64 4, label %sw.bb3
129 ]
130
131 sw.bb: ; preds = %for.body
132 %call1 = call i32 @sum(i32* getelementptr inbounds ([25 x i32], [25 x i32]* @arry, i64 0, i64 0), i32 25)
133 %5 = load i32, i32* %val, align 4, !tbaa !4
134 %add = add nsw i32 %5, %call1
135 store i32 %add, i32* %val, align 4, !tbaa !4
136 br label %sw.epilog
137
138 sw.bb2: ; preds = %for.body, %for.body, %for.body
139 br label %sw.epilog
140
141 sw.bb3: ; preds = %for.body
142 %call4 = call i32 @random_sample(i32* getelementptr inbounds ([25 x i32], [25 x i32]* @arry, i64 0, i64 0), i32 25)
143 %6 = load i32, i32* %val, align 4, !tbaa !4
144 %add5 = add nsw i32 %6, %call4
145 store i32 %add5, i32* %val, align 4, !tbaa !4
146 br label %sw.epilog
147
148 sw.default: ; preds = %for.body
149 unreachable
150
151 sw.epilog: ; preds = %sw.bb3, %sw.bb2, %sw.bb
152 %7 = bitcast i32* %condition to i8*
153 call void @llvm.lifetime.end.p0i8(i64 4, i8* %7) #6
154 br label %for.inc
155
156 for.inc: ; preds = %sw.epilog
157 %8 = load i32, i32* %j, align 4, !tbaa !4
158 %inc = add nsw i32 %8, 1
159 store i32 %inc, i32* %j, align 4, !tbaa !4
160 br label %for.cond
161
162 for.end: ; preds = %for.cond
163 %9 = bitcast i32* %j to i8*
164 call void @llvm.lifetime.end.p0i8(i64 4, i8* %9) #6
165 %10 = bitcast i32* %val to i8*
166 call void @llvm.lifetime.end.p0i8(i64 4, i8* %10) #6
167 ret i32 0
168 }
169
170 ; Function Attrs: nounwind readnone willreturn
171 declare i64 @llvm.expect.i64(i64, i64) #4
172
173 declare dso_local i32 @sum(i32*, i32) #5
174
175 declare dso_local i32 @random_sample(i32*, i32) #5
176
177 attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
178 attributes #1 = { argmemonly nounwind willreturn }
179 attributes #2 = { nounwind readnone speculatable willreturn }
180 attributes #3 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
181 attributes #4 = { nounwind readnone willreturn }
182 attributes #5 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
183 attributes #6 = { nounwind }
184
185 !llvm.module.flags = !{!0, !1, !2}
186 !llvm.ident = !{!3}
187
188 !0 = !{i32 2, !"Dwarf Version", i32 4}
189 !1 = !{i32 2, !"Debug Info Version", i32 3}
190 !2 = !{i32 1, !"wchar_size", i32 4}
191 !3 = !{!"clang version 10.0.0 (60b79b85b1763d3d25630261e5cd1adb7f0835bc)"}
192 !4 = !{!5, !5, i64 0}
193 !5 = !{!"int", !6, i64 0}
194 !6 = !{!"omnipotent char", !7, i64 0}
195 !7 = !{!"Simple C/C++ TBAA"}
0
1 ; RUN: llvm-profdata merge %S/Inputs/misexpect-switch.proftext -o %t.profdata
2 ; RUN: llvm-profdata merge %S/Inputs/misexpect-switch-correct.proftext -o %t.c.profdata
3
4 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pgo-warn-misexpect 2>&1 | FileCheck %s --check-prefix=WARNING
5 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pass-remarks=misexpect 2>&1 | FileCheck %s --check-prefix=REMARK
6 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S -pgo-warn-misexpect -pass-remarks=misexpect 2>&1 | FileCheck %s --check-prefix=BOTH
7 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.profdata -S 2>&1 | FileCheck %s --check-prefix=DISABLED
8
9 ; New PM
10 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pgo-warn-misexpect -S 2>&1 | FileCheck %s --check-prefix=WARNING
11 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pass-remarks=misexpect -S 2>&1 | FileCheck %s --check-prefix=REMARK
12 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -pgo-warn-misexpect -pass-remarks=misexpect -S 2>&1 | FileCheck %s --check-prefix=BOTH
13 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.profdata -S 2>&1 | FileCheck %s --check-prefix=DISABLED
14
15 ; RUN: opt < %s -lower-expect -pgo-instr-use -pgo-test-profile-file=%t.c.profdata -S -pgo-warn-misexpect -pass-remarks=misexpect 2>&1 | FileCheck %s --check-prefix=CORRECT
16 ; RUN: opt < %s -passes="function(lower-expect),pgo-instr-use" -pgo-test-profile-file=%t.c.profdata -pgo-warn-misexpect -pass-remarks=misexpect -S 2>&1 | FileCheck %s --check-prefix=CORRECT
17
18 ; WARNING-DAG: warning: misexpect-switch.c:26:5: 0.00%
19 ; WARNING-NOT: remark: misexpect-switch.c:26:5: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 0.00% (0 / 8112) of profiled executions.
20
21 ; REMARK-NOT: warning: misexpect-switch.c:26:5: 0.00%
22 ; REMARK-DAG: remark: misexpect-switch.c:26:5: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 0.00% (0 / 8112) of profiled executions.
23
24 ; BOTH-DAG: warning: misexpect-switch.c:26:5: 0.00%
25 ; BOTH-DAG: remark: misexpect-switch.c:26:5: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 0.00% (0 / 8112) of profiled executions.
26
27 ; DISABLED-NOT: warning: misexpect-switch.c:26:5: 0.00%
28 ; DISABLED-NOT: remark: misexpect-switch.c:26:5: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 0.00% (0 / 8112) of profiled executions.
29
30 ; DISABLED-NOT: warning: misexpect-switch.c:26:5: 0.00%
31 ; DISABLED-NOT: remark: misexpect-switch.c:26:5: Potential performance regression from use of the llvm.expect intrinsic: Annotation was correct on 0.00% (0 / 8112) of profiled executions.
32
33 ; CORRECT-NOT: warning: {{.*}}
34 ; CORRECT-NOT: remark: {{.*}}
35 ; CHECK-DAG: !{!"misexpect", i64 0, i64 2000, i64 1}
36
37
38
39 ; ModuleID = 'misexpect-switch.c'
40 source_filename = "misexpect-switch.c"
41 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
42 target triple = "x86_64-unknown-linux-gnu"
43
44 @inner_loop = dso_local constant i32 1000, align 4, !dbg !0
45 @outer_loop = dso_local constant i32 20, align 4, !dbg !6
46 @arry_size = dso_local constant i32 25, align 4, !dbg !10
47 @arry = dso_local global [25 x i32] zeroinitializer, align 16, !dbg !12
48
49 ; Function Attrs: nounwind uwtable
50 define dso_local void @init_arry() #0 !dbg !21 {
51 entry:
52 %i = alloca i32, align 4
53 %0 = bitcast i32* %i to i8*, !dbg !26
54 call void @llvm.lifetime.start.p0i8(i64 4, i8* %0) #6, !dbg !26
55 call void @llvm.dbg.declare(metadata i32* %i, metadata !25, metadata !DIExpression()), !dbg !27
56 store i32 0, i32* %i, align 4, !dbg !28, !tbaa !30
57 br label %for.cond, !dbg !34
58
59 for.cond: ; preds = %for.inc, %entry
60 %1 = load i32, i32* %i, align 4, !dbg !35, !tbaa !30
61 %cmp = icmp slt i32 %1, 25, !dbg !37
62 br i1 %cmp, label %for.body, label %for.end, !dbg !38
63
64 for.body: ; preds = %for.cond
65 %call = call i32 @rand() #6, !dbg !39
66 %rem = srem i32 %call, 10, !dbg !41
67 %2 = load i32, i32* %i, align 4, !dbg !42, !tbaa !30
68 %idxprom = sext i32 %2 to i64, !dbg !43
69 %arrayidx = getelementptr inbounds [25 x i32], [25 x i32]* @arry, i64 0, i64 %idxprom, !dbg !43
70 store i32 %rem, i32* %arrayidx, align 4, !dbg !44, !tbaa !30
71 br label %for.inc, !dbg !45
72
73 for.inc: ; preds = %for.body
74 %3 = load i32, i32* %i, align 4, !dbg !46, !tbaa !30
75 %inc = add nsw i32 %3, 1, !dbg !46
76 store i32 %inc, i32* %i, align 4, !dbg !46, !tbaa !30
77 br label %for.cond, !dbg !47, !llvm.loop !48
78
79 for.end: ; preds = %for.cond
80 %4 = bitcast i32* %i to i8*, !dbg !50
81 call void @llvm.lifetime.end.p0i8(i64 4, i8* %4) #6, !dbg !50
82 ret void, !dbg !50
83 }
84
85 ; Function Attrs: argmemonly nounwind willreturn
86 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
87
88 ; Function Attrs: nounwind readnone speculatable willreturn
89 declare void @llvm.dbg.declare(metadata, metadata, metadata) #2
90
91 ; Function Attrs: nounwind
92 declare dso_local i32 @rand() #3
93
94 ; Function Attrs: argmemonly nounwind willreturn
95 declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
96
97 ; Function Attrs: nounwind uwtable
98 define dso_local i32 @main() #0 !dbg !51 {
99 entry:
100 %retval = alloca i32, align 4
101 %val = alloca i32, align 4
102 %j = alloca i32, align 4
103 %condition = alloca i32, align 4
104 store i32 0, i32* %retval, align 4
105 call void @init_arry(), !dbg !62
106 %0 = bitcast i32* %val to i8*, !dbg !63
107 call void @llvm.lifetime.start.p0i8(i64 4, i8* %0) #6, !dbg !63
108 call void @llvm.dbg.declare(metadata i32* %val, metadata !55, metadata !DIExpression()), !dbg !64
109 store i32 0, i32* %val, align 4, !dbg !64, !tbaa !30
110 %1 = bitcast i32* %j to i8*, !dbg !65
111 call void @llvm.lifetime.start.p0i8(i64 4, i8* %1) #6, !dbg !65
112 call void @llvm.dbg.declare(metadata i32* %j, metadata !56, metadata !DIExpression()), !dbg !66
113 store i32 0, i32* %j, align 4, !dbg !67, !tbaa !30
114 br label %for.cond, !dbg !68
115
116 for.cond: ; preds = %for.inc, %entry
117 %2 = load i32, i32* %j, align 4, !dbg !69, !tbaa !30
118 %cmp = icmp slt i32 %2, 20000, !dbg !70
119 br i1 %cmp, label %for.body, label %for.end, !dbg !71
120
121 for.body: ; preds = %for.cond
122 %3 = bitcast i32* %condition to i8*, !dbg !72
123 call void @llvm.lifetime.start.p0i8(i64 4, i8* %3) #6, !dbg !72
124 call void @llvm.dbg.declare(metadata i32* %condition, metadata !57, metadata !DIExpression()), !dbg !73
125 %call = call i32 @rand() #6, !dbg !74
126 %rem = srem i32 %call, 5, !dbg !75
127 store i32 %rem, i32* %condition, align 4, !dbg !73, !tbaa !30
128 %4 = load i32, i32* %condition, align 4, !dbg !76, !tbaa !30
129 %conv = zext i32 %4 to i64, !dbg !76
130 %expval = call i64 @llvm.expect.i64(i64 %conv, i64 0), !dbg !77
131 switch i64 %expval, label %sw.default [
132 i64 0, label %sw.bb
133 i64 1, label %sw.bb2
134 i64 2, label %sw.bb2
135 i64 3, label %sw.bb2
136 i64 4, label %sw.bb3
137 ], !dbg !78
138
139 sw.bb: ; preds = %for.body
140 %call1 = call i32 @sum(i32* getelementptr inbounds ([25 x i32], [25 x i32]* @arry, i64 0, i64 0), i32 25), !dbg !79
141 %5 = load i32, i32* %val, align 4, !dbg !81, !tbaa !30
142 %add = add nsw i32 %5, %call1, !dbg !81
143 store i32 %add, i32* %val, align 4, !dbg !81, !tbaa !30
144 br label %sw.epilog, !dbg !82
145
146 sw.bb2: ; preds = %for.body, %for.body, %for.body
147 br label %sw.epilog, !dbg !83
148
149 sw.bb3: ; preds = %for.body
150 %call4 = call i32 @random_sample(i32* getelementptr inbounds ([25 x i32], [25 x i32]* @arry, i64 0, i64 0), i32 25), !dbg !84
151 %6 = load i32, i32* %val, align 4, !dbg !85, !tbaa !30
152 %add5 = add nsw i32 %6, %call4, !dbg !85
153 store i32 %add5, i32* %val, align 4, !dbg !85, !tbaa !30
154 br label %sw.epilog, !dbg !86
155
156 sw.default: ; preds = %for.body
157 unreachable, !dbg !87
158
159 sw.epilog: ; preds = %sw.bb3, %sw.bb2, %sw.bb
160 %7 = bitcast i32* %condition to i8*, !dbg !88
161 call void @llvm.lifetime.end.p0i8(i64 4, i8* %7) #6, !dbg !88
162 br label %for.inc, !dbg !89
163
164 for.inc: ; preds = %sw.epilog
165 %8 = load i32, i32* %j, align 4, !dbg !90, !tbaa !30
166 %inc = add nsw i32 %8, 1, !dbg !90
167 store i32 %inc, i32* %j, align 4, !dbg !90, !tbaa !30
168 br label %for.cond, !dbg !91, !llvm.loop !92
169
170 for.end: ; preds = %for.cond
171 %9 = bitcast i32* %j to i8*, !dbg !94
172 call void @llvm.lifetime.end.p0i8(i64 4, i8* %9) #6, !dbg !94
173 %10 = bitcast i32* %val to i8*, !dbg !94
174 call void @llvm.lifetime.end.p0i8(i64 4, i8* %10) #6, !dbg !94
175 ret i32 0, !dbg !95
176 }
177
178 ; Function Attrs: nounwind readnone willreturn
179 declare i64 @llvm.expect.i64(i64, i64) #4
180
181 declare dso_local i32 @sum(i32*, i32) #5
182
183 declare dso_local i32 @random_sample(i32*, i32) #5
184
185 attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
186 attributes #1 = { argmemonly nounwind willreturn }
187 attributes #2 = { nounwind readnone speculatable willreturn }
188 attributes #3 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
189 attributes #4 = { nounwind readnone willreturn }
190 attributes #5 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
191 attributes #6 = { nounwind }
192
193 !llvm.dbg.cu = !{!2}
194 !llvm.module.flags = !{!17, !18, !19}
195 !llvm.ident = !{!20}
196
197 !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
198 !1 = distinct !DIGlobalVariable(name: "inner_loop", scope: !2, file: !3, line: 7, type: !8, isLocal: false, isDefinition: true)
199 !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None)
200 !3 = !DIFile(filename: "misexpect-switch.c", directory: ".")
201 !4 = !{}
202 !5 = !{!0, !6, !10, !12}
203 !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
204 !7 = distinct !DIGlobalVariable(name: "outer_loop", scope: !2, file: !3, line: 8, type: !8, isLocal: false, isDefinition: true)
205 !8 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !9)
206 !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
207 !10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression())
208 !11 = distinct !DIGlobalVariable(name: "arry_size", scope: !2, file: !3, line: 9, type: !8, isLocal: false, isDefinition: true)
209 !12 = !DIGlobalVariableExpression(var: !13, expr: !DIExpression())
210 !13 = distinct !DIGlobalVariable(name: "arry", scope: !2, file: !3, line: 11, type: !14, isLocal: false, isDefinition: true)
211 !14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 800, elements: !15)
212 !15 = !{!16}
213 !16 = !DISubrange(count: 25)
214 !17 = !{i32 2, !"Dwarf Version", i32 4}
215 !18 = !{i32 2, !"Debug Info Version", i32 3}
216 !19 = !{i32 1, !"wchar_size", i32 4}
217 !20 = !{!"clang version 10.0.0"}
218 !21 = distinct !DISubprogram(name: "init_arry", scope: !3, file: !3, line: 13, type: !22, scopeLine: 13, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !24)
219 !22 = !DISubroutineType(types: !23)
220 !23 = !{null}
221 !24 = !{!25}
222 !25 = !DILocalVariable(name: "i", scope: !21, file: !3, line: 14, type: !9)
223 !26 = !DILocation(line: 14, column: 3, scope: !21)
224 !27 = !DILocation(line: 14, column: 7, scope: !21)
225 !28 = !DILocation(line: 15, column: 10, scope: !29)
226 !29 = distinct !DILexicalBlock(scope: !21, file: !3, line: 15, column: 3)
227 !30 = !{!31, !31, i64 0}
228 !31 = !{!"int", !32, i64 0}
229 !32 = !{!"omnipotent char", !33, i64 0}
230 !33 = !{!"Simple C/C++ TBAA"}
231 !34 = !DILocation(line: 15, column: 8, scope: !29)
232 !35 = !DILocation(line: 15, column: 15, scope: !36)
233 !36 = distinct !DILexicalBlock(scope: !29, file: !3, line: 15, column: 3)
234 !37 = !DILocation(line: 15, column: 17, scope: !36)
235 !38 = !DILocation(line: 15, column: 3, scope: !29)
236 !39 = !DILocation(line: 16, column: 15, scope: !40)
237 !40 = distinct !DILexicalBlock(scope: !36, file: !3, line: 15, column: 35)
238 !41 = !DILocation(line: 16, column: 22, scope: !40)
239 !42 = !DILocation(line: 16, column: 10, scope: !40)
240 !43 = !DILocation(line: 16, column: 5, scope: !40)
241 !44 = !DILocation(line: 16, column: 13, scope: !40)
242 !45 = !DILocation(line: 17, column: 3, scope: !40)
243 !46 = !DILocation(line: 15, column: 30, scope: !36)
244 !47 = !DILocation(line: 15, column: 3, scope: !36)
245 !48 = distinct !{!48, !38, !49}
246 !49 = !DILocation(line: 17, column: 3, scope: !29)
247 !50 = !DILocation(line: 18, column: 1, scope: !21)
248 !51 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 20, type: !52, scopeLine: 20, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !54)
249 !52 = !DISubroutineType(types: !53)
250 !53 = !{!9}
251 !54 = !{!55, !56, !57}
252 !55 = !DILocalVariable(name: "val", scope: !51, file: !3, line: 22, type: !9)
253 !56 = !DILocalVariable(name: "j", scope: !51, file: !3, line: 23, type: !9)
254 !57 = !DILocalVariable(name: "condition", scope: !58, file: !3, line: 25, type: !61)
255 !58 = distinct !DILexicalBlock(scope: !59, file: !3, line: 24, column: 49)
256 !59 = distinct !DILexicalBlock(scope: !60, file: !3, line: 24, column: 3)
257 !60 = distinct !DILexicalBlock(scope: !51, file: !3, line: 24, column: 3)
258 !61 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
259 !62 = !DILocation(line: 21, column: 3, scope: !51)
260 !63 = !DILocation(line: 22, column: 3, scope: !51)
261 !64 = !DILocation(line: 22, column: 7, scope: !51)
262 !65 = !DILocation(line: 23, column: 3, scope: !51)
263 !66 = !DILocation(line: 23, column: 7, scope: !51)
264 !67 = !DILocation(line: 24, column: 10, scope: !60)
265 !68 = !DILocation(line: 24, column: 8, scope: !60)
266 !69 = !DILocation(line: 24, column: 15, scope: !59)
267 !70 = !DILocation(line: 24, column: 17, scope: !59)
268 !71 = !DILocation(line: 24, column: 3, scope: !60)
269 !72 = !DILocation(line: 25, column: 5, scope: !58)
270 !73 = !DILocation(line: 25, column: 14, scope: !58)
271 !74 = !DILocation(line: 25, column: 26, scope: !58)
272 !75 = !DILocation(line: 25, column: 33, scope: !58)
273 !76 = !DILocation(line: 26, column: 30, scope: !58)
274 !77 = !DILocation(line: 26, column: 13, scope: !58)
275 !78 = !DILocation(line: 26, column: 5, scope: !58)
276 !79 = !DILocation(line: 28, column: 14, scope: !80)
277 !80 = distinct !DILexicalBlock(scope: !58, file: !3, line: 26, column: 45)
278 !81 = !DILocation(line: 28, column: 11, scope: !80)
279 !82 = !DILocation(line: 29, column: 7, scope: !80)
280 !83 = !DILocation(line: 33, column: 7, scope: !80)
281 !84 = !DILocation(line: 35, column: 14, scope: !80)
282 !85 = !DILocation(line: 35, column: 11, scope: !80)
283 !86 = !DILocation(line: 36, column: 7, scope: !80)
284 !87 = !DILocation(line: 38, column: 7, scope: !80)
285 !88 = !DILocation(line: 40, column: 3, scope: !59)
286 !89 = !DILocation(line: 40, column: 3, scope: !58)
287 !90 = !DILocation(line: 24, column: 44, scope: !59)
288 !91 = !DILocation(line: 24, column: 3, scope: !59)
289 !92 = distinct !{!92, !71, !93}
290 !93 = !DILocation(line: 40, column: 3, scope: !60)
291 !94 = !DILocation(line: 43, column: 1, scope: !51)
292 !95 = !DILocation(line: 42, column: 3, scope: !51)