Skip to content

Commit 1f88d80

Browse files
committed
[SCCP] Don't mark edges feasible when resolving undefs
As branch on undef is immediate undefined behavior, there is no need to mark one of the edges as feasible. We can leave all the edges non-feasible. In IPSCCP, we can replace the branch with an unreachable terminator. Differential Revision: https://reviews.llvm.org/D126962
1 parent 74f0660 commit 1f88d80

12 files changed

+71
-215
lines changed

llvm/lib/Transforms/Scalar/SCCP.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,19 @@ static bool removeNonFeasibleEdges(const SCCPSolver &Solver, BasicBlock *BB,
371371
isa<IndirectBrInst>(TI)) &&
372372
"Terminator must be a br, switch or indirectbr");
373373

374-
if (FeasibleSuccessors.size() == 1) {
374+
if (FeasibleSuccessors.size() == 0) {
375+
// Branch on undef/poison, replace with unreachable.
376+
SmallPtrSet<BasicBlock *, 8> SeenSuccs;
377+
SmallVector<DominatorTree::UpdateType, 8> Updates;
378+
for (BasicBlock *Succ : successors(BB)) {
379+
Succ->removePredecessor(BB);
380+
if (SeenSuccs.insert(Succ).second)
381+
Updates.push_back({DominatorTree::Delete, BB, Succ});
382+
}
383+
TI->eraseFromParent();
384+
new UnreachableInst(BB->getContext(), BB);
385+
DTU.applyUpdatesPermissive(Updates);
386+
} else if (FeasibleSuccessors.size() == 1) {
375387
// Replace with an unconditional branch to the only feasible successor.
376388
BasicBlock *OnlyFeasibleSuccessor = *FeasibleSuccessors.begin();
377389
SmallVector<DominatorTree::UpdateType, 8> Updates;

llvm/lib/Transforms/Utils/SCCPSolver.cpp

Lines changed: 12 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,22 +1444,19 @@ void SCCPInstVisitor::solve() {
14441444
}
14451445
}
14461446

1447-
/// resolvedUndefsIn - While solving the dataflow for a function, we assume
1448-
/// that branches on undef values cannot reach any of their successors.
1449-
/// However, this is not a safe assumption. After we solve dataflow, this
1450-
/// method should be use to handle this. If this returns true, the solver
1451-
/// should be rerun.
1447+
/// While solving the dataflow for a function, we don't compute a result for
1448+
/// operations with an undef operand, to allow undef to be lowered to a
1449+
/// constant later. For example, constant folding of "zext i8 undef to i16"
1450+
/// would result in "i16 0", and if undef is later lowered to "i8 1", then the
1451+
/// zext result would become "i16 1" and would result into an overdefined
1452+
/// lattice value once merged with the previous result. Not computing the
1453+
/// result of the zext (treating undef the same as unknown) allows us to handle
1454+
/// a later undef->constant lowering more optimally.
14521455
///
1453-
/// This method handles this by finding an unresolved branch and marking it one
1454-
/// of the edges from the block as being feasible, even though the condition
1455-
/// doesn't say it would otherwise be. This allows SCCP to find the rest of the
1456-
/// CFG and only slightly pessimizes the analysis results (by marking one,
1457-
/// potentially infeasible, edge feasible). This cannot usefully modify the
1458-
/// constraints on the condition of the branch, as that would impact other users
1459-
/// of the value.
1460-
///
1461-
/// This scan also checks for values that use undefs. It conservatively marks
1462-
/// them as overdefined.
1456+
/// However, if the operand remains undef when the solver returns, we do need
1457+
/// to assign some result to the instruction (otherwise we would treat it as
1458+
/// unreachable). For simplicity, we mark any instructions that are still
1459+
/// unknown/undef as overdefined.
14631460
bool SCCPInstVisitor::resolvedUndefsIn(Function &F) {
14641461
bool MadeChange = false;
14651462
for (BasicBlock &BB : F) {
@@ -1520,91 +1517,6 @@ bool SCCPInstVisitor::resolvedUndefsIn(Function &F) {
15201517
markOverdefined(&I);
15211518
MadeChange = true;
15221519
}
1523-
1524-
// Check to see if we have a branch or switch on an undefined value. If so
1525-
// we force the branch to go one way or the other to make the successor
1526-
// values live. It doesn't really matter which way we force it.
1527-
Instruction *TI = BB.getTerminator();
1528-
if (auto *BI = dyn_cast<BranchInst>(TI)) {
1529-
if (!BI->isConditional())
1530-
continue;
1531-
if (!getValueState(BI->getCondition()).isUnknownOrUndef())
1532-
continue;
1533-
1534-
// If the input to SCCP is actually branch on undef, fix the undef to
1535-
// false.
1536-
if (isa<UndefValue>(BI->getCondition())) {
1537-
BI->setCondition(ConstantInt::getFalse(BI->getContext()));
1538-
markEdgeExecutable(&BB, TI->getSuccessor(1));
1539-
MadeChange = true;
1540-
continue;
1541-
}
1542-
1543-
// Otherwise, it is a branch on a symbolic value which is currently
1544-
// considered to be undef. Make sure some edge is executable, so a
1545-
// branch on "undef" always flows somewhere.
1546-
// FIXME: Distinguish between dead code and an LLVM "undef" value.
1547-
BasicBlock *DefaultSuccessor = TI->getSuccessor(1);
1548-
if (markEdgeExecutable(&BB, DefaultSuccessor))
1549-
MadeChange = true;
1550-
1551-
continue;
1552-
}
1553-
1554-
if (auto *IBR = dyn_cast<IndirectBrInst>(TI)) {
1555-
// Indirect branch with no successor ?. Its ok to assume it branches
1556-
// to no target.
1557-
if (IBR->getNumSuccessors() < 1)
1558-
continue;
1559-
1560-
if (!getValueState(IBR->getAddress()).isUnknownOrUndef())
1561-
continue;
1562-
1563-
// If the input to SCCP is actually branch on undef, fix the undef to
1564-
// the first successor of the indirect branch.
1565-
if (isa<UndefValue>(IBR->getAddress())) {
1566-
IBR->setAddress(BlockAddress::get(IBR->getSuccessor(0)));
1567-
markEdgeExecutable(&BB, IBR->getSuccessor(0));
1568-
MadeChange = true;
1569-
continue;
1570-
}
1571-
1572-
// Otherwise, it is a branch on a symbolic value which is currently
1573-
// considered to be undef. Make sure some edge is executable, so a
1574-
// branch on "undef" always flows somewhere.
1575-
// FIXME: IndirectBr on "undef" doesn't actually need to go anywhere:
1576-
// we can assume the branch has undefined behavior instead.
1577-
BasicBlock *DefaultSuccessor = IBR->getSuccessor(0);
1578-
if (markEdgeExecutable(&BB, DefaultSuccessor))
1579-
MadeChange = true;
1580-
1581-
continue;
1582-
}
1583-
1584-
if (auto *SI = dyn_cast<SwitchInst>(TI)) {
1585-
if (!SI->getNumCases() ||
1586-
!getValueState(SI->getCondition()).isUnknownOrUndef())
1587-
continue;
1588-
1589-
// If the input to SCCP is actually switch on undef, fix the undef to
1590-
// the first constant.
1591-
if (isa<UndefValue>(SI->getCondition())) {
1592-
SI->setCondition(SI->case_begin()->getCaseValue());
1593-
markEdgeExecutable(&BB, SI->case_begin()->getCaseSuccessor());
1594-
MadeChange = true;
1595-
continue;
1596-
}
1597-
1598-
// Otherwise, it is a branch on a symbolic value which is currently
1599-
// considered to be undef. Make sure some edge is executable, so a
1600-
// branch on "undef" always flows somewhere.
1601-
// FIXME: Distinguish between dead code and an LLVM "undef" value.
1602-
BasicBlock *DefaultSuccessor = SI->case_begin()->getCaseSuccessor();
1603-
if (markEdgeExecutable(&BB, DefaultSuccessor))
1604-
MadeChange = true;
1605-
1606-
continue;
1607-
}
16081520
}
16091521

16101522
return MadeChange;

llvm/test/Transforms/FunctionSpecialization/bug52821-use-after-free.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ for.body: ; preds = %for.cond
3434

3535
for.cond2: ; preds = %for.body2, %for.cond
3636
%phi2 = phi %mystruct* [ undef, %for.body2 ], [ null, %for.cond ]
37-
br i1 undef, label %for.end, label %for.body2
37+
br i1 false, label %for.end, label %for.body2
3838

3939
for.body2: ; preds = %for.cond2
4040
%arrayidx = getelementptr inbounds %mystruct, %mystruct* %phi2, i64 0, i32 1, i64 3

llvm/test/Transforms/FunctionSpecialization/bug55000-read-uninitialized-value.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ declare hidden { i8, ptr } @getType(ptr) align 2
1010
define internal void @foo(ptr %TLI, ptr %DL, ptr %Ty, ptr %ValueVTs, ptr %Offsets, i64 %StartingOffset) {
1111
entry:
1212
%VT = alloca i64, align 8
13-
br i1 undef, label %if.then, label %if.end4
13+
br i1 false, label %if.then, label %if.end4
1414

1515
if.then: ; preds = %entry
1616
ret void

llvm/test/Transforms/SCCP/2004-12-10-UndefBranchBug.ll

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
22
; RUN: opt < %s -passes=sccp -S | FileCheck %s
33

4-
; This function definitely returns 1, even if we don't know the direction
5-
; of the branch.
4+
; Branch on undef is UB, so the T block is never executed, and we can return
5+
; undef (IPSCCP would replace the block with unreachable).
66

77
define i32 @foo() {
88
; CHECK-LABEL: @foo(
9-
; CHECK-NEXT: br i1 false, label [[T:%.*]], label [[T]]
9+
; CHECK-NEXT: br i1 undef, label [[T:%.*]], label [[T]]
1010
; CHECK: T:
11-
; CHECK-NEXT: [[X:%.*]] = add i32 0, 1
12-
; CHECK-NEXT: ret i32 [[X]]
11+
; CHECK-NEXT: ret i32 undef
1312
;
1413
br i1 undef, label %T, label %T
1514
T:

llvm/test/Transforms/SCCP/2008-01-27-UndefCorrelate.ll

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,16 @@ define i32 @main() {
77
; CHECK-NEXT: entry:
88
; CHECK-NEXT: br label [[BB:%.*]]
99
; CHECK: bb:
10-
; CHECK-NEXT: [[INDVAR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[K:%.*]], [[BB_BACKEDGE:%.*]] ]
11-
; CHECK-NEXT: [[K]] = add i32 [[INDVAR]], 1
12-
; CHECK-NEXT: br i1 false, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
10+
; CHECK-NEXT: br i1 undef, label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
1311
; CHECK: cond_true:
14-
; CHECK-NEXT: br i1 undef, label [[BB_BACKEDGE]], label [[BB12:%.*]]
12+
; CHECK-NEXT: br i1 undef, label [[BB_BACKEDGE:%.*]], label [[BB12:%.*]]
1513
; CHECK: bb.backedge:
1614
; CHECK-NEXT: br label [[BB]]
1715
; CHECK: cond_false:
18-
; CHECK-NEXT: [[TMP9:%.*]] = icmp slt i32 [[K]], 10
19-
; CHECK-NEXT: br i1 [[TMP9]], label [[BB_BACKEDGE]], label [[BB12]]
16+
; CHECK-NEXT: br i1 undef, label [[BB_BACKEDGE]], label [[BB12]]
2017
; CHECK: bb12:
21-
; CHECK-NEXT: [[TMP14:%.*]] = icmp eq i32 [[K]], 10
22-
; CHECK-NEXT: br i1 [[TMP14]], label [[COND_NEXT18:%.*]], label [[COND_TRUE17:%.*]]
18+
; CHECK-NEXT: br i1 undef, label [[COND_NEXT18:%.*]], label [[COND_TRUE17:%.*]]
2319
; CHECK: cond_true17:
24-
; CHECK-NEXT: tail call void @abort()
2520
; CHECK-NEXT: unreachable
2621
; CHECK: cond_next18:
2722
; CHECK-NEXT: ret i32 0

llvm/test/Transforms/SCCP/PR26044.ll

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ target triple = "x86_64-unknown-linux-gnu"
55

66
define void @fn2(i32* %P) {
77
; CHECK-LABEL: define {{[^@]+}}@fn2
8-
; CHECK-SAME: (i32* [[P:%.*]])
8+
; CHECK-SAME: (i32* [[P:%.*]]) {
99
; CHECK-NEXT: entry:
1010
; CHECK-NEXT: br label [[IF_END:%.*]]
1111
; CHECK: for.cond1:
12-
; CHECK-NEXT: br i1 false, label [[IF_END]], label [[IF_END]]
12+
; CHECK-NEXT: unreachable
1313
; CHECK: if.end:
14-
; CHECK-NEXT: [[CALL:%.*]] = call i32 @fn1(i32 undef)
15-
; CHECK-NEXT: store i32 [[CALL]], i32* [[P]]
14+
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* undef, align 4
15+
; CHECK-NEXT: [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]])
16+
; CHECK-NEXT: store i32 [[CALL]], i32* [[P]], align 4
1617
; CHECK-NEXT: br label [[FOR_COND1:%.*]]
1718
;
1819
entry:
@@ -31,10 +32,10 @@ if.end: ; preds = %lbl, %for.cond1
3132

3233
define internal i32 @fn1(i32 %p1) {
3334
; CHECK-LABEL: define {{[^@]+}}@fn1
34-
; CHECK-SAME: (i32 [[P1:%.*]])
35+
; CHECK-SAME: (i32 [[P1:%.*]]) {
3536
; CHECK-NEXT: entry:
36-
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 undef, 0
37-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 undef, i32 undef
37+
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[P1]], 0
38+
; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 [[P1]], i32 [[P1]]
3839
; CHECK-NEXT: ret i32 [[COND]]
3940
;
4041
entry:
@@ -45,15 +46,15 @@ entry:
4546

4647
define void @fn_no_null_opt(i32* %P) #0 {
4748
; CHECK-LABEL: define {{[^@]+}}@fn_no_null_opt
48-
; CHECK-SAME: (i32* [[P:%.*]])
49+
; CHECK-SAME: (i32* [[P:%.*]]) #[[ATTR0:[0-9]+]] {
4950
; CHECK-NEXT: entry:
5051
; CHECK-NEXT: br label [[IF_END:%.*]]
5152
; CHECK: for.cond1:
52-
; CHECK-NEXT: br i1 false, label [[IF_END]], label [[IF_END]]
53+
; CHECK-NEXT: unreachable
5354
; CHECK: if.end:
54-
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* null, align 4
55+
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* undef, align 4
5556
; CHECK-NEXT: [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]])
56-
; CHECK-NEXT: store i32 [[CALL]], i32* [[P]]
57+
; CHECK-NEXT: store i32 [[CALL]], i32* [[P]], align 4
5758
; CHECK-NEXT: br label [[FOR_COND1:%.*]]
5859
;
5960
entry:
@@ -72,7 +73,7 @@ if.end: ; preds = %lbl, %for.cond1
7273

7374
define internal i32 @fn0(i32 %p1) {
7475
; CHECK-LABEL: define {{[^@]+}}@fn0
75-
; CHECK-SAME: (i32 [[P1:%.*]])
76+
; CHECK-SAME: (i32 [[P1:%.*]]) {
7677
; CHECK-NEXT: entry:
7778
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[P1]], 0
7879
; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 [[P1]], i32 [[P1]]

llvm/test/Transforms/SCCP/indirectbr.ll

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,12 @@ BB1:
7474
ret void
7575
}
7676

77-
; Make sure we eliminate BB1 as we pick the first successor on undef.
77+
; Branch on undef is UB, so we can convert the indirectbr to unreachable.
7878

7979
define void @indbrtest4(i8** %Q) {
8080
; CHECK-LABEL: @indbrtest4(
8181
; CHECK-NEXT: entry:
82-
; CHECK-NEXT: br label [[BB0:%.*]]
83-
; CHECK: BB0:
84-
; CHECK-NEXT: call void @BB0_f()
85-
; CHECK-NEXT: ret void
82+
; CHECK-NEXT: unreachable
8683
;
8784
entry:
8885
indirectbr i8* undef, [label %BB0, label %BB1]

llvm/test/Transforms/SCCP/ipsccp-branch-unresolved-undef.ll

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ define void @main() {
1313
define internal i1 @patatino(i1 %a) {
1414
; CHECK-LABEL: define {{[^@]+}}@patatino
1515
; CHECK-SAME: (i1 [[A:%.*]]) {
16-
; CHECK-NEXT: br label [[ONFALSE:%.*]]
17-
; CHECK: onfalse:
18-
; CHECK-NEXT: ret i1 undef
16+
; CHECK-NEXT: unreachable
1917
;
2018
br i1 %a, label %ontrue, label %onfalse
2119
ontrue:

llvm/test/Transforms/SCCP/return-zapped.ll

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
22
; RUN: opt < %s -S -passes=ipsccp | FileCheck %s
33

4-
; After the first round of Solver.Solve(), the return value of @testf still
5-
; undefined as we hit a branch on undef. Therefore the conditional branch on
6-
; @testf's return value in @bar is unknown. In ResolvedUndefsIn, we force the
7-
; false branch to be feasible. We later discover that @testf actually
8-
; returns true, so we end up with an unfolded "br i1 true".
4+
; testf() performs an unconditional branch on undef, as such the testf() return
5+
; value used in test1() will remain "unknown" and the following branch on it
6+
; replaced by unreachable. This is fine, as the call to testf() will already
7+
; trigger undefined behavior.
98
define void @test1() {
109
; CHECK-LABEL: define {{[^@]+}}@test1() {
1110
; CHECK-NEXT: entry:
1211
; CHECK-NEXT: br label [[IF_THEN:%.*]]
1312
; CHECK: if.then:
14-
; CHECK-NEXT: [[FOO:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[IF_THEN]] ]
15-
; CHECK-NEXT: [[NEXT]] = add i32 [[FOO]], 1
1613
; CHECK-NEXT: [[CALL:%.*]] = call i1 @testf()
17-
; CHECK-NEXT: br i1 true, label [[IF_END:%.*]], label [[IF_THEN]]
18-
; CHECK: if.end:
19-
; CHECK-NEXT: ret void
14+
; CHECK-NEXT: unreachable
2015
;
2116
entry:
2217
br label %if.then
@@ -33,9 +28,7 @@ if.end: ; preds = %if.then, %entry
3328
define internal i1 @testf() {
3429
; CHECK-LABEL: define {{[^@]+}}@testf() {
3530
; CHECK-NEXT: entry:
36-
; CHECK-NEXT: br label [[IF_END3:%.*]]
37-
; CHECK: if.end3:
38-
; CHECK-NEXT: ret i1 undef
31+
; CHECK-NEXT: unreachable
3932
;
4033
entry:
4134
br i1 undef, label %if.then1, label %if.end3
@@ -54,7 +47,7 @@ define i1 @test2() {
5447
; CHECK-NEXT: br label [[IF_END:%.*]]
5548
; CHECK: if.end:
5649
; CHECK-NEXT: [[CALL2:%.*]] = call i1 @testf()
57-
; CHECK-NEXT: ret i1 true
50+
; CHECK-NEXT: ret i1 undef
5851
;
5952
entry:
6053
br label %if.end

0 commit comments

Comments
 (0)