diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 | 
| commit | eb11fae6d08f479c0799db45860a98af528fa6e7 (patch) | |
| tree | 44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/Support/APInt.cpp | |
| parent | b8a2042aa938069e862750553db0e4d82d25822c (diff) | |
Notes
Diffstat (limited to 'lib/Support/APInt.cpp')
| -rw-r--r-- | lib/Support/APInt.cpp | 188 | 
1 files changed, 119 insertions, 69 deletions
diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index 1ea6319acfadb..1fae0e9b8d6db 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -18,6 +18,7 @@  #include "llvm/ADT/Hashing.h"  #include "llvm/ADT/SmallString.h"  #include "llvm/ADT/StringRef.h" +#include "llvm/Config/llvm-config.h"  #include "llvm/Support/Debug.h"  #include "llvm/Support/ErrorHandling.h"  #include "llvm/Support/MathExtras.h" @@ -33,8 +34,7 @@ using namespace llvm;  /// A utility function for allocating memory, checking for allocation failures,  /// and ensuring the contents are zeroed.  inline static uint64_t* getClearedMemory(unsigned numWords) { -  uint64_t * result = new uint64_t[numWords]; -  assert(result && "APInt memory allocation fails!"); +  uint64_t *result = new uint64_t[numWords];    memset(result, 0, numWords * sizeof(uint64_t));    return result;  } @@ -42,9 +42,7 @@ inline static uint64_t* getClearedMemory(unsigned numWords) {  /// A utility function for allocating memory and checking for allocation  /// failure.  The content is not zeroed.  inline static uint64_t* getMemory(unsigned numWords) { -  uint64_t * result = new uint64_t[numWords]; -  assert(result && "APInt memory allocation fails!"); -  return result; +  return new uint64_t[numWords];  }  /// A utility function that converts a character to a digit. @@ -170,7 +168,7 @@ void APInt::Profile(FoldingSetNodeID& ID) const {      ID.AddInteger(U.pVal[i]);  } -/// @brief Prefix increment operator. Increments the APInt by one. +/// Prefix increment operator. Increments the APInt by one.  APInt& APInt::operator++() {    if (isSingleWord())      ++U.VAL; @@ -179,7 +177,7 @@ APInt& APInt::operator++() {    return clearUnusedBits();  } -/// @brief Prefix decrement operator. Decrements the APInt by one. +/// Prefix decrement operator. Decrements the APInt by one.  APInt& APInt::operator--() {    if (isSingleWord())      --U.VAL; @@ -190,7 +188,7 @@ APInt& APInt::operator--() {  /// Adds the RHS APint to this APInt.  /// @returns this, after addition of RHS. -/// @brief Addition assignment operator. +/// Addition assignment operator.  APInt& APInt::operator+=(const APInt& RHS) {    assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");    if (isSingleWord()) @@ -210,7 +208,7 @@ APInt& APInt::operator+=(uint64_t RHS) {  /// Subtracts the RHS APInt from this APInt  /// @returns this, after subtraction -/// @brief Subtraction assignment operator. +/// Subtraction assignment operator.  APInt& APInt::operator-=(const APInt& RHS) {    assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");    if (isSingleWord()) @@ -328,7 +326,7 @@ void APInt::setBitsSlowCase(unsigned loBit, unsigned hiBit) {      U.pVal[word] = WORD_MAX;  } -/// @brief Toggle every bit to its opposite value. +/// Toggle every bit to its opposite value.  void APInt::flipAllBitsSlowCase() {    tcComplement(U.pVal, getNumWords());    clearUnusedBits(); @@ -336,7 +334,7 @@ void APInt::flipAllBitsSlowCase() {  /// Toggle a given bit to its opposite value whose position is given  /// as "bitPosition". -/// @brief Toggles a given bit to its opposite value. +/// Toggles a given bit to its opposite value.  void APInt::flipBit(unsigned bitPosition) {    assert(bitPosition < BitWidth && "Out of the bit-width range!");    if ((*this)[bitPosition]) clearBit(bitPosition); @@ -428,11 +426,12 @@ APInt APInt::extractBits(unsigned numBits, unsigned bitPosition) const {    unsigned NumSrcWords = getNumWords();    unsigned NumDstWords = Result.getNumWords(); +  uint64_t *DestPtr = Result.isSingleWord() ? &Result.U.VAL : Result.U.pVal;    for (unsigned word = 0; word < NumDstWords; ++word) {      uint64_t w0 = U.pVal[loWord + word];      uint64_t w1 =          (loWord + word + 1) < NumSrcWords ? U.pVal[loWord + word + 1] : 0; -    Result.U.pVal[word] = (w0 >> loBit) | (w1 << (APINT_BITS_PER_WORD - loBit)); +    DestPtr[word] = (w0 >> loBit) | (w1 << (APINT_BITS_PER_WORD - loBit));    }    return Result.clearUnusedBits(); @@ -909,13 +908,13 @@ APInt APInt::sextOrSelf(unsigned width) const {  }  /// Arithmetic right-shift this APInt by shiftAmt. -/// @brief Arithmetic right-shift function. +/// Arithmetic right-shift function.  void APInt::ashrInPlace(const APInt &shiftAmt) {    ashrInPlace((unsigned)shiftAmt.getLimitedValue(BitWidth));  }  /// Arithmetic right-shift this APInt by shiftAmt. -/// @brief Arithmetic right-shift function. +/// Arithmetic right-shift function.  void APInt::ashrSlowCase(unsigned ShiftAmt) {    // Don't bother performing a no-op shift.    if (!ShiftAmt) @@ -924,7 +923,7 @@ void APInt::ashrSlowCase(unsigned ShiftAmt) {    // Save the original sign bit for later.    bool Negative = isNegative(); -  // WordShift is the inter-part shift; BitShift is is intra-part shift. +  // WordShift is the inter-part shift; BitShift is intra-part shift.    unsigned WordShift = ShiftAmt / APINT_BITS_PER_WORD;    unsigned BitShift = ShiftAmt % APINT_BITS_PER_WORD; @@ -958,19 +957,19 @@ void APInt::ashrSlowCase(unsigned ShiftAmt) {  }  /// Logical right-shift this APInt by shiftAmt. -/// @brief Logical right-shift function. +/// Logical right-shift function.  void APInt::lshrInPlace(const APInt &shiftAmt) {    lshrInPlace((unsigned)shiftAmt.getLimitedValue(BitWidth));  }  /// Logical right-shift this APInt by shiftAmt. -/// @brief Logical right-shift function. +/// Logical right-shift function.  void APInt::lshrSlowCase(unsigned ShiftAmt) {    tcShiftRight(U.pVal, getNumWords(), ShiftAmt);  }  /// Left-shift this APInt by shiftAmt. -/// @brief Left-shift function. +/// Left-shift function.  APInt &APInt::operator<<=(const APInt &shiftAmt) {    // It's undefined behavior in C to shift by BitWidth or greater.    *this <<= (unsigned)shiftAmt.getLimitedValue(BitWidth); @@ -1254,18 +1253,20 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,  // The DEBUG macros here tend to be spam in the debug output if you're not  // debugging this code. Disable them unless KNUTH_DEBUG is defined. -#pragma push_macro("DEBUG") +#pragma push_macro("LLVM_DEBUG")  #ifndef KNUTH_DEBUG -#undef DEBUG -#define DEBUG(X) do {} while (false) +#undef LLVM_DEBUG +#define LLVM_DEBUG(X)                                                          \ +  do {                                                                         \ +  } while (false)  #endif -  DEBUG(dbgs() << "KnuthDiv: m=" << m << " n=" << n << '\n'); -  DEBUG(dbgs() << "KnuthDiv: original:"); -  DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); -  DEBUG(dbgs() << " by"); -  DEBUG(for (int i = n; i >0; i--) dbgs() << " " << v[i-1]); -  DEBUG(dbgs() << '\n'); +  LLVM_DEBUG(dbgs() << "KnuthDiv: m=" << m << " n=" << n << '\n'); +  LLVM_DEBUG(dbgs() << "KnuthDiv: original:"); +  LLVM_DEBUG(for (int i = m + n; i >= 0; i--) dbgs() << " " << u[i]); +  LLVM_DEBUG(dbgs() << " by"); +  LLVM_DEBUG(for (int i = n; i > 0; i--) dbgs() << " " << v[i - 1]); +  LLVM_DEBUG(dbgs() << '\n');    // D1. [Normalize.] Set d = b / (v[n-1] + 1) and multiply all the digits of    // u and v by d. Note that we have taken Knuth's advice here to use a power    // of 2 value for d such that d * v[n-1] >= b/2 (b is the base). A power of @@ -1291,16 +1292,16 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,    }    u[m+n] = u_carry; -  DEBUG(dbgs() << "KnuthDiv:   normal:"); -  DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); -  DEBUG(dbgs() << " by"); -  DEBUG(for (int i = n; i >0; i--) dbgs() << " " << v[i-1]); -  DEBUG(dbgs() << '\n'); +  LLVM_DEBUG(dbgs() << "KnuthDiv:   normal:"); +  LLVM_DEBUG(for (int i = m + n; i >= 0; i--) dbgs() << " " << u[i]); +  LLVM_DEBUG(dbgs() << " by"); +  LLVM_DEBUG(for (int i = n; i > 0; i--) dbgs() << " " << v[i - 1]); +  LLVM_DEBUG(dbgs() << '\n');    // D2. [Initialize j.]  Set j to m. This is the loop counter over the places.    int j = m;    do { -    DEBUG(dbgs() << "KnuthDiv: quotient digit #" << j << '\n'); +    LLVM_DEBUG(dbgs() << "KnuthDiv: quotient digit #" << j << '\n');      // D3. [Calculate q'.].      //     Set qp = (u[j+n]*b + u[j+n-1]) / v[n-1]. (qp=qprime=q')      //     Set rp = (u[j+n]*b + u[j+n-1]) % v[n-1]. (rp=rprime=r') @@ -1310,7 +1311,7 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,      // value qp is one too large, and it eliminates all cases where qp is two      // too large.      uint64_t dividend = Make_64(u[j+n], u[j+n-1]); -    DEBUG(dbgs() << "KnuthDiv: dividend == " << dividend << '\n'); +    LLVM_DEBUG(dbgs() << "KnuthDiv: dividend == " << dividend << '\n');      uint64_t qp = dividend / v[n-1];      uint64_t rp = dividend % v[n-1];      if (qp == b || qp*v[n-2] > b*rp + u[j+n-2]) { @@ -1319,7 +1320,7 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,        if (rp < b && (qp == b || qp*v[n-2] > b*rp + u[j+n-2]))          qp--;      } -    DEBUG(dbgs() << "KnuthDiv: qp == " << qp << ", rp == " << rp << '\n'); +    LLVM_DEBUG(dbgs() << "KnuthDiv: qp == " << qp << ", rp == " << rp << '\n');      // D4. [Multiply and subtract.] Replace (u[j+n]u[j+n-1]...u[j]) with      // (u[j+n]u[j+n-1]..u[j]) - qp * (v[n-1]...v[1]v[0]). This computation @@ -1335,15 +1336,15 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,        int64_t subres = int64_t(u[j+i]) - borrow - Lo_32(p);        u[j+i] = Lo_32(subres);        borrow = Hi_32(p) - Hi_32(subres); -      DEBUG(dbgs() << "KnuthDiv: u[j+i] = " << u[j+i] -                   << ", borrow = " << borrow << '\n'); +      LLVM_DEBUG(dbgs() << "KnuthDiv: u[j+i] = " << u[j + i] +                        << ", borrow = " << borrow << '\n');      }      bool isNeg = u[j+n] < borrow;      u[j+n] -= Lo_32(borrow); -    DEBUG(dbgs() << "KnuthDiv: after subtraction:"); -    DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); -    DEBUG(dbgs() << '\n'); +    LLVM_DEBUG(dbgs() << "KnuthDiv: after subtraction:"); +    LLVM_DEBUG(for (int i = m + n; i >= 0; i--) dbgs() << " " << u[i]); +    LLVM_DEBUG(dbgs() << '\n');      // D5. [Test remainder.] Set q[j] = qp. If the result of step D4 was      // negative, go to step D6; otherwise go on to step D7. @@ -1364,16 +1365,16 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,        }        u[j+n] += carry;      } -    DEBUG(dbgs() << "KnuthDiv: after correction:"); -    DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); -    DEBUG(dbgs() << "\nKnuthDiv: digit result = " << q[j] << '\n'); +    LLVM_DEBUG(dbgs() << "KnuthDiv: after correction:"); +    LLVM_DEBUG(for (int i = m + n; i >= 0; i--) dbgs() << " " << u[i]); +    LLVM_DEBUG(dbgs() << "\nKnuthDiv: digit result = " << q[j] << '\n'); -  // D7. [Loop on j.]  Decrease j by one. Now if j >= 0, go back to D3. +    // D7. [Loop on j.]  Decrease j by one. Now if j >= 0, go back to D3.    } while (--j >= 0); -  DEBUG(dbgs() << "KnuthDiv: quotient:"); -  DEBUG(for (int i = m; i >=0; i--) dbgs() <<" " << q[i]); -  DEBUG(dbgs() << '\n'); +  LLVM_DEBUG(dbgs() << "KnuthDiv: quotient:"); +  LLVM_DEBUG(for (int i = m; i >= 0; i--) dbgs() << " " << q[i]); +  LLVM_DEBUG(dbgs() << '\n');    // D8. [Unnormalize]. Now q[...] is the desired quotient, and the desired    // remainder may be obtained by dividing u[...] by d. If r is non-null we @@ -1384,23 +1385,23 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,      // shift right here.      if (shift) {        uint32_t carry = 0; -      DEBUG(dbgs() << "KnuthDiv: remainder:"); +      LLVM_DEBUG(dbgs() << "KnuthDiv: remainder:");        for (int i = n-1; i >= 0; i--) {          r[i] = (u[i] >> shift) | carry;          carry = u[i] << (32 - shift); -        DEBUG(dbgs() << " " << r[i]); +        LLVM_DEBUG(dbgs() << " " << r[i]);        }      } else {        for (int i = n-1; i >= 0; i--) {          r[i] = u[i]; -        DEBUG(dbgs() << " " << r[i]); +        LLVM_DEBUG(dbgs() << " " << r[i]);        }      } -    DEBUG(dbgs() << '\n'); +    LLVM_DEBUG(dbgs() << '\n');    } -  DEBUG(dbgs() << '\n'); +  LLVM_DEBUG(dbgs() << '\n'); -#pragma pop_macro("DEBUG") +#pragma pop_macro("LLVM_DEBUG")  }  void APInt::divide(const WordType *LHS, unsigned lhsWords, const WordType *RHS, @@ -1734,25 +1735,25 @@ void APInt::udivrem(const APInt &LHS, const APInt &RHS,    // Check the degenerate cases    if (lhsWords == 0) { -    Quotient = 0;                // 0 / Y ===> 0 -    Remainder = 0;               // 0 % Y ===> 0 +    Quotient = APInt(BitWidth, 0);    // 0 / Y ===> 0 +    Remainder = APInt(BitWidth, 0);   // 0 % Y ===> 0      return;    }    if (rhsBits == 1) { -    Quotient = LHS;             // X / 1 ===> X -    Remainder = 0;              // X % 1 ===> 0 +    Quotient = LHS;                   // X / 1 ===> X +    Remainder = APInt(BitWidth, 0);   // X % 1 ===> 0    }    if (lhsWords < rhsWords || LHS.ult(RHS)) { -    Remainder = LHS;            // X % Y ===> X, iff X < Y -    Quotient = 0;               // X / Y ===> 0, iff X < Y +    Remainder = LHS;                  // X % Y ===> X, iff X < Y +    Quotient = APInt(BitWidth, 0);    // X / Y ===> 0, iff X < Y      return;    }    if (LHS == RHS) { -    Quotient  = 1;              // X / X ===> 1 -    Remainder = 0;              // X % X ===> 0; +    Quotient  = APInt(BitWidth, 1);   // X / X ===> 1 +    Remainder = APInt(BitWidth, 0);   // X % X ===> 0;      return;    } @@ -1800,25 +1801,26 @@ void APInt::udivrem(const APInt &LHS, uint64_t RHS, APInt &Quotient,    // Check the degenerate cases    if (lhsWords == 0) { -    Quotient = 0;                // 0 / Y ===> 0 -    Remainder = 0;               // 0 % Y ===> 0 +    Quotient = APInt(BitWidth, 0);    // 0 / Y ===> 0 +    Remainder = 0;                    // 0 % Y ===> 0      return;    }    if (RHS == 1) { -    Quotient = LHS;             // X / 1 ===> X -    Remainder = 0;              // X % 1 ===> 0 +    Quotient = LHS;                   // X / 1 ===> X +    Remainder = 0;                    // X % 1 ===> 0 +    return;    }    if (LHS.ult(RHS)) { -    Remainder = LHS.getZExtValue(); // X % Y ===> X, iff X < Y -    Quotient = 0;                   // X / Y ===> 0, iff X < Y +    Remainder = LHS.getZExtValue();   // X % Y ===> X, iff X < Y +    Quotient = APInt(BitWidth, 0);    // X / Y ===> 0, iff X < Y      return;    }    if (LHS == RHS) { -    Quotient  = 1;              // X / X ===> 1 -    Remainder = 0;              // X % X ===> 0; +    Quotient  = APInt(BitWidth, 1);   // X / X ===> 1 +    Remainder = 0;                    // X % X ===> 0;      return;    } @@ -2657,3 +2659,51 @@ 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; +  } +  } +  llvm_unreachable("Unknown APInt::Rounding enum"); +} + +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); +  } +  llvm_unreachable("Unknown APInt::Rounding enum"); +}  | 
