Skip to content

Commit 8090a67

Browse files
antoniofrighettoLukacma
authored andcommitted
[SimplifyCFG] Extend simplifySwitchOfPowersOfTwo to reachable defaults
Favour a `cttz`-indexed table lookup over an indirect jump table when the default switch case is reachable, by branching non-power-of-two inputs to the default case. Proofs: https://alive2.llvm.org/ce/z/HeRAtf.
1 parent b05fd29 commit 8090a67

File tree

3 files changed

+90
-64
lines changed

3 files changed

+90
-64
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7551,6 +7551,7 @@ static bool reduceSwitchRange(SwitchInst *SI, IRBuilder<> &Builder,
75517551
/// log2(C)-indexed value table (instead of traditionally emitting a load of the
75527552
/// address of the jump target, and indirectly jump to it).
75537553
static bool simplifySwitchOfPowersOfTwo(SwitchInst *SI, IRBuilder<> &Builder,
7554+
DomTreeUpdater *DTU,
75547555
const DataLayout &DL,
75557556
const TargetTransformInfo &TTI) {
75567557
Value *Condition = SI->getCondition();
@@ -7573,12 +7574,6 @@ static bool simplifySwitchOfPowersOfTwo(SwitchInst *SI, IRBuilder<> &Builder,
75737574
if (SI->getNumCases() < 4)
75747575
return false;
75757576

7576-
// We perform this optimization only for switches with
7577-
// unreachable default case.
7578-
// This assumtion will save us from checking if `Condition` is a power of two.
7579-
if (!SI->defaultDestUnreachable())
7580-
return false;
7581-
75827577
// Check that switch cases are powers of two.
75837578
SmallVector<uint64_t, 4> Values;
75847579
for (const auto &Case : SI->cases()) {
@@ -7598,6 +7593,24 @@ static bool simplifySwitchOfPowersOfTwo(SwitchInst *SI, IRBuilder<> &Builder,
75987593

75997594
Builder.SetInsertPoint(SI);
76007595

7596+
if (!SI->defaultDestUnreachable()) {
7597+
// Let non-power-of-two inputs jump to the default case, when the latter is
7598+
// reachable.
7599+
auto *PopC = Builder.CreateUnaryIntrinsic(Intrinsic::ctpop, Condition);
7600+
auto *IsPow2 = Builder.CreateICmpEQ(PopC, ConstantInt::get(CondTy, 1));
7601+
7602+
auto *OrigBB = SI->getParent();
7603+
auto *DefaultCaseBB = SI->getDefaultDest();
7604+
BasicBlock *SplitBB = SplitBlock(OrigBB, SI, DTU);
7605+
auto It = OrigBB->getTerminator()->getIterator();
7606+
BranchInst::Create(SplitBB, DefaultCaseBB, IsPow2, It);
7607+
It->eraseFromParent();
7608+
7609+
addPredecessorToBlock(DefaultCaseBB, OrigBB, SplitBB);
7610+
if (DTU)
7611+
DTU->applyUpdates({{DominatorTree::Insert, OrigBB, DefaultCaseBB}});
7612+
}
7613+
76017614
// Replace each case with its trailing zeros number.
76027615
for (auto &Case : SI->cases()) {
76037616
auto *OrigValue = Case.getCaseValue();
@@ -7953,7 +7966,7 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
79537966
Options.ConvertSwitchToLookupTable))
79547967
return requestResimplify();
79557968

7956-
if (simplifySwitchOfPowersOfTwo(SI, Builder, DL, TTI))
7969+
if (simplifySwitchOfPowersOfTwo(SI, Builder, DTU, DL, TTI))
79577970
return requestResimplify();
79587971

79597972
if (reduceSwitchRange(SI, Builder, DL, TTI))

llvm/test/Transforms/SimplifyCFG/RISCV/switch-of-powers-of-two.ll

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -61,30 +61,49 @@ return:
6161
ret i32 %p
6262
}
6363

64-
; Check that switch's of powers of two range is not reduced if default case is reachable
64+
; Check that switch's of powers of two range with the default case reachable is reduced
65+
; w/ Zbb enabled, by jumping non-power-of-two inputs to the default block.
6566
define i32 @switch_of_powers_reachable_default(i32 %x) {
66-
; CHECK-LABEL: @switch_of_powers_reachable_default(
67-
; CHECK-NEXT: entry:
68-
; CHECK-NEXT: switch i32 [[X:%.*]], label [[RETURN:%.*]] [
69-
; CHECK-NEXT: i32 1, label [[BB1:%.*]]
70-
; CHECK-NEXT: i32 8, label [[BB2:%.*]]
71-
; CHECK-NEXT: i32 16, label [[BB3:%.*]]
72-
; CHECK-NEXT: i32 32, label [[BB4:%.*]]
73-
; CHECK-NEXT: i32 64, label [[BB5:%.*]]
74-
; CHECK-NEXT: ]
75-
; CHECK: bb1:
76-
; CHECK-NEXT: br label [[RETURN]]
77-
; CHECK: bb2:
78-
; CHECK-NEXT: br label [[RETURN]]
79-
; CHECK: bb3:
80-
; CHECK-NEXT: br label [[RETURN]]
81-
; CHECK: bb4:
82-
; CHECK-NEXT: br label [[RETURN]]
83-
; CHECK: bb5:
84-
; CHECK-NEXT: br label [[RETURN]]
85-
; CHECK: return:
86-
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 3, [[BB1]] ], [ 2, [[BB2]] ], [ 1, [[BB3]] ], [ 0, [[BB4]] ], [ 42, [[BB5]] ], [ -1, [[ENTRY:%.*]] ]
87-
; CHECK-NEXT: ret i32 [[P]]
67+
; RV64I-LABEL: @switch_of_powers_reachable_default(
68+
; RV64I-NEXT: entry:
69+
; RV64I-NEXT: switch i32 [[X:%.*]], label [[RETURN:%.*]] [
70+
; RV64I-NEXT: i32 1, label [[BB1:%.*]]
71+
; RV64I-NEXT: i32 8, label [[BB2:%.*]]
72+
; RV64I-NEXT: i32 16, label [[BB3:%.*]]
73+
; RV64I-NEXT: i32 32, label [[BB4:%.*]]
74+
; RV64I-NEXT: i32 64, label [[BB5:%.*]]
75+
; RV64I-NEXT: ]
76+
; RV64I: bb1:
77+
; RV64I-NEXT: br label [[RETURN]]
78+
; RV64I: bb2:
79+
; RV64I-NEXT: br label [[RETURN]]
80+
; RV64I: bb3:
81+
; RV64I-NEXT: br label [[RETURN]]
82+
; RV64I: bb4:
83+
; RV64I-NEXT: br label [[RETURN]]
84+
; RV64I: bb5:
85+
; RV64I-NEXT: br label [[RETURN]]
86+
; RV64I: return:
87+
; RV64I-NEXT: [[P:%.*]] = phi i32 [ 3, [[BB1]] ], [ 2, [[BB2]] ], [ 1, [[BB3]] ], [ 0, [[BB4]] ], [ 42, [[BB5]] ], [ -1, [[ENTRY:%.*]] ]
88+
; RV64I-NEXT: ret i32 [[P]]
89+
;
90+
; RV64ZBB-LABEL: @switch_of_powers_reachable_default(
91+
; RV64ZBB-NEXT: entry:
92+
; RV64ZBB-NEXT: [[TMP0:%.*]] = call i32 @llvm.ctpop.i32(i32 [[X:%.*]])
93+
; RV64ZBB-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 1
94+
; RV64ZBB-NEXT: br i1 [[TMP1]], label [[ENTRY_SPLIT:%.*]], label [[RETURN:%.*]]
95+
; RV64ZBB: entry.split:
96+
; RV64ZBB-NEXT: [[TMP2:%.*]] = call i32 @llvm.cttz.i32(i32 [[X]], i1 true)
97+
; RV64ZBB-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], 7
98+
; RV64ZBB-NEXT: br i1 [[TMP3]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN]]
99+
; RV64ZBB: switch.lookup:
100+
; RV64ZBB-NEXT: [[TMP4:%.*]] = zext nneg i32 [[TMP2]] to i64
101+
; RV64ZBB-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [7 x i32], ptr @switch.table.switch_of_powers_reachable_default, i64 0, i64 [[TMP4]]
102+
; RV64ZBB-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
103+
; RV64ZBB-NEXT: br label [[RETURN]]
104+
; RV64ZBB: return:
105+
; RV64ZBB-NEXT: [[P:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ -1, [[ENTRY_SPLIT]] ], [ [[SWITCH_LOAD]], [[SWITCH_LOOKUP]] ]
106+
; RV64ZBB-NEXT: ret i32 [[P]]
88107
;
89108
entry:
90109
switch i32 %x, label %default_case [

llvm/test/Transforms/SimplifyCFG/X86/switch-of-powers-of-two.ll

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,20 @@ define i32 @switch_of_powers_two_default_reachable(i32 %arg) {
3939
; CHECK-LABEL: define i32 @switch_of_powers_two_default_reachable(
4040
; CHECK-SAME: i32 [[ARG:%.*]]) {
4141
; CHECK-NEXT: [[ENTRY:.*]]:
42-
; CHECK-NEXT: switch i32 [[ARG]], label %[[RETURN:.*]] [
43-
; CHECK-NEXT: i32 1, label %[[BB1:.*]]
44-
; CHECK-NEXT: i32 8, label %[[BB2:.*]]
45-
; CHECK-NEXT: i32 16, label %[[BB3:.*]]
46-
; CHECK-NEXT: i32 32, label %[[BB4:.*]]
47-
; CHECK-NEXT: i32 64, label %[[BB5:.*]]
48-
; CHECK-NEXT: ]
49-
; CHECK: [[BB1]]:
50-
; CHECK-NEXT: br label %[[RETURN]]
51-
; CHECK: [[BB2]]:
52-
; CHECK-NEXT: br label %[[RETURN]]
53-
; CHECK: [[BB3]]:
54-
; CHECK-NEXT: br label %[[RETURN]]
55-
; CHECK: [[BB4]]:
56-
; CHECK-NEXT: br label %[[RETURN]]
57-
; CHECK: [[BB5]]:
42+
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.ctpop.i32(i32 [[ARG]])
43+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 1
44+
; CHECK-NEXT: br i1 [[TMP1]], label %[[ENTRY_SPLIT:.*]], label %[[RETURN:.*]]
45+
; CHECK: [[ENTRY_SPLIT]]:
46+
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.cttz.i32(i32 [[ARG]], i1 true)
47+
; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], 7
48+
; CHECK-NEXT: br i1 [[TMP3]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN]]
49+
; CHECK: [[SWITCH_LOOKUP]]:
50+
; CHECK-NEXT: [[TMP4:%.*]] = zext nneg i32 [[TMP2]] to i64
51+
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [7 x i32], ptr @switch.table.switch_of_powers_two_default_reachable, i64 0, i64 [[TMP4]]
52+
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
5853
; CHECK-NEXT: br label %[[RETURN]]
5954
; CHECK: [[RETURN]]:
60-
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 3, %[[BB1]] ], [ 2, %[[BB2]] ], [ 1, %[[BB3]] ], [ 0, %[[BB4]] ], [ 42, %[[BB5]] ], [ 5, %[[ENTRY]] ]
55+
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 5, %[[ENTRY]] ], [ 5, %[[ENTRY_SPLIT]] ], [ [[SWITCH_LOAD]], %[[SWITCH_LOOKUP]] ]
6156
; CHECK-NEXT: ret i32 [[PHI]]
6257
;
6358
entry:
@@ -87,25 +82,24 @@ define i32 @switch_of_powers_two_default_reachable_multipreds(i32 %arg, i1 %cond
8782
; CHECK-NEXT: [[ENTRY:.*]]:
8883
; CHECK-NEXT: br i1 [[COND]], label %[[SWITCH:.*]], label %[[RETURN:.*]]
8984
; CHECK: [[SWITCH]]:
90-
; CHECK-NEXT: switch i32 [[ARG]], label %[[RETURN]] [
91-
; CHECK-NEXT: i32 1, label %[[BB1:.*]]
92-
; CHECK-NEXT: i32 8, label %[[BB2:.*]]
93-
; CHECK-NEXT: i32 16, label %[[BB3:.*]]
94-
; CHECK-NEXT: i32 32, label %[[BB4:.*]]
95-
; CHECK-NEXT: i32 64, label %[[BB5:.*]]
96-
; CHECK-NEXT: ]
97-
; CHECK: [[BB1]]:
98-
; CHECK-NEXT: br label %[[RETURN]]
99-
; CHECK: [[BB2]]:
100-
; CHECK-NEXT: br label %[[RETURN]]
101-
; CHECK: [[BB3]]:
102-
; CHECK-NEXT: br label %[[RETURN]]
103-
; CHECK: [[BB4]]:
104-
; CHECK-NEXT: br label %[[RETURN]]
105-
; CHECK: [[BB5]]:
85+
; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.ctpop.i32(i32 [[ARG]])
86+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[TMP0]], 1
87+
; CHECK-NEXT: br i1 [[TMP1]], label %[[SWITCH_SPLIT:.*]], label %[[RETURN]]
88+
; CHECK: [[SWITCH_SPLIT]]:
89+
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.cttz.i32(i32 [[ARG]], i1 true)
90+
; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], 7
91+
; CHECK-NEXT: [[SWITCH_MASKINDEX:%.*]] = trunc i32 [[TMP2]] to i8
92+
; CHECK-NEXT: [[SWITCH_SHIFTED:%.*]] = lshr i8 121, [[SWITCH_MASKINDEX]]
93+
; CHECK-NEXT: [[SWITCH_LOBIT:%.*]] = trunc i8 [[SWITCH_SHIFTED]] to i1
94+
; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[TMP3]], i1 [[SWITCH_LOBIT]], i1 false
95+
; CHECK-NEXT: br i1 [[OR_COND]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN]]
96+
; CHECK: [[SWITCH_LOOKUP]]:
97+
; CHECK-NEXT: [[TMP4:%.*]] = zext nneg i32 [[TMP2]] to i64
98+
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [7 x i32], ptr @switch.table.switch_of_powers_two_default_reachable_multipreds, i64 0, i64 [[TMP4]]
99+
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
106100
; CHECK-NEXT: br label %[[RETURN]]
107101
; CHECK: [[RETURN]]:
108-
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 3, %[[BB1]] ], [ 2, %[[BB2]] ], [ 1, %[[BB3]] ], [ 0, %[[BB4]] ], [ 42, %[[BB5]] ], [ 0, %[[ENTRY]] ], [ [[ARG]], %[[SWITCH]] ]
102+
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[ARG]], %[[SWITCH_SPLIT]] ], [ [[ARG]], %[[SWITCH]] ], [ [[SWITCH_LOAD]], %[[SWITCH_LOOKUP]] ]
109103
; CHECK-NEXT: ret i32 [[PHI]]
110104
;
111105
entry:

0 commit comments

Comments
 (0)