Skip to content

Commit f622eca

Browse files
committed
[SimplifyCFG] Improve linear mapping in switch lookup tables
1 parent f907323 commit f622eca

File tree

3 files changed

+96
-43
lines changed

3 files changed

+96
-43
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 83 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6082,6 +6082,8 @@ class SwitchLookupTable {
60826082
ConstantInt *LinearOffset = nullptr;
60836083
ConstantInt *LinearMultiplier = nullptr;
60846084
bool LinearMapValWrapped = false;
6085+
unsigned LinearMapValMaskedBits = 0;
6086+
APInt LinearMapValHighBits;
60856087

60866088
// For ArrayKind, this is the array.
60876089
GlobalVariable *Array = nullptr;
@@ -6139,46 +6141,81 @@ SwitchLookupTable::SwitchLookupTable(
61396141
// Check if we can derive the value with a linear transformation from the
61406142
// table index.
61416143
if (isa<IntegerType>(ValueType)) {
6142-
bool LinearMappingPossible = true;
6143-
APInt PrevVal;
6144-
APInt DistToPrev;
6145-
// When linear map is monotonic and signed overflow doesn't happen on
6146-
// maximum index, we can attach nsw on Add and Mul.
6147-
bool NonMonotonic = false;
6148-
assert(TableSize >= 2 && "Should be a SingleValue table.");
6149-
// Check if there is the same distance between two consecutive values.
6150-
for (uint64_t I = 0; I < TableSize; ++I) {
6151-
ConstantInt *ConstVal = dyn_cast<ConstantInt>(TableContents[I]);
6152-
if (!ConstVal) {
6153-
// This is an undef. We could deal with it, but undefs in lookup tables
6154-
// are very seldom. It's probably not worth the additional complexity.
6155-
LinearMappingPossible = false;
6156-
break;
6157-
}
6158-
const APInt &Val = ConstVal->getValue();
6159-
if (I != 0) {
6160-
APInt Dist = Val - PrevVal;
6161-
if (I == 1) {
6162-
DistToPrev = Dist;
6163-
} else if (Dist != DistToPrev) {
6164-
LinearMappingPossible = false;
6165-
break;
6144+
auto MatchLinearMapping = [&](bool MaskOutHighBits, unsigned LowBits) {
6145+
APInt PrevVal;
6146+
APInt DistToPrev;
6147+
// When linear map is monotonic and signed overflow doesn't happen on
6148+
// maximum index, we can attach nsw on Add and Mul.
6149+
bool NonMonotonic = false;
6150+
assert(TableSize >= 2 && "Should be a SingleValue table.");
6151+
// Check if there is the same distance between two consecutive values.
6152+
for (uint64_t I = 0; I < TableSize; ++I) {
6153+
ConstantInt *ConstVal = dyn_cast<ConstantInt>(TableContents[I]);
6154+
if (!ConstVal) {
6155+
// This is an undef. We could deal with it, but undefs in lookup
6156+
// tables are very seldom. It's probably not worth the additional
6157+
// complexity.
6158+
return false;
61666159
}
6167-
NonMonotonic |=
6168-
Dist.isStrictlyPositive() ? Val.sle(PrevVal) : Val.sgt(PrevVal);
6160+
const APInt &Val = ConstVal->getValue();
6161+
if (I != 0) {
6162+
APInt Dist = Val - PrevVal;
6163+
if (MaskOutHighBits)
6164+
Dist = Dist.getLoBits(LowBits);
6165+
if (I == 1)
6166+
DistToPrev = Dist;
6167+
else if (Dist != DistToPrev)
6168+
return false;
6169+
if (!MaskOutHighBits)
6170+
NonMonotonic |=
6171+
Dist.isStrictlyPositive() ? Val.sle(PrevVal) : Val.sgt(PrevVal);
6172+
}
6173+
PrevVal = Val;
61696174
}
6170-
PrevVal = Val;
6171-
}
6172-
if (LinearMappingPossible) {
6175+
61736176
LinearOffset = cast<ConstantInt>(TableContents[0]);
61746177
LinearMultiplier = ConstantInt::get(M.getContext(), DistToPrev);
6175-
bool MayWrap = false;
6176-
APInt M = LinearMultiplier->getValue();
6177-
(void)M.smul_ov(APInt(M.getBitWidth(), TableSize - 1), MayWrap);
6178-
LinearMapValWrapped = NonMonotonic || MayWrap;
6178+
if (MaskOutHighBits)
6179+
LinearMapValWrapped = true;
6180+
else {
6181+
bool MayWrap = false;
6182+
APInt M = LinearMultiplier->getValue();
6183+
(void)M.smul_ov(APInt(M.getBitWidth(), TableSize - 1), MayWrap);
6184+
LinearMapValWrapped = NonMonotonic || MayWrap;
6185+
}
61796186
Kind = LinearMapKind;
61806187
++NumLinearMaps;
6188+
return true;
6189+
};
6190+
6191+
if (MatchLinearMapping(/* MaskOutHighBits */ false, /* LowBits */ 0))
61816192
return;
6193+
// Try matching highbits | ((offset + index * multiplier) & lowbits_mask)
6194+
APInt CommonOnes = APInt::getAllOnes(ValueType->getScalarSizeInBits());
6195+
APInt CommonZeros = APInt::getAllOnes(ValueType->getScalarSizeInBits());
6196+
bool IsCommonBitsValid = true;
6197+
for (uint64_t I = 0; I < TableSize; ++I) {
6198+
ConstantInt *ConstVal = dyn_cast<ConstantInt>(TableContents[I]);
6199+
if (!ConstVal) {
6200+
// ignore undefs
6201+
IsCommonBitsValid = false;
6202+
break;
6203+
}
6204+
const APInt &Val = ConstVal->getValue();
6205+
CommonOnes &= Val;
6206+
CommonZeros &= ~Val;
6207+
}
6208+
if (IsCommonBitsValid) {
6209+
unsigned CommonHighBits = (CommonOnes | CommonZeros).countLeadingOnes();
6210+
unsigned LowBits = CommonOnes.getBitWidth() - CommonHighBits;
6211+
assert(LowBits > 0 && "Should be a SingleValue table.");
6212+
if (CommonHighBits > 0 &&
6213+
MatchLinearMapping(/* MaskOutHighBits */ true, LowBits)) {
6214+
LinearMapValMaskedBits = LowBits;
6215+
LinearMapValHighBits = CommonOnes;
6216+
LinearMapValHighBits.clearLowBits(LowBits);
6217+
return;
6218+
}
61826219
}
61836220
}
61846221

@@ -6232,6 +6269,19 @@ Value *SwitchLookupTable::BuildLookup(Value *Index, IRBuilder<> &Builder) {
62326269
Result = Builder.CreateAdd(Result, LinearOffset, "switch.offset",
62336270
/*HasNUW = */ false,
62346271
/*HasNSW = */ !LinearMapValWrapped);
6272+
6273+
if (LinearMapValMaskedBits) {
6274+
Result = Builder.CreateAnd(
6275+
Result,
6276+
APInt::getLowBitsSet(
6277+
cast<IntegerType>(Result->getType())->getBitWidth(),
6278+
LinearMapValMaskedBits),
6279+
"switch.masked");
6280+
if (!LinearMapValHighBits.isZero())
6281+
Result = Builder.CreateOr(Result, LinearMapValHighBits,
6282+
"switch.with_high_bits");
6283+
}
6284+
62356285
return Result;
62366286
}
62376287
case BitMapKind: {

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ define i64 @_TFO6reduce1E5toRawfS0_FT_Si(i2) {
1010
; CHECK-LABEL: @_TFO6reduce1E5toRawfS0_FT_Si(
1111
; CHECK-NEXT: entry:
1212
; 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]]
13+
; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i2 [[SWITCH_TABLEIDX]] to i64
14+
; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i64 [[SWITCH_IDX_CAST]], 2
15+
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = and i64 [[SWITCH_OFFSET]], 3
16+
; CHECK-NEXT: ret i64 [[SWITCH_MASKED]]
1717
;
1818
entry:
1919
switch i2 %0, label %1 [

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2073,9 +2073,10 @@ define i32 @pr67843(i8 %0) {
20732073
; CHECK-LABEL: @pr67843(
20742074
; CHECK-NEXT: start:
20752075
; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub nsw i8 [[TMP0:%.*]], -1
2076-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x i32], ptr @switch.table.pr67843, i32 0, i8 [[SWITCH_TABLEIDX]]
2077-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2078-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2076+
; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i8 [[SWITCH_TABLEIDX]] to i32
2077+
; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i32 [[SWITCH_IDX_CAST]], 255
2078+
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = and i32 [[SWITCH_OFFSET]], 255
2079+
; CHECK-NEXT: ret i32 [[SWITCH_MASKED]]
20792080
;
20802081
start:
20812082
switch i8 %0, label %bb2 [
@@ -2102,9 +2103,11 @@ define i32 @linearmap_masked_with_common_highbits(i8 %0) {
21022103
; CHECK-LABEL: @linearmap_masked_with_common_highbits(
21032104
; CHECK-NEXT: start:
21042105
; CHECK-NEXT: [[SWITCH_TABLEIDX:%.*]] = sub nsw i8 [[TMP0:%.*]], -1
2105-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x i32], ptr @switch.table.linearmap_masked_with_common_highbits, i32 0, i8 [[SWITCH_TABLEIDX]]
2106-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2107-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2106+
; CHECK-NEXT: [[SWITCH_IDX_CAST:%.*]] = zext i8 [[SWITCH_TABLEIDX]] to i32
2107+
; CHECK-NEXT: [[SWITCH_OFFSET:%.*]] = add i32 [[SWITCH_IDX_CAST]], 511
2108+
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = and i32 [[SWITCH_OFFSET]], 255
2109+
; CHECK-NEXT: [[SWITCH_WITH_HIGH_BITS:%.*]] = or i32 [[SWITCH_MASKED]], 256
2110+
; CHECK-NEXT: ret i32 [[SWITCH_WITH_HIGH_BITS]]
21082111
;
21092112
start:
21102113
switch i8 %0, label %bb2 [

0 commit comments

Comments
 (0)