Skip to content

Commit ea2f539

Browse files
[SimplifyCFG] Avoid threading for loop headers (#151142)
Updates SimplifyCFG to avoid jump threading through loop headers if -keep-loops is requested. Canonical loop form requires a loop header that dominates all blocks in the loop. If we thread through a header, we risk breaking its domination of the loop. This change avoids this issue by conservatively avoiding threading through headers entirely. Fixes: #151144
1 parent 169b43d commit ea2f539

File tree

7 files changed

+80
-14
lines changed

7 files changed

+80
-14
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ class SimplifyCFGOpt {
291291
bool simplifyBranch(BranchInst *Branch, IRBuilder<> &Builder);
292292
bool simplifyUncondBranch(BranchInst *BI, IRBuilder<> &Builder);
293293
bool simplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder);
294+
bool foldCondBranchOnValueKnownInPredecessor(BranchInst *BI);
294295

295296
bool tryToSimplifyUncondBranchWithICmpInIt(ICmpInst *ICI,
296297
IRBuilder<> &Builder);
@@ -3669,15 +3670,19 @@ foldCondBranchOnValueKnownInPredecessorImpl(BranchInst *BI, DomTreeUpdater *DTU,
36693670
return false;
36703671
}
36713672

3672-
static bool foldCondBranchOnValueKnownInPredecessor(BranchInst *BI,
3673-
DomTreeUpdater *DTU,
3674-
const DataLayout &DL,
3675-
AssumptionCache *AC) {
3673+
bool SimplifyCFGOpt::foldCondBranchOnValueKnownInPredecessor(BranchInst *BI) {
3674+
// Note: If BB is a loop header then there is a risk that threading introduces
3675+
// a non-canonical loop by moving a back edge. So we avoid this optimization
3676+
// for loop headers if NeedCanonicalLoop is set.
3677+
if (Options.NeedCanonicalLoop && is_contained(LoopHeaders, BI->getParent()))
3678+
return false;
3679+
36763680
std::optional<bool> Result;
36773681
bool EverChanged = false;
36783682
do {
36793683
// Note that None means "we changed things, but recurse further."
3680-
Result = foldCondBranchOnValueKnownInPredecessorImpl(BI, DTU, DL, AC);
3684+
Result =
3685+
foldCondBranchOnValueKnownInPredecessorImpl(BI, DTU, DL, Options.AC);
36813686
EverChanged |= Result == std::nullopt || *Result;
36823687
} while (Result == std::nullopt);
36833688
return EverChanged;
@@ -8099,7 +8104,7 @@ bool SimplifyCFGOpt::simplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder) {
80998104
// If this is a branch on something for which we know the constant value in
81008105
// predecessors (e.g. a phi node in the current block), thread control
81018106
// through this block.
8102-
if (foldCondBranchOnValueKnownInPredecessor(BI, DTU, DL, Options.AC))
8107+
if (foldCondBranchOnValueKnownInPredecessor(BI))
81038108
return requestResimplify();
81048109

81058110
// Scan predecessor blocks for conditional branches.

llvm/test/CodeGen/ARM/2013-05-05-IfConvertBug.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2-
; RUN: llc < %s -mtriple=thumbv7-apple-ios -mcpu=cortex-a8 | FileCheck %s
3-
; RUN: llc < %s -mtriple=thumbv8 | FileCheck -check-prefix=CHECK-V8 %s
4-
; RUN: llc < %s -mtriple=thumbv7 -arm-restrict-it | FileCheck -check-prefix=CHECK-RESTRICT-IT %s
2+
; RUN: llc -keep-loops="false" < %s -mtriple=thumbv7-apple-ios -mcpu=cortex-a8 | FileCheck %s
3+
; RUN: llc -keep-loops="false" < %s -mtriple=thumbv8 | FileCheck -check-prefix=CHECK-V8 %s
4+
; RUN: llc -keep-loops="false" < %s -mtriple=thumbv7 -arm-restrict-it | FileCheck -check-prefix=CHECK-RESTRICT-IT %s
55

66
define i32 @t1(i32 %a, i32 %b, ptr %retaddr) {
77
; CHECK-LABEL: t1:

llvm/test/Transforms/SimplifyCFG/2008-07-13-InfLoopMiscompile.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2-
; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
2+
; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -keep-loops="false" -S | FileCheck %s
33
; PR2540
44
; Outval should end up with a select from 0/2, not all constants.
55

@@ -52,4 +52,3 @@ func_1.exit: ; preds = %cowblock, %entry
5252
}
5353

5454
declare i32 @printf(ptr, ...) nounwind
55-
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 --keep-loops="true" -S | FileCheck --check-prefix=NO-THREADING %s
3+
; Checks that we do not thread the control flow through the loop header loop_header as
4+
; that will introduce a non-canonical loop.
5+
6+
; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 --keep-loops="false" -S | FileCheck --check-prefix=THREADING %s
7+
; Checks that we thread the control flow through the loop header loop_header since we
8+
; do not request --keep-loops.
9+
10+
define void @__start(i1 %cond) {
11+
; NO-THREADING-LABEL: define void @__start(
12+
; NO-THREADING-SAME: i1 [[COND:%.*]]) {
13+
; NO-THREADING-NEXT: [[ENTRY:.*:]]
14+
; NO-THREADING-NEXT: br label %[[LOOP_HEADER:.*]]
15+
; NO-THREADING: [[LOOP_HEADER]]:
16+
; NO-THREADING-NEXT: br i1 [[COND]], label %[[LOOP_BODY_1:.*]], label %[[LOOP_BODY_0:.*]]
17+
; NO-THREADING: [[LOOP_BODY_0]]:
18+
; NO-THREADING-NEXT: [[_0_:%.*]] = add i16 0, 0
19+
; NO-THREADING-NEXT: br label %[[LOOP_EXIT:.*]]
20+
; NO-THREADING: [[LOOP_BODY_1]]:
21+
; NO-THREADING-NEXT: [[_1_:%.*]] = add i32 0, 1
22+
; NO-THREADING-NEXT: br label %[[LOOP_EXIT]]
23+
; NO-THREADING: [[LOOP_EXIT]]:
24+
; NO-THREADING-NEXT: br i1 [[COND]], label %[[LOOP_HEADER]], label %[[EXIT:.*]]
25+
; NO-THREADING: [[EXIT]]:
26+
; NO-THREADING-NEXT: ret void
27+
;
28+
; THREADING-LABEL: define void @__start(
29+
; THREADING-SAME: i1 [[COND:%.*]]) {
30+
; THREADING-NEXT: [[ENTRY:.*:]]
31+
; THREADING-NEXT: br i1 [[COND]], label %[[LOOP_BODY_1:.*]], label %[[LOOP_BODY_0:.*]]
32+
; THREADING: [[LOOP_BODY_0]]:
33+
; THREADING-NEXT: [[_0_:%.*]] = add i16 0, 0
34+
; THREADING-NEXT: br label %[[LOOP_EXIT:.*]]
35+
; THREADING: [[LOOP_BODY_1]]:
36+
; THREADING-NEXT: [[_1_:%.*]] = add i32 0, 1
37+
; THREADING-NEXT: br label %[[LOOP_EXIT]]
38+
; THREADING: [[LOOP_EXIT]]:
39+
; THREADING-NEXT: br i1 [[COND]], label %[[LOOP_BODY_1]], label %[[EXIT:.*]]
40+
; THREADING: [[EXIT]]:
41+
; THREADING-NEXT: ret void
42+
;
43+
entry:
44+
br label %loop_header
45+
46+
loop_header: ; preds = %loop_exit, %entry
47+
br i1 %cond, label %loop_body_1, label %loop_body_0
48+
49+
loop_body_0: ; preds = %loop_header
50+
%_0_ = add i16 0, 0
51+
br label %loop_exit
52+
53+
loop_body_1: ; preds = %loop_header
54+
%_1_ = add i32 0, 1
55+
br label %loop_exit
56+
57+
loop_exit: ; preds = %loop_body_1, %loop_body_0
58+
br i1 %cond, label %loop_header, label %exit
59+
60+
exit: ; preds = %loop_exit
61+
ret void
62+
}

llvm/test/Transforms/SimplifyCFG/branch-phi-thread.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2-
; RUN: opt < %s -passes=simplifycfg,adce -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
2+
; RUN: opt < %s -passes=simplifycfg,adce -simplifycfg-require-and-preserve-domtree=1 -keep-loops="false" -S | FileCheck %s
33

44
declare void @f1()
55

llvm/test/Transforms/SimplifyCFG/jump-threading.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2-
; RUN: opt -S -passes=simplifycfg < %s | FileCheck %s
2+
; RUN: opt -S -passes=simplifycfg -keep-loops="false" < %s | FileCheck %s
33

44
declare void @foo()
55
declare void @bar()

llvm/test/Transforms/SimplifyCFG/two-entry-phi-return.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2-
; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
2+
; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -keep-loops="false" -S | FileCheck %s
33

44
define i1 @qux(ptr %m, ptr %n, ptr %o, ptr %p) nounwind {
55
; CHECK-LABEL: @qux(

0 commit comments

Comments
 (0)