Implement signed output for toString.

Fix bugs in countLeadingZeros and countTrailingZeros.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@34386 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Reid Spencer
2007-02-18 00:44:22 +00:00
parent 63925c831a
commit 443b570149
2 changed files with 76 additions and 45 deletions

View File

@ -456,7 +456,7 @@ public:
} }
/// @returns a character interpretation of the APInt. /// @returns a character interpretation of the APInt.
std::string toString(uint8_t radix = 10) const; std::string toString(uint8_t radix = 10, bool wantSigned = true) const;
/// Get an APInt with the same BitWidth as this APInt, just zero mask /// Get an APInt with the same BitWidth as this APInt, just zero mask
/// the low bits and right shift to the least significant bit. /// the low bits and right shift to the least significant bit.

View File

@ -26,7 +26,7 @@ using namespace llvm;
/// the most significant digit. /// the most significant digit.
static uint64_t lshift(uint64_t dest[], unsigned d_offset, static uint64_t lshift(uint64_t dest[], unsigned d_offset,
uint64_t x[], unsigned len, unsigned shiftAmt) { uint64_t x[], unsigned len, unsigned shiftAmt) {
unsigned count = 64 - shiftAmt; unsigned count = APINT_BITS_PER_WORD - shiftAmt;
int i = len - 1; int i = len - 1;
uint64_t high_word = x[i], retVal = high_word >> count; uint64_t high_word = x[i], retVal = high_word >> count;
++d_offset; ++d_offset;
@ -70,7 +70,9 @@ APInt::APInt(unsigned numBits, unsigned numWords, uint64_t bigVal[])
unsigned maxN = std::max<unsigned>(numWords, getNumWords()); unsigned maxN = std::max<unsigned>(numWords, getNumWords());
unsigned minN = std::min<unsigned>(numWords, getNumWords()); unsigned minN = std::min<unsigned>(numWords, getNumWords());
memcpy(pVal, bigVal, (minN - 1) * 8); memcpy(pVal, bigVal, (minN - 1) * 8);
pVal[minN-1] = bigVal[minN-1] & (~uint64_t(0ULL) >> (64 - BitWidth % 64)); pVal[minN-1] = bigVal[minN-1] &
(~uint64_t(0ULL) >>
(APINT_BITS_PER_WORD - BitWidth % APINT_BITS_PER_WORD));
if (maxN == getNumWords()) if (maxN == getNumWords())
memset(pVal+numWords, 0, (getNumWords() - numWords) * 8); memset(pVal+numWords, 0, (getNumWords() - numWords) * 8);
} }
@ -511,7 +513,7 @@ bool APInt::operator==(const APInt& RHS) const {
else if (isSingleWord()) else if (isSingleWord())
return VAL == (RHS.isSingleWord() ? RHS.VAL : RHS.pVal[0]); return VAL == (RHS.isSingleWord() ? RHS.VAL : RHS.pVal[0]);
else { else {
if (n1 <= 64) if (n1 <= APINT_BITS_PER_WORD)
return pVal[0] == (RHS.isSingleWord() ? RHS.VAL : RHS.pVal[0]); return pVal[0] == (RHS.isSingleWord() ? RHS.VAL : RHS.pVal[0]);
for (int i = whichWord(n1 - 1); i >= 0; --i) for (int i = whichWord(n1 - 1); i >= 0; --i)
if (pVal[i] != RHS.pVal[i]) return false; if (pVal[i] != RHS.pVal[i]) return false;
@ -526,7 +528,7 @@ bool APInt::operator==(uint64_t Val) const {
return VAL == Val; return VAL == Val;
else { else {
unsigned n = getActiveBits(); unsigned n = getActiveBits();
if (n <= 64) if (n <= APINT_BITS_PER_WORD)
return pVal[0] == Val; return pVal[0] == Val;
else else
return false; return false;
@ -545,7 +547,7 @@ bool APInt::ult(const APInt& RHS) const {
return true; return true;
else if (n2 < n1) else if (n2 < n1)
return false; return false;
else if (n1 <= 64 && n2 <= 64) else if (n1 <= APINT_BITS_PER_WORD && n2 <= APINT_BITS_PER_WORD)
return pVal[0] < RHS.pVal[0]; return pVal[0] < RHS.pVal[0];
for (int i = whichWord(n1 - 1); i >= 0; --i) { for (int i = whichWord(n1 - 1); i >= 0; --i) {
if (pVal[i] > RHS.pVal[i]) return false; if (pVal[i] > RHS.pVal[i]) return false;
@ -567,7 +569,7 @@ bool APInt::slt(const APInt& RHS) const {
return true; return true;
else if (n2 < n1) else if (n2 < n1)
return false; return false;
else if (n1 <= 64 && n2 <= 64) else if (n1 <= APINT_BITS_PER_WORD && n2 <= APINT_BITS_PER_WORD)
return pVal[0] < RHS.pVal[0]; return pVal[0] < RHS.pVal[0];
for (int i = whichWord(n1 - 1); i >= 0; --i) { for (int i = whichWord(n1 - 1); i >= 0; --i) {
if (pVal[i] > RHS.pVal[i]) return false; if (pVal[i] > RHS.pVal[i]) return false;
@ -587,11 +589,13 @@ APInt& APInt::set(unsigned bitPosition) {
/// @brief Set every bit to 1. /// @brief Set every bit to 1.
APInt& APInt::set() { APInt& APInt::set() {
if (isSingleWord()) VAL = ~0ULL >> (64 - BitWidth); if (isSingleWord())
VAL = ~0ULL >> (APINT_BITS_PER_WORD - BitWidth);
else { else {
for (unsigned i = 0; i < getNumWords() - 1; ++i) for (unsigned i = 0; i < getNumWords() - 1; ++i)
pVal[i] = -1ULL; pVal[i] = -1ULL;
pVal[getNumWords() - 1] = ~0ULL >> (64 - BitWidth % 64); pVal[getNumWords() - 1] = ~0ULL >>
(APINT_BITS_PER_WORD - BitWidth % APINT_BITS_PER_WORD);
} }
return *this; return *this;
} }
@ -622,12 +626,14 @@ APInt APInt::operator~() const {
/// @brief Toggle every bit to its opposite value. /// @brief Toggle every bit to its opposite value.
APInt& APInt::flip() { APInt& APInt::flip() {
if (isSingleWord()) VAL = (~(VAL << (64 - BitWidth))) >> (64 - BitWidth); if (isSingleWord()) VAL = (~(VAL <<
(APINT_BITS_PER_WORD - BitWidth))) >> (APINT_BITS_PER_WORD - BitWidth);
else { else {
unsigned i = 0; unsigned i = 0;
for (; i < getNumWords() - 1; ++i) for (; i < getNumWords() - 1; ++i)
pVal[i] = ~pVal[i]; pVal[i] = ~pVal[i];
unsigned offset = 64 - (BitWidth - 64 * (i - 1)); unsigned offset =
APINT_BITS_PER_WORD - (BitWidth - APINT_BITS_PER_WORD * (i - 1));
pVal[i] = (~(pVal[i] << offset)) >> offset; pVal[i] = (~(pVal[i] << offset)) >> offset;
} }
return *this; return *this;
@ -644,7 +650,7 @@ APInt& APInt::flip(unsigned bitPosition) {
} }
/// to_string - This function translates the APInt into a string. /// to_string - This function translates the APInt into a string.
std::string APInt::toString(uint8_t radix) const { std::string APInt::toString(uint8_t radix, bool wantSigned) const {
assert((radix == 10 || radix == 8 || radix == 16 || radix == 2) && assert((radix == 10 || radix == 8 || radix == 16 || radix == 2) &&
"Radix should be 2, 8, 10, or 16!"); "Radix should be 2, 8, 10, or 16!");
static const char *digits[] = { static const char *digits[] = {
@ -654,10 +660,15 @@ std::string APInt::toString(uint8_t radix) const {
unsigned bits_used = getActiveBits(); unsigned bits_used = getActiveBits();
if (isSingleWord()) { if (isSingleWord()) {
char buf[65]; char buf[65];
const char *format = (radix == 10 ? "%llu" : const char *format = (radix == 10 ? (wantSigned ? "%lld" : "%llu") :
(radix == 16 ? "%llX" : (radix == 8 ? "%llo" : 0))); (radix == 16 ? "%llX" : (radix == 8 ? "%llo" : 0)));
if (format) { if (format) {
sprintf(buf, format, VAL); if (wantSigned) {
int64_t sextVal = (int64_t(VAL) << (APINT_BITS_PER_WORD-BitWidth)) >>
(APINT_BITS_PER_WORD-BitWidth);
sprintf(buf, format, sextVal);
} else
sprintf(buf, format, VAL);
} else { } else {
memset(buf, 0, 65); memset(buf, 0, 65);
uint64_t v = VAL; uint64_t v = VAL;
@ -675,13 +686,23 @@ std::string APInt::toString(uint8_t radix) const {
APInt tmp(*this); APInt tmp(*this);
APInt divisor(tmp.getBitWidth(), radix); APInt divisor(tmp.getBitWidth(), radix);
APInt zero(tmp.getBitWidth(), 0); APInt zero(tmp.getBitWidth(), 0);
size_t insert_at = 0;
if (wantSigned && tmp[BitWidth-1]) {
// They want to print the signed version and it is a negative value
// Flip the bits and add one to turn it into the equivalent positive
// value and put a '-' in the result.
tmp.flip();
tmp++;
result = "-";
insert_at = 1;
}
if (tmp == 0) if (tmp == 0)
result = "0"; result = "0";
else while (tmp.ne(zero)) { else while (tmp.ne(zero)) {
APInt APdigit = APIntOps::urem(tmp,divisor); APInt APdigit = APIntOps::urem(tmp,divisor);
unsigned digit = APdigit.getValue(); unsigned digit = APdigit.getValue();
assert(digit < radix && "urem failed"); assert(digit < radix && "urem failed");
result.insert(0,digits[digit]); result.insert(insert_at,digits[digit]);
tmp = APIntOps::udiv(tmp, divisor); tmp = APIntOps::udiv(tmp, divisor);
} }
@ -741,12 +762,14 @@ bool APInt::isPowerOf2() const {
/// @returns numWord() * 64 if the value is zero. /// @returns numWord() * 64 if the value is zero.
unsigned APInt::countLeadingZeros() const { unsigned APInt::countLeadingZeros() const {
if (isSingleWord()) if (isSingleWord())
return CountLeadingZeros_64(VAL); return CountLeadingZeros_64(VAL) - (APINT_BITS_PER_WORD - BitWidth);
unsigned Count = 0; unsigned Count = 0;
for (int i = getNumWords() - 1; i >= 0; --i) { for (unsigned i = getNumWords(); i > 0u; --i) {
unsigned tmp = CountLeadingZeros_64(pVal[i]); unsigned tmp = CountLeadingZeros_64(pVal[i-1]);
Count += tmp; Count += tmp;
if (tmp != 64) if (tmp != APINT_BITS_PER_WORD)
if (i == getNumWords())
Count -= (APINT_BITS_PER_WORD - whichBit(BitWidth));
break; break;
} }
return Count; return Count;
@ -759,7 +782,7 @@ unsigned APInt::countLeadingZeros() const {
/// @returns numWord() * 64 if the value is zero. /// @returns numWord() * 64 if the value is zero.
unsigned APInt::countTrailingZeros() const { unsigned APInt::countTrailingZeros() const {
if (isSingleWord()) if (isSingleWord())
return CountTrailingZeros_64(~VAL & (VAL - 1)); return CountTrailingZeros_64(VAL);
APInt Tmp( ~(*this) & ((*this) - APInt(BitWidth,1)) ); APInt Tmp( ~(*this) & ((*this) - APInt(BitWidth,1)) );
return getNumWords() * APINT_BITS_PER_WORD - Tmp.countLeadingZeros(); return getNumWords() * APINT_BITS_PER_WORD - Tmp.countLeadingZeros();
} }
@ -855,7 +878,7 @@ double APInt::roundToDouble(bool isSigned) const {
if (Tmp.isSingleWord()) if (Tmp.isSingleWord())
return isSigned ? double(int64_t(Tmp.VAL)) : double(Tmp.VAL); return isSigned ? double(int64_t(Tmp.VAL)) : double(Tmp.VAL);
unsigned n = Tmp.getActiveBits(); unsigned n = Tmp.getActiveBits();
if (n <= 64) if (n <= APINT_BITS_PER_WORD)
return isSigned ? double(int64_t(Tmp.pVal[0])) : double(Tmp.pVal[0]); return isSigned ? double(int64_t(Tmp.pVal[0])) : double(Tmp.pVal[0]);
// Exponent when normalized to have decimal point directly after // Exponent when normalized to have decimal point directly after
// leading one. This is stored excess 1023 in the exponent bit field. // leading one. This is stored excess 1023 in the exponent bit field.
@ -867,14 +890,15 @@ double APInt::roundToDouble(bool isSigned) const {
// Number of bits in mantissa including the leading one // Number of bits in mantissa including the leading one
// equals to 53. // equals to 53.
uint64_t mantissa; uint64_t mantissa;
if (n % 64 >= 53) if (n % APINT_BITS_PER_WORD >= 53)
mantissa = Tmp.pVal[whichWord(n - 1)] >> (n % 64 - 53); mantissa = Tmp.pVal[whichWord(n - 1)] >> (n % APINT_BITS_PER_WORD - 53);
else else
mantissa = (Tmp.pVal[whichWord(n - 1)] << (53 - n % 64)) | mantissa = (Tmp.pVal[whichWord(n - 1)] << (53 - n % APINT_BITS_PER_WORD)) |
(Tmp.pVal[whichWord(n - 1) - 1] >> (11 + n % 64)); (Tmp.pVal[whichWord(n - 1) - 1] >>
(11 + n % APINT_BITS_PER_WORD));
// The leading bit of mantissa is implicit, so get rid of it. // The leading bit of mantissa is implicit, so get rid of it.
mantissa &= ~(1ULL << 52); mantissa &= ~(1ULL << 52);
uint64_t sign = isNeg ? (1ULL << 63) : 0; uint64_t sign = isNeg ? (1ULL << (APINT_BITS_PER_WORD - 1)) : 0;
exp += 1023; exp += 1023;
union { union {
double D; double D;
@ -904,13 +928,16 @@ void APInt::zext(unsigned width) {
APInt APInt::ashr(unsigned shiftAmt) const { APInt APInt::ashr(unsigned shiftAmt) const {
APInt API(*this); APInt API(*this);
if (API.isSingleWord()) if (API.isSingleWord())
API.VAL = (((int64_t(API.VAL) << (64 - API.BitWidth)) >> (64 - API.BitWidth)) API.VAL =
>> shiftAmt) & (~uint64_t(0UL) >> (64 - API.BitWidth)); (((int64_t(API.VAL) << (APINT_BITS_PER_WORD - API.BitWidth)) >>
(APINT_BITS_PER_WORD - API.BitWidth)) >> shiftAmt) &
(~uint64_t(0UL) >> (APINT_BITS_PER_WORD - API.BitWidth));
else { else {
if (shiftAmt >= API.BitWidth) { if (shiftAmt >= API.BitWidth) {
memset(API.pVal, API[API.BitWidth-1] ? 1 : 0, (API.getNumWords()-1) * 8); memset(API.pVal, API[API.BitWidth-1] ? 1 : 0, (API.getNumWords()-1) * 8);
API.pVal[API.getNumWords() - 1] = ~uint64_t(0UL) >> API.pVal[API.getNumWords() - 1] =
(64 - API.BitWidth % 64); ~uint64_t(0UL) >>
(APINT_BITS_PER_WORD - API.BitWidth % APINT_BITS_PER_WORD);
} else { } else {
unsigned i = 0; unsigned i = 0;
for (; i < API.BitWidth - shiftAmt; ++i) for (; i < API.BitWidth - shiftAmt; ++i)
@ -955,16 +982,16 @@ APInt APInt::shl(unsigned shiftAmt) const {
else if (shiftAmt >= API.BitWidth) else if (shiftAmt >= API.BitWidth)
memset(API.pVal, 0, API.getNumWords() * 8); memset(API.pVal, 0, API.getNumWords() * 8);
else { else {
if (unsigned offset = shiftAmt / 64) { if (unsigned offset = shiftAmt / APINT_BITS_PER_WORD) {
for (unsigned i = API.getNumWords() - 1; i > offset - 1; --i) for (unsigned i = API.getNumWords() - 1; i > offset - 1; --i)
API.pVal[i] = API.pVal[i-offset]; API.pVal[i] = API.pVal[i-offset];
memset(API.pVal, 0, offset * 8); memset(API.pVal, 0, offset * 8);
} }
shiftAmt %= 64; shiftAmt %= APINT_BITS_PER_WORD;
unsigned i; unsigned i;
for (i = API.getNumWords() - 1; i > 0; --i) for (i = API.getNumWords() - 1; i > 0; --i)
API.pVal[i] = (API.pVal[i] << shiftAmt) | API.pVal[i] = (API.pVal[i] << shiftAmt) |
(API.pVal[i-1] >> (64-shiftAmt)); (API.pVal[i-1] >> (APINT_BITS_PER_WORD - shiftAmt));
API.pVal[i] <<= shiftAmt; API.pVal[i] <<= shiftAmt;
} }
API.clearUnusedBits(); API.clearUnusedBits();
@ -1099,7 +1126,9 @@ APInt APInt::udiv(const APInt& RHS) const {
// Compute it the hard way .. // Compute it the hard way ..
APInt X(BitWidth, 0); APInt X(BitWidth, 0);
APInt Y(BitWidth, 0); APInt Y(BitWidth, 0);
if (unsigned nshift = 63 - ((rhsBits - 1) % 64 )) { unsigned nshift =
(APINT_BITS_PER_WORD - 1) - ((rhsBits - 1) % APINT_BITS_PER_WORD );
if (nshift) {
Y = APIntOps::shl(RHS, nshift); Y = APIntOps::shl(RHS, nshift);
X = APIntOps::shl(Result, nshift); X = APIntOps::shl(Result, nshift);
++lhsWords; ++lhsWords;
@ -1148,9 +1177,10 @@ APInt APInt::urem(const APInt& RHS) const {
Result.pVal[0] %= RHS.pVal[0]; Result.pVal[0] %= RHS.pVal[0];
else { else {
// Do it the hard way // Do it the hard way
APInt X((lhsWords+1)*64, 0); APInt X((lhsWords+1)*APINT_BITS_PER_WORD, 0);
APInt Y(rhsWords*64, 0); APInt Y(rhsWords*APINT_BITS_PER_WORD, 0);
unsigned nshift = 63 - (rhsBits - 1) % 64; unsigned nshift =
(APINT_BITS_PER_WORD - 1) - (rhsBits - 1) % APINT_BITS_PER_WORD;
if (nshift) { if (nshift) {
APIntOps::shl(Y, nshift); APIntOps::shl(Y, nshift);
APIntOps::shl(X, nshift); APIntOps::shl(X, nshift);
@ -1159,7 +1189,8 @@ APInt APInt::urem(const APInt& RHS) const {
(unsigned*)(Y.isSingleWord()? &Y.VAL : Y.pVal), rhsWords*2); (unsigned*)(Y.isSingleWord()? &Y.VAL : Y.pVal), rhsWords*2);
memset(Result.pVal, 0, Result.getNumWords() * 8); memset(Result.pVal, 0, Result.getNumWords() * 8);
for (unsigned i = 0; i < rhsWords-1; ++i) for (unsigned i = 0; i < rhsWords-1; ++i)
Result.pVal[i] = (X.pVal[i] >> nshift) | (X.pVal[i+1] << (64 - nshift)); Result.pVal[i] = (X.pVal[i] >> nshift) |
(X.pVal[i+1] << (APINT_BITS_PER_WORD - nshift));
Result.pVal[rhsWords-1] = X.pVal[rhsWords-1] >> nshift; Result.pVal[rhsWords-1] = X.pVal[rhsWords-1] >> nshift;
} }
return Result; return Result;
@ -1182,16 +1213,16 @@ void APInt::fromString(unsigned numbits, const char *StrStart, unsigned slen,
assert((pVal = new uint64_t[getNumWords()]) && assert((pVal = new uint64_t[getNumWords()]) &&
"APInt memory allocation fails!"); "APInt memory allocation fails!");
for (int i = slen - 1; i >= 0; --i) { for (int i = slen - 1; i >= 0; --i) {
uint64_t digit = StrStart[i] - 48; // '0' == 48. uint64_t digit = StrStart[i] - '0';
resDigit |= digit << nextBitPos; resDigit |= digit << nextBitPos;
nextBitPos += bits_per_digit; nextBitPos += bits_per_digit;
if (nextBitPos >= 64) { if (nextBitPos >= APINT_BITS_PER_WORD) {
if (isSingleWord()) { if (isSingleWord()) {
VAL = resDigit; VAL = resDigit;
break; break;
} }
pVal[size++] = resDigit; pVal[size++] = resDigit;
nextBitPos -= 64; nextBitPos -= APINT_BITS_PER_WORD;
resDigit = digit >> (bits_per_digit - nextBitPos); resDigit = digit >> (bits_per_digit - nextBitPos);
} }
} }
@ -1204,10 +1235,10 @@ void APInt::fromString(unsigned numbits, const char *StrStart, unsigned slen,
if (slen < chars_per_word || if (slen < chars_per_word ||
(slen == chars_per_word && // In case the value <= 2^64 - 1 (slen == chars_per_word && // In case the value <= 2^64 - 1
strcmp(StrStart, "18446744073709551615") <= 0)) { strcmp(StrStart, "18446744073709551615") <= 0)) {
BitWidth = 64; BitWidth = APINT_BITS_PER_WORD;
VAL = strtoull(StrStart, 0, 10); VAL = strtoull(StrStart, 0, 10);
} else { // In case the value > 2^64 - 1 } else { // In case the value > 2^64 - 1
BitWidth = (slen / chars_per_word + 1) * 64; BitWidth = (slen / chars_per_word + 1) * APINT_BITS_PER_WORD;
assert((pVal = new uint64_t[getNumWords()]) && assert((pVal = new uint64_t[getNumWords()]) &&
"APInt memory allocation fails!"); "APInt memory allocation fails!");
memset(pVal, 0, getNumWords() * 8); memset(pVal, 0, getNumWords() * 8);
@ -1216,10 +1247,10 @@ void APInt::fromString(unsigned numbits, const char *StrStart, unsigned slen,
unsigned chunk = slen - str_pos; unsigned chunk = slen - str_pos;
if (chunk > chars_per_word - 1) if (chunk > chars_per_word - 1)
chunk = chars_per_word - 1; chunk = chars_per_word - 1;
uint64_t resDigit = StrStart[str_pos++] - 48; // 48 == '0'. uint64_t resDigit = StrStart[str_pos++] - '0';
uint64_t big_base = radix; uint64_t big_base = radix;
while (--chunk > 0) { while (--chunk > 0) {
resDigit = resDigit * radix + StrStart[str_pos++] - 48; resDigit = resDigit * radix + StrStart[str_pos++] - '0';
big_base *= radix; big_base *= radix;
} }