Skip to content

Commit 4c16eaf

Browse files
committed
[SCCP] Remove dead switch cases based on range information
Determine whether switch edges are feasible based on range information, and remove non-feasible edges lateron. This does not try to determine whether the default edge is dead, as we'd have to determine that the range is fully covered by the cases for that. Another limitation here is that we don't remove dead cases that have the same successor as a live case. I'm not handling this because I wanted to keep the edge removal based on feasible edges only, rather than inspecting ranges again there -- this does not seem like a particularly useful case to handle. Differential Revision: https://reviews.llvm.org/D84270
1 parent 3bb4889 commit 4c16eaf

File tree

2 files changed

+58
-41
lines changed

2 files changed

+58
-41
lines changed

llvm/lib/Transforms/Scalar/SCCP.cpp

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -649,17 +649,30 @@ void SCCPSolver::getFeasibleSuccessors(Instruction &TI,
649649
Succs[0] = true;
650650
return;
651651
}
652-
ValueLatticeElement SCValue = getValueState(SI->getCondition());
653-
ConstantInt *CI = getConstantInt(SCValue);
652+
const ValueLatticeElement &SCValue = getValueState(SI->getCondition());
653+
if (ConstantInt *CI = getConstantInt(SCValue)) {
654+
Succs[SI->findCaseValue(CI)->getSuccessorIndex()] = true;
655+
return;
656+
}
654657

655-
if (!CI) { // Overdefined or unknown condition?
656-
// All destinations are executable!
657-
if (!SCValue.isUnknownOrUndef())
658-
Succs.assign(TI.getNumSuccessors(), true);
658+
// TODO: Switch on undef is UB. Stop passing false once the rest of LLVM
659+
// is ready.
660+
if (SCValue.isConstantRange(/*UndefAllowed=*/false)) {
661+
const ConstantRange &Range = SCValue.getConstantRange();
662+
for (const auto &Case : SI->cases()) {
663+
const APInt &CaseValue = Case.getCaseValue()->getValue();
664+
if (Range.contains(CaseValue))
665+
Succs[Case.getSuccessorIndex()] = true;
666+
}
667+
668+
// TODO: Determine whether default case is reachable.
669+
Succs[SI->case_default()->getSuccessorIndex()] = true;
659670
return;
660671
}
661672

662-
Succs[SI->findCaseValue(CI)->getSuccessorIndex()] = true;
673+
// Overdefined or unknown condition? All destinations are executable!
674+
if (!SCValue.isUnknownOrUndef())
675+
Succs.assign(TI.getNumSuccessors(), true);
663676
return;
664677
}
665678

@@ -1847,9 +1860,26 @@ static bool removeNonFeasibleEdges(const SCCPSolver &Solver, BasicBlock *BB,
18471860

18481861
BranchInst::Create(OnlyFeasibleSuccessor, BB);
18491862
TI->eraseFromParent();
1863+
DTU.applyUpdatesPermissive(Updates);
1864+
} else if (FeasibleSuccessors.size() > 1) {
1865+
SwitchInstProfUpdateWrapper SI(*cast<SwitchInst>(TI));
1866+
SmallVector<DominatorTree::UpdateType, 8> Updates;
1867+
for (auto CI = SI->case_begin(); CI != SI->case_end();) {
1868+
if (FeasibleSuccessors.contains(CI->getCaseSuccessor())) {
1869+
++CI;
1870+
continue;
1871+
}
1872+
1873+
BasicBlock *Succ = CI->getCaseSuccessor();
1874+
Succ->removePredecessor(BB);
1875+
Updates.push_back({DominatorTree::Delete, BB, Succ});
1876+
SI.removeCase(CI);
1877+
// Don't increment CI, as we removed a case.
1878+
}
1879+
18501880
DTU.applyUpdatesPermissive(Updates);
18511881
} else {
1852-
llvm_unreachable("Either all successors are feasible, or exactly one is");
1882+
llvm_unreachable("Must have at least one feasible successor");
18531883
}
18541884
return true;
18551885
}

llvm/test/Transforms/SCCP/switch.ll

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -73,34 +73,29 @@ end:
7373
ret i32 %phi
7474
}
7575

76-
define i32 @test_duplicate_successors_phi_3(i1 %c1, i32 %x) {
76+
define i32 @test_duplicate_successors_phi_3(i1 %c1, i32* %p, i32 %y) {
7777
; CHECK-LABEL: @test_duplicate_successors_phi_3(
7878
; CHECK-NEXT: entry:
7979
; CHECK-NEXT: br i1 [[C1:%.*]], label [[SWITCH:%.*]], label [[SWITCH_1:%.*]]
8080
; CHECK: switch:
81-
; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[X:%.*]], 3
82-
; CHECK-NEXT: call void @llvm.assume(i1 [[C2]])
81+
; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P:%.*]], align 4, !range !0
8382
; CHECK-NEXT: switch i32 [[X]], label [[SWITCH_DEFAULT:%.*]] [
8483
; CHECK-NEXT: i32 0, label [[SWITCH_DEFAULT]]
8584
; CHECK-NEXT: i32 1, label [[SWITCH_0:%.*]]
8685
; CHECK-NEXT: i32 2, label [[SWITCH_0]]
87-
; CHECK-NEXT: i32 3, label [[SWITCH_1]]
88-
; CHECK-NEXT: i32 4, label [[SWITCH_1]]
8986
; CHECK-NEXT: ]
9087
; CHECK: switch.default:
9188
; CHECK-NEXT: ret i32 -1
9289
; CHECK: switch.0:
9390
; CHECK-NEXT: ret i32 0
9491
; CHECK: switch.1:
95-
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ 0, [[SWITCH]] ], [ 0, [[SWITCH]] ]
96-
; CHECK-NEXT: ret i32 [[PHI]]
92+
; CHECK-NEXT: ret i32 [[Y:%.*]]
9793
;
9894
entry:
9995
br i1 %c1, label %switch, label %switch.1
10096

10197
switch:
102-
%c2 = icmp ult i32 %x, 3
103-
call void @llvm.assume(i1 %c2)
98+
%x = load i32, i32* %p, !range !{i32 0, i32 3}
10499
switch i32 %x, label %switch.default [
105100
i32 0, label %switch.default
106101
i32 1, label %switch.0
@@ -116,19 +111,18 @@ switch.0:
116111
ret i32 0
117112

118113
switch.1:
119-
%phi = phi i32 [ %x, %entry ], [ 0, %switch ], [ 0, %switch ]
114+
%phi = phi i32 [ %y, %entry ], [ 0, %switch ], [ 0, %switch ]
120115
ret i32 %phi
121116
}
122117

123-
define i32 @test_local_range(i32 %x) {
118+
; TODO: Determine that the default destination is dead.
119+
define i32 @test_local_range(i32* %p) {
124120
; CHECK-LABEL: @test_local_range(
125-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[X:%.*]], 3
126-
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
121+
; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P:%.*]], align 4, !range !0
127122
; CHECK-NEXT: switch i32 [[X]], label [[SWITCH_DEFAULT:%.*]] [
128123
; CHECK-NEXT: i32 0, label [[SWITCH_0:%.*]]
129124
; CHECK-NEXT: i32 1, label [[SWITCH_1:%.*]]
130125
; CHECK-NEXT: i32 2, label [[SWITCH_2:%.*]]
131-
; CHECK-NEXT: i32 3, label [[SWITCH_3:%.*]]
132126
; CHECK-NEXT: ]
133127
; CHECK: switch.default:
134128
; CHECK-NEXT: ret i32 -1
@@ -138,11 +132,8 @@ define i32 @test_local_range(i32 %x) {
138132
; CHECK-NEXT: ret i32 1
139133
; CHECK: switch.2:
140134
; CHECK-NEXT: ret i32 2
141-
; CHECK: switch.3:
142-
; CHECK-NEXT: ret i32 3
143135
;
144-
%c = icmp ult i32 %x, 3
145-
call void @llvm.assume(i1 %c)
136+
%x = load i32, i32* %p, !range !{i32 0, i32 3}
146137
switch i32 %x, label %switch.default [
147138
i32 0, label %switch.0
148139
i32 1, label %switch.1
@@ -166,29 +157,24 @@ switch.3:
166157
ret i32 3
167158
}
168159

169-
define i32 @test_duplicate_successors(i32 %x) {
160+
; TODO: Determine that case i3 is dead, even though the edge is shared?
161+
define i32 @test_duplicate_successors(i32* %p) {
170162
; CHECK-LABEL: @test_duplicate_successors(
171-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[X:%.*]], 3
172-
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
163+
; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P:%.*]], align 4, !range !0
173164
; CHECK-NEXT: switch i32 [[X]], label [[SWITCH_DEFAULT:%.*]] [
174165
; CHECK-NEXT: i32 0, label [[SWITCH_0:%.*]]
175166
; CHECK-NEXT: i32 1, label [[SWITCH_0]]
176167
; CHECK-NEXT: i32 2, label [[SWITCH_1:%.*]]
177168
; CHECK-NEXT: i32 3, label [[SWITCH_1]]
178-
; CHECK-NEXT: i32 4, label [[SWITCH_2:%.*]]
179-
; CHECK-NEXT: i32 5, label [[SWITCH_2]]
180169
; CHECK-NEXT: ]
181170
; CHECK: switch.default:
182171
; CHECK-NEXT: ret i32 -1
183172
; CHECK: switch.0:
184173
; CHECK-NEXT: ret i32 0
185174
; CHECK: switch.1:
186175
; CHECK-NEXT: ret i32 1
187-
; CHECK: switch.2:
188-
; CHECK-NEXT: ret i32 2
189176
;
190-
%c = icmp ult i32 %x, 3
191-
call void @llvm.assume(i1 %c)
177+
%x = load i32, i32* %p, !range !{i32 0, i32 3}
192178
switch i32 %x, label %switch.default [
193179
i32 0, label %switch.0
194180
i32 1, label %switch.0
@@ -211,18 +197,17 @@ switch.2:
211197
ret i32 2
212198
}
213199

200+
; Case i32 2 is dead as well, but this cannot be determined based on
201+
; range information.
214202
define internal i32 @test_ip_range(i32 %x) {
215203
; CHECK-LABEL: @test_ip_range(
216204
; CHECK-NEXT: switch i32 [[X:%.*]], label [[SWITCH_DEFAULT:%.*]] [
217-
; CHECK-NEXT: i32 0, label [[SWITCH_0:%.*]]
205+
; CHECK-NEXT: i32 3, label [[SWITCH_3:%.*]]
218206
; CHECK-NEXT: i32 1, label [[SWITCH_1:%.*]]
219207
; CHECK-NEXT: i32 2, label [[SWITCH_2:%.*]]
220-
; CHECK-NEXT: i32 3, label [[SWITCH_3:%.*]]
221-
; CHECK-NEXT: ]
208+
; CHECK-NEXT: ], !prof !1
222209
; CHECK: switch.default:
223210
; CHECK-NEXT: ret i32 -1
224-
; CHECK: switch.0:
225-
; CHECK-NEXT: ret i32 0
226211
; CHECK: switch.1:
227212
; CHECK-NEXT: ret i32 1
228213
; CHECK: switch.2:
@@ -235,7 +220,7 @@ define internal i32 @test_ip_range(i32 %x) {
235220
i32 1, label %switch.1
236221
i32 2, label %switch.2
237222
i32 3, label %switch.3
238-
]
223+
], !prof !{!"branch_weights", i32 1, i32 2, i32 3, i32 4, i32 5}
239224

240225
switch.default:
241226
ret i32 -1
@@ -265,3 +250,5 @@ define void @call_test_ip_range() {
265250
}
266251

267252
declare void @llvm.assume(i1)
253+
254+
; CHECK: !1 = !{!"branch_weights", i32 1, i32 5, i32 3, i32 4}

0 commit comments

Comments
 (0)