Skip to content

Commit 4eaa728

Browse files
committed
[SimplifyCFG] Find the smallest table considering overflow in switchToLookupTable
1 parent 6a3b696 commit 4eaa728

File tree

2 files changed

+71
-51
lines changed

2 files changed

+71
-51
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

+64-28
Original file line numberDiff line numberDiff line change
@@ -6516,18 +6516,20 @@ ShouldBuildLookupTable(SwitchInst *SI, uint64_t TableSize,
65166516
}
65176517

65186518
static bool ShouldUseSwitchConditionAsTableIndex(
6519-
ConstantInt &MinCaseVal, const ConstantInt &MaxCaseVal,
6519+
const ConstantInt &BeginCaseVal, const ConstantInt &EndCaseVal,
65206520
bool HasDefaultResults, const SmallDenseMap<PHINode *, Type *> &ResultTypes,
65216521
const DataLayout &DL, const TargetTransformInfo &TTI) {
6522-
if (MinCaseVal.isNullValue())
6522+
if (BeginCaseVal.isNullValue())
65236523
return true;
6524-
if (MinCaseVal.isNegative() ||
6525-
MaxCaseVal.getLimitedValue() == std::numeric_limits<uint64_t>::max() ||
6524+
if (BeginCaseVal.getValue().sge(EndCaseVal.getValue()))
6525+
return false;
6526+
if (BeginCaseVal.isNegative() ||
6527+
EndCaseVal.getLimitedValue() == std::numeric_limits<uint64_t>::max() ||
65266528
!HasDefaultResults)
65276529
return false;
65286530
return all_of(ResultTypes, [&](const auto &KV) {
65296531
return SwitchLookupTable::WouldFitInRegister(
6530-
DL, MaxCaseVal.getLimitedValue() + 1 /* TableSize */,
6532+
DL, EndCaseVal.getLimitedValue() + 1 /* TableSize */,
65316533
KV.second /* ResultType */);
65326534
});
65336535
}
@@ -6618,7 +6620,8 @@ static void reuseTableCompare(
66186620
/// lookup tables.
66196621
static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
66206622
DomTreeUpdater *DTU, const DataLayout &DL,
6621-
const TargetTransformInfo &TTI) {
6623+
const TargetTransformInfo &TTI,
6624+
bool TryMinTableSize) {
66226625
assert(SI->getNumCases() > 1 && "Degenerate switch?");
66236626

66246627
BasicBlock *BB = SI->getParent();
@@ -6644,9 +6647,6 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
66446647
// Figure out the corresponding result for each case value and phi node in the
66456648
// common destination, as well as the min and max case values.
66466649
assert(!SI->cases().empty());
6647-
SwitchInst::CaseIt CI = SI->case_begin();
6648-
ConstantInt *MinCaseVal = CI->getCaseValue();
6649-
ConstantInt *MaxCaseVal = CI->getCaseValue();
66506650

66516651
BasicBlock *CommonDest = nullptr;
66526652

@@ -6657,17 +6657,49 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
66576657
SmallDenseMap<PHINode *, Type *> ResultTypes;
66586658
SmallVector<PHINode *, 4> PHIs;
66596659

6660-
for (SwitchInst::CaseIt E = SI->case_end(); CI != E; ++CI) {
6661-
ConstantInt *CaseVal = CI->getCaseValue();
6662-
if (CaseVal->getValue().slt(MinCaseVal->getValue()))
6663-
MinCaseVal = CaseVal;
6664-
if (CaseVal->getValue().sgt(MaxCaseVal->getValue()))
6665-
MaxCaseVal = CaseVal;
6660+
SmallVector<ConstantInt *, 8> CaseVals(llvm::map_range(
6661+
SI->cases(), [](const auto &C) { return C.getCaseValue(); }));
6662+
6663+
llvm::sort(CaseVals, [](const auto *L, const auto *R) {
6664+
return L->getValue().slt(R->getValue());
6665+
});
6666+
auto *CaseValIter = CaseVals.begin();
6667+
ConstantInt *BeginCaseVal = *CaseValIter;
6668+
ConstantInt *EndCaseVal = CaseVals.back();
6669+
bool RangeOverflow = false;
6670+
uint64_t MinTableSize = EndCaseVal->getValue()
6671+
.ssub_ov(BeginCaseVal->getValue(), RangeOverflow)
6672+
.getLimitedValue() +
6673+
1;
6674+
// If there is no overflow, then this must be the minimal table.
6675+
// The signed max-min can no longer build a lookup table, so return.
6676+
if (RangeOverflow && TryMinTableSize) {
6677+
// We consider cases where the starting to the endpoint will cross the
6678+
// signed max and min. For example, for the i8 range `[-128, -127, 126,
6679+
// 127]`, we choose from 126 to -127. The length of the lookup table is 4.
6680+
while (CaseValIter != CaseVals.end()) {
6681+
auto *CurCaseVal = *CaseValIter++;
6682+
if (CaseValIter == CaseVals.end())
6683+
break;
6684+
auto *NextCaseVal = *CaseValIter;
6685+
const auto &NextVal = NextCaseVal->getValue();
6686+
const auto &CurVal = CurCaseVal->getValue();
6687+
uint64_t RequireTableSize = (CurVal - NextVal).getLimitedValue() + 1;
6688+
if (RequireTableSize < MinTableSize) {
6689+
BeginCaseVal = NextCaseVal;
6690+
EndCaseVal = CurCaseVal;
6691+
MinTableSize = RequireTableSize;
6692+
}
6693+
}
6694+
}
6695+
6696+
for (const auto &CI : SI->cases()) {
6697+
ConstantInt *CaseVal = CI.getCaseValue();
66666698

66676699
// Resulting value at phi nodes for this case value.
66686700
using ResultsTy = SmallVector<std::pair<PHINode *, Constant *>, 4>;
66696701
ResultsTy Results;
6670-
if (!getCaseResults(SI, CaseVal, CI->getCaseSuccessor(), &CommonDest,
6702+
if (!getCaseResults(SI, CaseVal, CI.getCaseSuccessor(), &CommonDest,
66716703
Results, DL, TTI))
66726704
return false;
66736705

@@ -6702,13 +6734,12 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
67026734
}
67036735

67046736
bool UseSwitchConditionAsTableIndex = ShouldUseSwitchConditionAsTableIndex(
6705-
*MinCaseVal, *MaxCaseVal, HasDefaultResults, ResultTypes, DL, TTI);
6737+
*BeginCaseVal, *EndCaseVal, HasDefaultResults, ResultTypes, DL, TTI);
67066738
uint64_t TableSize;
67076739
if (UseSwitchConditionAsTableIndex)
6708-
TableSize = MaxCaseVal->getLimitedValue() + 1;
6740+
TableSize = EndCaseVal->getLimitedValue() + 1;
67096741
else
6710-
TableSize =
6711-
(MaxCaseVal->getValue() - MinCaseVal->getValue()).getLimitedValue() + 1;
6742+
TableSize = MinTableSize;
67126743

67136744
bool TableHasHoles = (NumResults < TableSize);
67146745
bool NeedMask = (TableHasHoles && !HasDefaultResults);
@@ -6721,13 +6752,16 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
67216752
}
67226753

67236754
if (!ShouldBuildLookupTable(SI, TableSize, TTI, DL, ResultTypes))
6724-
return false;
6755+
// When a signed max-min cannot construct a lookup table, try to find a
6756+
// range with a minimal lookup table.
6757+
return !TryMinTableSize &&
6758+
SwitchToLookupTable(SI, Builder, DTU, DL, TTI, true);
67256759

67266760
std::vector<DominatorTree::UpdateType> Updates;
67276761

67286762
// Compute the maximum table size representable by the integer type we are
67296763
// switching upon.
6730-
unsigned CaseSize = MinCaseVal->getType()->getPrimitiveSizeInBits();
6764+
unsigned CaseSize = BeginCaseVal->getType()->getPrimitiveSizeInBits();
67316765
uint64_t MaxTableSize = CaseSize > 63 ? UINT64_MAX : 1ULL << CaseSize;
67326766
assert(MaxTableSize >= TableSize &&
67336767
"It is impossible for a switch to have more entries than the max "
@@ -6749,15 +6783,17 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
67496783
Value *TableIndex;
67506784
ConstantInt *TableIndexOffset;
67516785
if (UseSwitchConditionAsTableIndex) {
6752-
TableIndexOffset = ConstantInt::get(MaxCaseVal->getIntegerType(), 0);
6786+
TableIndexOffset = ConstantInt::get(EndCaseVal->getIntegerType(), 0);
67536787
TableIndex = SI->getCondition();
67546788
} else {
6755-
TableIndexOffset = MinCaseVal;
6789+
TableIndexOffset = BeginCaseVal;
67566790
// If the default is unreachable, all case values are s>= MinCaseVal. Then
67576791
// we can try to attach nsw.
67586792
bool MayWrap = true;
6759-
if (!DefaultIsReachable) {
6760-
APInt Res = MaxCaseVal->getValue().ssub_ov(MinCaseVal->getValue(), MayWrap);
6793+
if (!DefaultIsReachable &&
6794+
EndCaseVal->getValue().sge(BeginCaseVal->getValue())) {
6795+
APInt Res =
6796+
EndCaseVal->getValue().ssub_ov(BeginCaseVal->getValue(), MayWrap);
67616797
(void)Res;
67626798
}
67636799

@@ -6798,7 +6834,7 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
67986834
// PHI value for the default case in case we're using a bit mask.
67996835
} else {
68006836
Value *Cmp = Builder.CreateICmpULT(
6801-
TableIndex, ConstantInt::get(MinCaseVal->getType(), TableSize));
6837+
TableIndex, ConstantInt::get(BeginCaseVal->getType(), TableSize));
68026838
RangeCheckBranch =
68036839
Builder.CreateCondBr(Cmp, LookupBB, SI->getDefaultDest());
68046840
if (DTU)
@@ -7112,7 +7148,7 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
71127148
// CVP. Therefore, only apply this transformation during late stages of the
71137149
// optimisation pipeline.
71147150
if (Options.ConvertSwitchToLookupTable &&
7115-
SwitchToLookupTable(SI, Builder, DTU, DL, TTI))
7151+
SwitchToLookupTable(SI, Builder, DTU, DL, TTI, false))
71167152
return requestResimplify();
71177153

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

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

+7-23
Original file line numberDiff line numberDiff line change
@@ -120,31 +120,15 @@ return:
120120
define i32 @f_i8_128(i8 %c) {
121121
; CHECK-LABEL: @f_i8_128(
122122
; CHECK-NEXT: entry:
123-
; CHECK-NEXT: switch i8 [[C:%.*]], label [[SW_DEFAULT:%.*]] [
124-
; CHECK-NEXT: i8 122, label [[RETURN:%.*]]
125-
; CHECK-NEXT: i8 123, label [[SW_BB1:%.*]]
126-
; CHECK-NEXT: i8 124, label [[SW_BB2:%.*]]
127-
; CHECK-NEXT: i8 125, label [[SW_BB3:%.*]]
128-
; CHECK-NEXT: i8 126, label [[SW_BB4:%.*]]
129-
; CHECK-NEXT: i8 127, label [[SW_BB5:%.*]]
130-
; CHECK-NEXT: i8 -128, label [[SW_BB6:%.*]]
131-
; CHECK-NEXT: ]
132-
; CHECK: sw.bb1:
133-
; CHECK-NEXT: br label [[RETURN]]
134-
; CHECK: sw.bb2:
135-
; CHECK-NEXT: br label [[RETURN]]
136-
; CHECK: sw.bb3:
137-
; CHECK-NEXT: br label [[RETURN]]
138-
; CHECK: sw.bb4:
139-
; CHECK-NEXT: br label [[RETURN]]
140-
; CHECK: sw.bb5:
141-
; CHECK-NEXT: br label [[RETURN]]
142-
; CHECK: sw.bb6:
143-
; CHECK-NEXT: br label [[RETURN]]
144-
; CHECK: sw.default:
123+
; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i8 [[C:%.*]], 122
124+
; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i8 [[SWITCH_TABLEIDX]], 7
125+
; CHECK-NEXT: br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label [[RETURN:%.*]]
126+
; CHECK: switch.lookup:
127+
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [7 x i32], ptr @switch.table.f_i8_128, i32 0, i8 [[SWITCH_TABLEIDX]]
128+
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
145129
; CHECK-NEXT: br label [[RETURN]]
146130
; CHECK: return:
147-
; 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:%.*]] ]
131+
; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[SWITCH_LOAD]], [[SWITCH_LOOKUP]] ], [ 15, [[ENTRY:%.*]] ]
148132
; CHECK-NEXT: ret i32 [[RETVAL_0]]
149133
;
150134
entry:

0 commit comments

Comments
 (0)