[llvm-commits] CVS: llvm/lib/Support/APInt.cpp

Reid Spencer reid at x10sys.com
Tue Feb 20 19:56:01 PST 2007



Changes in directory llvm/lib/Support:

APInt.cpp updated: 1.26 -> 1.27
---
Log message:

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.


---
Diffs of the changes:  (+80 -81)

 APInt.cpp |  161 ++++++++++++++++++++++++++++++--------------------------------
 1 files changed, 80 insertions(+), 81 deletions(-)


Index: llvm/lib/Support/APInt.cpp
diff -u llvm/lib/Support/APInt.cpp:1.26 llvm/lib/Support/APInt.cpp:1.27
--- llvm/lib/Support/APInt.cpp:1.26	Tue Feb 20 18:29:48 2007
+++ llvm/lib/Support/APInt.cpp	Tue Feb 20 21:55:44 2007
@@ -17,6 +17,11 @@
 #include "llvm/Support/MathExtras.h"
 #include <cstring>
 #include <cstdlib>
+#ifndef NDEBUG
+#include <iostream>
+#include <iomanip>
+#endif
+
 using namespace llvm;
 
 // A utility function for allocating memory, checking for allocation failures,
@@ -36,7 +41,7 @@
 }
 
 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::MAX_INT_BITS && "bitwidth too large");
   if (isSingleWord()) 
@@ -48,7 +53,7 @@
 }
 
 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::MAX_INT_BITS && "bitwidth too large");
   assert(bigVal && "Null pointer detected!");
@@ -72,21 +77,21 @@
 /// integer value.
 APInt::APInt(uint32_t numbits, const char StrStart[], uint32_t slen, 
              uint8_t radix) 
-  : BitWidth(numbits), pVal(0) {
+  : BitWidth(numbits), VAL(0) {
   fromString(numbits, StrStart, slen, radix);
 }
 
 /// @brief Create a new APInt by translating the string represented
 /// integer value.
 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?");
   fromString(numbits, Val.c_str(), Val.size(), radix);
 }
 
 /// @brief Copy constructor
 APInt::APInt(const APInt& that)
-  : BitWidth(that.BitWidth), pVal(0) {
+  : BitWidth(that.BitWidth), VAL(0) {
   if (isSingleWord()) 
     VAL = that.VAL;
   else {
@@ -184,11 +189,10 @@
 
 /// add - This function adds the integer array x[] by integer array
 /// y[] and returns the carry.
-static uint64_t add(uint64_t dest[], uint64_t x[], 
-                           uint64_t y[], uint32_t len) {
+static uint64_t add(uint64_t dest[], uint64_t x[], uint64_t y[], uint32_t len) {
   uint64_t carry = 0;
   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;
     carry = dest[i] < save ? 1 : 0;
   }
@@ -210,13 +214,13 @@
 
 /// sub - This function subtracts the integer array x[] by
 /// integer array y[], and returns the borrow-out carry.
-static uint64_t sub(uint64_t dest[], uint64_t x[], 
-                           uint64_t y[], uint32_t len) {
-  uint64_t borrow = 0;
+static uint64_t sub(uint64_t *dest, const uint64_t *x, const uint64_t *y, 
+                    uint32_t len) {
+  bool borrow = false;
   for (uint32_t i = 0; i < len; ++i) {
-    uint64_t save = x[i];
-    dest[i] = x[i] - borrow - y[i];
-    borrow = save < dest[i] ? 1 : 0;
+    uint64_t x_tmp = borrow ? x[i] - 1 : x[i];
+    borrow = y[i] > x_tmp || (borrow && x[i] == 0);
+    dest[i] = x_tmp - y[i];
   }
   return borrow;
 }
@@ -1385,72 +1389,55 @@
 }
 
 /// @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) {
+  // Check our assumptions here
   assert((radix == 10 || radix == 8 || radix == 16 || radix == 2) &&
          "Radix should be 2, 8, 10, or 16!");
-  assert(StrStart && "String is null?");
-  uint32_t size = 0;
-  // If the radix is a power of 2, read the input
-  // from most significant to least significant.
-  if ((radix & (radix - 1)) == 0) {
-    uint32_t nextBitPos = 0; 
-    uint32_t bits_per_digit = radix / 8 + 2;
-    uint64_t resDigit = 0;
-    BitWidth = slen * bits_per_digit;
-    if (getNumWords() > 1)
-      pVal = getMemory(getNumWords());
-    for (int i = slen - 1; i >= 0; --i) {
-      uint64_t digit = StrStart[i] - '0';
-      resDigit |= digit << nextBitPos;
-      nextBitPos += bits_per_digit;
-      if (nextBitPos >= APINT_BITS_PER_WORD) {
-        if (isSingleWord()) {
-          VAL = resDigit;
-           break;
-        }
-        pVal[size++] = resDigit;
-        nextBitPos -= APINT_BITS_PER_WORD;
-        resDigit = digit >> (bits_per_digit - nextBitPos);
-      }
-    }
-    if (!isSingleWord() && size <= getNumWords()) 
-      pVal[size] = resDigit;
-  } else {   // General case.  The radix is not a power of 2.
-    // For 10-radix, the max value of 64-bit integer is 18446744073709551615,
-    // and its digits number is 20.
-    const uint32_t chars_per_word = 20;
-    if (slen < chars_per_word || 
-        (slen == chars_per_word &&             // In case the value <= 2^64 - 1
-         strcmp(StrStart, "18446744073709551615") <= 0)) {
-      BitWidth = APINT_BITS_PER_WORD;
-      VAL = strtoull(StrStart, 0, 10);
-    } else { // In case the value > 2^64 - 1
-      BitWidth = (slen / chars_per_word + 1) * APINT_BITS_PER_WORD;
-      pVal = getClearedMemory(getNumWords());
-      uint32_t str_pos = 0;
-      while (str_pos < slen) {
-        uint32_t chunk = slen - str_pos;
-        if (chunk > chars_per_word - 1)
-          chunk = chars_per_word - 1;
-        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;
-      }
-    }
+  assert(str && "String is null?");
+  assert(slen <= numbits || radix != 2 && "Insufficient bit width");
+  assert(slen*3 <= numbits || radix != 8 && "Insufficient bit width");
+  assert(slen*4 <= numbits || radix != 16 && "Insufficient bit width");
+  assert((slen*64)/20 <= numbits || radix != 10 && "Insufficient bit width");
+
+  // Allocate memory
+  if (!isSingleWord())
+    pVal = getClearedMemory(getNumWords());
+
+  // Figure out if we can shift instead of multiply
+  uint32_t shift = (radix == 16 ? 4 : radix == 8 ? 3 : radix == 2 ? 1 : 0);
+
+  // Set up an APInt for the digit to add outside the loop so we don't
+  // constantly construct/destruct it.
+  APInt apdigit(getBitWidth(), 0);
+  APInt apradix(getBitWidth(), radix);
+
+  // Enter digit traversal loop
+  for (unsigned i = 0; i < slen; i++) {
+    // Get a digit
+    uint32_t digit = 0;
+    char cdigit = str[i];
+    if (isdigit(cdigit))
+      digit = cdigit - '0';
+    else if (isxdigit(cdigit))
+      if (cdigit >= 'a')
+        digit = cdigit - 'a' + 10;
+      else if (cdigit >= 'A')
+        digit = cdigit - 'A' + 10;
+      else
+        assert(0 && "huh?");
+    else
+      assert(0 && "Invalid character in digit string");
+
+    // Shift or multiple the value by the radix
+    if (shift)
+      this->shl(shift);
+    else
+      *this *= apradix;
+
+    // Add in the digit we just interpreted
+    apdigit.pVal[0] = digit;
+    *this += apdigit;
   }
 }
 
@@ -1519,15 +1506,27 @@
     result = "0";
   else while (tmp.ne(zero)) {
     APInt APdigit(1,0);
-    divide(tmp, tmp.getNumWords(), divisor, divisor.getNumWords(), 0, &APdigit);
+    APInt tmp2(tmp.getBitWidth(), 0);
+    divide(tmp, tmp.getNumWords(), divisor, divisor.getNumWords(), &tmp2, 
+           &APdigit);
     uint32_t digit = APdigit.getValue();
-    assert(digit < radix && "urem failed");
+    assert(digit < radix && "divide failed");
     result.insert(insert_at,digits[digit]);
-    APInt tmp2(tmp.getBitWidth(), 0);
-    divide(tmp, tmp.getNumWords(), divisor, divisor.getNumWords(), &tmp2, 0);
     tmp = tmp2;
   }
 
   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






More information about the llvm-commits mailing list