llvm.org GIT mirror llvm / 0a14fbb
[PGO] Implementate profile counter regiser promotion Differential Revision: http://reviews.llvm.org/D34085 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306231 91177308-0d34-0410-b5e6-96231b3b80d8 Xinliang David Li 2 years ago
8 changed file(s) with 463 addition(s) and 15 deletion(s). Raw diff Collapse all Expand all
2727 namespace llvm {
2828
2929 class TargetLibraryInfo;
30 using LoadStorePair = std::pair;
3031
3132 /// Instrumentation based profiling lowering pass. This pass lowers
3233 /// the profile instrumented code generated by FE or the IR based
5960 GlobalVariable *NamesVar;
6061 size_t NamesSize;
6162
63 // vector of counter load/store pairs to be register promoted.
64 std::vector PromotionCandidates;
65
6266 // The start value of precise value profile range for memory intrinsic sizes.
6367 int64_t MemOPSizeRangeStart;
6468 // The end value of precise value profile range for memory intrinsic sizes.
6569 int64_t MemOPSizeRangeLast;
70
71 int64_t TotalCountersPromoted = 0;
72
73 /// Lower instrumentation intrinsics in the function. Returns true if there
74 /// any lowering.
75 bool lowerIntrinsics(Function *F);
76
77 /// Register-promote counter loads and stores in loops.
78 void promoteCounterLoadStores(Function *F);
79
80 /// Returns true if profile counter update register promotion is enabled.
81 bool isCounterPromotionEnabled() const;
6682
6783 /// Count the number of instrumented value sites for the function.
6884 void computeNumValueSiteCounts(InstrProfValueProfileInst *Ins);
114114 struct InstrProfOptions {
115115 // Add the 'noredzone' attribute to added runtime library calls.
116116 bool NoRedZone = false;
117
118 // Do counter register promotion
119 bool DoCounterPromotion = false;
117120
118121 // Name of the profile file to use as output
119122 std::string InstrProfileOutput;
463463 if (RunProfileGen) {
464464 MPM.addPass(PGOInstrumentationGen());
465465
466 FunctionPassManager FPM;
467 FPM.addPass(createFunctionToLoopPassAdaptor(LoopRotatePass()));
468 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
469
466470 // Add the profile lowering pass.
467471 InstrProfOptions Options;
468472 if (!ProfileGenFile.empty())
469473 Options.InstrProfileOutput = ProfileGenFile;
474 Options.DoCounterPromotion = true;
470475 MPM.addPass(InstrProfiling(Options));
471476 }
472477
290290 InstrProfOptions Options;
291291 if (!PGOInstrGen.empty())
292292 Options.InstrProfileOutput = PGOInstrGen;
293 Options.DoCounterPromotion = true;
294 MPM.add(createLoopRotatePass());
293295 MPM.add(createInstrProfilingLegacyPass(Options));
294296 }
295297 if (!PGOInstrUse.empty())
1818 #include "llvm/ADT/StringRef.h"
1919 #include "llvm/ADT/Triple.h"
2020 #include "llvm/ADT/Twine.h"
21 #include "llvm/Analysis/LoopInfo.h"
2122 #include "llvm/Analysis/TargetLibraryInfo.h"
2223 #include "llvm/IR/Attributes.h"
2324 #include "llvm/IR/BasicBlock.h"
2425 #include "llvm/IR/Constant.h"
2526 #include "llvm/IR/Constants.h"
2627 #include "llvm/IR/DerivedTypes.h"
28 #include "llvm/IR/Dominators.h"
2729 #include "llvm/IR/Function.h"
2830 #include "llvm/IR/GlobalValue.h"
2931 #include "llvm/IR/GlobalVariable.h"
3941 #include "llvm/Support/CommandLine.h"
4042 #include "llvm/Support/Error.h"
4143 #include "llvm/Support/ErrorHandling.h"
44 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
45 #include "llvm/Transforms/Utils/LoopSimplify.h"
4246 #include "llvm/Transforms/Utils/ModuleUtils.h"
47 #include "llvm/Transforms/Utils/SSAUpdater.h"
4348 #include
4449 #include
4550 #include
9196 // is usually smaller than 2.
9297 cl::init(1.0));
9398
99 cl::opt AtomicCounterUpdatePromoted(
100 "atomic-counter-update-promoted", cl::ZeroOrMore,
101 cl::desc("Do counter update using atomic fetch add "
102 " for promoted counters only"),
103 cl::init(false));
104
105 // If the option is not specified, the default behavior about whether
106 // counter promotion is done depends on how instrumentaiton lowering
107 // pipeline is setup, i.e., the default value of true of this option
108 // does not mean the promotion will be done by default. Explicitly
109 // setting this option can override the default behavior.
110 cl::opt DoCounterPromotion("do-counter-promotion", cl::ZeroOrMore,
111 cl::desc("Do counter register promotion"),
112 cl::init(false));
113 cl::opt MaxNumOfPromotionsPerLoop(
114 cl::ZeroOrMore, "max-counter-promotions-per-loop", cl::init(10),
115 cl::desc("Max number counter promotions per loop to avoid"
116 " increasing register pressure too much"));
117
118 // A debug option
119 cl::opt
120 MaxNumOfPromotions(cl::ZeroOrMore, "max-counter-promotions", cl::init(-1),
121 cl::desc("Max number of allowed counter promotions"));
122
123 cl::opt SpeculativeCounterPromotion(
124 cl::ZeroOrMore, "speculative-counter-promotion", cl::init(false),
125 cl::desc("Allow counter promotion for loops with multiple exiting blocks "
126 " or top-tested loops. "));
127
94128 class InstrProfilingLegacyPass : public ModulePass {
95129 InstrProfiling InstrProf;
96130
113147 AU.setPreservesCFG();
114148 AU.addRequired();
115149 }
150 };
151
152 /// A helper class to promote one counter RMW operation in the loop
153 /// into register update.
154 ///
155 /// RWM update for the counter will be sinked out of the loop after
156 /// the transformation.
157 ///
158 class PGOCounterPromoterHelper : public LoadAndStorePromoter {
159 public:
160 PGOCounterPromoterHelper(Instruction *L, Instruction *S, SSAUpdater &SSA,
161 Value *Init, BasicBlock *PH,
162 ArrayRef ExitBlocks,
163 ArrayRef InsertPts)
164 : LoadAndStorePromoter({L, S}, SSA), Store(S), ExitBlocks(ExitBlocks),
165 InsertPts(InsertPts) {
166 assert(isa(L));
167 assert(isa(S));
168 SSA.AddAvailableValue(PH, Init);
169 }
170 void doExtraRewritesBeforeFinalDeletion() const override {
171 for (unsigned i = 0, e = ExitBlocks.size(); i != e; ++i) {
172 BasicBlock *ExitBlock = ExitBlocks[i];
173 Instruction *InsertPos = InsertPts[i];
174 // Get LiveIn value into the ExitBlock. If there are multiple
175 // predecessors, the value is defined by a PHI node in this
176 // block.
177 Value *LiveInValue = SSA.GetValueInMiddleOfBlock(ExitBlock);
178 Value *Addr = cast(Store)->getPointerOperand();
179 IRBuilder<> Builder(InsertPos);
180 if (AtomicCounterUpdatePromoted)
181 Builder.CreateAtomicRMW(AtomicRMWInst::Add, Addr, LiveInValue,
182 AtomicOrdering::SequentiallyConsistent);
183 else {
184 LoadInst *OldVal = Builder.CreateLoad(Addr, "pgocount.promoted");
185 auto *NewVal = Builder.CreateAdd(OldVal, LiveInValue);
186 Builder.CreateStore(NewVal, Addr);
187 }
188 }
189 }
190
191 private:
192 Instruction *Store;
193 ArrayRef ExitBlocks;
194 ArrayRef InsertPts;
195 };
196
197 /// A helper class to do register promotion for all profile counter
198 /// updates in a loop.
199 ///
200 class PGOCounterPromoter {
201 public:
202 PGOCounterPromoter(ArrayRef Cands, Loop &Loop)
203 : Candidates(Cands), ExitBlocks(), InsertPts(), ParentLoop(Loop) {
204
205 SmallVector LoopExitBlocks;
206 SmallPtrSet BlockSet;
207 ParentLoop.getExitBlocks(LoopExitBlocks);
208
209 for (BasicBlock *ExitBlock : LoopExitBlocks) {
210 if (BlockSet.insert(ExitBlock).second) {
211 ExitBlocks.push_back(ExitBlock);
212 InsertPts.push_back(&*ExitBlock->getFirstInsertionPt());
213 }
214 }
215 }
216
217 bool run(int64_t *NumPromoted) {
218 // We can't insert into a catchswitch.
219 bool HasCatchSwitch = llvm::any_of(ExitBlocks, [](BasicBlock *Exit) {
220 return isa(Exit->getTerminator());
221 });
222
223 if (HasCatchSwitch)
224 return false;
225
226 if (!ParentLoop.hasDedicatedExits())
227 return false;
228
229 BasicBlock *PH = ParentLoop.getLoopPreheader();
230 if (!PH)
231 return false;
232
233 BasicBlock *H = ParentLoop.getHeader();
234 bool TopTested =
235 ((ParentLoop.getBlocks().size() > 1) && ParentLoop.isLoopExiting(H));
236 if (!SpeculativeCounterPromotion &&
237 (TopTested || ParentLoop.getExitingBlock() == nullptr))
238 return false;
239
240 unsigned Promoted = 0;
241 for (auto &Cand : Candidates) {
242
243 SmallVector NewPHIs;
244 SSAUpdater SSA(&NewPHIs);
245 Value *InitVal = ConstantInt::get(Cand.first->getType(), 0);
246 PGOCounterPromoterHelper Promoter(Cand.first, Cand.second, SSA, InitVal,
247 PH, ExitBlocks, InsertPts);
248 Promoter.run(SmallVector({Cand.first, Cand.second}));
249 Promoted++;
250 if (Promoted >= MaxNumOfPromotionsPerLoop)
251 break;
252 (*NumPromoted)++;
253 if (MaxNumOfPromotions != -1 && *NumPromoted >= MaxNumOfPromotions)
254 break;
255 }
256
257 DEBUG(dbgs() << Promoted << " counters promoted for loop (depth="
258 << ParentLoop.getLoopDepth() << ")\n");
259 return Promoted != 0;
260 }
261
262 private:
263 ArrayRef Candidates;
264 SmallVector ExitBlocks;
265 SmallVector InsertPts;
266 Loop &ParentLoop;
116267 };
117268
118269 } // end anonymous namespace
144295 if (Inc)
145296 return Inc;
146297 return dyn_cast(Instr);
298 }
299
300 bool InstrProfiling::lowerIntrinsics(Function *F) {
301 bool MadeChange = false;
302 PromotionCandidates.clear();
303 for (BasicBlock &BB : *F) {
304 for (auto I = BB.begin(), E = BB.end(); I != E;) {
305 auto Instr = I++;
306 InstrProfIncrementInst *Inc = castToIncrementInst(&*Instr);
307 if (Inc) {
308 lowerIncrement(Inc);
309 MadeChange = true;
310 } else if (auto *Ind = dyn_cast(Instr)) {
311 lowerValueProfileInst(Ind);
312 MadeChange = true;
313 }
314 }
315 }
316
317 if (!MadeChange)
318 return false;
319
320 promoteCounterLoadStores(F);
321 return true;
322 }
323
324 bool InstrProfiling::isCounterPromotionEnabled() const {
325 if (DoCounterPromotion.getNumOccurrences() > 0)
326 return DoCounterPromotion;
327
328 return Options.DoCounterPromotion;
329 }
330
331 void InstrProfiling::promoteCounterLoadStores(Function *F) {
332 if (!isCounterPromotionEnabled())
333 return;
334
335 DominatorTree DT(*F);
336 LoopInfo LI(DT);
337 DenseMap> LoopPromotionCandidates;
338
339 for (const auto &LoadStore : PromotionCandidates) {
340 auto *CounterLoad = LoadStore.first;
341 auto *CounterStore = LoadStore.second;
342 BasicBlock *BB = CounterLoad->getParent();
343 Loop *ParentLoop = LI.getLoopFor(BB);
344 if (!ParentLoop)
345 continue;
346 LoopPromotionCandidates[ParentLoop].emplace_back(CounterLoad, CounterStore);
347 }
348
349 SmallVector Loops = LI.getLoopsInPreorder();
350
351 for (auto *Loop : Loops) {
352 PGOCounterPromoter Promoter(LoopPromotionCandidates[Loop], *Loop);
353 Promoter.run(&TotalCountersPromoted);
354 }
147355 }
148356
149357 bool InstrProfiling::run(Module &M, const TargetLibraryInfo &TLI) {
178386 }
179387
180388 for (Function &F : M)
181 for (BasicBlock &BB : F)
182 for (auto I = BB.begin(), E = BB.end(); I != E;) {
183 auto Instr = I++;
184 InstrProfIncrementInst *Inc = castToIncrementInst(&*Instr);
185 if (Inc) {
186 lowerIncrement(Inc);
187 MadeChange = true;
188 } else if (auto *Ind = dyn_cast(Instr)) {
189 lowerValueProfileInst(Ind);
190 MadeChange = true;
191 }
192 }
389 MadeChange |= lowerIntrinsics(&F);
193390
194391 if (GlobalVariable *CoverageNamesVar =
195392 M.getNamedGlobal(getCoverageUnusedNamesVarName())) {
302499 IRBuilder<> Builder(Inc);
303500 uint64_t Index = Inc->getIndex()->getZExtValue();
304501 Value *Addr = Builder.CreateConstInBoundsGEP2_64(Counters, 0, Index);
305 Value *Count = Builder.CreateLoad(Addr, "pgocount");
306 Count = Builder.CreateAdd(Count, Inc->getStep());
307 Inc->replaceAllUsesWith(Builder.CreateStore(Count, Addr));
502 Value *Load = Builder.CreateLoad(Addr, "pgocount");
503 auto *Count = Builder.CreateAdd(Load, Inc->getStep());
504 auto *Store = Builder.CreateStore(Count, Addr);
505 Inc->replaceAllUsesWith(Store);
506 if (isCounterPromotionEnabled())
507 PromotionCandidates.emplace_back(cast(Load), Store);
308508 Inc->eraseFromParent();
309509 }
310510
0 ; RUN: opt < %s -pgo-instr-gen -instrprof -do-counter-promotion=true -S | FileCheck --check-prefix=PROMO --check-prefix=NONATOMIC_PROMO %s
1 ; RUN: opt < %s --passes=pgo-instr-gen,instrprof -do-counter-promotion=true -S | FileCheck --check-prefix=PROMO --check-prefix=NONATOMIC_PROMO %s
2 ; RUN: opt < %s -pgo-instr-gen -instrprof -do-counter-promotion=true -atomic-counter-update-promoted -S | FileCheck --check-prefix=PROMO --check-prefix=ATOMIC_PROMO %s
3 ; RUN: opt < %s --passes=pgo-instr-gen,instrprof -do-counter-promotion=true -atomic-counter-update-promoted -S | FileCheck --check-prefix=PROMO --check-prefix=ATOMIC_PROMO %s
4
5 define void @foo(i32 %n, i32 %N) {
6 ; PROMO-LABEL: @foo
7 bb:
8 %tmp = add nsw i32 %n, 1
9 %tmp1 = add nsw i32 %n, -1
10 br label %bb2
11
12 bb2: ; preds = %bb9, %bb
13 ; PROMO: phi {{.*}}
14 ; PROMO-NEXT: phi {{.*}}
15 ; PROMO-NEXT: phi {{.*}}
16 ; PROMO-NEXT: phi {{.*}}
17 %i.0 = phi i32 [ 0, %bb ], [ %tmp10, %bb9 ]
18 %tmp3 = icmp slt i32 %i.0, %tmp
19 br i1 %tmp3, label %bb4, label %bb5
20
21 bb4: ; preds = %bb2
22 tail call void @bar(i32 1)
23 br label %bb9
24
25 bb5: ; preds = %bb2
26 %tmp6 = icmp slt i32 %i.0, %tmp1
27 br i1 %tmp6, label %bb7, label %bb8
28
29 bb7: ; preds = %bb5
30 tail call void @bar(i32 2)
31 br label %bb9
32
33 bb8: ; preds = %bb5
34 tail call void @bar(i32 3)
35 br label %bb9
36
37 bb9: ; preds = %bb8, %bb7, %bb4
38 ; PROMO: %[[LIVEOUT3:[a-z0-9]+]] = phi {{.*}}
39 ; PROMO-NEXT: %[[LIVEOUT2:[a-z0-9]+]] = phi {{.*}}
40 ; PROMO-NEXT: %[[LIVEOUT1:[a-z0-9]+]] = phi {{.*}}
41 %tmp10 = add nsw i32 %i.0, 1
42 %tmp11 = icmp slt i32 %tmp10, %N
43 br i1 %tmp11, label %bb2, label %bb12
44
45 bb12: ; preds = %bb9
46 ret void
47 ; NONATOMIC_PROMO: %[[PROMO1:[a-z0-9.]+]] = load {{.*}} @__profc_foo{{.*}} 0)
48 ; NONATOMIC_PROMO-NEXT: add {{.*}} %[[PROMO1]], %[[LIVEOUT1]]
49 ; NONATOMIC_PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}0)
50 ; NONATOMIC_PROMO-NEXT: %[[PROMO2:[a-z0-9.]+]] = load {{.*}} @__profc_foo{{.*}} 1)
51 ; NONATOMIC_PROMO-NEXT: add {{.*}} %[[PROMO2]], %[[LIVEOUT2]]
52 ; NONATOMIC_PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}1)
53 ; NONATOMIC_PROMO-NEXT: %[[PROMO3:[a-z0-9.]+]] = load {{.*}} @__profc_foo{{.*}} 2)
54 ; NONATOMIC_PROMO-NEXT: add {{.*}} %[[PROMO3]], %[[LIVEOUT3]]
55 ; NONATOMIC_PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}2)
56 ; ATOMIC_PROMO: atomicrmw add {{.*}} @__profc_foo{{.*}}0), i64 %[[LIVEOUT1]] seq_cst
57 ; ATOMIC_PROMO-NEXT: atomicrmw add {{.*}} @__profc_foo{{.*}}1), i64 %[[LIVEOUT2]] seq_cst
58 ; ATOMIC_PROMO-NEXT: atomicrmw add {{.*}} @__profc_foo{{.*}}2), i64 %[[LIVEOUT3]] seq_cst
59 ; PROMO: {{.*}} = load {{.*}} @__profc_foo{{.*}} 3)
60 ; PROMO-NEXT: add
61 ; PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}3)
62 ; PROMO-NOT: @__profc_foo
63
64
65 }
66
67 declare void @bar(i32)
0 ; RUN: opt < %s -instrprof -do-counter-promotion=true -speculative-counter-promotion -S | FileCheck --check-prefix=PROMO %s
1 ; RUN: opt < %s --passes=instrprof -do-counter-promotion=true -speculative-counter-promotion -S | FileCheck --check-prefix=PROMO %s
2
3 $__llvm_profile_raw_version = comdat any
4
5 @g = common local_unnamed_addr global i32 0, align 4
6 @__llvm_profile_raw_version = constant i64 72057594037927940, comdat
7 @__profn_foo = private constant [3 x i8] c"foo"
8
9 define void @foo(i32 %arg) local_unnamed_addr {
10 bb:
11 %tmp = add nsw i32 %arg, -1
12 br label %bb1
13
14 bb1: ; preds = %bb11, %bb
15 %tmp2 = phi i32 [ 0, %bb ], [ %tmp12, %bb11 ]
16 %tmp3 = icmp sgt i32 %tmp2, %arg
17 br i1 %tmp3, label %bb7, label %bb4
18
19 bb4: ; preds = %bb1
20 call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_foo, i32 0, i32 0), i64 63969943867, i32 5, i32 1)
21 tail call void @bar(i32 1)
22 %tmp5 = load i32, i32* @g, align 4
23 %tmp6 = icmp sgt i32 %tmp5, 100
24 br i1 %tmp6, label %bb14, label %bb11
25
26 bb7: ; preds = %bb1
27 %tmp8 = icmp slt i32 %tmp2, %tmp
28 br i1 %tmp8, label %bb9, label %bb10
29
30 bb9: ; preds = %bb7
31 call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_foo, i32 0, i32 0), i64 63969943867, i32 5, i32 2)
32 tail call void @bar(i32 2)
33 br label %bb11
34
35 bb10: ; preds = %bb7
36 call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_foo, i32 0, i32 0), i64 63969943867, i32 5, i32 3)
37 tail call void @bar(i32 3)
38 br label %bb11
39
40 bb11: ; preds = %bb10, %bb9, %bb4
41 %tmp12 = add nuw nsw i32 %tmp2, 1
42 %tmp13 = icmp slt i32 %tmp2, 99
43 br i1 %tmp13, label %bb1, label %bb14
44
45 bb14: ; preds = %bb4.bb14_crit_edge, %bb11
46 tail call void @bar(i32 0)
47 br label %bb15
48 ; PROMO-LABEL: bb14:
49 ; PROMO: %[[MERGE1:[a-z0-9]+]] = phi {{.*}}
50 ; PROMO-NEXT: %[[MERGE2:[a-z0-9.]+]] = phi {{.*}}
51 ; PROMO-NEXT: %[[MERGE3:[a-z0-9.]+]] = phi {{.*}}
52 ; PROMO-NEXT: %[[PROMO3:[a-z0-9.]+]] = load{{.*}}@__profc_foo{{.*}}1)
53 ; PROMO-NEXT: {{.*}} = add {{.*}}%[[PROMO3]], %[[MERGE3]]
54 ; PROMO-NEXT: store{{.*}}@__profc_foo{{.*}}1)
55 ; PROMO-NEXT: %[[PROMO2:[a-z0-9.]+]] = load{{.*}}@__profc_foo{{.*}}2)
56 ; PROMO-NEXT: {{.*}} = add {{.*}}%[[PROMO2]], %[[MERGE2]]
57 ; PROMO-NEXT: store{{.*}}@__profc_foo{{.*}}2)
58 ; PROMO-NEXT: %[[PROMO1:[a-z0-9.]+]] = load{{.*}}@__profc_foo{{.*}}3)
59 ; PROMO-NEXT: {{.*}} = add {{.*}}%[[PROMO1]], %[[MERGE1]]
60 ; PROMO-NEXT: store{{.*}}@__profc_foo{{.*}}3)
61
62 bb15: ; preds = %bb14
63 call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_foo, i32 0, i32 0), i64 63969943867, i32 5, i32 4)
64 tail call void @bar(i32 1)
65 ret void
66 }
67
68 declare void @bar(i32) local_unnamed_addr
69
70 ; Function Attrs: nounwind
71 declare void @llvm.instrprof.increment(i8*, i64, i32, i32) #0
72
73 attributes #0 = { nounwind }
0 ; RUN: opt < %s -pgo-instr-gen -instrprof -do-counter-promotion=true -speculative-counter-promotion -S | FileCheck --check-prefix=PROMO %s
1 ; RUN: opt < %s --passes=pgo-instr-gen,instrprof -do-counter-promotion=true -speculative-counter-promotion -S | FileCheck --check-prefix=PROMO %s
2
3 @g = common local_unnamed_addr global i32 0, align 4
4
5 define void @foo(i32 %arg) local_unnamed_addr {
6 ; PROMO-LABEL: @foo
7 bb:
8 %tmp = add nsw i32 %arg, -1
9 br label %bb1
10 bb1: ; preds = %bb11, %bb
11 %tmp2 = phi i32 [ 0, %bb ], [ %tmp12, %bb11 ]
12 %tmp3 = icmp sgt i32 %tmp2, %arg
13 br i1 %tmp3, label %bb7, label %bb4
14
15 bb4: ; preds = %bb1
16 tail call void @bar(i32 1)
17 %tmp5 = load i32, i32* @g, align 4
18 %tmp6 = icmp sgt i32 %tmp5, 100
19 br i1 %tmp6, label %bb15_0, label %bb11
20
21 bb7: ; preds = %bb1
22 %tmp8 = icmp slt i32 %tmp2, %tmp
23 br i1 %tmp8, label %bb9, label %bb10
24
25 bb9: ; preds = %bb7
26 tail call void @bar(i32 2)
27 br label %bb11
28
29 bb10: ; preds = %bb7
30 tail call void @bar(i32 3)
31 br label %bb11
32
33 bb11: ; preds = %bb10, %bb9, %bb4
34 %tmp12 = add nuw nsw i32 %tmp2, 1
35 %tmp13 = icmp slt i32 %tmp2, 99
36 br i1 %tmp13, label %bb1, label %bb14
37
38 bb14: ; preds = %bb11
39 ; PROMO-LABEL: bb14:
40 tail call void @bar(i32 0)
41 br label %bb15
42 ; PROMO: %pgocount.promoted{{.*}} = load {{.*}} @__profc_foo{{.*}} 0)
43 ; PROMO-NEXT: add
44 ; PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}0)
45 ; PROMO-NEXT: %pgocount.promoted{{.*}} = load {{.*}} @__profc_foo{{.*}} 1)
46 ; PROMO-NEXT: add
47 ; PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}1)
48 ; PROMO-NEXT: %pgocount.promoted{{.*}} = load {{.*}} @__profc_foo{{.*}} 2)
49 ; PROMO-NEXT: add
50 ; PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}2)
51 ; PROMO-NEXT: %pgocount{{.*}} = load {{.*}} @__profc_foo{{.*}} 3)
52 ; PROMO-NEXT: add
53 ; PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}3)
54
55
56 bb15_0: ; preds = %bb11
57 ; PROMO-LABEL: bb15_0:
58 br label %bb15
59 ; PROMO: %pgocount.promoted{{.*}} = load {{.*}} @__profc_foo{{.*}} 0)
60 ; PROMO-NEXT: add
61 ; PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}0)
62 ; PROMO-NEXT: %pgocount.promoted{{.*}} = load {{.*}} @__profc_foo{{.*}} 1)
63 ; PROMO-NEXT: add
64 ; PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}1)
65 ; PROMO-NEXT: %pgocount.promoted{{.*}} = load {{.*}} @__profc_foo{{.*}} 2)
66 ; PROMO-NEXT: add
67 ; PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}2)
68 ; PROMO-NEXT: %pgocount{{.*}} = load {{.*}} @__profc_foo{{.*}} 4)
69 ; PROMO-NEXT: add
70 ; PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}4)
71 ; PROMO-NOT: @__profc_foo
72
73
74 bb15: ; preds = %bb14, %bb4
75 tail call void @bar(i32 1)
76 ret void
77 }
78
79 declare void @bar(i32) local_unnamed_addr