Skip to content

Commit 135b2d4

Browse files
committed
[SimplifyCFG] Find the smallest table considering overflow in switchToLookupTable
1 parent 5abafcb commit 135b2d4

File tree

2 files changed

+71
-51
lines changed

2 files changed

+71
-51
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6534,18 +6534,20 @@ ShouldBuildLookupTable(SwitchInst *SI, uint64_t TableSize,
65346534
}
65356535

65366536
static bool ShouldUseSwitchConditionAsTableIndex(
6537-
ConstantInt &MinCaseVal, const ConstantInt &MaxCaseVal,
6537+
const ConstantInt &BeginCaseVal, const ConstantInt &EndCaseVal,
65386538
bool HasDefaultResults, const SmallDenseMap<PHINode *, Type *> &ResultTypes,
65396539
const DataLayout &DL, const TargetTransformInfo &TTI) {
6540-
if (MinCaseVal.isNullValue())
6540+
if (BeginCaseVal.isNullValue())
65416541
return true;
6542-
if (MinCaseVal.isNegative() ||
6543-
MaxCaseVal.getLimitedValue() == std::numeric_limits<uint64_t>::max() ||
6542+
if (BeginCaseVal.getValue().sge(EndCaseVal.getValue()))
6543+
return false;
6544+
if (BeginCaseVal.isNegative() ||
6545+
EndCaseVal.getLimitedValue() == std::numeric_limits<uint64_t>::max() ||
65446546
!HasDefaultResults)
65456547
return false;
65466548
return all_of(ResultTypes, [&](const auto &KV) {
65476549
return SwitchLookupTable::WouldFitInRegister(
6548-
DL, MaxCaseVal.getLimitedValue() + 1 /* TableSize */,
6550+
DL, EndCaseVal.getLimitedValue() + 1 /* TableSize */,
65496551
KV.second /* ResultType */);
65506552
});
65516553
}
@@ -6637,7 +6639,8 @@ static void reuseTableCompare(
66376639
/// lookup tables.
66386640
static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
66396641
DomTreeUpdater *DTU, const DataLayout &DL,
6640-
const TargetTransformInfo &TTI) {
6642+
const TargetTransformInfo &TTI,
6643+
bool TryMinTableSize) {
66416644
assert(SI->getNumCases() > 1 && "Degenerate switch?");
66426645

66436646
BasicBlock *BB = SI->getParent();
@@ -6663,9 +6666,6 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
66636666
// Figure out the corresponding result for each case value and phi node in the
66646667
// common destination, as well as the min and max case values.
66656668
assert(!SI->cases().empty());
6666-
SwitchInst::CaseIt CI = SI->case_begin();
6667-
ConstantInt *MinCaseVal = CI->getCaseValue();
6668-
ConstantInt *MaxCaseVal = CI->getCaseValue();
66696669

66706670
BasicBlock *CommonDest = nullptr;
66716671

@@ -6676,17 +6676,49 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
66766676
SmallDenseMap<PHINode *, Type *> ResultTypes;
66776677
SmallVector<PHINode *, 4> PHIs;
66786678

6679-
for (SwitchInst::CaseIt E = SI->case_end(); CI != E; ++CI) {
6680-
ConstantInt *CaseVal = CI->getCaseValue();
6681-
if (CaseVal->getValue().slt(MinCaseVal->getValue()))
6682-
MinCaseVal = CaseVal;
6683-
if (CaseVal->getValue().sgt(MaxCaseVal->getValue()))
6684-
MaxCaseVal = CaseVal;
6679+
SmallVector<ConstantInt *, 8> CaseVals(llvm::map_range(
6680+
SI->cases(), [](const auto &C) { return C.getCaseValue(); }));
6681+
6682+
llvm::sort(CaseVals, [](const auto *L, const auto *R) {
6683+
return L->getValue().slt(R->getValue());
6684+
});
6685+
auto *CaseValIter = CaseVals.begin();
6686+
ConstantInt *BeginCaseVal = *CaseValIter;
6687+
ConstantInt *EndCaseVal = CaseVals.back();
6688+
bool RangeOverflow = false;
6689+
uint64_t MinTableSize = EndCaseVal->getValue()
6690+
.ssub_ov(BeginCaseVal->getValue(), RangeOverflow)
6691+
.getLimitedValue() +
6692+
1;
6693+
// If there is no overflow, then this must be the minimal table.
6694+
// The signed max-min can no longer build a lookup table, so return.
6695+
if (RangeOverflow && TryMinTableSize) {
6696+
// We consider cases where the starting to the endpoint will cross the
6697+
// signed max and min. For example, for the i8 range `[-128, -127, 126,
6698+
// 127]`, we choose from 126 to -127. The length of the lookup table is 4.
6699+
while (CaseValIter != CaseVals.end()) {
6700+
auto *CurCaseVal = *CaseValIter++;
6701+
if (CaseValIter == CaseVals.end())
6702+
break;
6703+
auto *NextCaseVal = *CaseValIter;
6704+
const auto &NextVal = NextCaseVal->getValue();
6705+
const auto &CurVal = CurCaseVal->getValue();
6706+
uint64_t RequireTableSize = (CurVal - NextVal).getLimitedValue() + 1;
6707+
if (RequireTableSize < MinTableSize) {
6708+
BeginCaseVal = NextCaseVal;
6709+
EndCaseVal = CurCaseVal;
6710+
MinTableSize = RequireTableSize;
6711+
}
6712+
}
6713+
}
6714+
6715+
for (const auto &CI : SI->cases()) {
6716+
ConstantInt *CaseVal = CI.getCaseValue();
66856717

66866718
// Resulting value at phi nodes for this case value.
66876719
using ResultsTy = SmallVector<std::pair<PHINode *, Constant *>, 4>;
66886720
ResultsTy Results;
6689-
if (!getCaseResults(SI, CaseVal, CI->getCaseSuccessor(), &CommonDest,
6721+
if (!getCaseResults(SI, CaseVal, CI.getCaseSuccessor(), &CommonDest,
66906722
Results, DL, TTI))
66916723
return false;
66926724

@@ -6721,13 +6753,12 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
67216753
}
67226754

67236755
bool UseSwitchConditionAsTableIndex = ShouldUseSwitchConditionAsTableIndex(
6724-
*MinCaseVal, *MaxCaseVal, HasDefaultResults, ResultTypes, DL, TTI);
6756+
*BeginCaseVal, *EndCaseVal, HasDefaultResults, ResultTypes, DL, TTI);
67256757
uint64_t TableSize;
67266758
if (UseSwitchConditionAsTableIndex)
6727-
TableSize = MaxCaseVal->getLimitedValue() + 1;
6759+
TableSize = EndCaseVal->getLimitedValue() + 1;
67286760
else
6729-
TableSize =
6730-
(MaxCaseVal->getValue() - MinCaseVal->getValue()).getLimitedValue() + 1;
6761+
TableSize = MinTableSize;
67316762

67326763
// If the default destination is unreachable, or if the lookup table covers
67336764
// all values of the conditional variable, branch directly to the lookup table
@@ -6757,13 +6788,16 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
67576788
}
67586789

67596790
if (!ShouldBuildLookupTable(SI, TableSize, TTI, DL, ResultTypes))
6760-
return false;
6791+
// When a signed max-min cannot construct a lookup table, try to find a
6792+
// range with a minimal lookup table.
6793+
return !TryMinTableSize &&
6794+
SwitchToLookupTable(SI, Builder, DTU, DL, TTI, true);
67616795

67626796
std::vector<DominatorTree::UpdateType> Updates;
67636797

67646798
// Compute the maximum table size representable by the integer type we are
67656799
// switching upon.
6766-
unsigned CaseSize = MinCaseVal->getType()->getPrimitiveSizeInBits();
6800+
unsigned CaseSize = BeginCaseVal->getType()->getPrimitiveSizeInBits();
67676801
uint64_t MaxTableSize = CaseSize > 63 ? UINT64_MAX : 1ULL << CaseSize;
67686802
assert(MaxTableSize >= TableSize &&
67696803
"It is impossible for a switch to have more entries than the max "
@@ -6779,15 +6813,17 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
67796813
Value *TableIndex;
67806814
ConstantInt *TableIndexOffset;
67816815
if (UseSwitchConditionAsTableIndex) {
6782-
TableIndexOffset = ConstantInt::get(MaxCaseVal->getIntegerType(), 0);
6816+
TableIndexOffset = ConstantInt::get(EndCaseVal->getIntegerType(), 0);
67836817
TableIndex = SI->getCondition();
67846818
} else {
6785-
TableIndexOffset = MinCaseVal;
6819+
TableIndexOffset = BeginCaseVal;
67866820
// If the default is unreachable, all case values are s>= MinCaseVal. Then
67876821
// we can try to attach nsw.
67886822
bool MayWrap = true;
6789-
if (!DefaultIsReachable) {
6790-
APInt Res = MaxCaseVal->getValue().ssub_ov(MinCaseVal->getValue(), MayWrap);
6823+
if (!DefaultIsReachable &&
6824+
EndCaseVal->getValue().sge(BeginCaseVal->getValue())) {
6825+
APInt Res =
6826+
EndCaseVal->getValue().ssub_ov(BeginCaseVal->getValue(), MayWrap);
67916827
(void)Res;
67926828
}
67936829

@@ -6830,7 +6866,7 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
68306866
// PHI value for the default case in case we're using a bit mask.
68316867
} else {
68326868
Value *Cmp = Builder.CreateICmpULT(
6833-
TableIndex, ConstantInt::get(MinCaseVal->getType(), TableSize));
6869+
TableIndex, ConstantInt::get(BeginCaseVal->getType(), TableSize));
68346870
RangeCheckBranch =
68356871
Builder.CreateCondBr(Cmp, LookupBB, SI->getDefaultDest());
68366872
if (DTU)
@@ -7145,7 +7181,7 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
71457181
// CVP. Therefore, only apply this transformation during late stages of the
71467182
// optimisation pipeline.
71477183
if (Options.ConvertSwitchToLookupTable &&
7148-
SwitchToLookupTable(SI, Builder, DTU, DL, TTI))
7184+
SwitchToLookupTable(SI, Builder, DTU, DL, TTI, false))
71497185
return requestResimplify();
71507186

71517187
if (simplifySwitchOfPowersOfTwo(SI, Builder, DL, TTI))

llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -127,31 +127,15 @@ return:
127127
define i32 @f_i8_128(i8 %c) {
128128
; CHECK-LABEL: @f_i8_128(
129129
; CHECK-NEXT: entry:
130-
; CHECK-NEXT: switch i8 [[C:%.*]], label [[SW_DEFAULT:%.*]] [
131-
; CHECK-NEXT: i8 122, label [[RETURN:%.*]]
132-
; CHECK-NEXT: i8 123, label [[SW_BB1:%.*]]
133-
; CHECK-NEXT: i8 124, label [[SW_BB2:%.*]]
134-
; CHECK-NEXT: i8 125, label [[SW_BB3:%.*]]
135-
; CHECK-NEXT: i8 126, label [[SW_BB4:%.*]]
136-
; CHECK-NEXT: i8 127, label [[SW_BB5:%.*]]
137-
; CHECK-NEXT: i8 -128, label [[SW_BB6:%.*]]
138-
; CHECK-NEXT: ]
139-
; CHECK: sw.bb1:
140-
; CHECK-NEXT: br label [[RETURN]]
141-
; CHECK: sw.bb2:
142-
; CHECK-NEXT: br label [[RETURN]]
143-
; CHECK: sw.bb3:
144-
; CHECK-NEXT: br label [[RETURN]]
145-
; CHECK: sw.bb4:
146-
; CHECK-NEXT: br label [[RETURN]]
147-
; CHECK: sw.bb5:
148-
; CHECK-NEXT: br label [[RETURN]]
149-
; CHECK: sw.bb6:
150-
; CHECK-NEXT: br label [[RETURN]]
151-
; CHECK: sw.default:
130+
; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i8 [[C:%.*]], 122
131+
; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i8 [[SWITCH_TABLEIDX]], 7
132+
; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
133+
; CHECK: switch.lookup:
134+
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [7 x i32], ptr @switch.table.f_i8_128, i32 0, i8 [[SWITCH_TABLEIDX]]
135+
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
152136
; CHECK-NEXT: br label [[RETURN]]
153137
; CHECK: return:
154-
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ 15, [[SW_DEFAULT]] ], [ 1, [[SW_BB6]] ], [ 62, [[SW_BB5]] ], [ 27, [[SW_BB4]] ], [ -1, [[SW_BB3]] ], [ 0, [[SW_BB2]] ], [ 123, [[SW_BB1]] ], [ 55, [[ENTRY:%.*]] ]
138+
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[SWITCH_LOAD]], [[SWITCH_LOOKUP]] ], [ 15, [[ENTRY:%.*]] ]
155139
; CHECK-NEXT: ret i32 [[RETVAL_0]]
156140
;
157141
entry:

0 commit comments

Comments
 (0)