@@ -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: {
0 commit comments