llvm.org GIT mirror llvm / 0d0472f
[APInt] Add ashrInPlace method and implement ashr using it. Also fix a bug in the shift by BitWidth handling. For single word, shift by BitWidth was always returning 0, but for multiword it was based on original sign. Now single word matches multi word. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301094 91177308-0d34-0410-b5e6-96231b3b80d8 Craig Topper 3 years ago
4 changed file(s) with 82 addition(s) and 82 deletion(s). Raw diff Collapse all Expand all
197197 /// out-of-line slow case for lshr.
198198 void lshrSlowCase(unsigned ShiftAmt);
199199
200 /// out-of-line slow case for ashr.
201 void ashrSlowCase(unsigned ShiftAmt);
202
200203 /// out-of-line slow case for operator=
201204 void AssignSlowCase(const APInt &RHS);
202205
897900 /// \brief Arithmetic right-shift function.
898901 ///
899902 /// Arithmetic right-shift this APInt by shiftAmt.
900 APInt ashr(unsigned shiftAmt) const;
903 APInt ashr(unsigned ShiftAmt) const {
904 APInt R(*this);
905 R.ashrInPlace(ShiftAmt);
906 return R;
907 }
908
909 /// Arithmetic right-shift this APInt by ShiftAmt in place.
910 void ashrInPlace(unsigned ShiftAmt) {
911 assert(ShiftAmt <= BitWidth && "Invalid shift amount");
912 if (isSingleWord()) {
913 int64_t SExtVAL = SignExtend64(VAL, BitWidth);
914 if (ShiftAmt == BitWidth)
915 VAL = SExtVAL >> (APINT_BITS_PER_WORD - 1); // undefined
916 else
917 VAL = SExtVAL >> ShiftAmt;
918 clearUnusedBits();
919 return;
920 }
921 ashrSlowCase(ShiftAmt);
922 }
901923
902924 /// \brief Logical right-shift function.
903925 ///
939961 /// \brief Arithmetic right-shift function.
940962 ///
941963 /// Arithmetic right-shift this APInt by shiftAmt.
942 APInt ashr(const APInt &shiftAmt) const;
964 APInt ashr(const APInt &ShiftAmt) const {
965 APInt R(*this);
966 R.ashrInPlace(ShiftAmt);
967 return R;
968 }
969
970 /// Arithmetic right-shift this APInt by shiftAmt in place.
971 void ashrInPlace(const APInt &shiftAmt);
943972
944973 /// \brief Logical right-shift function.
945974 ///
127127 if (IsUnsigned)
128128 lshrInPlace(Amt);
129129 else
130 *this = *this >> Amt;
130 ashrInPlace(Amt);
131131 return *this;
132132 }
133133
10281028
10291029 /// Arithmetic right-shift this APInt by shiftAmt.
10301030 /// @brief Arithmetic right-shift function.
1031 APInt APInt::ashr(const APInt &shiftAmt) const {
1032 return ashr((unsigned)shiftAmt.getLimitedValue(BitWidth));
1031 void APInt::ashrInPlace(const APInt &shiftAmt) {
1032 ashrInPlace((unsigned)shiftAmt.getLimitedValue(BitWidth));
10331033 }
10341034
10351035 /// Arithmetic right-shift this APInt by shiftAmt.
10361036 /// @brief Arithmetic right-shift function.
1037 APInt APInt::ashr(unsigned shiftAmt) const {
1038 assert(shiftAmt <= BitWidth && "Invalid shift amount");
1039 // Handle a degenerate case
1040 if (shiftAmt == 0)
1041 return *this;
1042
1043 // Handle single word shifts with built-in ashr
1044 if (isSingleWord()) {
1045 if (shiftAmt == BitWidth)
1046 return APInt(BitWidth, 0); // undefined
1047 return APInt(BitWidth, SignExtend64(VAL, BitWidth) >> shiftAmt);
1048 }
1049
1050 // If all the bits were shifted out, the result is, technically, undefined.
1051 // We return -1 if it was negative, 0 otherwise. We check this early to avoid
1052 // issues in the algorithm below.
1053 if (shiftAmt == BitWidth) {
1054 if (isNegative())
1055 return APInt(BitWidth, WORD_MAX, true);
1056 else
1057 return APInt(BitWidth, 0);
1058 }
1059
1060 // Create some space for the result.
1061 uint64_t * val = new uint64_t[getNumWords()];
1062
1063 // Compute some values needed by the following shift algorithms
1064 unsigned wordShift = shiftAmt % APINT_BITS_PER_WORD; // bits to shift per word
1065 unsigned offset = shiftAmt / APINT_BITS_PER_WORD; // word offset for shift
1066 unsigned breakWord = getNumWords() - 1 - offset; // last word affected
1067 unsigned bitsInWord = whichBit(BitWidth); // how many bits in last word?
1068 if (bitsInWord == 0)
1069 bitsInWord = APINT_BITS_PER_WORD;
1070
1071 // If we are shifting whole words, just move whole words
1072 if (wordShift == 0) {
1073 // Move the words containing significant bits
1074 for (unsigned i = 0; i <= breakWord; ++i)
1075 val[i] = pVal[i+offset]; // move whole word
1076
1077 // Adjust the top significant word for sign bit fill, if negative
1078 if (isNegative())
1079 if (bitsInWord < APINT_BITS_PER_WORD)
1080 val[breakWord] |= WORD_MAX << bitsInWord; // set high bits
1037 void APInt::ashrSlowCase(unsigned ShiftAmt) {
1038 // Don't bother performing a no-op shift.
1039 if (!ShiftAmt)
1040 return;
1041
1042 bool Negative = isNegative();
1043
1044 // WordShift is the inter-part shift; BitShift is is intra-part shift.
1045 unsigned Words = getNumWords();
1046 unsigned WordShift = std::min(ShiftAmt / APINT_BITS_PER_WORD, Words);
1047 unsigned BitShift = ShiftAmt % APINT_BITS_PER_WORD;
1048
1049 unsigned WordsToMove = Words - WordShift;
1050 // Fastpath for moving by whole words.
1051 if (BitShift == 0) {
1052 std::memmove(pVal, pVal + WordShift, WordsToMove * APINT_WORD_SIZE);
10811053 } else {
1082 // Shift the low order words
1083 for (unsigned i = 0; i < breakWord; ++i) {
1084 // This combines the shifted corresponding word with the low bits from
1085 // the next word (shifted into this word's high bits).
1086 val[i] = (pVal[i+offset] >> wordShift) |
1087 (pVal[i+offset+1] << (APINT_BITS_PER_WORD - wordShift));
1088 }
1089
1090 // Shift the break word. In this case there are no bits from the next word
1091 // to include in this word.
1092 val[breakWord] = pVal[breakWord+offset] >> wordShift;
1093
1094 // Deal with sign extension in the break word, and possibly the word before
1095 // it.
1096 if (isNegative()) {
1097 if (wordShift > bitsInWord) {
1098 if (breakWord > 0)
1099 val[breakWord-1] |=
1100 WORD_MAX << (APINT_BITS_PER_WORD - (wordShift - bitsInWord));
1101 val[breakWord] |= WORD_MAX;
1102 } else
1103 val[breakWord] |= WORD_MAX << (bitsInWord - wordShift);
1104 }
1105 }
1106
1107 // Remaining words are 0 or -1, just assign them.
1108 uint64_t fillValue = (isNegative() ? WORD_MAX : 0);
1109 for (unsigned i = breakWord+1; i < getNumWords(); ++i)
1110 val[i] = fillValue;
1111 APInt Result(val, BitWidth);
1112 Result.clearUnusedBits();
1113 return Result;
1054 for (unsigned i = 0; i != WordsToMove; ++i) {
1055 pVal[i] = pVal[i + WordShift] >> BitShift;
1056 if (i + 1 != WordsToMove)
1057 pVal[i] |= pVal[i + WordShift + 1] << (APINT_BITS_PER_WORD - BitShift);
1058 else if (Negative)
1059 pVal[i] |= WORD_MAX << (APINT_BITS_PER_WORD - BitShift);
1060 }
1061 }
1062
1063 // Fill in the remainder based on the original sign.
1064 std::memset(pVal + WordsToMove, Negative ? -1 : 0,
1065 WordShift * APINT_WORD_SIZE);
1066 clearUnusedBits();
11141067 }
11151068
11161069 /// Logical right-shift this APInt by shiftAmt.
287287 EXPECT_EQ(zero, one.shl(1));
288288 EXPECT_EQ(one, one.shl(0));
289289 EXPECT_EQ(zero, one.lshr(1));
290 EXPECT_EQ(zero, one.ashr(1));
290 EXPECT_EQ(one, one.ashr(1));
291291
292292 // Rotates.
293293 EXPECT_EQ(one, one.rotl(0));
20232023 EXPECT_EQ(0, neg_one.lshr(128));
20242024 }
20252025
2026 TEST(APIntTest, ArithmeticRightShift) {
2027 // Ensure we handle large shifts of multi-word.
2028 const APInt signmin32(APInt::getSignedMinValue(32));
2029 EXPECT_TRUE(signmin32.ashr(32).isAllOnesValue());
2030
2031 // Ensure we handle large shifts of multi-word.
2032 const APInt umax32(APInt::getSignedMaxValue(32));
2033 EXPECT_EQ(0, umax32.ashr(32));
2034
2035 // Ensure we handle large shifts of multi-word.
2036 const APInt signmin128(APInt::getSignedMinValue(128));
2037 EXPECT_TRUE(signmin128.ashr(128).isAllOnesValue());
2038
2039 // Ensure we handle large shifts of multi-word.
2040 const APInt umax128(APInt::getSignedMaxValue(128));
2041 EXPECT_EQ(0, umax128.ashr(128));
2042 }
2043
20262044 TEST(APIntTest, LeftShift) {
20272045 APInt i256(APInt::getLowBitsSet(256, 2));
20282046