@@ -6082,6 +6082,8 @@ class SwitchLookupTable {
6082
6082
ConstantInt *LinearOffset = nullptr ;
6083
6083
ConstantInt *LinearMultiplier = nullptr ;
6084
6084
bool LinearMapValWrapped = false ;
6085
+ unsigned LinearMapValMaskedBits = 0 ;
6086
+ APInt LinearMapValHighBits;
6085
6087
6086
6088
// For ArrayKind, this is the array.
6087
6089
GlobalVariable *Array = nullptr ;
@@ -6139,46 +6141,81 @@ SwitchLookupTable::SwitchLookupTable(
6139
6141
// Check if we can derive the value with a linear transformation from the
6140
6142
// table index.
6141
6143
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 ;
6166
6159
}
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;
6169
6174
}
6170
- PrevVal = Val;
6171
- }
6172
- if (LinearMappingPossible) {
6175
+
6173
6176
LinearOffset = cast<ConstantInt>(TableContents[0 ]);
6174
6177
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
+ }
6179
6186
Kind = LinearMapKind;
6180
6187
++NumLinearMaps;
6188
+ return true ;
6189
+ };
6190
+
6191
+ if (MatchLinearMapping (/* MaskOutHighBits */ false , /* LowBits */ 0 ))
6181
6192
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
+ }
6182
6219
}
6183
6220
}
6184
6221
@@ -6232,6 +6269,19 @@ Value *SwitchLookupTable::BuildLookup(Value *Index, IRBuilder<> &Builder) {
6232
6269
Result = Builder.CreateAdd (Result, LinearOffset, " switch.offset" ,
6233
6270
/* HasNUW = */ false ,
6234
6271
/* 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
+
6235
6285
return Result;
6236
6286
}
6237
6287
case BitMapKind: {
0 commit comments