Skip to content

Commit 1c3c48f

Browse files
committed
[SimplifyCFG] Find an arrayless index for the covered lookup table
1 parent 6dc5ba4 commit 1c3c48f

File tree

4 files changed

+185
-96
lines changed

4 files changed

+185
-96
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

+175-81
Original file line numberDiff line numberDiff line change
@@ -6105,6 +6105,21 @@ class SwitchLookupTable {
61056105
static bool WouldFitInRegister(const DataLayout &DL, uint64_t TableSize,
61066106
Type *ElementType);
61076107

6108+
static SmallVector<Constant *, 64> buildTableContents(
6109+
uint64_t TableSize, ConstantInt *Offset,
6110+
const SmallVectorImpl<std::pair<ConstantInt *, Constant *>> &Values,
6111+
Constant *DefaultValue);
6112+
static bool
6113+
canBeSingleValueKind(const SmallVectorImpl<Constant *> &TableContents);
6114+
static bool
6115+
canBeLinearMapKind(const SmallVectorImpl<Constant *> &TableContents,
6116+
bool &NonMonotonic, APInt &DistToPrev);
6117+
static bool canBeBitMapKind(const SmallVectorImpl<Constant *> &TableContents,
6118+
const DataLayout &DL);
6119+
static bool
6120+
canOnlyFallbackToArrayKind(const SmallVectorImpl<Constant *> &TableContents,
6121+
const DataLayout &DL);
6122+
61086123
private:
61096124
// Depending on the contents of the table, it can be represented in
61106125
// different ways.
@@ -6150,97 +6165,36 @@ SwitchLookupTable::SwitchLookupTable(
61506165
Module &M, uint64_t TableSize, ConstantInt *Offset,
61516166
const SmallVectorImpl<std::pair<ConstantInt *, Constant *>> &Values,
61526167
Constant *DefaultValue, const DataLayout &DL, const StringRef &FuncName) {
6153-
assert(Values.size() && "Can't build lookup table without values!");
6154-
assert(TableSize >= Values.size() && "Can't fit values in table!");
6155-
6156-
// If all values in the table are equal, this is that value.
6157-
SingleValue = Values.begin()->second;
6158-
6159-
Type *ValueType = Values.begin()->second->getType();
6160-
61616168
// Build up the table contents.
6162-
SmallVector<Constant *, 64> TableContents(TableSize);
6163-
for (size_t I = 0, E = Values.size(); I != E; ++I) {
6164-
ConstantInt *CaseVal = Values[I].first;
6165-
Constant *CaseRes = Values[I].second;
6166-
assert(CaseRes->getType() == ValueType);
6167-
6168-
uint64_t Idx = (CaseVal->getValue() - Offset->getValue()).getLimitedValue();
6169-
TableContents[Idx] = CaseRes;
6170-
6171-
if (CaseRes != SingleValue)
6172-
SingleValue = nullptr;
6173-
}
6174-
6175-
// Fill in any holes in the table with the default result.
6176-
if (Values.size() < TableSize) {
6177-
assert(DefaultValue &&
6178-
"Need a default value to fill the lookup table holes.");
6179-
assert(DefaultValue->getType() == ValueType);
6180-
for (uint64_t I = 0; I < TableSize; ++I) {
6181-
if (!TableContents[I])
6182-
TableContents[I] = DefaultValue;
6183-
}
6184-
6185-
if (DefaultValue != SingleValue)
6186-
SingleValue = nullptr;
6187-
}
6169+
SmallVector<Constant *, 64> TableContents =
6170+
buildTableContents(TableSize, Offset, Values, DefaultValue);
61886171

61896172
// If each element in the table contains the same value, we only need to store
61906173
// that single value.
6191-
if (SingleValue) {
6174+
if (canBeSingleValueKind(TableContents)) {
6175+
SingleValue = TableContents[0];
61926176
Kind = SingleValueKind;
61936177
return;
61946178
}
6195-
6196-
// Check if we can derive the value with a linear transformation from the
6197-
// table index.
6198-
if (isa<IntegerType>(ValueType)) {
6199-
bool LinearMappingPossible = true;
6200-
APInt PrevVal;
6201-
APInt DistToPrev;
6202-
// When linear map is monotonic and signed overflow doesn't happen on
6203-
// maximum index, we can attach nsw on Add and Mul.
6204-
bool NonMonotonic = false;
6205-
assert(TableSize >= 2 && "Should be a SingleValue table.");
6206-
// Check if there is the same distance between two consecutive values.
6207-
for (uint64_t I = 0; I < TableSize; ++I) {
6208-
ConstantInt *ConstVal = dyn_cast<ConstantInt>(TableContents[I]);
6209-
if (!ConstVal) {
6210-
// This is an undef. We could deal with it, but undefs in lookup tables
6211-
// are very seldom. It's probably not worth the additional complexity.
6212-
LinearMappingPossible = false;
6213-
break;
6214-
}
6215-
const APInt &Val = ConstVal->getValue();
6216-
if (I != 0) {
6217-
APInt Dist = Val - PrevVal;
6218-
if (I == 1) {
6219-
DistToPrev = Dist;
6220-
} else if (Dist != DistToPrev) {
6221-
LinearMappingPossible = false;
6222-
break;
6223-
}
6224-
NonMonotonic |=
6225-
Dist.isStrictlyPositive() ? Val.sle(PrevVal) : Val.sgt(PrevVal);
6226-
}
6227-
PrevVal = Val;
6228-
}
6229-
if (LinearMappingPossible) {
6230-
LinearOffset = cast<ConstantInt>(TableContents[0]);
6231-
LinearMultiplier = ConstantInt::get(M.getContext(), DistToPrev);
6232-
bool MayWrap = false;
6233-
APInt M = LinearMultiplier->getValue();
6234-
(void)M.smul_ov(APInt(M.getBitWidth(), TableSize - 1), MayWrap);
6235-
LinearMapValWrapped = NonMonotonic || MayWrap;
6236-
Kind = LinearMapKind;
6237-
++NumLinearMaps;
6238-
return;
6239-
}
6179+
// When linear map is monotonic and signed overflow doesn't happen on
6180+
// maximum index, we can attach nsw on Add and Mul.
6181+
bool NonMonotonic = false;
6182+
APInt DistToPrev;
6183+
if (canBeLinearMapKind(TableContents, NonMonotonic, DistToPrev)) {
6184+
LinearOffset = cast<ConstantInt>(TableContents[0]);
6185+
LinearMultiplier = ConstantInt::get(M.getContext(), DistToPrev);
6186+
bool MayWrap = false;
6187+
APInt M = LinearMultiplier->getValue();
6188+
(void)M.smul_ov(APInt(M.getBitWidth(), TableSize - 1), MayWrap);
6189+
LinearMapValWrapped = NonMonotonic || MayWrap;
6190+
Kind = LinearMapKind;
6191+
++NumLinearMaps;
6192+
return;
62406193
}
62416194

6195+
Type *ValueType = Values.begin()->second->getType();
62426196
// If the type is integer and the table fits in a register, build a bitmap.
6243-
if (WouldFitInRegister(DL, TableSize, ValueType)) {
6197+
if (canBeBitMapKind(TableContents, DL)) {
62446198
IntegerType *IT = cast<IntegerType>(ValueType);
62456199
APInt TableInt(TableSize * IT->getBitWidth(), 0);
62466200
for (uint64_t I = TableSize; I > 0; --I) {
@@ -6349,6 +6303,110 @@ bool SwitchLookupTable::WouldFitInRegister(const DataLayout &DL,
63496303
return DL.fitsInLegalInteger(TableSize * IT->getBitWidth());
63506304
}
63516305

6306+
SmallVector<Constant *, 64> SwitchLookupTable::buildTableContents(
6307+
uint64_t TableSize, ConstantInt *Offset,
6308+
const SmallVectorImpl<std::pair<ConstantInt *, Constant *>> &Values,
6309+
Constant *DefaultValue) {
6310+
assert(Values.size() && "Can't build lookup table without values!");
6311+
assert(TableSize >= Values.size() && "Can't fit values in table!");
6312+
6313+
Type *ValueType = Values.begin()->second->getType();
6314+
6315+
// Build up the table contents.
6316+
SmallVector<Constant *, 64> TableContents(TableSize);
6317+
for (size_t I = 0, E = Values.size(); I != E; ++I) {
6318+
ConstantInt *CaseVal = Values[I].first;
6319+
Constant *CaseRes = Values[I].second;
6320+
assert(CaseRes->getType() == ValueType);
6321+
6322+
uint64_t Idx = (CaseVal->getValue() - Offset->getValue()).getLimitedValue();
6323+
TableContents[Idx] = CaseRes;
6324+
}
6325+
6326+
// Fill in any holes in the table with the default result.
6327+
if (Values.size() < TableSize) {
6328+
assert(DefaultValue &&
6329+
"Need a default value to fill the lookup table holes.");
6330+
assert(DefaultValue->getType() == ValueType);
6331+
for (uint64_t I = 0; I < TableSize; ++I) {
6332+
if (!TableContents[I])
6333+
TableContents[I] = DefaultValue;
6334+
}
6335+
}
6336+
return TableContents;
6337+
}
6338+
6339+
bool SwitchLookupTable::canBeSingleValueKind(
6340+
const SmallVectorImpl<Constant *> &TableContents) {
6341+
// If all values in the table are equal, this is that value.
6342+
const Constant *SingleValue = TableContents[0];
6343+
for (const Constant *Value : TableContents) {
6344+
if (Value != SingleValue)
6345+
return false;
6346+
}
6347+
return true;
6348+
}
6349+
6350+
bool SwitchLookupTable::canBeLinearMapKind(
6351+
const SmallVectorImpl<Constant *> &TableContents, bool &NonMonotonic,
6352+
APInt &DistToPrev) {
6353+
Type *ValueType = TableContents[0]->getType();
6354+
// Check if we can derive the value with a linear transformation from the
6355+
// table index.
6356+
if (!isa<IntegerType>(ValueType))
6357+
return false;
6358+
bool LinearMappingPossible = true;
6359+
APInt PrevVal;
6360+
auto TableSize = TableContents.size();
6361+
6362+
// When linear map is monotonic and signed overflow doesn't happen on
6363+
// maximum index, we can attach nsw on Add and Mul.
6364+
assert(TableSize >= 2 && "Should be a SingleValue table.");
6365+
// Check if there is the same distance between two consecutive values.
6366+
for (uint64_t I = 0; I < TableSize; ++I) {
6367+
ConstantInt *ConstVal = dyn_cast<ConstantInt>(TableContents[I]);
6368+
if (!ConstVal) {
6369+
// This is an undef. We could deal with it, but undefs in lookup tables
6370+
// are very seldom. It's probably not worth the additional complexity.
6371+
LinearMappingPossible = false;
6372+
break;
6373+
}
6374+
const APInt &Val = ConstVal->getValue();
6375+
if (I != 0) {
6376+
APInt Dist = Val - PrevVal;
6377+
if (I == 1) {
6378+
DistToPrev = Dist;
6379+
} else if (Dist != DistToPrev) {
6380+
LinearMappingPossible = false;
6381+
break;
6382+
}
6383+
NonMonotonic |=
6384+
Dist.isStrictlyPositive() ? Val.sle(PrevVal) : Val.sgt(PrevVal);
6385+
}
6386+
PrevVal = Val;
6387+
}
6388+
return LinearMappingPossible;
6389+
}
6390+
6391+
bool SwitchLookupTable::canBeBitMapKind(
6392+
const SmallVectorImpl<Constant *> &TableContents, const DataLayout &DL) {
6393+
return WouldFitInRegister(DL, TableContents.size(),
6394+
TableContents[0]->getType());
6395+
}
6396+
6397+
bool SwitchLookupTable::canOnlyFallbackToArrayKind(
6398+
const SmallVectorImpl<Constant *> &TableContents, const DataLayout &DL) {
6399+
if (canBeSingleValueKind(TableContents))
6400+
return false;
6401+
bool NonMonotonic = false;
6402+
APInt DistToPrev;
6403+
if (canBeLinearMapKind(TableContents, NonMonotonic, DistToPrev))
6404+
return false;
6405+
if (canBeBitMapKind(TableContents, DL))
6406+
return false;
6407+
return true;
6408+
}
6409+
63526410
static bool isTypeLegalForLookupTable(Type *Ty, const TargetTransformInfo &TTI,
63536411
const DataLayout &DL) {
63546412
// Allow any legal type.
@@ -6662,6 +6720,42 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
66626720
Module &Mod = *CommonDest->getParent()->getParent();
66636721
BasicBlock *LookupBB = BasicBlock::Create(
66646722
Mod.getContext(), "switch.lookup", CommonDest->getParent(), CommonDest);
6723+
// If we are generating a covered lookup table, try to find an index that
6724+
// doesn't create an array of values.
6725+
// TODO: We could more expensive check, and choose the index with the best sum
6726+
// of all kinds.
6727+
if (MaxTableSize == TableSize && TableSize * PHIs.size() <= 128) {
6728+
for (uint64_t Offset = 0; Offset < TableSize; Offset++) {
6729+
auto *TableIndexOffset =
6730+
ConstantInt::get(MaxCaseVal->getIntegerType(), Offset);
6731+
bool CanOnlyFallbackToArrayKind = false;
6732+
for (PHINode *PHI : PHIs) {
6733+
const ResultListTy &ResultList = ResultLists[PHI];
6734+
6735+
// If using a bitmask, use any value to fill the lookup table holes.
6736+
Constant *DV =
6737+
NeedMask ? ResultLists[PHI][0].second : DefaultResults[PHI];
6738+
SmallVector<Constant *, 64> TableContents =
6739+
SwitchLookupTable::buildTableContents(TableSize, TableIndexOffset,
6740+
ResultList, DV);
6741+
if (SwitchLookupTable::canOnlyFallbackToArrayKind(TableContents, DL)) {
6742+
CanOnlyFallbackToArrayKind = true;
6743+
break;
6744+
}
6745+
}
6746+
if (!CanOnlyFallbackToArrayKind) {
6747+
if (Offset == 0)
6748+
UseSwitchConditionAsTableIndex = true;
6749+
MinCaseVal = TableIndexOffset;
6750+
APInt One(TableIndexOffset->getValue().getBitWidth(), 1);
6751+
bool Overflow = false;
6752+
MaxCaseVal = cast<ConstantInt>(ConstantInt::get(
6753+
MaxCaseVal->getType(),
6754+
TableIndexOffset->getValue().usub_ov(One, Overflow)));
6755+
break;
6756+
}
6757+
}
6758+
}
66656759

66666760
// Compute the table index value.
66676761
Builder.SetInsertPoint(SI);

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

+4-5
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

+2-5
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

+4-5
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)