diff options
author | Noah Goldstein <goldstein.w.n@gmail.com> | 2023-05-06 20:58:23 -0500 |
---|---|---|
committer | Noah Goldstein <goldstein.w.n@gmail.com> | 2023-05-16 18:58:12 -0500 |
commit | 7d05ab99edb9f5ef06c3d635afcd22502866f447 (patch) | |
tree | 1e1b4191245d697489c5d28f28aecb08a3d1fa84 | |
parent | 8c569c922bc5bbe9fb67ff3ff3ac28e17b012360 (diff) | |
download | llvm-7d05ab99edb9f5ef06c3d635afcd22502866f447.zip llvm-7d05ab99edb9f5ef06c3d635afcd22502866f447.tar.gz llvm-7d05ab99edb9f5ef06c3d635afcd22502866f447.tar.bz2 |
[KnownBits] Improve `KnownBits::udiv`
We can more precisely determine the upper bits doing `MaxNum /
MinDenum` as opposed to only using the MSB.
As well, if the `exact` flag is set, we can sometimes determine some
of the low-bits.
Differential Revision: https://reviews.llvm.org/D150094
-rw-r--r-- | llvm/include/llvm/Support/KnownBits.h | 3 | ||||
-rw-r--r-- | llvm/lib/Support/KnownBits.cpp | 30 | ||||
-rw-r--r-- | llvm/test/Analysis/ValueTracking/knownbits-div.ll | 7 | ||||
-rw-r--r-- | llvm/unittests/Support/KnownBitsTest.cpp | 10 |
4 files changed, 34 insertions, 16 deletions
diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h index bce234e..a997d8d 100644 --- a/llvm/include/llvm/Support/KnownBits.h +++ b/llvm/include/llvm/Support/KnownBits.h @@ -347,7 +347,8 @@ public: bool Exact = false); /// Compute known bits for udiv(LHS, RHS). - static KnownBits udiv(const KnownBits &LHS, const KnownBits &RHS); + static KnownBits udiv(const KnownBits &LHS, const KnownBits &RHS, + bool Exact = false); /// Compute known bits for urem(LHS, RHS). static KnownBits urem(const KnownBits &LHS, const KnownBits &RHS); diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp index a00cc04..a806ac2 100644 --- a/llvm/lib/Support/KnownBits.cpp +++ b/llvm/lib/Support/KnownBits.cpp @@ -540,7 +540,7 @@ KnownBits KnownBits::sdiv(const KnownBits &LHS, const KnownBits &RHS, bool Exact) { // Equivilent of `udiv`. We must have caught this before it was folded. if (LHS.isNonNegative() && RHS.isNonNegative()) - return udiv(LHS, RHS); + return udiv(LHS, RHS, Exact); unsigned BitWidth = LHS.getBitWidth(); assert(!LHS.hasConflict() && !RHS.hasConflict() && "Bad inputs"); @@ -604,21 +604,33 @@ KnownBits KnownBits::sdiv(const KnownBits &LHS, const KnownBits &RHS, return Known; } -KnownBits KnownBits::udiv(const KnownBits &LHS, const KnownBits &RHS) { +KnownBits KnownBits::udiv(const KnownBits &LHS, const KnownBits &RHS, + bool Exact) { unsigned BitWidth = LHS.getBitWidth(); assert(!LHS.hasConflict() && !RHS.hasConflict()); KnownBits Known(BitWidth); - // For the purposes of computing leading zeros we can conservatively - // treat a udiv as a logical right shift by the power of 2 known to - // be less than the denominator. - unsigned LeadZ = LHS.countMinLeadingZeros(); - unsigned RHSMaxLeadingZeros = RHS.countMaxLeadingZeros(); + // We can figure out the minimum number of upper zero bits by doing + // MaxNumerator / MinDenominator. If the Numerator gets smaller or Denominator + // gets larger, the number of upper zero bits increases. + APInt MinDenum = RHS.getMinValue(); + APInt MaxNum = LHS.getMaxValue(); + APInt MaxRes = MinDenum.isZero() ? MaxNum : MaxNum.udiv(MinDenum); - if (RHSMaxLeadingZeros != BitWidth) - LeadZ = std::min(BitWidth, LeadZ + BitWidth - RHSMaxLeadingZeros - 1); + unsigned LeadZ = MaxRes.countLeadingZeros(); Known.Zero.setHighBits(LeadZ); + if (Exact) { + // Odd / Odd -> Odd + if (LHS.One[0] && RHS.One[0]) + Known.One.setBit(0); + // Even / Odd -> Even + else if (LHS.Zero[0] && RHS.One[0]) + Known.Zero.setBit(0); + // Odd / Even -> impossible + // Even / Even -> unknown + } + return Known; } diff --git a/llvm/test/Analysis/ValueTracking/knownbits-div.ll b/llvm/test/Analysis/ValueTracking/knownbits-div.ll index ece4121..586d3af 100644 --- a/llvm/test/Analysis/ValueTracking/knownbits-div.ll +++ b/llvm/test/Analysis/ValueTracking/knownbits-div.ll @@ -185,12 +185,7 @@ define i1 @sdiv_exact_even_even_fail_unknown2(i8 %x, i8 %y) { define i1 @udiv_high_bits(i8 %x, i8 %y) { ; CHECK-LABEL: @udiv_high_bits( -; CHECK-NEXT: [[NUM:%.*]] = and i8 [[X:%.*]], -127 -; CHECK-NEXT: [[DENUM:%.*]] = or i8 [[Y:%.*]], 31 -; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[NUM]], [[DENUM]] -; CHECK-NEXT: [[AND:%.*]] = and i8 [[DIV]], 8 -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 8 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 false ; %num = and i8 %x, 129 %denum = or i8 %y, 31 diff --git a/llvm/unittests/Support/KnownBitsTest.cpp b/llvm/unittests/Support/KnownBitsTest.cpp index 22dcbed..0322da6 100644 --- a/llvm/unittests/Support/KnownBitsTest.cpp +++ b/llvm/unittests/Support/KnownBitsTest.cpp @@ -251,6 +251,16 @@ TEST(KnownBitsTest, BinaryExhaustive) { checkCorrectnessOnlyBinary); testBinaryOpExhaustive( [](const KnownBits &Known1, const KnownBits &Known2) { + return KnownBits::udiv(Known1, Known2, /*Exact*/ true); + }, + [](const APInt &N1, const APInt &N2) -> std::optional<APInt> { + if (N2.isZero() || !N1.urem(N2).isZero()) + return std::nullopt; + return N1.udiv(N2); + }, + checkCorrectnessOnlyBinary); + testBinaryOpExhaustive( + [](const KnownBits &Known1, const KnownBits &Known2) { return KnownBits::sdiv(Known1, Known2); }, [](const APInt &N1, const APInt &N2) -> std::optional<APInt> { |