llvm.org GIT mirror llvm / f322f92
[APInt] Add ashrInPlace method and rewrite ashr to make a copy and then call ashrInPlace. This patch adds an in place version of ashr to match lshr and shl which were recently added. I've tried to make this similar to the lshr code with additions to handle the sign extension. I've also tried to do this with less if checks than the current ashr code by sign extending the original result to a word boundary before doing any of the shifting. This removes a lot of the complexity of determining where to fill in sign bits after the shifting. Differential Revision: https://reviews.llvm.org/D32415 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301198 91177308-0d34-0410-b5e6-96231b3b80d8 Craig Topper 3 years ago
4 changed file(s) with 109 addition(s) and 84 deletion(s). Raw diff Collapse all Expand all
192192 /// out-of-line slow case for lshr.
193193 void lshrSlowCase(unsigned ShiftAmt);
194194
195 /// out-of-line slow case for ashr.
196 void ashrSlowCase(unsigned ShiftAmt);
197
195198 /// out-of-line slow case for operator=
196199 void AssignSlowCase(const APInt &RHS);
197200
892895 /// \brief Arithmetic right-shift function.
893896 ///
894897 /// Arithmetic right-shift this APInt by shiftAmt.
895 APInt ashr(unsigned shiftAmt) const;
898 APInt ashr(unsigned ShiftAmt) const {
899 APInt R(*this);
900 R.ashrInPlace(ShiftAmt);
901 return R;
902 }
903
904 /// Arithmetic right-shift this APInt by ShiftAmt in place.
905 void ashrInPlace(unsigned ShiftAmt) {
906 assert(ShiftAmt <= BitWidth && "Invalid shift amount");
907 if (isSingleWord()) {
908 int64_t SExtVAL = SignExtend64(VAL, BitWidth);
909 if (ShiftAmt == BitWidth)
910 VAL = SExtVAL >> (APINT_BITS_PER_WORD - 1); // Fill with sign bit.
911 else
912 VAL = SExtVAL >> ShiftAmt;
913 clearUnusedBits();
914 return;
915 }
916 ashrSlowCase(ShiftAmt);
917 }
896918
897919 /// \brief Logical right-shift function.
898920 ///
934956 /// \brief Arithmetic right-shift function.
935957 ///
936958 /// Arithmetic right-shift this APInt by shiftAmt.
937 APInt ashr(const APInt &shiftAmt) const;
959 APInt ashr(const APInt &ShiftAmt) const {
960 APInt R(*this);
961 R.ashrInPlace(ShiftAmt);
962 return R;
963 }
964
965 /// Arithmetic right-shift this APInt by shiftAmt in place.
966 void ashrInPlace(const APInt &shiftAmt);
938967
939968 /// \brief Logical right-shift function.
940969 ///
127127 if (IsUnsigned)
128128 lshrInPlace(Amt);
129129 else
130 *this = *this >> Amt;
130 ashrInPlace(Amt);
131131 return *this;
132132 }
133133
10251025
10261026 /// Arithmetic right-shift this APInt by shiftAmt.
10271027 /// @brief Arithmetic right-shift function.
1028 APInt APInt::ashr(const APInt &shiftAmt) const {
1029 return ashr((unsigned)shiftAmt.getLimitedValue(BitWidth));
1028 void APInt::ashrInPlace(const APInt &shiftAmt) {
1029 ashrInPlace((unsigned)shiftAmt.getLimitedValue(BitWidth));
10301030 }
10311031
10321032 /// Arithmetic right-shift this APInt by shiftAmt.
10331033 /// @brief Arithmetic right-shift function.
1034 APInt APInt::ashr(unsigned shiftAmt) const {
1035 assert(shiftAmt <= BitWidth && "Invalid shift amount");
1036 // Handle a degenerate case
1037 if (shiftAmt == 0)
1038 return *this;
1039
1040 // Handle single word shifts with built-in ashr
1041 if (isSingleWord()) {
1042 if (shiftAmt == BitWidth)
1043 // Undefined
1044 return APInt(BitWidth,
1045 SignExtend64(VAL, BitWidth) >> (APINT_BITS_PER_WORD - 1));
1046 return APInt(BitWidth, SignExtend64(VAL, BitWidth) >> shiftAmt);
1047 }
1048
1049 // If all the bits were shifted out, the result is, technically, undefined.
1050 // We return -1 if it was negative, 0 otherwise. We check this early to avoid
1051 // issues in the algorithm below.
1052 if (shiftAmt == BitWidth) {
1053 if (isNegative())
1054 return APInt(BitWidth, WORD_MAX, true);
1055 else
1056 return APInt(BitWidth, 0);
1057 }
1058
1059 // Create some space for the result.
1060 uint64_t * val = new uint64_t[getNumWords()];
1061
1062 // Compute some values needed by the following shift algorithms
1063 unsigned wordShift = shiftAmt % APINT_BITS_PER_WORD; // bits to shift per word
1064 unsigned offset = shiftAmt / APINT_BITS_PER_WORD; // word offset for shift
1065 unsigned breakWord = getNumWords() - 1 - offset; // last word affected
1066 unsigned bitsInWord = whichBit(BitWidth); // how many bits in last word?
1067 if (bitsInWord == 0)
1068 bitsInWord = APINT_BITS_PER_WORD;
1069
1070 // If we are shifting whole words, just move whole words
1071 if (wordShift == 0) {
1072 // Move the words containing significant bits
1073 for (unsigned i = 0; i <= breakWord; ++i)
1074 val[i] = pVal[i+offset]; // move whole word
1075
1076 // Adjust the top significant word for sign bit fill, if negative
1077 if (isNegative())
1078 if (bitsInWord < APINT_BITS_PER_WORD)
1079 val[breakWord] |= WORD_MAX << bitsInWord; // set high bits
1080 } else {
1081 // Shift the low order words
1082 for (unsigned i = 0; i < breakWord; ++i) {
1083 // This combines the shifted corresponding word with the low bits from
1084 // the next word (shifted into this word's high bits).
1085 val[i] = (pVal[i+offset] >> wordShift) |
1086 (pVal[i+offset+1] << (APINT_BITS_PER_WORD - wordShift));
1087 }
1088
1089 // Shift the break word. In this case there are no bits from the next word
1090 // to include in this word.
1091 val[breakWord] = pVal[breakWord+offset] >> wordShift;
1092
1093 // Deal with sign extension in the break word, and possibly the word before
1094 // it.
1095 if (isNegative()) {
1096 if (wordShift > bitsInWord) {
1097 if (breakWord > 0)
1098 val[breakWord-1] |=
1099 WORD_MAX << (APINT_BITS_PER_WORD - (wordShift - bitsInWord));
1100 val[breakWord] |= WORD_MAX;
1101 } else
1102 val[breakWord] |= WORD_MAX << (bitsInWord - wordShift);
1103 }
1104 }
1105
1106 // Remaining words are 0 or -1, just assign them.
1107 uint64_t fillValue = (isNegative() ? WORD_MAX : 0);
1108 for (unsigned i = breakWord+1; i < getNumWords(); ++i)
1109 val[i] = fillValue;
1110 APInt Result(val, BitWidth);
1111 Result.clearUnusedBits();
1112 return Result;
1034 void APInt::ashrSlowCase(unsigned ShiftAmt) {
1035 // Don't bother performing a no-op shift.
1036 if (!ShiftAmt)
1037 return;
1038
1039 // Save the original sign bit for later.
1040 bool Negative = isNegative();
1041
1042 // WordShift is the inter-part shift; BitShift is is intra-part shift.
1043 unsigned WordShift = ShiftAmt / APINT_BITS_PER_WORD;
1044 unsigned BitShift = ShiftAmt % APINT_BITS_PER_WORD;
1045
1046 unsigned WordsToMove = getNumWords() - WordShift;
1047 if (WordsToMove != 0) {
1048 // Sign extend the last word to fill in the unused bits.
1049 pVal[getNumWords() - 1] = SignExtend64(
1050 pVal[getNumWords() - 1], ((BitWidth - 1) % APINT_BITS_PER_WORD) + 1);
1051
1052 // Fastpath for moving by whole words.
1053 if (BitShift == 0) {
1054 std::memmove(pVal, pVal + WordShift, WordsToMove * APINT_WORD_SIZE);
1055 } else {
1056 // Move the words containing significant bits.
1057 for (unsigned i = 0; i != WordsToMove - 1; ++i)
1058 pVal[i] = (pVal[i + WordShift] >> BitShift) |
1059 (pVal[i + WordShift + 1] << (APINT_BITS_PER_WORD - BitShift));
1060
1061 // Handle the last word which has no high bits to copy.
1062 pVal[WordsToMove - 1] = pVal[WordShift + WordsToMove - 1] >> BitShift;
1063 // Sign extend one more time.
1064 pVal[WordsToMove - 1] =
1065 SignExtend64(pVal[WordsToMove - 1], APINT_BITS_PER_WORD - BitShift);
1066 }
1067 }
1068
1069 // Fill in the remainder based on the original sign.
1070 std::memset(pVal + WordsToMove, Negative ? -1 : 0,
1071 WordShift * APINT_WORD_SIZE);
1072 clearUnusedBits();
11131073 }
11141074
11151075 /// Logical right-shift this APInt by shiftAmt.
20232023 EXPECT_EQ(0, neg_one.lshr(128));
20242024 }
20252025
2026 TEST(APIntTest, ArithmeticRightShift) {
2027 APInt i72(APInt::getHighBitsSet(72, 1));
2028 i72.ashrInPlace(46);
2029 EXPECT_EQ(47U, i72.countLeadingOnes());
2030 EXPECT_EQ(25U, i72.countTrailingZeros());
2031 EXPECT_EQ(47U, i72.countPopulation());
2032
2033 i72 = APInt::getHighBitsSet(72, 1);
2034 i72.ashrInPlace(64);
2035 EXPECT_EQ(65U, i72.countLeadingOnes());
2036 EXPECT_EQ(7U, i72.countTrailingZeros());
2037 EXPECT_EQ(65U, i72.countPopulation());
2038
2039 APInt i128(APInt::getHighBitsSet(128, 1));
2040 i128.ashrInPlace(64);
2041 EXPECT_EQ(65U, i128.countLeadingOnes());
2042 EXPECT_EQ(63U, i128.countTrailingZeros());
2043 EXPECT_EQ(65U, i128.countPopulation());
2044
2045 // Ensure we handle large shifts of multi-word.
2046 const APInt signmin32(APInt::getSignedMinValue(32));
2047 EXPECT_TRUE(signmin32.ashr(32).isAllOnesValue());
2048
2049 // Ensure we handle large shifts of multi-word.
2050 const APInt umax32(APInt::getSignedMaxValue(32));
2051 EXPECT_EQ(0, umax32.ashr(32));
2052
2053 // Ensure we handle large shifts of multi-word.
2054 const APInt signmin128(APInt::getSignedMinValue(128));
2055 EXPECT_TRUE(signmin128.ashr(128).isAllOnesValue());
2056
2057 // Ensure we handle large shifts of multi-word.
2058 const APInt umax128(APInt::getSignedMaxValue(128));
2059 EXPECT_EQ(0, umax128.ashr(128));
2060 }
2061
20262062 TEST(APIntTest, LeftShift) {
20272063 APInt i256(APInt::getLowBitsSet(256, 2));
20282064