mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 16:06:07 +00:00
[APInt] Make operator<<= shift in place. Improve the implementation of tcShiftLeft and use it to implement operator<<=.
llvm-svn: 300526
This commit is contained in:
parent
8439c8ed13
commit
a8a4f0db79
@ -189,7 +189,7 @@ private:
|
||||
void initSlowCase(const APInt &that);
|
||||
|
||||
/// out-of-line slow case for shl
|
||||
APInt shlSlowCase(unsigned shiftAmt) const;
|
||||
void shlSlowCase(unsigned ShiftAmt);
|
||||
|
||||
/// out-of-line slow case for operator=
|
||||
APInt &AssignSlowCase(const APInt &RHS);
|
||||
@ -842,9 +842,16 @@ public:
|
||||
///
|
||||
/// Shifts *this left by shiftAmt and assigns the result to *this.
|
||||
///
|
||||
/// \returns *this after shifting left by shiftAmt
|
||||
APInt &operator<<=(unsigned shiftAmt) {
|
||||
*this = shl(shiftAmt);
|
||||
/// \returns *this after shifting left by ShiftAmt
|
||||
APInt &operator<<=(unsigned ShiftAmt) {
|
||||
if (isSingleWord()) {
|
||||
if (ShiftAmt >= BitWidth)
|
||||
VAL = 0;
|
||||
else
|
||||
VAL <<= ShiftAmt;
|
||||
return clearUnusedBits();
|
||||
}
|
||||
shlSlowCase(ShiftAmt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -888,13 +895,9 @@ public:
|
||||
///
|
||||
/// Left-shift this APInt by shiftAmt.
|
||||
APInt shl(unsigned shiftAmt) const {
|
||||
assert(shiftAmt <= BitWidth && "Invalid shift amount");
|
||||
if (isSingleWord()) {
|
||||
if (shiftAmt >= BitWidth)
|
||||
return APInt(BitWidth, 0); // avoid undefined shift results
|
||||
return APInt(BitWidth, VAL << shiftAmt);
|
||||
}
|
||||
return shlSlowCase(shiftAmt);
|
||||
APInt R(*this);
|
||||
R <<= shiftAmt;
|
||||
return R;
|
||||
}
|
||||
|
||||
/// \brief Rotate left by rotateAmt.
|
||||
@ -1765,9 +1768,9 @@ public:
|
||||
WordType *remainder, WordType *scratch,
|
||||
unsigned parts);
|
||||
|
||||
/// Shift a bignum left COUNT bits. Shifted in bits are zero. There are no
|
||||
/// restrictions on COUNT.
|
||||
static void tcShiftLeft(WordType *, unsigned parts, unsigned count);
|
||||
/// Shift a bignum left Count bits. Shifted in bits are zero. There are no
|
||||
/// restrictions on Count.
|
||||
static void tcShiftLeft(WordType *, unsigned Words, unsigned Count);
|
||||
|
||||
/// Shift a bignum right Count bits. Shifted in bits are zero. There are no
|
||||
/// restrictions on Count.
|
||||
|
@ -1161,60 +1161,9 @@ APInt APInt::shl(const APInt &shiftAmt) const {
|
||||
return shl((unsigned)shiftAmt.getLimitedValue(BitWidth));
|
||||
}
|
||||
|
||||
APInt APInt::shlSlowCase(unsigned shiftAmt) const {
|
||||
// If all the bits were shifted out, the result is 0. This avoids issues
|
||||
// with shifting by the size of the integer type, which produces undefined
|
||||
// results. We define these "undefined results" to always be 0.
|
||||
if (shiftAmt == BitWidth)
|
||||
return APInt(BitWidth, 0);
|
||||
|
||||
// If none of the bits are shifted out, the result is *this. This avoids a
|
||||
// lshr by the words size in the loop below which can produce incorrect
|
||||
// results. It also avoids the expensive computation below for a common case.
|
||||
if (shiftAmt == 0)
|
||||
return *this;
|
||||
|
||||
// Create some space for the result.
|
||||
uint64_t * val = new uint64_t[getNumWords()];
|
||||
|
||||
// If we are shifting less than a word, do it the easy way
|
||||
if (shiftAmt < APINT_BITS_PER_WORD) {
|
||||
uint64_t carry = 0;
|
||||
for (unsigned i = 0; i < getNumWords(); i++) {
|
||||
val[i] = pVal[i] << shiftAmt | carry;
|
||||
carry = pVal[i] >> (APINT_BITS_PER_WORD - shiftAmt);
|
||||
}
|
||||
APInt Result(val, BitWidth);
|
||||
Result.clearUnusedBits();
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Compute some values needed by the remaining shift algorithms
|
||||
unsigned wordShift = shiftAmt % APINT_BITS_PER_WORD;
|
||||
unsigned offset = shiftAmt / APINT_BITS_PER_WORD;
|
||||
|
||||
// If we are shifting whole words, just move whole words
|
||||
if (wordShift == 0) {
|
||||
for (unsigned i = 0; i < offset; i++)
|
||||
val[i] = 0;
|
||||
for (unsigned i = offset; i < getNumWords(); i++)
|
||||
val[i] = pVal[i-offset];
|
||||
APInt Result(val, BitWidth);
|
||||
Result.clearUnusedBits();
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Copy whole words from this to Result.
|
||||
unsigned i = getNumWords() - 1;
|
||||
for (; i > offset; --i)
|
||||
val[i] = pVal[i-offset] << wordShift |
|
||||
pVal[i-offset-1] >> (APINT_BITS_PER_WORD - wordShift);
|
||||
val[offset] = pVal[0] << wordShift;
|
||||
for (i = 0; i < offset; ++i)
|
||||
val[i] = 0;
|
||||
APInt Result(val, BitWidth);
|
||||
Result.clearUnusedBits();
|
||||
return Result;
|
||||
void APInt::shlSlowCase(unsigned ShiftAmt) {
|
||||
tcShiftLeft(pVal, getNumWords(), ShiftAmt);
|
||||
clearUnusedBits();
|
||||
}
|
||||
|
||||
// Calculate the rotate amount modulo the bit width.
|
||||
@ -2657,34 +2606,31 @@ int APInt::tcDivide(WordType *lhs, const WordType *rhs,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Shift a bignum left COUNT bits in-place. Shifted in bits are zero.
|
||||
There are no restrictions on COUNT. */
|
||||
void APInt::tcShiftLeft(WordType *dst, unsigned parts, unsigned count) {
|
||||
if (count) {
|
||||
/* Jump is the inter-part jump; shift is is intra-part shift. */
|
||||
unsigned jump = count / APINT_BITS_PER_WORD;
|
||||
unsigned shift = count % APINT_BITS_PER_WORD;
|
||||
/// Shift a bignum left Cound bits in-place. Shifted in bits are zero. There are
|
||||
/// no restrictions on Count.
|
||||
void APInt::tcShiftLeft(WordType *Dst, unsigned Words, unsigned Count) {
|
||||
// Don't bother performing a no-op shift.
|
||||
if (!Count)
|
||||
return;
|
||||
|
||||
while (parts > jump) {
|
||||
WordType part;
|
||||
/* WordShift is the inter-part shift; BitShift is is intra-part shift. */
|
||||
unsigned WordShift = std::min(Count / APINT_BITS_PER_WORD, Words);
|
||||
unsigned BitShift = Count % APINT_BITS_PER_WORD;
|
||||
|
||||
parts--;
|
||||
|
||||
/* dst[i] comes from the two parts src[i - jump] and, if we have
|
||||
an intra-part shift, src[i - jump - 1]. */
|
||||
part = dst[parts - jump];
|
||||
if (shift) {
|
||||
part <<= shift;
|
||||
if (parts >= jump + 1)
|
||||
part |= dst[parts - jump - 1] >> (APINT_BITS_PER_WORD - shift);
|
||||
}
|
||||
|
||||
dst[parts] = part;
|
||||
// Fastpath for moving by whole words.
|
||||
if (BitShift == 0) {
|
||||
std::memmove(Dst + WordShift, Dst, (Words - WordShift) * APINT_WORD_SIZE);
|
||||
} else {
|
||||
while (Words-- > WordShift) {
|
||||
Dst[Words] = Dst[Words - WordShift] << BitShift;
|
||||
if (Words > WordShift)
|
||||
Dst[Words] |=
|
||||
Dst[Words - WordShift - 1] >> (APINT_BITS_PER_WORD - BitShift);
|
||||
}
|
||||
|
||||
while (parts > 0)
|
||||
dst[--parts] = 0;
|
||||
}
|
||||
|
||||
// Fill in the remainder with 0s.
|
||||
std::memset(Dst, 0, WordShift * APINT_WORD_SIZE);
|
||||
}
|
||||
|
||||
/// Shift a bignum right Count bits in-place. Shifted in bits are zero. There
|
||||
|
@ -2024,4 +2024,37 @@ TEST(APIntTest, LogicalRightShift) {
|
||||
EXPECT_EQ(0, neg_one.lshr(257));
|
||||
}
|
||||
|
||||
TEST(APIntTest, LeftShift) {
|
||||
APInt i256(APInt::getLowBitsSet(256, 2));
|
||||
|
||||
i256 <<= 1;
|
||||
EXPECT_EQ(253U, i256.countLeadingZeros());
|
||||
EXPECT_EQ(1U, i256.countTrailingZeros());
|
||||
EXPECT_EQ(2U, i256.countPopulation());
|
||||
|
||||
i256 <<= 62;
|
||||
EXPECT_EQ(191U, i256.countLeadingZeros());
|
||||
EXPECT_EQ(63U, i256.countTrailingZeros());
|
||||
EXPECT_EQ(2U, i256.countPopulation());
|
||||
|
||||
i256 <<= 65;
|
||||
EXPECT_EQ(126U, i256.countLeadingZeros());
|
||||
EXPECT_EQ(128U, i256.countTrailingZeros());
|
||||
EXPECT_EQ(2U, i256.countPopulation());
|
||||
|
||||
i256 <<= 64;
|
||||
EXPECT_EQ(62U, i256.countLeadingZeros());
|
||||
EXPECT_EQ(192U, i256.countTrailingZeros());
|
||||
EXPECT_EQ(2U, i256.countPopulation());
|
||||
|
||||
i256 <<= 63;
|
||||
EXPECT_EQ(0U, i256.countLeadingZeros());
|
||||
EXPECT_EQ(255U, i256.countTrailingZeros());
|
||||
EXPECT_EQ(1U, i256.countPopulation());
|
||||
|
||||
// Ensure we handle large shifts of multi-word.
|
||||
const APInt neg_one(128, static_cast<uint64_t>(-1), true);
|
||||
EXPECT_EQ(0, neg_one.shl(257));
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
Loading…
x
Reference in New Issue
Block a user