Skip to content

Commit 83c7304

Browse files
committed
[SimplifyCFG] Find the smallest table considering overflow in switchToLookupTable
1 parent b489f66 commit 83c7304

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
@@ -6435,18 +6435,20 @@ ShouldBuildLookupTable(SwitchInst *SI, uint64_t TableSize,
64356435
}
64366436

64376437
static bool ShouldUseSwitchConditionAsTableIndex(
6438-
ConstantInt &MinCaseVal, const ConstantInt &MaxCaseVal,
6438+
const ConstantInt &BeginCaseVal, const ConstantInt &EndCaseVal,
64396439
bool HasDefaultResults, const SmallDenseMap<PHINode *, Type *> &ResultTypes,
64406440
const DataLayout &DL, const TargetTransformInfo &TTI) {
6441-
if (MinCaseVal.isNullValue())
6441+
if (BeginCaseVal.isNullValue())
64426442
return true;
6443-
if (MinCaseVal.isNegative() ||
6444-
MaxCaseVal.getLimitedValue() == std::numeric_limits<uint64_t>::max() ||
6443+
if (BeginCaseVal.getValue().sge(EndCaseVal.getValue()))
6444+
return false;
6445+
if (BeginCaseVal.isNegative() ||
6446+
EndCaseVal.getLimitedValue() == std::numeric_limits<uint64_t>::max() ||
64456447
!HasDefaultResults)
64466448
return false;
64476449
return all_of(ResultTypes, [&](const auto &KV) {
64486450
return SwitchLookupTable::WouldFitInRegister(
6449-
DL, MaxCaseVal.getLimitedValue() + 1 /* TableSize */,
6451+
DL, EndCaseVal.getLimitedValue() + 1 /* TableSize */,
64506452
KV.second /* ResultType */);
64516453
});
64526454
}
@@ -6537,7 +6539,8 @@ static void reuseTableCompare(
65376539
/// lookup tables.
65386540
static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
65396541
DomTreeUpdater *DTU, const DataLayout &DL,
6540-
const TargetTransformInfo &TTI) {
6542+
const TargetTransformInfo &TTI,
6543+
bool TryMinTableSize) {
65416544
assert(SI->getNumCases() > 1 && "Degenerate switch?");
65426545

65436546
BasicBlock *BB = SI->getParent();
@@ -6563,9 +6566,6 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
65636566
// Figure out the corresponding result for each case value and phi node in the
65646567
// common destination, as well as the min and max case values.
65656568
assert(!SI->cases().empty());
6566-
SwitchInst::CaseIt CI = SI->case_begin();
6567-
ConstantInt *MinCaseVal = CI->getCaseValue();
6568-
ConstantInt *MaxCaseVal = CI->getCaseValue();
65696569

65706570
BasicBlock *CommonDest = nullptr;
65716571

@@ -6576,17 +6576,49 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
65766576
SmallDenseMap<PHINode *, Type *> ResultTypes;
65776577
SmallVector<PHINode *, 4> PHIs;
65786578

6579-
for (SwitchInst::CaseIt E = SI->case_end(); CI != E; ++CI) {
6580-
ConstantInt *CaseVal = CI->getCaseValue();
6581-
if (CaseVal->getValue().slt(MinCaseVal->getValue()))
6582-
MinCaseVal = CaseVal;
6583-
if (CaseVal->getValue().sgt(MaxCaseVal->getValue()))
6584-
MaxCaseVal = CaseVal;
6579+
SmallVector<ConstantInt *, 8> CaseVals(llvm::map_range(
6580+
SI->cases(), [](const auto &C) { return C.getCaseValue(); }));
6581+
6582+
llvm::sort(CaseVals, [](const auto *L, const auto *R) {
6583+
return L->getValue().slt(R->getValue());
6584+
});
6585+
auto *CaseValIter = CaseVals.begin();
6586+
ConstantInt *BeginCaseVal = *CaseValIter;
6587+
ConstantInt *EndCaseVal = CaseVals.back();
6588+
bool RangeOverflow = false;
6589+
uint64_t MinTableSize = EndCaseVal->getValue()
6590+
.ssub_ov(BeginCaseVal->getValue(), RangeOverflow)
6591+
.getLimitedValue() +
6592+
1;
6593+
// If there is no overflow, then this must be the minimal table.
6594+
// The signed max-min can no longer build a lookup table, so return.
6595+
if (RangeOverflow && TryMinTableSize) {
6596+
// We consider cases where the starting to the endpoint will cross the
6597+
// signed max and min. For example, for the i8 range `[-128, -127, 126,
6598+
// 127]`, we choose from 126 to -127. The length of the lookup table is 4.
6599+
while (CaseValIter != CaseVals.end()) {
6600+
auto *CurCaseVal = *CaseValIter++;
6601+
if (CaseValIter == CaseVals.end())
6602+
break;
6603+
auto *NextCaseVal = *CaseValIter;
6604+
const auto &NextVal = NextCaseVal->getValue();
6605+
const auto &CurVal = CurCaseVal->getValue();
6606+
uint64_t RequireTableSize = (CurVal - NextVal).getLimitedValue() + 1;
6607+
if (RequireTableSize < MinTableSize) {
6608+
BeginCaseVal = NextCaseVal;
6609+
EndCaseVal = CurCaseVal;
6610+
MinTableSize = RequireTableSize;
6611+
}
6612+
}
6613+
}
6614+
6615+
for (const auto &CI : SI->cases()) {
6616+
ConstantInt *CaseVal = CI.getCaseValue();
65856617

65866618
// Resulting value at phi nodes for this case value.
65876619
using ResultsTy = SmallVector<std::pair<PHINode *, Constant *>, 4>;
65886620
ResultsTy Results;
6589-
if (!getCaseResults(SI, CaseVal, CI->getCaseSuccessor(), &CommonDest,
6621+
if (!getCaseResults(SI, CaseVal, CI.getCaseSuccessor(), &CommonDest,
65906622
Results, DL, TTI))
65916623
return false;
65926624

@@ -6621,13 +6653,12 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
66216653
}
66226654

66236655
bool UseSwitchConditionAsTableIndex = ShouldUseSwitchConditionAsTableIndex(
6624-
*MinCaseVal, *MaxCaseVal, HasDefaultResults, ResultTypes, DL, TTI);
6656+
*BeginCaseVal, *EndCaseVal, HasDefaultResults, ResultTypes, DL, TTI);
66256657
uint64_t TableSize;
66266658
if (UseSwitchConditionAsTableIndex)
6627-
TableSize = MaxCaseVal->getLimitedValue() + 1;
6659+
TableSize = EndCaseVal->getLimitedValue() + 1;
66286660
else
6629-
TableSize =
6630-
(MaxCaseVal->getValue() - MinCaseVal->getValue()).getLimitedValue() + 1;
6661+
TableSize = MinTableSize;
66316662

66326663
bool TableHasHoles = (NumResults < TableSize);
66336664
bool NeedMask = (TableHasHoles && !HasDefaultResults);
@@ -6640,13 +6671,16 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
66406671
}
66416672

66426673
if (!ShouldBuildLookupTable(SI, TableSize, TTI, DL, ResultTypes))
6643-
return false;
6674+
// When a signed max-min cannot construct a lookup table, try to find a
6675+
// range with a minimal lookup table.
6676+
return !TryMinTableSize &&
6677+
SwitchToLookupTable(SI, Builder, DTU, DL, TTI, true);
66446678

66456679
std::vector<DominatorTree::UpdateType> Updates;
66466680

66476681
// Compute the maximum table size representable by the integer type we are
66486682
// switching upon.
6649-
unsigned CaseSize = MinCaseVal->getType()->getPrimitiveSizeInBits();
6683+
unsigned CaseSize = BeginCaseVal->getType()->getPrimitiveSizeInBits();
66506684
uint64_t MaxTableSize = CaseSize > 63 ? UINT64_MAX : 1ULL << CaseSize;
66516685
assert(MaxTableSize >= TableSize &&
66526686
"It is impossible for a switch to have more entries than the max "
@@ -6668,15 +6702,17 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
66686702
Value *TableIndex;
66696703
ConstantInt *TableIndexOffset;
66706704
if (UseSwitchConditionAsTableIndex) {
6671-
TableIndexOffset = ConstantInt::get(MaxCaseVal->getIntegerType(), 0);
6705+
TableIndexOffset = ConstantInt::get(EndCaseVal->getIntegerType(), 0);
66726706
TableIndex = SI->getCondition();
66736707
} else {
6674-
TableIndexOffset = MinCaseVal;
6708+
TableIndexOffset = BeginCaseVal;
66756709
// If the default is unreachable, all case values are s>= MinCaseVal. Then
66766710
// we can try to attach nsw.
66776711
bool MayWrap = true;
6678-
if (!DefaultIsReachable) {
6679-
APInt Res = MaxCaseVal->getValue().ssub_ov(MinCaseVal->getValue(), MayWrap);
6712+
if (!DefaultIsReachable &&
6713+
EndCaseVal->getValue().sge(BeginCaseVal->getValue())) {
6714+
APInt Res =
6715+
EndCaseVal->getValue().ssub_ov(BeginCaseVal->getValue(), MayWrap);
66806716
(void)Res;
66816717
}
66826718

@@ -6717,7 +6753,7 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
67176753
// PHI value for the default case in case we're using a bit mask.
67186754
} else {
67196755
Value *Cmp = Builder.CreateICmpULT(
6720-
TableIndex, ConstantInt::get(MinCaseVal->getType(), TableSize));
6756+
TableIndex, ConstantInt::get(BeginCaseVal->getType(), TableSize));
67216757
RangeCheckBranch =
67226758
Builder.CreateCondBr(Cmp, LookupBB, SI->getDefaultDest());
67236759
if (DTU)
@@ -7032,7 +7068,7 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
70327068
// CVP. Therefore, only apply this transformation during late stages of the
70337069
// optimisation pipeline.
70347070
if (Options.ConvertSwitchToLookupTable &&
7035-
SwitchToLookupTable(SI, Builder, DTU, DL, TTI))
7071+
SwitchToLookupTable(SI, Builder, DTU, DL, TTI, false))
70367072
return requestResimplify();
70377073

70387074
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)