[PATCH] D71011: [ConstantRange] Add `shlWithNoWrap()` method

Nikita Popov via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 8 08:47:37 PST 2019


nikic added a comment.

Unlike the mul case, it should be possible to efficiently compute a precise shl range. This is the implementation I came up with for the nuw case:

  if (NoWrapKind == OBO::NoUnsignedWrap) {
    APInt Min = getUnsignedMin(), Max = getUnsignedMax();
    unsigned MinLeadingZeros = Max.countLeadingZeros();
    unsigned MaxLeadingZeros = Min.countLeadingZeros();
    unsigned ShAmtMax = ShAmt.getUnsignedMax().getLimitedValue();
    unsigned ShAmtMin = ShAmt.getUnsignedMin().getLimitedValue();
    if (ShAmtMin > MaxLeadingZeros)
      // All possible shifts will overflow.
      return getEmpty();
  
    APInt ResMin = Min.shl(ShAmtMin);
    // We'll pick the larger of two possible upper bounds, initialize to zero.
    APInt ResMax = APInt::getNullValue(BitWidth);
    // Shift the maximum as far as possible without overflowing.
    if (ShAmtMin <= MinLeadingZeros)
      ResMax = Max.shl(std::min(ShAmtMax, MinLeadingZeros));
    // Pick the largest number with all low bits sets that is both in the LHS
    // range and can be shifted without overflowing.
    if (MinLeadingZeros != MaxLeadingZeros && ShAmtMax >= MinLeadingZeros + 1) {
      unsigned Shift = std::max(ShAmtMin, MinLeadingZeros + 1);
      ResMax = APIntOps::umax(ResMax,
          APInt::getLowBitsSet(BitWidth, BitWidth - Shift).shl(Shift));
    }
    return getNonEmpty(ResMin, ResMax + 1);
  }

It passes the exhaustive test without the correctness only flag.

Extending this to the nuw+nsw case should be fairly simple, as it basically just has one less usable bit. I haven't thought about the nsw case yet.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D71011/new/

https://reviews.llvm.org/D71011





More information about the llvm-commits mailing list