From 6f75c6681d47164072daea54dde2727c51b0e739 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 26 May 2023 12:09:44 +0200 Subject: [PATCH] [KnownBits] Add fast-path for shl with unknown shift amount (NFC) We currently don't call into KnownBits::shl() from ValueTracking if the shift amount is unknown. If we do try to do so, we get significant compile-time regressions, because evaluating all 64 shift amounts if quite expensive, and mostly pointless in this case. Add a fast-path for the case where the shift amount is the full [0, BitWidth-1] range. This primarily requires a more accurate estimate of the max shift amount, to avoid taking the fast-path in too many cases. Differential Revision: https://reviews.llvm.org/D151540 --- llvm/lib/Support/KnownBits.cpp | 68 +++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp index 8491ac5..c8e4a89 100644 --- a/llvm/lib/Support/KnownBits.cpp +++ b/llvm/lib/Support/KnownBits.cpp @@ -164,41 +164,33 @@ KnownBits KnownBits::smin(const KnownBits &LHS, const KnownBits &RHS) { return Flip(umax(Flip(LHS), Flip(RHS))); } +static unsigned getMaxShiftAmount(const APInt &MaxValue, unsigned BitWidth) { + if (isPowerOf2_32(BitWidth)) + return MaxValue.extractBitsAsZExtValue(Log2_32(BitWidth), 0); + // This is only an approximate upper bound. + return MaxValue.getLimitedValue(BitWidth - 1); +} + KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW, bool NSW) { unsigned BitWidth = LHS.getBitWidth(); - auto ShiftByConst = [&](const KnownBits &LHS, - unsigned ShiftAmt) -> std::optional { + auto ShiftByConst = [&](const KnownBits &LHS, unsigned ShiftAmt) { KnownBits Known; bool ShiftedOutZero, ShiftedOutOne; Known.Zero = LHS.Zero.ushl_ov(ShiftAmt, ShiftedOutZero); Known.Zero.setLowBits(ShiftAmt); Known.One = LHS.One.ushl_ov(ShiftAmt, ShiftedOutOne); - if (NUW) { - if (ShiftedOutOne) - // One bit has been shifted out. - return std::nullopt; - if (ShiftAmt != 0) + // All cases returning poison have been handled by MaxShiftAmount already. + if (NSW) { + if (NUW && ShiftAmt != 0) // NUW means we can assume anything shifted out was a zero. ShiftedOutZero = true; - } - if (NSW) { - if (ShiftedOutZero && ShiftedOutOne) - // Both zeros and ones have been shifted out. - return std::nullopt; - if (ShiftedOutZero) { - if (Known.isNegative()) - // Zero bit has been shifted out, but result sign is negative. - return std::nullopt; + if (ShiftedOutZero) Known.makeNonNegative(); - } else if (ShiftedOutOne) { - if (Known.isNonNegative()) - // One bit has been shifted out, but result sign is non-negative. - return std::nullopt; + else if (ShiftedOutOne) Known.makeNegative(); - } } return Known; }; @@ -218,8 +210,34 @@ KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW, return Known; } + // Determine maximum shift amount, taking NUW/NSW flags into account. + APInt MaxValue = RHS.getMaxValue(); + unsigned MaxShiftAmount = getMaxShiftAmount(MaxValue, BitWidth); + if (NUW && NSW) + MaxShiftAmount = std::min(MaxShiftAmount, LHS.countMaxLeadingZeros() - 1); + if (NUW) + MaxShiftAmount = std::min(MaxShiftAmount, LHS.countMaxLeadingZeros()); + if (NSW) + MaxShiftAmount = std::min( + MaxShiftAmount, + std::max(LHS.countMaxLeadingZeros(), LHS.countMaxLeadingOnes()) - 1); + + // Fast path for common case where the shift amount is unknown. + if (MinShiftAmount == 0 && MaxShiftAmount == BitWidth - 1 && + isPowerOf2_32(BitWidth)) { + Known.Zero.setLowBits(LHS.countMinTrailingZeros()); + if (LHS.isAllOnes()) + Known.One.setSignBit(); + if (NSW) { + if (LHS.isNonNegative()) + Known.makeNonNegative(); + if (LHS.isNegative()) + Known.makeNegative(); + } + return Known; + } + // Find the common bits from all possible shifts. - unsigned MaxShiftAmount = RHS.getMaxValue().getLimitedValue(BitWidth - 1); unsigned ShiftAmtZeroMask = RHS.Zero.zextOrTrunc(32).getZExtValue(); unsigned ShiftAmtOneMask = RHS.One.zextOrTrunc(32).getZExtValue(); Known.Zero.setAllBits(); @@ -230,11 +248,7 @@ KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS, bool NUW, if ((ShiftAmtZeroMask & ShiftAmt) != 0 || (ShiftAmtOneMask | ShiftAmt) != ShiftAmt) continue; - auto Res = ShiftByConst(LHS, ShiftAmt); - if (!Res) - // All larger shift amounts will overflow as well. - break; - Known = Known.intersectWith(*Res); + Known = Known.intersectWith(ShiftByConst(LHS, ShiftAmt)); if (Known.isUnknown()) break; } -- 2.7.4