Skip to content

Commit ce9209f

Browse files
authored
[ctx_prof] Fix ProfileAnnotator::allTakenPathsExit (#109183)
Added tests to the validator and fixed issues stemming from the previous skipping over BBs with single successors - which is incorrect. That would be now picked by added tests where the assertions are expected to be triggered.
1 parent 156035e commit ce9209f

File tree

2 files changed

+104
-10
lines changed

2 files changed

+104
-10
lines changed

llvm/lib/Transforms/Instrumentation/PGOCtxProfFlattening.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -233,28 +233,37 @@ class ProfileAnnotator final {
233233
std::deque<const BasicBlock *> Worklist;
234234
DenseSet<const BasicBlock *> Visited;
235235
Worklist.push_back(&F.getEntryBlock());
236-
Visited.insert(&F.getEntryBlock());
236+
bool HitExit = false;
237237
while (!Worklist.empty()) {
238238
const auto *BB = Worklist.front();
239239
Worklist.pop_front();
240-
if (succ_size(BB) <= 1)
240+
if (!Visited.insert(BB).second)
241241
continue;
242+
if (succ_size(BB) == 0) {
243+
if (isa<UnreachableInst>(BB->getTerminator()))
244+
return false;
245+
HitExit = true;
246+
continue;
247+
}
248+
if (succ_size(BB) == 1) {
249+
llvm::append_range(Worklist, successors(BB));
250+
continue;
251+
}
242252
const auto &BBInfo = getBBInfo(*BB);
243-
bool Inserted = false;
253+
bool HasAWayOut = false;
244254
for (auto I = 0U; I < BB->getTerminator()->getNumSuccessors(); ++I) {
245255
const auto *Succ = BB->getTerminator()->getSuccessor(I);
246256
if (!shouldExcludeEdge(*BB, *Succ)) {
247-
if (BBInfo.getEdgeCount(I) > 0)
248-
if (Visited.insert(Succ).second) {
249-
Worklist.push_back(Succ);
250-
Inserted = true;
251-
}
257+
if (BBInfo.getEdgeCount(I) > 0) {
258+
HasAWayOut = true;
259+
Worklist.push_back(Succ);
260+
}
252261
}
253262
}
254-
if (!Inserted)
263+
if (!HasAWayOut)
255264
return false;
256265
}
257-
return true;
266+
return HitExit;
258267
}
259268

260269
public:
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
; REQUIRES: asserts && x86_64-linux
2+
; Check that the profile annotator works: we hit an exit and non-zero paths to
3+
; already visited blocks count as taken (i.e. the flow continues through them).
4+
;
5+
; RUN: split-file %s %t
6+
; RUN: llvm-ctxprof-util fromJSON --input=%t/profile_ok.json --output=%t/profile_ok.ctxprofdata
7+
; RUN: llvm-ctxprof-util fromJSON --input=%t/profile_pump.json --output=%t/profile_pump.ctxprofdata
8+
; RUN: llvm-ctxprof-util fromJSON --input=%t/profile_unreachable.json --output=%t/profile_unreachable.ctxprofdata
9+
;
10+
; RUN: opt -passes=ctx-prof-flatten %t/example_ok.ll -use-ctx-profile=%t/profile_ok.ctxprofdata -S -o - | FileCheck %s
11+
; RUN: not --crash opt -passes=ctx-prof-flatten %t/message_pump.ll -use-ctx-profile=%t/profile_pump.ctxprofdata -S 2>&1 | FileCheck %s --check-prefix=ASSERTION
12+
; RUN: not --crash opt -passes=ctx-prof-flatten %t/unreachable.ll -use-ctx-profile=%t/profile_unreachable.ctxprofdata -S 2>&1 | FileCheck %s --check-prefix=ASSERTION
13+
14+
; CHECK: br i1 %x, label %b1, label %exit, !prof ![[PROF1:[0-9]+]]
15+
; CHECK: br i1 %y, label %blk, label %exit, !prof ![[PROF2:[0-9]+]]
16+
; CHECK: ![[PROF1]] = !{!"branch_weights", i32 1, i32 1}
17+
; CHECK: ![[PROF2]] = !{!"branch_weights", i32 0, i32 1}
18+
; ASSERTION: Assertion `allTakenPathsExit()
19+
20+
; b1->exit is the only way out from b1, but the exit block would have been
21+
; already visited from blk. That should not result in an assertion, though.
22+
;--- example_ok.ll
23+
define void @foo(i32 %t) !guid !0 {
24+
entry:
25+
call void @llvm.instrprof.increment(ptr @foo, i64 42, i32 42, i32 0)
26+
br label %blk
27+
blk:
28+
call void @llvm.instrprof.increment(ptr @foo, i64 42, i32 42, i32 1)
29+
%x = icmp eq i32 %t, 0
30+
br i1 %x, label %b1, label %exit
31+
b1:
32+
call void @llvm.instrprof.increment(ptr @foo, i64 42, i32 42, i32 2)
33+
%y = icmp eq i32 %t, 0
34+
br i1 %y, label %blk, label %exit
35+
exit:
36+
call void @llvm.instrprof.increment(ptr @foo, i64 42, i32 42, i32 3)
37+
ret void
38+
}
39+
!0 = !{i64 1234}
40+
41+
;--- profile_ok.json
42+
[{"Guid":1234, "Counters":[2, 2, 1, 2]}]
43+
44+
;--- message_pump.ll
45+
; This is a message pump: the loop never exits. This should result in an
46+
; assertion because we can't reach an exit BB
47+
48+
define void @foo(i32 %t) !guid !0 {
49+
entry:
50+
call void @llvm.instrprof.increment(ptr @foo, i64 42, i32 42, i32 0)
51+
br label %blk
52+
blk:
53+
call void @llvm.instrprof.increment(ptr @foo, i64 42, i32 42, i32 1)
54+
%x = icmp eq i32 %t, 0
55+
br i1 %x, label %blk, label %exit
56+
exit:
57+
call void @llvm.instrprof.increment(ptr @foo, i64 42, i32 42, i32 2)
58+
ret void
59+
}
60+
!0 = !{i64 1234}
61+
62+
;--- profile_pump.json
63+
[{"Guid":1234, "Counters":[2, 10, 0]}]
64+
65+
;--- unreachable.ll
66+
; An unreachable block is reached, that's an error
67+
define void @foo(i32 %t) !guid !0 {
68+
entry:
69+
call void @llvm.instrprof.increment(ptr @foo, i64 42, i32 42, i32 0)
70+
br label %blk
71+
blk:
72+
call void @llvm.instrprof.increment(ptr @foo, i64 42, i32 42, i32 1)
73+
%x = icmp eq i32 %t, 0
74+
br i1 %x, label %b1, label %exit
75+
b1:
76+
call void @llvm.instrprof.increment(ptr @foo, i64 42, i32 42, i32 2)
77+
unreachable
78+
exit:
79+
call void @llvm.instrprof.increment(ptr @foo, i64 42, i32 42, i32 3)
80+
ret void
81+
}
82+
!0 = !{i64 1234}
83+
84+
;--- profile_unreachable.json
85+
[{"Guid":1234, "Counters":[2, 1, 1, 2]}]

0 commit comments

Comments
 (0)