Skip to content

Commit 6d1d384

Browse files
committed
[SimplifyCFG] Find an arrayless index for the covered lookup table
1 parent 89ec940 commit 6d1d384

File tree

4 files changed

+185
-96
lines changed

4 files changed

+185
-96
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 175 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -6186,6 +6186,21 @@ class SwitchLookupTable {
61866186
static bool WouldFitInRegister(const DataLayout &DL, uint64_t TableSize,
61876187
Type *ElementType);
61886188

6189+
static SmallVector<Constant *, 64> buildTableContents(
6190+
uint64_t TableSize, ConstantInt *Offset,
6191+
const SmallVectorImpl<std::pair<ConstantInt *, Constant *>> &Values,
6192+
Constant *DefaultValue);
6193+
static bool
6194+
canBeSingleValueKind(const SmallVectorImpl<Constant *> &TableContents);
6195+
static bool
6196+
canBeLinearMapKind(const SmallVectorImpl<Constant *> &TableContents,
6197+
bool &NonMonotonic, APInt &DistToPrev);
6198+
static bool canBeBitMapKind(const SmallVectorImpl<Constant *> &TableContents,
6199+
const DataLayout &DL);
6200+
static bool
6201+
canOnlyFallbackToArrayKind(const SmallVectorImpl<Constant *> &TableContents,
6202+
const DataLayout &DL);
6203+
61896204
private:
61906205
// Depending on the contents of the table, it can be represented in
61916206
// different ways.
@@ -6231,97 +6246,36 @@ SwitchLookupTable::SwitchLookupTable(
62316246
Module &M, uint64_t TableSize, ConstantInt *Offset,
62326247
const SmallVectorImpl<std::pair<ConstantInt *, Constant *>> &Values,
62336248
Constant *DefaultValue, const DataLayout &DL, const StringRef &FuncName) {
6234-
assert(Values.size() && "Can't build lookup table without values!");
6235-
assert(TableSize >= Values.size() && "Can't fit values in table!");
6236-
6237-
// If all values in the table are equal, this is that value.
6238-
SingleValue = Values.begin()->second;
6239-
6240-
Type *ValueType = Values.begin()->second->getType();
6241-
62426249
// Build up the table contents.
6243-
SmallVector<Constant *, 64> TableContents(TableSize);
6244-
for (size_t I = 0, E = Values.size(); I != E; ++I) {
6245-
ConstantInt *CaseVal = Values[I].first;
6246-
Constant *CaseRes = Values[I].second;
6247-
assert(CaseRes->getType() == ValueType);
6248-
6249-
uint64_t Idx = (CaseVal->getValue() - Offset->getValue()).getLimitedValue();
6250-
TableContents[Idx] = CaseRes;
6251-
6252-
if (CaseRes != SingleValue)
6253-
SingleValue = nullptr;
6254-
}
6255-
6256-
// Fill in any holes in the table with the default result.
6257-
if (Values.size() < TableSize) {
6258-
assert(DefaultValue &&
6259-
"Need a default value to fill the lookup table holes.");
6260-
assert(DefaultValue->getType() == ValueType);
6261-
for (uint64_t I = 0; I < TableSize; ++I) {
6262-
if (!TableContents[I])
6263-
TableContents[I] = DefaultValue;
6264-
}
6265-
6266-
if (DefaultValue != SingleValue)
6267-
SingleValue = nullptr;
6268-
}
6250+
SmallVector<Constant *, 64> TableContents =
6251+
buildTableContents(TableSize, Offset, Values, DefaultValue);
62696252

62706253
// If each element in the table contains the same value, we only need to store
62716254
// that single value.
6272-
if (SingleValue) {
6255+
if (canBeSingleValueKind(TableContents)) {
6256+
SingleValue = TableContents[0];
62736257
Kind = SingleValueKind;
62746258
return;
62756259
}
6276-
6277-
// Check if we can derive the value with a linear transformation from the
6278-
// table index.
6279-
if (isa<IntegerType>(ValueType)) {
6280-
bool LinearMappingPossible = true;
6281-
APInt PrevVal;
6282-
APInt DistToPrev;
6283-
// When linear map is monotonic and signed overflow doesn't happen on
6284-
// maximum index, we can attach nsw on Add and Mul.
6285-
bool NonMonotonic = false;
6286-
assert(TableSize >= 2 && "Should be a SingleValue table.");
6287-
// Check if there is the same distance between two consecutive values.
6288-
for (uint64_t I = 0; I < TableSize; ++I) {
6289-
ConstantInt *ConstVal = dyn_cast<ConstantInt>(TableContents[I]);
6290-
if (!ConstVal) {
6291-
// This is an undef. We could deal with it, but undefs in lookup tables
6292-
// are very seldom. It's probably not worth the additional complexity.
6293-
LinearMappingPossible = false;
6294-
break;
6295-
}
6296-
const APInt &Val = ConstVal->getValue();
6297-
if (I != 0) {
6298-
APInt Dist = Val - PrevVal;
6299-
if (I == 1) {
6300-
DistToPrev = Dist;
6301-
} else if (Dist != DistToPrev) {
6302-
LinearMappingPossible = false;
6303-
break;
6304-
}
6305-
NonMonotonic |=
6306-
Dist.isStrictlyPositive() ? Val.sle(PrevVal) : Val.sgt(PrevVal);
6307-
}
6308-
PrevVal = Val;
6309-
}
6310-
if (LinearMappingPossible) {
6311-
LinearOffset = cast<ConstantInt>(TableContents[0]);
6312-
LinearMultiplier = ConstantInt::get(M.getContext(), DistToPrev);
6313-
bool MayWrap = false;
6314-
APInt M = LinearMultiplier->getValue();
6315-
(void)M.smul_ov(APInt(M.getBitWidth(), TableSize - 1), MayWrap);
6316-
LinearMapValWrapped = NonMonotonic || MayWrap;
6317-
Kind = LinearMapKind;
6318-
++NumLinearMaps;
6319-
return;
6320-
}
6260+
// When linear map is monotonic and signed overflow doesn't happen on
6261+
// maximum index, we can attach nsw on Add and Mul.
6262+
bool NonMonotonic = false;
6263+
APInt DistToPrev;
6264+
if (canBeLinearMapKind(TableContents, NonMonotonic, DistToPrev)) {
6265+
LinearOffset = cast<ConstantInt>(TableContents[0]);
6266+
LinearMultiplier = ConstantInt::get(M.getContext(), DistToPrev);
6267+
bool MayWrap = false;
6268+
APInt M = LinearMultiplier->getValue();
6269+
(void)M.smul_ov(APInt(M.getBitWidth(), TableSize - 1), MayWrap);
6270+
LinearMapValWrapped = NonMonotonic || MayWrap;
6271+
Kind = LinearMapKind;
6272+
++NumLinearMaps;
6273+
return;
63216274
}
63226275

6276+
Type *ValueType = Values.begin()->second->getType();
63236277
// If the type is integer and the table fits in a register, build a bitmap.
6324-
if (WouldFitInRegister(DL, TableSize, ValueType)) {
6278+
if (canBeBitMapKind(TableContents, DL)) {
63256279
IntegerType *IT = cast<IntegerType>(ValueType);
63266280
APInt TableInt(TableSize * IT->getBitWidth(), 0);
63276281
for (uint64_t I = TableSize; I > 0; --I) {
@@ -6430,6 +6384,110 @@ bool SwitchLookupTable::WouldFitInRegister(const DataLayout &DL,
64306384
return DL.fitsInLegalInteger(TableSize * IT->getBitWidth());
64316385
}
64326386

6387+
SmallVector<Constant *, 64> SwitchLookupTable::buildTableContents(
6388+
uint64_t TableSize, ConstantInt *Offset,
6389+
const SmallVectorImpl<std::pair<ConstantInt *, Constant *>> &Values,
6390+
Constant *DefaultValue) {
6391+
assert(Values.size() && "Can't build lookup table without values!");
6392+
assert(TableSize >= Values.size() && "Can't fit values in table!");
6393+
6394+
Type *ValueType = Values.begin()->second->getType();
6395+
6396+
// Build up the table contents.
6397+
SmallVector<Constant *, 64> TableContents(TableSize);
6398+
for (size_t I = 0, E = Values.size(); I != E; ++I) {
6399+
ConstantInt *CaseVal = Values[I].first;
6400+
Constant *CaseRes = Values[I].second;
6401+
assert(CaseRes->getType() == ValueType);
6402+
6403+
uint64_t Idx = (CaseVal->getValue() - Offset->getValue()).getLimitedValue();
6404+
TableContents[Idx] = CaseRes;
6405+
}
6406+
6407+
// Fill in any holes in the table with the default result.
6408+
if (Values.size() < TableSize) {
6409+
assert(DefaultValue &&
6410+
"Need a default value to fill the lookup table holes.");
6411+
assert(DefaultValue->getType() == ValueType);
6412+
for (uint64_t I = 0; I < TableSize; ++I) {
6413+
if (!TableContents[I])
6414+
TableContents[I] = DefaultValue;
6415+
}
6416+
}
6417+
return TableContents;
6418+
}
6419+
6420+
bool SwitchLookupTable::canBeSingleValueKind(
6421+
const SmallVectorImpl<Constant *> &TableContents) {
6422+
// If all values in the table are equal, this is that value.
6423+
const Constant *SingleValue = TableContents[0];
6424+
for (const Constant *Value : TableContents) {
6425+
if (Value != SingleValue)
6426+
return false;
6427+
}
6428+
return true;
6429+
}
6430+
6431+
bool SwitchLookupTable::canBeLinearMapKind(
6432+
const SmallVectorImpl<Constant *> &TableContents, bool &NonMonotonic,
6433+
APInt &DistToPrev) {
6434+
Type *ValueType = TableContents[0]->getType();
6435+
// Check if we can derive the value with a linear transformation from the
6436+
// table index.
6437+
if (!isa<IntegerType>(ValueType))
6438+
return false;
6439+
bool LinearMappingPossible = true;
6440+
APInt PrevVal;
6441+
auto TableSize = TableContents.size();
6442+
6443+
// When linear map is monotonic and signed overflow doesn't happen on
6444+
// maximum index, we can attach nsw on Add and Mul.
6445+
assert(TableSize >= 2 && "Should be a SingleValue table.");
6446+
// Check if there is the same distance between two consecutive values.
6447+
for (uint64_t I = 0; I < TableSize; ++I) {
6448+
ConstantInt *ConstVal = dyn_cast<ConstantInt>(TableContents[I]);
6449+
if (!ConstVal) {
6450+
// This is an undef. We could deal with it, but undefs in lookup tables
6451+
// are very seldom. It's probably not worth the additional complexity.
6452+
LinearMappingPossible = false;
6453+
break;
6454+
}
6455+
const APInt &Val = ConstVal->getValue();
6456+
if (I != 0) {
6457+
APInt Dist = Val - PrevVal;
6458+
if (I == 1) {
6459+
DistToPrev = Dist;
6460+
} else if (Dist != DistToPrev) {
6461+
LinearMappingPossible = false;
6462+
break;
6463+
}
6464+
NonMonotonic |=
6465+
Dist.isStrictlyPositive() ? Val.sle(PrevVal) : Val.sgt(PrevVal);
6466+
}
6467+
PrevVal = Val;
6468+
}
6469+
return LinearMappingPossible;
6470+
}
6471+
6472+
bool SwitchLookupTable::canBeBitMapKind(
6473+
const SmallVectorImpl<Constant *> &TableContents, const DataLayout &DL) {
6474+
return WouldFitInRegister(DL, TableContents.size(),
6475+
TableContents[0]->getType());
6476+
}
6477+
6478+
bool SwitchLookupTable::canOnlyFallbackToArrayKind(
6479+
const SmallVectorImpl<Constant *> &TableContents, const DataLayout &DL) {
6480+
if (canBeSingleValueKind(TableContents))
6481+
return false;
6482+
bool NonMonotonic = false;
6483+
APInt DistToPrev;
6484+
if (canBeLinearMapKind(TableContents, NonMonotonic, DistToPrev))
6485+
return false;
6486+
if (canBeBitMapKind(TableContents, DL))
6487+
return false;
6488+
return true;
6489+
}
6490+
64336491
static bool isTypeLegalForLookupTable(Type *Ty, const TargetTransformInfo &TTI,
64346492
const DataLayout &DL) {
64356493
// Allow any legal type.
@@ -6743,6 +6801,42 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
67436801
Module &Mod = *CommonDest->getParent()->getParent();
67446802
BasicBlock *LookupBB = BasicBlock::Create(
67456803
Mod.getContext(), "switch.lookup", CommonDest->getParent(), CommonDest);
6804+
// If we are generating a covered lookup table, try to find an index that
6805+
// doesn't create an array of values.
6806+
// TODO: We could more expensive check, and choose the index with the best sum
6807+
// of all kinds.
6808+
if (MaxTableSize == TableSize && TableSize * PHIs.size() <= 128) {
6809+
for (uint64_t Offset = 0; Offset < TableSize; Offset++) {
6810+
auto *TableIndexOffset =
6811+
ConstantInt::get(MaxCaseVal->getIntegerType(), Offset);
6812+
bool CanOnlyFallbackToArrayKind = false;
6813+
for (PHINode *PHI : PHIs) {
6814+
const ResultListTy &ResultList = ResultLists[PHI];
6815+
6816+
// If using a bitmask, use any value to fill the lookup table holes.
6817+
Constant *DV =
6818+
NeedMask ? ResultLists[PHI][0].second : DefaultResults[PHI];
6819+
SmallVector<Constant *, 64> TableContents =
6820+
SwitchLookupTable::buildTableContents(TableSize, TableIndexOffset,
6821+
ResultList, DV);
6822+
if (SwitchLookupTable::canOnlyFallbackToArrayKind(TableContents, DL)) {
6823+
CanOnlyFallbackToArrayKind = true;
6824+
break;
6825+
}
6826+
}
6827+
if (!CanOnlyFallbackToArrayKind) {
6828+
if (Offset == 0)
6829+
UseSwitchConditionAsTableIndex = true;
6830+
MinCaseVal = TableIndexOffset;
6831+
APInt One(TableIndexOffset->getValue().getBitWidth(), 1);
6832+
bool Overflow = false;
6833+
MaxCaseVal = cast<ConstantInt>(ConstantInt::get(
6834+
MaxCaseVal->getType(),
6835+
TableIndexOffset->getValue().usub_ov(One, Overflow)));
6836+
break;
6837+
}
6838+
}
6839+
}
67466840

67476841
// Compute the table index value.
67486842
Builder.SetInsertPoint(SI);

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ target triple = "x86_64-apple-darwin12.0.0"
99
define i3 @coveredswitch_test(i3 %input) {
1010
; CHECK-LABEL: @coveredswitch_test(
1111
; CHECK-NEXT: entry:
12-
; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i3 [[INPUT:%.*]], -4
13-
; CHECK-NEXT: [[SWITCH_CAST:%.*]] = zext i3 [[SWITCH_TABLEIDX]] to i24
14-
; CHECK-NEXT: [[SWITCH_SHIFTAMT:%.*]] = mul nuw nsw i24 [[SWITCH_CAST]], 3
15-
; CHECK-NEXT: [[SWITCH_DOWNSHIFT:%.*]] = lshr i24 7507338, [[SWITCH_SHIFTAMT]]
16-
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = trunc i24 [[SWITCH_DOWNSHIFT]] to i3
12+
; CHECK-NEXT: [[SWITCH_CAST:%.*]] = zext i3 [[INPUT:%.*]] to i21
13+
; CHECK-NEXT: [[SWITCH_SHIFTAMT:%.*]] = mul nuw nsw i21 [[SWITCH_CAST]], 3
14+
; CHECK-NEXT: [[SWITCH_DOWNSHIFT:%.*]] = lshr i21 -481496, [[SWITCH_SHIFTAMT]]
15+
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = trunc i21 [[SWITCH_DOWNSHIFT]] to i3
1716
; CHECK-NEXT: ret i3 [[SWITCH_MASKED]]
1817
;
1918
entry:

llvm/test/Transforms/SimplifyCFG/X86/switch-table-bug.ll

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@ target triple = "x86_64-apple-darwin12.0.0"
99
define i64 @_TFO6reduce1E5toRawfS0_FT_Si(i2) {
1010
; CHECK-LABEL: @_TFO6reduce1E5toRawfS0_FT_Si(
1111
; CHECK-NEXT: entry:
12-
; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i2 [[TMP0:%.*]], -2
13-
; CHECK-NEXT: [[SWITCH_TABLEIDX_ZEXT:%.*]] = zext i2 [[SWITCH_TABLEIDX]] to i3
14-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i64], ptr @switch.table._TFO6reduce1E5toRawfS0_FT_Si, i32 0, i3 [[SWITCH_TABLEIDX_ZEXT]]
15-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i64, ptr [[SWITCH_GEP]], align 8
16-
; CHECK-NEXT: ret i64 [[SWITCH_LOAD]]
12+
; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i2 [[TMP0:%.*]] to i64
13+
; CHECK-NEXT: ret i64 [[SWITCH_IDX_CAST]]
1714
;
1815
entry:
1916
switch i2 %0, label %1 [

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,11 +1696,10 @@ define i32 @signed_overflow1(i8 %n) {
16961696
; CHECK-LABEL: @signed_overflow1(
16971697
; CHECK-NEXT: start:
16981698
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[N:%.*]] to i2
1699-
; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub i2 [[TRUNC]], -2
1700-
; CHECK-NEXT: [[SWITCH_TABLEIDX_ZEXT:%.*]] = zext i2 [[SWITCH_TABLEIDX]] to i3
1701-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i32], ptr @switch.table.signed_overflow1, i32 0, i3 [[SWITCH_TABLEIDX_ZEXT]]
1702-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
1703-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
1699+
; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i2 [[TRUNC]] to i32
1700+
; CHECK-NEXT: [[SWITCH_IDX_MULT:%.*]] = mul nsw i32 [[SWITCH_IDX_CAST]], 1111
1701+
; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add nsw i32 [[SWITCH_IDX_MULT]], 1111
1702+
; CHECK-NEXT: ret i32 [[SWITCH_OFFSET]]
17041703
;
17051704
start:
17061705
%trunc = trunc i8 %n to i2

0 commit comments

Comments
 (0)