Skip to content

Commit 3ab467b

Browse files
committed
Ensure collectTransitivePredecessors returns Pred only from the Loop.
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.
1 parent 0b7e8c2 commit 3ab467b

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)