Skip to content

Commit 0856592

Browse files
authored
Ensure collectTransitivePredecessors returns Pred only from the Loop. (#113831)
It's possible that we encounter Irreducible control flow, due to which, we may find that a few predecessors of BB are not a part of the CurLoop. Currently we crash in the function for such cases. This patch ensures that we only return Predecessors that are a part of CurLoop and gracefully ignore other Predecessors. For example, consider Irreducible IR of this form: ``` define i64 @baz() { bb: br label %bb1 bb1: ; preds = %bb3, %bb br label %bb3 bb2: ; No predecessors! br label %bb3 bb3: ; preds = %bb2, %bb1 %load = load ptr addrspace(1), ptr addrspace(1) null, align 8 br label %bb1 } ``` This crashes when `collectTransitivePredecessors` is called on the `%bb1<Header>, %bb3<latch>` loop, because the loop body has a predecessor `%bb2` which is not a part of the loop. See https://godbolt.org/z/E9fM1q3cT for the crash
1 parent 25fd366 commit 0856592

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

llvm/lib/Analysis/MustExecute.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ static bool CanProveNotTakenFirstIteration(const BasicBlock *ExitBlock,
162162
/// Collect all blocks from \p CurLoop which lie on all possible paths from
163163
/// the header of \p CurLoop (inclusive) to BB (exclusive) into the set
164164
/// \p Predecessors. If \p BB is the header, \p Predecessors will be empty.
165+
/// Note: It's possible that we encounter Irreducible control flow, due to
166+
/// which, we may find that a few predecessors of \p BB are not a part of the
167+
/// \p CurLoop. We only return Predecessors that are a part of \p CurLoop.
165168
static void collectTransitivePredecessors(
166169
const Loop *CurLoop, const BasicBlock *BB,
167170
SmallPtrSetImpl<const BasicBlock *> &Predecessors) {
@@ -171,6 +174,8 @@ static void collectTransitivePredecessors(
171174
return;
172175
SmallVector<const BasicBlock *, 4> WorkList;
173176
for (const auto *Pred : predecessors(BB)) {
177+
if (!CurLoop->contains(Pred))
178+
continue;
174179
Predecessors.insert(Pred);
175180
WorkList.push_back(Pred);
176181
}
@@ -187,7 +192,7 @@ static void collectTransitivePredecessors(
187192
// We can ignore backedge of all loops containing BB to get a sligtly more
188193
// optimistic result.
189194
for (const auto *PredPred : predecessors(Pred))
190-
if (Predecessors.insert(PredPred).second)
195+
if (CurLoop->contains(PredPred) && Predecessors.insert(PredPred).second)
191196
WorkList.push_back(PredPred);
192197
}
193198
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -disable-output -passes=print-mustexecute %s 2>&1 | FileCheck %s
3+
4+
; The loop body has two predecessors, %header and %side-entry. This leads to irreducible-cfg
5+
define i64 @baz() {
6+
; CHECK-LABEL: define i64 @baz() {
7+
; CHECK-NEXT: [[ENTRY:.*:]]
8+
; CHECK-NEXT: br label %[[HEADER:.*]]
9+
; CHECK: [[HEADER]]:
10+
; CHECK-NEXT: br label %[[BODY:.*]] ; (mustexec in: header)
11+
; CHECK: [[SIDE_ENTRY:.*:]]
12+
; CHECK-NEXT: br label %[[BODY]]
13+
; CHECK: [[BODY]]:
14+
; CHECK-NEXT: [[LOAD:%.*]] = load ptr addrspace(1), ptr addrspace(1) null, align 8 ; (mustexec in: header)
15+
; CHECK-NEXT: br label %[[HEADER]] ; (mustexec in: header)
16+
;
17+
entry:
18+
br label %header
19+
20+
header:
21+
br label %body
22+
23+
side-entry:
24+
br label %body
25+
26+
body:
27+
%load = load ptr addrspace(1), ptr addrspace(1) null, align 8
28+
br label %header
29+
}

0 commit comments

Comments
 (0)