diff options
author | Renato Golin <renato.golin@linaro.org> | 2017-04-23 12:02:07 +0000 |
---|---|---|
committer | Renato Golin <renato.golin@linaro.org> | 2017-04-23 12:02:07 +0000 |
commit | cc4a9120f6944a48d1df4c676ee77af3904b4442 (patch) | |
tree | 6dd41ba00fdfbb394e8dc3fd2107ede0cea9db8b /llvm/lib/Support/APInt.cpp | |
parent | 137c44fe64ad900e234e38b8c61f5b972b58e051 (diff) | |
download | llvm-cc4a9120f6944a48d1df4c676ee77af3904b4442.zip llvm-cc4a9120f6944a48d1df4c676ee77af3904b4442.tar.gz llvm-cc4a9120f6944a48d1df4c676ee77af3904b4442.tar.bz2 |
Revert "[APInt] Add ashrInPlace method and implement ashr using it. Also fix a bug in the shift by BitWidth handling."
This reverts commit r301094, as it broke all ARM self-hosting bots.
PR32754.
llvm-svn: 301110
Diffstat (limited to 'llvm/lib/Support/APInt.cpp')
-rw-r--r-- | llvm/lib/Support/APInt.cpp | 99 |
1 files changed, 73 insertions, 26 deletions
diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp index 5f3358d..1c697d3 100644 --- a/llvm/lib/Support/APInt.cpp +++ b/llvm/lib/Support/APInt.cpp @@ -1029,42 +1029,89 @@ APInt APInt::sextOrSelf(unsigned width) const { /// Arithmetic right-shift this APInt by shiftAmt. /// @brief Arithmetic right-shift function. -void APInt::ashrInPlace(const APInt &shiftAmt) { - ashrInPlace((unsigned)shiftAmt.getLimitedValue(BitWidth)); +APInt APInt::ashr(const APInt &shiftAmt) const { + return ashr((unsigned)shiftAmt.getLimitedValue(BitWidth)); } /// Arithmetic right-shift this APInt by shiftAmt. /// @brief Arithmetic right-shift function. -void APInt::ashrSlowCase(unsigned ShiftAmt) { - // Don't bother performing a no-op shift. - if (!ShiftAmt) - return; - - bool Negative = isNegative(); +APInt APInt::ashr(unsigned shiftAmt) const { + assert(shiftAmt <= BitWidth && "Invalid shift amount"); + // Handle a degenerate case + if (shiftAmt == 0) + return *this; - // WordShift is the inter-part shift; BitShift is is intra-part shift. - unsigned Words = getNumWords(); - unsigned WordShift = std::min(ShiftAmt / APINT_BITS_PER_WORD, Words); - unsigned BitShift = ShiftAmt % APINT_BITS_PER_WORD; + // Handle single word shifts with built-in ashr + if (isSingleWord()) { + if (shiftAmt == BitWidth) + return APInt(BitWidth, 0); // undefined + return APInt(BitWidth, SignExtend64(VAL, BitWidth) >> shiftAmt); + } - unsigned WordsToMove = Words - WordShift; - // Fastpath for moving by whole words. - if (BitShift == 0) { - std::memmove(pVal, pVal + WordShift, WordsToMove * APINT_WORD_SIZE); + // If all the bits were shifted out, the result is, technically, undefined. + // We return -1 if it was negative, 0 otherwise. We check this early to avoid + // issues in the algorithm below. + if (shiftAmt == BitWidth) { + if (isNegative()) + return APInt(BitWidth, WORD_MAX, true); + else + return APInt(BitWidth, 0); + } + + // Create some space for the result. + uint64_t * val = new uint64_t[getNumWords()]; + + // Compute some values needed by the following shift algorithms + unsigned wordShift = shiftAmt % APINT_BITS_PER_WORD; // bits to shift per word + unsigned offset = shiftAmt / APINT_BITS_PER_WORD; // word offset for shift + unsigned breakWord = getNumWords() - 1 - offset; // last word affected + unsigned bitsInWord = whichBit(BitWidth); // how many bits in last word? + if (bitsInWord == 0) + bitsInWord = APINT_BITS_PER_WORD; + + // If we are shifting whole words, just move whole words + if (wordShift == 0) { + // Move the words containing significant bits + for (unsigned i = 0; i <= breakWord; ++i) + val[i] = pVal[i+offset]; // move whole word + + // Adjust the top significant word for sign bit fill, if negative + if (isNegative()) + if (bitsInWord < APINT_BITS_PER_WORD) + val[breakWord] |= WORD_MAX << bitsInWord; // set high bits } else { - for (unsigned i = 0; i != WordsToMove; ++i) { - pVal[i] = pVal[i + WordShift] >> BitShift; - if (i + 1 != WordsToMove) - pVal[i] |= pVal[i + WordShift + 1] << (APINT_BITS_PER_WORD - BitShift); - else if (Negative) - pVal[i] |= WORD_MAX << (APINT_BITS_PER_WORD - BitShift); + // Shift the low order words + for (unsigned i = 0; i < breakWord; ++i) { + // This combines the shifted corresponding word with the low bits from + // the next word (shifted into this word's high bits). + val[i] = (pVal[i+offset] >> wordShift) | + (pVal[i+offset+1] << (APINT_BITS_PER_WORD - wordShift)); + } + + // Shift the break word. In this case there are no bits from the next word + // to include in this word. + val[breakWord] = pVal[breakWord+offset] >> wordShift; + + // Deal with sign extension in the break word, and possibly the word before + // it. + if (isNegative()) { + if (wordShift > bitsInWord) { + if (breakWord > 0) + val[breakWord-1] |= + WORD_MAX << (APINT_BITS_PER_WORD - (wordShift - bitsInWord)); + val[breakWord] |= WORD_MAX; + } else + val[breakWord] |= WORD_MAX << (bitsInWord - wordShift); } } - // Fill in the remainder based on the original sign. - std::memset(pVal + WordsToMove, Negative ? -1 : 0, - WordShift * APINT_WORD_SIZE); - clearUnusedBits(); + // Remaining words are 0 or -1, just assign them. + uint64_t fillValue = (isNegative() ? WORD_MAX : 0); + for (unsigned i = breakWord+1; i < getNumWords(); ++i) + val[i] = fillValue; + APInt Result(val, BitWidth); + Result.clearUnusedBits(); + return Result; } /// Logical right-shift this APInt by shiftAmt. |