Skip to content

Commit e94372d

Browse files
rotaterighttstellar
authored andcommitted
[SimplifyCFG] avoid sinking insts within an infinite-loop
The test is reduced from a C source example in: https://llvm.org/PR49541 It's possible that the test could be reduced further or the predicate generalized further, but it seems to require a few ingredients (including the "late" SimplifyCFG options on the RUN line) to fall into the infinite-loop trap. (cherry picked from commit bd197ed)
1 parent f4c01f3 commit e94372d

File tree

2 files changed

+61
-7
lines changed

2 files changed

+61
-7
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,11 @@ static bool canSinkInstructions(
16281628
I->getType()->isTokenTy())
16291629
return false;
16301630

1631+
// Do not try to sink an instruction in an infinite loop - it can cause
1632+
// this algorithm to infinite loop.
1633+
if (I->getParent()->getSingleSuccessor() == I->getParent())
1634+
return false;
1635+
16311636
// Conservatively return false if I is an inline-asm instruction. Sinking
16321637
// and merging inline-asm instructions can potentially create arguments
16331638
// that cannot satisfy the inline-asm constraints.
@@ -1714,13 +1719,13 @@ static bool canSinkInstructions(
17141719
return true;
17151720
}
17161721

1717-
// Assuming canSinkLastInstruction(Blocks) has returned true, sink the last
1722+
// Assuming canSinkInstructions(Blocks) has returned true, sink the last
17181723
// instruction of every block in Blocks to their common successor, commoning
17191724
// into one instruction.
17201725
static bool sinkLastInstruction(ArrayRef<BasicBlock*> Blocks) {
17211726
auto *BBEnd = Blocks[0]->getTerminator()->getSuccessor(0);
17221727

1723-
// canSinkLastInstruction returning true guarantees that every block has at
1728+
// canSinkInstructions returning true guarantees that every block has at
17241729
// least one non-terminator instruction.
17251730
SmallVector<Instruction*,4> Insts;
17261731
for (auto *BB : Blocks) {
@@ -1733,9 +1738,9 @@ static bool sinkLastInstruction(ArrayRef<BasicBlock*> Blocks) {
17331738
}
17341739

17351740
// The only checking we need to do now is that all users of all instructions
1736-
// are the same PHI node. canSinkLastInstruction should have checked this but
1737-
// it is slightly over-aggressive - it gets confused by commutative instructions
1738-
// so double-check it here.
1741+
// are the same PHI node. canSinkInstructions should have checked this but
1742+
// it is slightly over-aggressive - it gets confused by commutative
1743+
// instructions so double-check it here.
17391744
Instruction *I0 = Insts.front();
17401745
if (!I0->user_empty()) {
17411746
auto *PNUse = dyn_cast<PHINode>(*I0->user_begin());
@@ -1746,11 +1751,11 @@ static bool sinkLastInstruction(ArrayRef<BasicBlock*> Blocks) {
17461751
return false;
17471752
}
17481753

1749-
// We don't need to do any more checking here; canSinkLastInstruction should
1754+
// We don't need to do any more checking here; canSinkInstructions should
17501755
// have done it all for us.
17511756
SmallVector<Value*, 4> NewOperands;
17521757
for (unsigned O = 0, E = I0->getNumOperands(); O != E; ++O) {
1753-
// This check is different to that in canSinkLastInstruction. There, we
1758+
// This check is different to that in canSinkInstructions. There, we
17541759
// cared about the global view once simplifycfg (and instcombine) have
17551760
// completed - it takes into account PHIs that become trivially
17561761
// simplifiable. However here we need a more local view; if an operand
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -keep-loops=false -sink-common-insts=true -S | FileCheck %s
3+
4+
; This would infinite-loop because we allowed code sinking to examine an infinite-loop block (%j).
5+
6+
define void @PR49541(i32* %t1, i32 %a, i1 %bool) {
7+
; CHECK-LABEL: @PR49541(
8+
; CHECK-NEXT: entry:
9+
; CHECK-NEXT: br label [[I:%.*]]
10+
; CHECK: j:
11+
; CHECK-NEXT: [[T3:%.*]] = phi i32 [ [[B:%.*]], [[J:%.*]] ], [ [[A:%.*]], [[COND_TRUE:%.*]] ], [ [[A]], [[COND_FALSE:%.*]] ]
12+
; CHECK-NEXT: [[T2:%.*]] = phi i32 [ [[T2]], [[J]] ], [ [[PRE2:%.*]], [[COND_TRUE]] ], [ 0, [[COND_FALSE]] ]
13+
; CHECK-NEXT: [[B]] = load i32, i32* [[T1:%.*]], align 4
14+
; CHECK-NEXT: br label [[J]]
15+
; CHECK: i:
16+
; CHECK-NEXT: [[G_1:%.*]] = phi i16 [ undef, [[ENTRY:%.*]] ], [ [[G_1]], [[COND_FALSE]] ]
17+
; CHECK-NEXT: br i1 [[BOOL:%.*]], label [[COND_FALSE]], label [[COND_TRUE]]
18+
; CHECK: cond.true:
19+
; CHECK-NEXT: [[TOBOOL9_NOT:%.*]] = icmp eq i16 [[G_1]], 0
20+
; CHECK-NEXT: [[PRE2]] = load i32, i32* [[T1]], align 4
21+
; CHECK-NEXT: br label [[J]]
22+
; CHECK: cond.false:
23+
; CHECK-NEXT: [[T5:%.*]] = load i32, i32* [[T1]], align 4
24+
; CHECK-NEXT: [[B2:%.*]] = icmp eq i32 [[T5]], 0
25+
; CHECK-NEXT: br i1 [[B2]], label [[J]], label [[I]]
26+
;
27+
entry:
28+
br label %i
29+
30+
j:
31+
%t3 = phi i32 [ %b, %j ], [ %a, %cond.true ], [ %a, %cond.false ]
32+
%t2 = phi i32 [ %t2, %j ], [ %pre2, %cond.true ], [ 0, %cond.false ]
33+
%b = load i32, i32* %t1, align 4
34+
br label %j
35+
36+
i:
37+
%g.1 = phi i16 [ undef, %entry ], [ %g.1, %cond.false ]
38+
br i1 %bool, label %cond.false, label %cond.true
39+
40+
cond.true:
41+
%tobool9.not = icmp eq i16 %g.1, 0
42+
%pre2 = load i32, i32* %t1, align 4
43+
br label %j
44+
45+
cond.false:
46+
%t5 = load i32, i32* %t1, align 4
47+
%b2 = icmp eq i32 %t5, 0
48+
br i1 %b2, label %j, label %i
49+
}

0 commit comments

Comments
 (0)