Skip to content

Commit d218092

Browse files
authored
[SCCP] Check whether the default case is reachable (#76295)
This patch eliminates unreachable default cases using range information. Fixes #76085.
1 parent 67782d2 commit d218092

File tree

2 files changed

+86
-15
lines changed

2 files changed

+86
-15
lines changed

llvm/lib/Transforms/Utils/SCCPSolver.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ bool SCCPSolver::removeNonFeasibleEdges(BasicBlock *BB, DomTreeUpdater &DTU,
310310
new UnreachableInst(DefaultDest->getContext(), NewUnreachableBB);
311311
}
312312

313+
DefaultDest->removePredecessor(BB);
313314
SI->setDefaultDest(NewUnreachableBB);
314315
Updates.push_back({DominatorTree::Delete, BB, DefaultDest});
315316
Updates.push_back({DominatorTree::Insert, BB, NewUnreachableBB});
@@ -1063,14 +1064,17 @@ void SCCPInstVisitor::getFeasibleSuccessors(Instruction &TI,
10631064
// is ready.
10641065
if (SCValue.isConstantRange(/*UndefAllowed=*/false)) {
10651066
const ConstantRange &Range = SCValue.getConstantRange();
1067+
unsigned ReachableCaseCount = 0;
10661068
for (const auto &Case : SI->cases()) {
10671069
const APInt &CaseValue = Case.getCaseValue()->getValue();
1068-
if (Range.contains(CaseValue))
1070+
if (Range.contains(CaseValue)) {
10691071
Succs[Case.getSuccessorIndex()] = true;
1072+
++ReachableCaseCount;
1073+
}
10701074
}
10711075

1072-
// TODO: Determine whether default case is reachable.
1073-
Succs[SI->case_default()->getSuccessorIndex()] = true;
1076+
Succs[SI->case_default()->getSuccessorIndex()] =
1077+
Range.isSizeLargerThan(ReachableCaseCount);
10741078
return;
10751079
}
10761080

llvm/test/Transforms/SCCP/switch.ll

+79-12
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
; Make sure we always consider the default edge executable for a switch
55
; with no cases.
66
declare void @foo()
7+
declare i32 @g(i32)
8+
79
define void @test1() {
810
; CHECK-LABEL: @test1(
911
; CHECK-NEXT: switch i32 undef, label [[D:%.*]] [
@@ -115,17 +117,16 @@ switch.1:
115117
ret i32 %phi
116118
}
117119

118-
; TODO: Determine that the default destination is dead.
119120
define i32 @test_local_range(ptr %p) {
120121
; CHECK-LABEL: @test_local_range(
121122
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P:%.*]], align 4, !range [[RNG0]]
122-
; CHECK-NEXT: switch i32 [[X]], label [[SWITCH_DEFAULT:%.*]] [
123+
; CHECK-NEXT: switch i32 [[X]], label [[DEFAULT_UNREACHABLE:%.*]] [
123124
; CHECK-NEXT: i32 0, label [[SWITCH_0:%.*]]
124125
; CHECK-NEXT: i32 1, label [[SWITCH_1:%.*]]
125126
; CHECK-NEXT: i32 2, label [[SWITCH_2:%.*]]
126127
; CHECK-NEXT: ]
127-
; CHECK: switch.default:
128-
; CHECK-NEXT: ret i32 -1
128+
; CHECK: default.unreachable:
129+
; CHECK-NEXT: unreachable
129130
; CHECK: switch.0:
130131
; CHECK-NEXT: ret i32 0
131132
; CHECK: switch.1:
@@ -161,14 +162,14 @@ switch.3:
161162
define i32 @test_duplicate_successors(ptr %p) {
162163
; CHECK-LABEL: @test_duplicate_successors(
163164
; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P:%.*]], align 4, !range [[RNG0]]
164-
; CHECK-NEXT: switch i32 [[X]], label [[SWITCH_DEFAULT:%.*]] [
165+
; CHECK-NEXT: switch i32 [[X]], label [[DEFAULT_UNREACHABLE:%.*]] [
165166
; CHECK-NEXT: i32 0, label [[SWITCH_0:%.*]]
166167
; CHECK-NEXT: i32 1, label [[SWITCH_0]]
167168
; CHECK-NEXT: i32 2, label [[SWITCH_1:%.*]]
168169
; CHECK-NEXT: i32 3, label [[SWITCH_1]]
169170
; CHECK-NEXT: ]
170-
; CHECK: switch.default:
171-
; CHECK-NEXT: ret i32 -1
171+
; CHECK: default.unreachable:
172+
; CHECK-NEXT: unreachable
172173
; CHECK: switch.0:
173174
; CHECK-NEXT: ret i32 0
174175
; CHECK: switch.1:
@@ -201,13 +202,13 @@ switch.2:
201202
; range information.
202203
define internal i32 @test_ip_range(i32 %x) {
203204
; CHECK-LABEL: @test_ip_range(
204-
; CHECK-NEXT: switch i32 [[X:%.*]], label [[SWITCH_DEFAULT:%.*]] [
205+
; CHECK-NEXT: switch i32 [[X:%.*]], label [[DEFAULT_UNREACHABLE:%.*]] [
205206
; CHECK-NEXT: i32 3, label [[SWITCH_3:%.*]]
206207
; CHECK-NEXT: i32 1, label [[SWITCH_1:%.*]]
207208
; CHECK-NEXT: i32 2, label [[SWITCH_2:%.*]]
208209
; CHECK-NEXT: ], !prof [[PROF1:![0-9]+]]
209-
; CHECK: switch.default:
210-
; CHECK-NEXT: ret i32 -1
210+
; CHECK: default.unreachable:
211+
; CHECK-NEXT: unreachable
211212
; CHECK: switch.1:
212213
; CHECK-NEXT: ret i32 1
213214
; CHECK: switch.2:
@@ -240,8 +241,8 @@ switch.3:
240241

241242
define void @call_test_ip_range() {
242243
; CHECK-LABEL: @call_test_ip_range(
243-
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @test_ip_range(i32 1)
244-
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @test_ip_range(i32 3)
244+
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @test_ip_range(i32 1), !range [[RNG2:![0-9]+]]
245+
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @test_ip_range(i32 3), !range [[RNG2]]
245246
; CHECK-NEXT: ret void
246247
;
247248
call i32 @test_ip_range(i32 1)
@@ -301,6 +302,72 @@ end.2:
301302
ret i32 20
302303
}
303304

305+
define i32 @test_default_unreachable_by_dom_cond(i32 %x) {
306+
; CHECK-LABEL: @test_default_unreachable_by_dom_cond(
307+
; CHECK-NEXT: entry:
308+
; CHECK-NEXT: [[OR_COND:%.*]] = icmp ult i32 [[X:%.*]], 4
309+
; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_THEN:%.*]], label [[RETURN:%.*]]
310+
; CHECK: if.then:
311+
; CHECK-NEXT: switch i32 [[X]], label [[DEFAULT_UNREACHABLE:%.*]] [
312+
; CHECK-NEXT: i32 0, label [[SW_BB:%.*]]
313+
; CHECK-NEXT: i32 1, label [[SW_BB2:%.*]]
314+
; CHECK-NEXT: i32 2, label [[SW_BB4:%.*]]
315+
; CHECK-NEXT: i32 3, label [[SW_BB6:%.*]]
316+
; CHECK-NEXT: ]
317+
; CHECK: sw.bb:
318+
; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @g(i32 2)
319+
; CHECK-NEXT: br label [[RETURN]]
320+
; CHECK: sw.bb2:
321+
; CHECK-NEXT: [[CALL3:%.*]] = tail call i32 @g(i32 3)
322+
; CHECK-NEXT: br label [[RETURN]]
323+
; CHECK: sw.bb4:
324+
; CHECK-NEXT: [[CALL5:%.*]] = tail call i32 @g(i32 4)
325+
; CHECK-NEXT: br label [[RETURN]]
326+
; CHECK: sw.bb6:
327+
; CHECK-NEXT: [[CALL7:%.*]] = tail call i32 @g(i32 5)
328+
; CHECK-NEXT: br label [[RETURN]]
329+
; CHECK: default.unreachable:
330+
; CHECK-NEXT: unreachable
331+
; CHECK: return:
332+
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CALL7]], [[SW_BB6]] ], [ [[CALL5]], [[SW_BB4]] ], [ [[CALL3]], [[SW_BB2]] ], [ [[CALL]], [[SW_BB]] ], [ -23, [[ENTRY:%.*]] ]
333+
; CHECK-NEXT: ret i32 [[RETVAL_0]]
334+
;
335+
entry:
336+
%or.cond = icmp ult i32 %x, 4
337+
br i1 %or.cond, label %if.then, label %return
338+
339+
if.then:
340+
switch i32 %x, label %sw.epilog [
341+
i32 0, label %sw.bb
342+
i32 1, label %sw.bb2
343+
i32 2, label %sw.bb4
344+
i32 3, label %sw.bb6
345+
]
346+
347+
sw.bb:
348+
%call = tail call i32 @g(i32 2)
349+
br label %return
350+
351+
sw.bb2:
352+
%call3 = tail call i32 @g(i32 3)
353+
br label %return
354+
355+
sw.bb4:
356+
%call5 = tail call i32 @g(i32 4)
357+
br label %return
358+
359+
sw.bb6:
360+
%call7 = tail call i32 @g(i32 5)
361+
br label %return
362+
363+
sw.epilog:
364+
call void @foo()
365+
br label %return
366+
367+
return:
368+
%retval.0 = phi i32 [ %call7, %sw.bb6 ], [ %call5, %sw.bb4 ], [ %call3, %sw.bb2 ], [ %call, %sw.bb ], [ -23, %sw.epilog ], [ -23, %entry ]
369+
ret i32 %retval.0
370+
}
304371

305372
declare void @llvm.assume(i1)
306373

0 commit comments

Comments
 (0)