mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
1. Add a dump() method for faster debugging.
2. Change 0 initialization of union to larger component so all is zeroed. 3. Fix the borrow logic in subtraction so it works for > 128 bits. 4. Rewrite fromString to use a simpler but correct algorithm and also to not set the bit width contrary to the user's request. 5. Optimize toString a bit by making it only do one Knuth divide per iteration instead of two. With these changes, all arithmetic passes (verified by pari/GP) up to 1024 bits except for certain division cases. llvm-svn: 34463
This commit is contained in:
parent
96f62d7c95
commit
c4662ad089
@ -17,6 +17,11 @@
|
|||||||
#include "llvm/Support/MathExtras.h"
|
#include "llvm/Support/MathExtras.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
// A utility function for allocating memory, checking for allocation failures,
|
// A utility function for allocating memory, checking for allocation failures,
|
||||||
@ -36,7 +41,7 @@ inline static uint64_t* getMemory(uint32_t numWords) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
APInt::APInt(uint32_t numBits, uint64_t val)
|
APInt::APInt(uint32_t numBits, uint64_t val)
|
||||||
: BitWidth(numBits), pVal(0) {
|
: BitWidth(numBits), VAL(0) {
|
||||||
assert(BitWidth >= IntegerType::MIN_INT_BITS && "bitwidth too small");
|
assert(BitWidth >= IntegerType::MIN_INT_BITS && "bitwidth too small");
|
||||||
assert(BitWidth <= IntegerType::MAX_INT_BITS && "bitwidth too large");
|
assert(BitWidth <= IntegerType::MAX_INT_BITS && "bitwidth too large");
|
||||||
if (isSingleWord())
|
if (isSingleWord())
|
||||||
@ -48,7 +53,7 @@ APInt::APInt(uint32_t numBits, uint64_t val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
APInt::APInt(uint32_t numBits, uint32_t numWords, uint64_t bigVal[])
|
APInt::APInt(uint32_t numBits, uint32_t numWords, uint64_t bigVal[])
|
||||||
: BitWidth(numBits), pVal(0) {
|
: BitWidth(numBits), VAL(0) {
|
||||||
assert(BitWidth >= IntegerType::MIN_INT_BITS && "bitwidth too small");
|
assert(BitWidth >= IntegerType::MIN_INT_BITS && "bitwidth too small");
|
||||||
assert(BitWidth <= IntegerType::MAX_INT_BITS && "bitwidth too large");
|
assert(BitWidth <= IntegerType::MAX_INT_BITS && "bitwidth too large");
|
||||||
assert(bigVal && "Null pointer detected!");
|
assert(bigVal && "Null pointer detected!");
|
||||||
@ -72,21 +77,21 @@ APInt::APInt(uint32_t numBits, uint32_t numWords, uint64_t bigVal[])
|
|||||||
/// integer value.
|
/// integer value.
|
||||||
APInt::APInt(uint32_t numbits, const char StrStart[], uint32_t slen,
|
APInt::APInt(uint32_t numbits, const char StrStart[], uint32_t slen,
|
||||||
uint8_t radix)
|
uint8_t radix)
|
||||||
: BitWidth(numbits), pVal(0) {
|
: BitWidth(numbits), VAL(0) {
|
||||||
fromString(numbits, StrStart, slen, radix);
|
fromString(numbits, StrStart, slen, radix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Create a new APInt by translating the string represented
|
/// @brief Create a new APInt by translating the string represented
|
||||||
/// integer value.
|
/// integer value.
|
||||||
APInt::APInt(uint32_t numbits, const std::string& Val, uint8_t radix)
|
APInt::APInt(uint32_t numbits, const std::string& Val, uint8_t radix)
|
||||||
: BitWidth(numbits), pVal(0) {
|
: BitWidth(numbits), VAL(0) {
|
||||||
assert(!Val.empty() && "String empty?");
|
assert(!Val.empty() && "String empty?");
|
||||||
fromString(numbits, Val.c_str(), Val.size(), radix);
|
fromString(numbits, Val.c_str(), Val.size(), radix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Copy constructor
|
/// @brief Copy constructor
|
||||||
APInt::APInt(const APInt& that)
|
APInt::APInt(const APInt& that)
|
||||||
: BitWidth(that.BitWidth), pVal(0) {
|
: BitWidth(that.BitWidth), VAL(0) {
|
||||||
if (isSingleWord())
|
if (isSingleWord())
|
||||||
VAL = that.VAL;
|
VAL = that.VAL;
|
||||||
else {
|
else {
|
||||||
@ -184,11 +189,10 @@ APInt& APInt::operator--() {
|
|||||||
|
|
||||||
/// add - This function adds the integer array x[] by integer array
|
/// add - This function adds the integer array x[] by integer array
|
||||||
/// y[] and returns the carry.
|
/// y[] and returns the carry.
|
||||||
static uint64_t add(uint64_t dest[], uint64_t x[],
|
static uint64_t add(uint64_t dest[], uint64_t x[], uint64_t y[], uint32_t len) {
|
||||||
uint64_t y[], uint32_t len) {
|
|
||||||
uint64_t carry = 0;
|
uint64_t carry = 0;
|
||||||
for (uint32_t i = 0; i< len; ++i) {
|
for (uint32_t i = 0; i< len; ++i) {
|
||||||
uint64_t save = x[i];
|
uint64_t save = std::max(x[i],y[i]);
|
||||||
dest[i] = x[i] + y[i] + carry;
|
dest[i] = x[i] + y[i] + carry;
|
||||||
carry = dest[i] < save ? 1 : 0;
|
carry = dest[i] < save ? 1 : 0;
|
||||||
}
|
}
|
||||||
@ -210,13 +214,13 @@ APInt& APInt::operator+=(const APInt& RHS) {
|
|||||||
|
|
||||||
/// sub - This function subtracts the integer array x[] by
|
/// sub - This function subtracts the integer array x[] by
|
||||||
/// integer array y[], and returns the borrow-out carry.
|
/// integer array y[], and returns the borrow-out carry.
|
||||||
static uint64_t sub(uint64_t dest[], uint64_t x[],
|
static uint64_t sub(uint64_t *dest, const uint64_t *x, const uint64_t *y,
|
||||||
uint64_t y[], uint32_t len) {
|
uint32_t len) {
|
||||||
uint64_t borrow = 0;
|
bool borrow = false;
|
||||||
for (uint32_t i = 0; i < len; ++i) {
|
for (uint32_t i = 0; i < len; ++i) {
|
||||||
uint64_t save = x[i];
|
uint64_t x_tmp = borrow ? x[i] - 1 : x[i];
|
||||||
dest[i] = x[i] - borrow - y[i];
|
borrow = y[i] > x_tmp || (borrow && x[i] == 0);
|
||||||
borrow = save < dest[i] ? 1 : 0;
|
dest[i] = x_tmp - y[i];
|
||||||
}
|
}
|
||||||
return borrow;
|
return borrow;
|
||||||
}
|
}
|
||||||
@ -1385,72 +1389,55 @@ APInt APInt::urem(const APInt& RHS) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Converts a char array into an integer.
|
/// @brief Converts a char array into an integer.
|
||||||
void APInt::fromString(uint32_t numbits, const char *StrStart, uint32_t slen,
|
void APInt::fromString(uint32_t numbits, const char *str, uint32_t slen,
|
||||||
uint8_t radix) {
|
uint8_t radix) {
|
||||||
|
// Check our assumptions here
|
||||||
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!");
|
||||||
assert(StrStart && "String is null?");
|
assert(str && "String is null?");
|
||||||
uint32_t size = 0;
|
assert(slen <= numbits || radix != 2 && "Insufficient bit width");
|
||||||
// If the radix is a power of 2, read the input
|
assert(slen*3 <= numbits || radix != 8 && "Insufficient bit width");
|
||||||
// from most significant to least significant.
|
assert(slen*4 <= numbits || radix != 16 && "Insufficient bit width");
|
||||||
if ((radix & (radix - 1)) == 0) {
|
assert((slen*64)/20 <= numbits || radix != 10 && "Insufficient bit width");
|
||||||
uint32_t nextBitPos = 0;
|
|
||||||
uint32_t bits_per_digit = radix / 8 + 2;
|
// Allocate memory
|
||||||
uint64_t resDigit = 0;
|
if (!isSingleWord())
|
||||||
BitWidth = slen * bits_per_digit;
|
pVal = getClearedMemory(getNumWords());
|
||||||
if (getNumWords() > 1)
|
|
||||||
pVal = getMemory(getNumWords());
|
// Figure out if we can shift instead of multiply
|
||||||
for (int i = slen - 1; i >= 0; --i) {
|
uint32_t shift = (radix == 16 ? 4 : radix == 8 ? 3 : radix == 2 ? 1 : 0);
|
||||||
uint64_t digit = StrStart[i] - '0';
|
|
||||||
resDigit |= digit << nextBitPos;
|
// Set up an APInt for the digit to add outside the loop so we don't
|
||||||
nextBitPos += bits_per_digit;
|
// constantly construct/destruct it.
|
||||||
if (nextBitPos >= APINT_BITS_PER_WORD) {
|
APInt apdigit(getBitWidth(), 0);
|
||||||
if (isSingleWord()) {
|
APInt apradix(getBitWidth(), radix);
|
||||||
VAL = resDigit;
|
|
||||||
break;
|
// Enter digit traversal loop
|
||||||
}
|
for (unsigned i = 0; i < slen; i++) {
|
||||||
pVal[size++] = resDigit;
|
// Get a digit
|
||||||
nextBitPos -= APINT_BITS_PER_WORD;
|
uint32_t digit = 0;
|
||||||
resDigit = digit >> (bits_per_digit - nextBitPos);
|
char cdigit = str[i];
|
||||||
}
|
if (isdigit(cdigit))
|
||||||
}
|
digit = cdigit - '0';
|
||||||
if (!isSingleWord() && size <= getNumWords())
|
else if (isxdigit(cdigit))
|
||||||
pVal[size] = resDigit;
|
if (cdigit >= 'a')
|
||||||
} else { // General case. The radix is not a power of 2.
|
digit = cdigit - 'a' + 10;
|
||||||
// For 10-radix, the max value of 64-bit integer is 18446744073709551615,
|
else if (cdigit >= 'A')
|
||||||
// and its digits number is 20.
|
digit = cdigit - 'A' + 10;
|
||||||
const uint32_t chars_per_word = 20;
|
else
|
||||||
if (slen < chars_per_word ||
|
assert(0 && "huh?");
|
||||||
(slen == chars_per_word && // In case the value <= 2^64 - 1
|
else
|
||||||
strcmp(StrStart, "18446744073709551615") <= 0)) {
|
assert(0 && "Invalid character in digit string");
|
||||||
BitWidth = APINT_BITS_PER_WORD;
|
|
||||||
VAL = strtoull(StrStart, 0, 10);
|
// Shift or multiple the value by the radix
|
||||||
} else { // In case the value > 2^64 - 1
|
if (shift)
|
||||||
BitWidth = (slen / chars_per_word + 1) * APINT_BITS_PER_WORD;
|
this->shl(shift);
|
||||||
pVal = getClearedMemory(getNumWords());
|
else
|
||||||
uint32_t str_pos = 0;
|
*this *= apradix;
|
||||||
while (str_pos < slen) {
|
|
||||||
uint32_t chunk = slen - str_pos;
|
// Add in the digit we just interpreted
|
||||||
if (chunk > chars_per_word - 1)
|
apdigit.pVal[0] = digit;
|
||||||
chunk = chars_per_word - 1;
|
*this += apdigit;
|
||||||
uint64_t resDigit = StrStart[str_pos++] - '0';
|
|
||||||
uint64_t big_base = radix;
|
|
||||||
while (--chunk > 0) {
|
|
||||||
resDigit = resDigit * radix + StrStart[str_pos++] - '0';
|
|
||||||
big_base *= radix;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t carry;
|
|
||||||
if (!size)
|
|
||||||
carry = resDigit;
|
|
||||||
else {
|
|
||||||
carry = mul_1(pVal, pVal, size, big_base);
|
|
||||||
carry += add_1(pVal, pVal, size, resDigit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (carry) pVal[size++] = carry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1519,15 +1506,27 @@ std::string APInt::toString(uint8_t radix, bool wantSigned) const {
|
|||||||
result = "0";
|
result = "0";
|
||||||
else while (tmp.ne(zero)) {
|
else while (tmp.ne(zero)) {
|
||||||
APInt APdigit(1,0);
|
APInt APdigit(1,0);
|
||||||
divide(tmp, tmp.getNumWords(), divisor, divisor.getNumWords(), 0, &APdigit);
|
|
||||||
uint32_t digit = APdigit.getValue();
|
|
||||||
assert(digit < radix && "urem failed");
|
|
||||||
result.insert(insert_at,digits[digit]);
|
|
||||||
APInt tmp2(tmp.getBitWidth(), 0);
|
APInt tmp2(tmp.getBitWidth(), 0);
|
||||||
divide(tmp, tmp.getNumWords(), divisor, divisor.getNumWords(), &tmp2, 0);
|
divide(tmp, tmp.getNumWords(), divisor, divisor.getNumWords(), &tmp2,
|
||||||
|
&APdigit);
|
||||||
|
uint32_t digit = APdigit.getValue();
|
||||||
|
assert(digit < radix && "divide failed");
|
||||||
|
result.insert(insert_at,digits[digit]);
|
||||||
tmp = tmp2;
|
tmp = tmp2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
void APInt::dump() const
|
||||||
|
{
|
||||||
|
std::cerr << "APInt(" << BitWidth << ")=" << std::setbase(16);
|
||||||
|
if (isSingleWord())
|
||||||
|
std::cerr << VAL;
|
||||||
|
else for (unsigned i = getNumWords(); i > 0; i--) {
|
||||||
|
std::cerr << pVal[i-1] << " ";
|
||||||
|
}
|
||||||
|
std::cerr << " (" << this->toString(10, false) << ")\n" << std::setbase(10);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user