[llvm] r335557 - [APInt] Add helpers for rounding u/sdivs.
Tim Shen via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 25 16:49:20 PDT 2018
Author: timshen
Date: Mon Jun 25 16:49:20 2018
New Revision: 335557
URL: http://llvm.org/viewvc/llvm-project?rev=335557&view=rev
Log:
[APInt] Add helpers for rounding u/sdivs.
Reviewers: sanjoy, craig.topper
Subscribers: jlebar, hiraditya, bixia, llvm-commits
Differential Revision: https://reviews.llvm.org/D48498
Modified:
llvm/trunk/include/llvm/ADT/APInt.h
llvm/trunk/lib/Support/APInt.cpp
llvm/trunk/unittests/ADT/APIntTest.cpp
Modified: llvm/trunk/include/llvm/ADT/APInt.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/APInt.h?rev=335557&r1=335556&r2=335557&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/APInt.h (original)
+++ llvm/trunk/include/llvm/ADT/APInt.h Mon Jun 25 16:49:20 2018
@@ -78,6 +78,12 @@ public:
APINT_BITS_PER_WORD = APINT_WORD_SIZE * CHAR_BIT
};
+ enum class Rounding {
+ DOWN,
+ TOWARD_ZERO,
+ UP,
+ };
+
static const WordType WORD_MAX = ~WordType(0);
private:
@@ -1039,13 +1045,16 @@ public:
/// Perform an unsigned divide operation on this APInt by RHS. Both this and
/// RHS are treated as unsigned quantities for purposes of this division.
///
- /// \returns a new APInt value containing the division result
+ /// \returns a new APInt value containing the division result, rounded towards
+ /// zero.
APInt udiv(const APInt &RHS) const;
APInt udiv(uint64_t RHS) const;
/// Signed division function for APInt.
///
/// Signed divide this APInt by APInt RHS.
+ ///
+ /// The result is rounded towards zero.
APInt sdiv(const APInt &RHS) const;
APInt sdiv(int64_t RHS) const;
@@ -2151,6 +2160,12 @@ inline APInt RoundFloatToAPInt(float Flo
return RoundDoubleToAPInt(double(Float), width);
}
+/// Return A unsign-divided by B, rounded by the given rounding mode.
+APInt RoundingUDiv(const APInt &A, const APInt &B, APInt::Rounding RM);
+
+/// Return A sign-divided by B, rounded by the given rounding mode.
+APInt RoundingSDiv(const APInt &A, const APInt &B, APInt::Rounding RM);
+
} // End of APIntOps namespace
// See friend declaration above. This additional declaration is required in
Modified: llvm/trunk/lib/Support/APInt.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/APInt.cpp?rev=335557&r1=335556&r2=335557&view=diff
==============================================================================
--- llvm/trunk/lib/Support/APInt.cpp (original)
+++ llvm/trunk/lib/Support/APInt.cpp Mon Jun 25 16:49:20 2018
@@ -2658,3 +2658,49 @@ void APInt::tcSetLeastSignificantBits(Wo
while (i < parts)
dst[i++] = 0;
}
+
+APInt llvm::APIntOps::RoundingUDiv(const APInt &A, const APInt &B,
+ APInt::Rounding RM) {
+ // Currently udivrem always rounds down.
+ switch (RM) {
+ case APInt::Rounding::DOWN:
+ case APInt::Rounding::TOWARD_ZERO:
+ return A.udiv(B);
+ case APInt::Rounding::UP: {
+ APInt Quo, Rem;
+ APInt::udivrem(A, B, Quo, Rem);
+ if (Rem == 0)
+ return Quo;
+ return Quo + 1;
+ }
+ }
+}
+
+APInt llvm::APIntOps::RoundingSDiv(const APInt &A, const APInt &B,
+ APInt::Rounding RM) {
+ switch (RM) {
+ case APInt::Rounding::DOWN:
+ case APInt::Rounding::UP: {
+ APInt Quo, Rem;
+ APInt::sdivrem(A, B, Quo, Rem);
+ if (Rem == 0)
+ return Quo;
+ // This algorithm deals with arbitrary rounding mode used by sdivrem.
+ // We want to check whether the non-integer part of the mathematical value
+ // is negative or not. If the non-integer part is negative, we need to round
+ // down from Quo; otherwise, if it's positive or 0, we return Quo, as it's
+ // already rounded down.
+ if (RM == APInt::Rounding::DOWN) {
+ if (Rem.isNegative() != B.isNegative())
+ return Quo - 1;
+ return Quo;
+ }
+ if (Rem.isNegative() != B.isNegative())
+ return Quo;
+ return Quo + 1;
+ }
+ // Currently sdiv rounds twards zero.
+ case APInt::Rounding::TOWARD_ZERO:
+ return A.sdiv(B);
+ }
+}
Modified: llvm/trunk/unittests/ADT/APIntTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/APIntTest.cpp?rev=335557&r1=335556&r2=335557&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/APIntTest.cpp (original)
+++ llvm/trunk/unittests/ADT/APIntTest.cpp Mon Jun 25 16:49:20 2018
@@ -2258,4 +2258,71 @@ TEST(APIntTest, multiply) {
EXPECT_EQ(64U, i96.countTrailingZeros());
}
+TEST(APIntTest, RoundingUDiv) {
+ for (uint64_t Ai = 1; Ai <= 255; Ai++) {
+ APInt A(8, Ai);
+ APInt Zero(8, 0);
+ EXPECT_EQ(0, APIntOps::RoundingUDiv(Zero, A, APInt::Rounding::UP));
+ EXPECT_EQ(0, APIntOps::RoundingUDiv(Zero, A, APInt::Rounding::DOWN));
+ EXPECT_EQ(0, APIntOps::RoundingUDiv(Zero, A, APInt::Rounding::TOWARD_ZERO));
+
+ for (uint64_t Bi = 1; Bi <= 255; Bi++) {
+ APInt B(8, Bi);
+ {
+ APInt Quo = APIntOps::RoundingUDiv(A, B, APInt::Rounding::UP);
+ auto Prod = Quo.zext(16) * B.zext(16);
+ EXPECT_TRUE(Prod.uge(Ai));
+ if (Prod.ugt(Ai)) {
+ EXPECT_TRUE(((Quo - 1).zext(16) * B.zext(16)).ult(Ai));
+ }
+ }
+ {
+ APInt Quo = A.udiv(B);
+ EXPECT_EQ(Quo, APIntOps::RoundingUDiv(A, B, APInt::Rounding::TOWARD_ZERO));
+ EXPECT_EQ(Quo, APIntOps::RoundingUDiv(A, B, APInt::Rounding::DOWN));
+ }
+ }
+ }
+}
+
+TEST(APIntTest, RoundingSDiv) {
+ for (int64_t Ai = -128; Ai <= 127; Ai++) {
+ APInt A(8, Ai);
+
+ if (Ai != 0) {
+ APInt Zero(8, 0);
+ EXPECT_EQ(0, APIntOps::RoundingSDiv(Zero, A, APInt::Rounding::UP));
+ EXPECT_EQ(0, APIntOps::RoundingSDiv(Zero, A, APInt::Rounding::DOWN));
+ EXPECT_EQ(0, APIntOps::RoundingSDiv(Zero, A, APInt::Rounding::TOWARD_ZERO));
+ }
+
+ for (uint64_t Bi = -128; Bi <= 127; Bi++) {
+ if (Bi == 0)
+ continue;
+
+ APInt B(8, Bi);
+ {
+ APInt Quo = APIntOps::RoundingSDiv(A, B, APInt::Rounding::UP);
+ auto Prod = Quo.sext(16) * B.sext(16);
+ EXPECT_TRUE(Prod.uge(A));
+ if (Prod.ugt(A)) {
+ EXPECT_TRUE(((Quo - 1).sext(16) * B.sext(16)).ult(A));
+ }
+ }
+ {
+ APInt Quo = APIntOps::RoundingSDiv(A, B, APInt::Rounding::DOWN);
+ auto Prod = Quo.sext(16) * B.sext(16);
+ EXPECT_TRUE(Prod.ule(A));
+ if (Prod.ult(A)) {
+ EXPECT_TRUE(((Quo + 1).sext(16) * B.sext(16)).ugt(A));
+ }
+ }
+ {
+ APInt Quo = A.sdiv(B);
+ EXPECT_EQ(Quo, APIntOps::RoundingSDiv(A, B, APInt::Rounding::TOWARD_ZERO));
+ }
+ }
+ }
+}
+
} // end anonymous namespace
More information about the llvm-commits
mailing list