Skip to content

Commit 2b089e9

Browse files
committed
[SimplifyCFG] Try to merge edge block when threading (PR55765)
When threading, we always create a new block for the threaded edge (even if the edge is not critical), which will later get folded back into the predecessor if possible. Depending on precise processing order, this separate block may break the detection of trivial cycles in the threading code, which normally avoids infinite threading of loops. Explicitly merge the created edge block into the predecessor to avoid this. Fixes llvm#55765. Differential Revision: https://reviews.llvm.org/D127216
1 parent 809999a commit 2b089e9

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3145,6 +3145,12 @@ FoldCondBranchOnValueKnownInPredecessorImpl(BranchInst *BI, DomTreeUpdater *DTU,
31453145
DTU->applyUpdates(Updates);
31463146
}
31473147

3148+
// For simplicity, we created a separate basic block for the edge. Merge
3149+
// it back into the predecessor if possible. This not only avoids
3150+
// unnecessary SimplifyCFG iterations, but also makes sure that we don't
3151+
// bypass the check for trivial cycles above.
3152+
MergeBlockIntoPredecessor(EdgeBB, DTU);
3153+
31483154
// Signal repeat, simplifying any other constants.
31493155
return None;
31503156
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -S -simplifycfg < %s | FileCheck %s
3+
4+
; This used to infinitely thread between loop and loop.latch without reaching a
5+
; fixed point.
6+
7+
declare void @dummy()
8+
9+
define i32 @main(i1 %c1, i1 %c2, i32 %y) {
10+
; CHECK-LABEL: @main(
11+
; CHECK-NEXT: br i1 [[C1:%.*]], label [[EXIT:%.*]], label [[LOOP_PRE_PREHEADER:%.*]]
12+
; CHECK: loop.pre.preheader:
13+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[Y:%.*]], -1
14+
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP_PREHEADER:%.*]], label [[EXIT]]
15+
; CHECK: loop.preheader:
16+
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[Y]], 0
17+
; CHECK-NEXT: br label [[LOOP:%.*]]
18+
; CHECK: loop:
19+
; CHECK-NEXT: br i1 [[C1]], label [[LOOP2:%.*]], label [[LOOP]]
20+
; CHECK: loop.latch:
21+
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT]]
22+
; CHECK: loop2:
23+
; CHECK-NEXT: br i1 [[CMP2]], label [[JOIN:%.*]], label [[IF:%.*]]
24+
; CHECK: if:
25+
; CHECK-NEXT: call void @dummy()
26+
; CHECK-NEXT: br label [[JOIN]]
27+
; CHECK: join:
28+
; CHECK-NEXT: br i1 [[C2:%.*]], label [[LOOP2]], label [[LOOP_LATCH:%.*]]
29+
; CHECK: exit:
30+
; CHECK-NEXT: ret i32 0
31+
;
32+
br i1 %c1, label %exit, label %loop.pre.preheader
33+
34+
loop.pre.preheader:
35+
%cmp = icmp sgt i32 %y, -1
36+
br i1 %cmp, label %loop.preheader, label %exit
37+
38+
loop.preheader:
39+
%cmp2 = icmp eq i32 %y, 0
40+
br label %loop
41+
42+
loop:
43+
br i1 %c1, label %loop2, label %loop.latch
44+
45+
loop.latch:
46+
br i1 %cmp, label %loop, label %exit
47+
48+
loop2:
49+
br i1 %cmp2, label %join, label %if
50+
51+
if:
52+
call void @dummy()
53+
br label %join
54+
55+
join:
56+
br i1 %c2, label %loop2, label %loop.latch
57+
58+
exit:
59+
ret i32 0
60+
61+
; uselistorder directives
62+
uselistorder label %loop2, { 1, 0 }
63+
}

0 commit comments

Comments
 (0)