Skip to content

Commit 60c8e02

Browse files
fhahntstellar
authored andcommitted
[IPSCCP] Support unfeasible default dests for switch.
At the moment, unfeasible default destinations are not handled properly in removeNonFeasibleEdges. So far, only unfeasible cases are removed, but later code expects unreachable blocks to have no predecessors. This is causing the crash reported in PR49573. If the default destination is unfeasible it won't be executed. Create a new unreachable block on demand and use that as default destination. Note that at the moment this only is relevant for cases where resolvedUndefsIn marks the first case as executable. Regular switch handling has a FIXME/TODO to support determining whether the default case is feasible or not. Fixes #48917. Differential Revision: https://reviews.llvm.org/D113497 (cherry picked from commit 857c612)
1 parent 0108630 commit 60c8e02

File tree

2 files changed

+166
-7
lines changed

2 files changed

+166
-7
lines changed

llvm/lib/Transforms/Scalar/SCCP.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,8 @@ static void findReturnsToZap(Function &F,
342342
}
343343

344344
static bool removeNonFeasibleEdges(const SCCPSolver &Solver, BasicBlock *BB,
345-
DomTreeUpdater &DTU) {
345+
DomTreeUpdater &DTU,
346+
BasicBlock *&NewUnreachableBB) {
346347
SmallPtrSet<BasicBlock *, 8> FeasibleSuccessors;
347348
bool HasNonFeasibleEdges = false;
348349
for (BasicBlock *Succ : successors(BB)) {
@@ -385,6 +386,23 @@ static bool removeNonFeasibleEdges(const SCCPSolver &Solver, BasicBlock *BB,
385386
} else if (FeasibleSuccessors.size() > 1) {
386387
SwitchInstProfUpdateWrapper SI(*cast<SwitchInst>(TI));
387388
SmallVector<DominatorTree::UpdateType, 8> Updates;
389+
390+
// If the default destination is unfeasible it will never be taken. Replace
391+
// it with a new block with a single Unreachable instruction.
392+
BasicBlock *DefaultDest = SI->getDefaultDest();
393+
if (!FeasibleSuccessors.contains(DefaultDest)) {
394+
if (!NewUnreachableBB) {
395+
NewUnreachableBB =
396+
BasicBlock::Create(DefaultDest->getContext(), "default.unreachable",
397+
DefaultDest->getParent(), DefaultDest);
398+
new UnreachableInst(DefaultDest->getContext(), NewUnreachableBB);
399+
}
400+
401+
SI->setDefaultDest(NewUnreachableBB);
402+
Updates.push_back({DominatorTree::Delete, BB, DefaultDest});
403+
Updates.push_back({DominatorTree::Insert, BB, NewUnreachableBB});
404+
}
405+
388406
for (auto CI = SI->case_begin(); CI != SI->case_end();) {
389407
if (FeasibleSuccessors.contains(CI->getCaseSuccessor())) {
390408
++CI;
@@ -532,8 +550,9 @@ bool llvm::runIPSCCP(
532550
NumInstRemoved += changeToUnreachable(F.front().getFirstNonPHI(),
533551
/*PreserveLCSSA=*/false, &DTU);
534552

553+
BasicBlock *NewUnreachableBB = nullptr;
535554
for (BasicBlock &BB : F)
536-
MadeChanges |= removeNonFeasibleEdges(Solver, &BB, DTU);
555+
MadeChanges |= removeNonFeasibleEdges(Solver, &BB, DTU, NewUnreachableBB);
537556

538557
for (BasicBlock *DeadBB : BlocksToErase)
539558
DTU.deleteBB(DeadBB);

llvm/test/Transforms/SCCP/switch-constantfold-crash.ll

Lines changed: 145 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2-
; RUN: opt -passes=ipsccp < %s -S | FileCheck %s
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
2+
; RUN: opt -passes=ipsccp < %s -S | FileCheck --check-prefixes=CHECK,ONCE %s
3+
; RUN: opt -passes='ipsccp,ipsccp' < %s -S | FileCheck --check-prefixes=CHECK,TWICE %s
34

45
define void @barney() {
5-
; CHECK-LABEL: @barney(
6+
; CHECK-LABEL: define {{[^@]+}}@barney() {
67
; CHECK-NEXT: bb:
78
; CHECK-NEXT: br label [[BB9:%.*]]
89
; CHECK: bb6:
@@ -26,7 +27,7 @@ bb9: ; preds = %bb
2627
}
2728

2829
define void @blam() {
29-
; CHECK-LABEL: @blam(
30+
; CHECK-LABEL: define {{[^@]+}}@blam() {
3031
; CHECK-NEXT: bb:
3132
; CHECK-NEXT: br label [[BB16:%.*]]
3233
; CHECK: bb16:
@@ -59,7 +60,7 @@ bb38: ; preds = %bb16
5960

6061

6162
define void @hoge() {
62-
; CHECK-LABEL: @hoge(
63+
; CHECK-LABEL: define {{[^@]+}}@hoge() {
6364
; CHECK-NEXT: bb:
6465
; CHECK-NEXT: br label [[BB2:%.*]]
6566
; CHECK: bb2:
@@ -89,3 +90,142 @@ bb3: ; preds = %bb2
8990
bb4: ; preds = %bb2, %bb2, %bb2
9091
unreachable
9192
}
93+
94+
; Test case from PR49573. %default.bb is unfeasible. Make sure it gets replaced
95+
; by an unreachable block.
96+
define void @pr49573_main() {
97+
; ONCE-LABEL: define {{[^@]+}}@pr49573_main() {
98+
; ONCE-NEXT: entry:
99+
; ONCE-NEXT: [[TGT:%.*]] = call i16 @pr49573_fn()
100+
; ONCE-NEXT: switch i16 2, label [[DEFAULT_UNREACHABLE:%.*]] [
101+
; ONCE-NEXT: i16 0, label [[CASE_0:%.*]]
102+
; ONCE-NEXT: i16 2, label [[CASE_2:%.*]]
103+
; ONCE-NEXT: ]
104+
; ONCE: case.0:
105+
; ONCE-NEXT: unreachable
106+
; ONCE: default.unreachable:
107+
; ONCE-NEXT: unreachable
108+
; ONCE: case.2:
109+
; ONCE-NEXT: br label [[NEXT:%.*]]
110+
; ONCE: next:
111+
; ONCE-NEXT: [[TGT_2:%.*]] = call i16 @pr49573_fn_2()
112+
; ONCE-NEXT: switch i16 2, label [[DEFAULT_UNREACHABLE]] [
113+
; ONCE-NEXT: i16 0, label [[CASE_0]]
114+
; ONCE-NEXT: i16 2, label [[CASE_2]]
115+
; ONCE-NEXT: ]
116+
;
117+
; TWICE-LABEL: define {{[^@]+}}@pr49573_main() {
118+
; TWICE-NEXT: entry:
119+
; TWICE-NEXT: [[TGT:%.*]] = call i16 @pr49573_fn()
120+
; TWICE-NEXT: br label [[CASE_2:%.*]]
121+
; TWICE: case.2:
122+
; TWICE-NEXT: br label [[NEXT:%.*]]
123+
; TWICE: next:
124+
; TWICE-NEXT: [[TGT_2:%.*]] = call i16 @pr49573_fn_2()
125+
; TWICE-NEXT: br label [[CASE_2]]
126+
;
127+
entry:
128+
%tgt = call i16 @pr49573_fn()
129+
switch i16 %tgt, label %default.bb [
130+
i16 0, label %case.0
131+
i16 1, label %case.1
132+
i16 2, label %case.2
133+
]
134+
135+
case.0:
136+
unreachable
137+
138+
default.bb:
139+
ret void
140+
141+
case.1:
142+
ret void
143+
144+
case.2:
145+
br label %next
146+
147+
next:
148+
%tgt.2 = call i16 @pr49573_fn_2()
149+
switch i16 %tgt.2, label %default.bb [
150+
i16 0, label %case.0
151+
i16 2, label %case.2
152+
]
153+
}
154+
155+
; Make sure a new unreachable BB is created.
156+
define void @pr49573_main_2() {
157+
; ONCE-LABEL: define {{[^@]+}}@pr49573_main_2() {
158+
; ONCE-NEXT: entry:
159+
; ONCE-NEXT: [[TGT:%.*]] = call i16 @pr49573_fn()
160+
; ONCE-NEXT: switch i16 2, label [[DEFAULT_UNREACHABLE:%.*]] [
161+
; ONCE-NEXT: i16 0, label [[CASE_0:%.*]]
162+
; ONCE-NEXT: i16 2, label [[CASE_2:%.*]]
163+
; ONCE-NEXT: ]
164+
; ONCE: case.0:
165+
; ONCE-NEXT: unreachable
166+
; ONCE: default.unreachable:
167+
; ONCE-NEXT: unreachable
168+
; ONCE: case.2:
169+
; ONCE-NEXT: ret void
170+
;
171+
; TWICE-LABEL: define {{[^@]+}}@pr49573_main_2() {
172+
; TWICE-NEXT: entry:
173+
; TWICE-NEXT: [[TGT:%.*]] = call i16 @pr49573_fn()
174+
; TWICE-NEXT: br label [[CASE_2:%.*]]
175+
; TWICE: case.2:
176+
; TWICE-NEXT: ret void
177+
;
178+
entry:
179+
%tgt = call i16 @pr49573_fn()
180+
switch i16 %tgt, label %default.bb [
181+
i16 0, label %case.0
182+
i16 1, label %case.1
183+
i16 2, label %case.2
184+
]
185+
186+
case.0:
187+
unreachable
188+
189+
default.bb:
190+
ret void
191+
192+
case.1:
193+
ret void
194+
195+
case.2:
196+
ret void
197+
}
198+
199+
define internal i16 @pr49573_fn() {
200+
; CHECK-LABEL: define {{[^@]+}}@pr49573_fn() {
201+
; CHECK-NEXT: entry:
202+
; CHECK-NEXT: br label [[ELSE:%.*]]
203+
; CHECK: else:
204+
; CHECK-NEXT: ret i16 undef
205+
;
206+
entry:
207+
br i1 undef, label %then, label %else
208+
209+
then:
210+
ret i16 0
211+
212+
else:
213+
ret i16 2
214+
}
215+
216+
define internal i16 @pr49573_fn_2() {
217+
; CHECK-LABEL: define {{[^@]+}}@pr49573_fn_2() {
218+
; CHECK-NEXT: entry:
219+
; CHECK-NEXT: br label [[ELSE:%.*]]
220+
; CHECK: else:
221+
; CHECK-NEXT: ret i16 undef
222+
;
223+
entry:
224+
br i1 undef, label %then, label %else
225+
226+
then:
227+
ret i16 0
228+
229+
else:
230+
ret i16 2
231+
}

0 commit comments

Comments
 (0)