mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[APInt] Add helpers for rounding u/sdivs.
Reviewers: sanjoy, craig.topper Subscribers: jlebar, hiraditya, bixia, llvm-commits Differential Revision: https://reviews.llvm.org/D48498 llvm-svn: 335557
This commit is contained in:
parent
758bcd038b
commit
41ecf3ef5e
@ -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 Float, unsigned width) {
|
||||
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
|
||||
|
@ -2658,3 +2658,49 @@ void APInt::tcSetLeastSignificantBits(WordType *dst, unsigned parts,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user