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

Reid Spencer reid at x10sys.com
Fri Feb 23 19:59:03 PST 2007



Changes in directory llvm/lib/Support:

APInt.cpp updated: 1.32 -> 1.33
---
Log message:

1. Make internal functions take const arguments where they should, just 
   to be safe.
2. Make internal functions that return a carry/borrow return bool instead
   of uint64_t because the carry/borrow can only be in range [0,1].
3. Assert that the pointers to KnuthDiv are all different so that the
   result and operands can't overlap.
4. Add debug output to KnuthDiv function.
5. Fix a problem with KnuthDiv by separating the b's complement operation
   from the subtraction borrow operation. This fixes a wide range of
   division problems, but alas, not all of them.
   



---
Diffs of the changes:  (+61 -21)

 APInt.cpp |   82 ++++++++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 61 insertions(+), 21 deletions(-)


Index: llvm/lib/Support/APInt.cpp
diff -u llvm/lib/Support/APInt.cpp:1.32 llvm/lib/Support/APInt.cpp:1.33
--- llvm/lib/Support/APInt.cpp:1.32	Thu Feb 22 19:57:13 2007
+++ llvm/lib/Support/APInt.cpp	Fri Feb 23 21:58:46 2007
@@ -12,8 +12,10 @@
 //
 //===----------------------------------------------------------------------===//
 
+#define DEBUG_TYPE "apint"
 #include "llvm/ADT/APInt.h"
 #include "llvm/DerivedTypes.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/MathExtras.h"
 #include <cstring>
 #include <cstdlib>
@@ -189,8 +191,9 @@
 
 /// 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) {
-  bool carry = 0;
+static bool add(uint64_t *dest, const uint64_t *x, const uint64_t *y, 
+                uint32_t len) {
+  bool carry = false;
   for (uint32_t i = 0; i< len; ++i) {
     uint64_t limit = std::min(x[i],y[i]); // must come first in case dest == x
     dest[i] = x[i] + y[i] + carry;
@@ -214,8 +217,8 @@
 
 /// 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, const uint64_t *x, const uint64_t *y, 
-                    uint32_t len) {
+static bool 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 x_tmp = borrow ? x[i] - 1 : x[i];
@@ -988,12 +991,19 @@
   assert(u && "Must provide dividend");
   assert(v && "Must provide divisor");
   assert(q && "Must provide quotient");
+  assert(u != v && u != q && v != q && "Must us different memory");
   assert(n>1 && "n must be > 1");
 
   // Knuth uses the value b as the base of the number system. In our case b
   // is 2^31 so we just set it to -1u.
   uint64_t b = uint64_t(1) << 32;
 
+  DEBUG(cerr << "KnuthDiv: m=" << m << " n=" << n << '\n');
+  DEBUG(cerr << "KnuthDiv: original:");
+  DEBUG(for (int i = m+n; i >=0; i--) cerr << " " << std::setbase(16) << u[i]);
+  DEBUG(cerr << " by");
+  DEBUG(for (int i = n; i >0; i--) cerr << " " << std::setbase(16) << v[i-1]);
+  DEBUG(cerr << '\n');
   // D1. [Normalize.] Set d = b / (v[n-1] + 1) and multiply all the digits of 
   // u and v by d. Note that we have taken Knuth's advice here to use a power 
   // of 2 value for d such that d * v[n-1] >= b/2 (b is the base). A power of 
@@ -1018,10 +1028,16 @@
     }
   }
   u[m+n] = u_carry;
+  DEBUG(cerr << "KnuthDiv:   normal:");
+  DEBUG(for (int i = m+n; i >=0; i--) cerr << " " << std::setbase(16) << u[i]);
+  DEBUG(cerr << " by");
+  DEBUG(for (int i = n; i >0; i--) cerr << " " << std::setbase(16) << v[i-1]);
+  DEBUG(cerr << '\n');
 
   // D2. [Initialize j.]  Set j to m. This is the loop counter over the places.
   int j = m;
   do {
+    DEBUG(cerr << "KnuthDiv: quotient digit #" << j << '\n');
     // D3. [Calculate q'.]. 
     //     Set qp = (u[j+n]*b + u[j+n-1]) / v[n-1]. (qp=qprime=q')
     //     Set rp = (u[j+n]*b + u[j+n-1]) % v[n-1]. (rp=rprime=r')
@@ -1031,41 +1047,54 @@
     // value qp is one too large, and it eliminates all cases where qp is two 
     // too large. 
     uint64_t dividend = ((uint64_t(u[j+n]) << 32) + u[j+n-1]);
+    DEBUG(cerr << "KnuthDiv: dividend == " << dividend << '\n');
     uint64_t qp = dividend / v[n-1];
     uint64_t rp = dividend % v[n-1];
     if (qp == b || qp*v[n-2] > b*rp + u[j+n-2]) {
       qp--;
       rp += v[n-1];
-      if (rp < b) {
-        if (qp == b || qp*v[n-2] > b*rp + u[j+n-2]) {
-          qp--;
-          rp += v[n-1];
-        }
+      if (rp < b && (qp == b || qp*v[n-2] > b*rp + u[j+n-2])) {
+        qp--;
+        //rp += v[n-1];
       }
     }
+    DEBUG(cerr << "KnuthDiv: qp == " << qp << ", rp == " << rp << '\n');
 
     // D4. [Multiply and subtract.] Replace (u[j+n]u[j+n-1]...u[j]) with
     // (u[j+n]u[j+n-1]..u[j]) - qp * (v[n-1]...v[1]v[0]). This computation
     // consists of a simple multiplication by a one-place number, combined with
     // a subtraction. The digits (u[j+n]...u[j]) should be kept positive;
-    bool borrow = 0;
+    bool borrow = false;
     for (uint32_t i = 0; i < n; ++i) {
-      uint64_t u_tmp = borrow ? u[j+i] - 1 : u[j+i];
-      uint64_t subtrahend = qp * v[i];
+      uint64_t u_tmp = borrow ? uint64_t(u[j+i] - 1) : uint64_t(u[j+i]);
+      uint64_t subtrahend = uint64_t(qp) * uint64_t(v[i]);
+      DEBUG(cerr << "KnuthDiv: u_tmp == " << u_tmp 
+                 << ", subtrahend == " << subtrahend << '\n');
+
       borrow = subtrahend > u_tmp || (borrow && u[j+i] == 0);
       u[j+i] = u_tmp - subtrahend;
     }
+    if (borrow) {
+      borrow = u[j+n] == 0;            // Was result negative?
+      u[j+n]--;  // handle the borrow
+    }
+    DEBUG(cerr << "KnuthDiv: after subtraction:");
+    DEBUG(for (int i = m+n; i >=0; i--) cerr << " " << u[i]);
+    DEBUG(cerr << '\n');
     // if the result of this step is actually negative, (u[j+n]...u[j]) should
-    // be left as the true value plus b**(n+1), names as the b's complement of
+    // be left as the true value plus b**(n+1), namely as the b's complement of
     // the true value, and a "borrow" to the left should be remembered.
     //
     if (borrow) {
-      borrow = u[j+n] == 0;
-      u[j+n]--;
-//      for (uint32_t i = 0; i < n; ++i) {
-//        u[j+i] = ~u[j+i] + 1; // b's complement
-//      }
+      bool carry = true;
+      for (uint32_t i = 0; i <= n; ++i) {
+        u[j+i] = ~u[j+i] + carry; // b's complement
+        carry = u[j+i] == 0;
+      }
     }
+    DEBUG(cerr << "KnuthDiv: after complement:");
+    DEBUG(for (int i = m+n; i >=0; i--) cerr << " " << u[i]);
+    DEBUG(cerr << '\n');
 
     // D5. [Test remainder.] Set q[j] = qp. If the result of step D4 was 
     // negative, go to step D6; otherwise go on to step D7.
@@ -1080,16 +1109,23 @@
       // since it cancels with the borrow that occurred in D4.
       bool carry = false;
       for (uint32_t i = 0; i < n; i++) {
-        uint32_t save = u[j+i];
+        uint32_t limit = std::min(u[j+i],v[i]);
         u[j+i] += v[i] + carry;
-        uint32_t limit = std::min(save,v[i]);
-        carry = u[j+i] < limit || (carry && u[j+1] == limit);
+        carry = u[j+i] < limit || (carry && u[j+i] == limit);
       }
+      u[j+n] += carry;
     }
+    DEBUG(cerr << "KnuthDiv: after correction:");
+    DEBUG(for (int i = m+n; i >=0; i--) cerr <<" " << u[i]);
+    DEBUG(cerr << "\nKnuthDiv: digit result = " << q[j] << '\n');
 
   // D7. [Loop on j.]  Decrease j by one. Now if j >= 0, go back to D3.
   } while (--j >= 0);
 
+  DEBUG(cerr << "KnuthDiv: quotient:");
+  DEBUG(for (int i = m; i >=0; i--) cerr <<" " << q[i]);
+  DEBUG(cerr << '\n');
+
   // D8. [Unnormalize]. Now q[...] is the desired quotient, and the desired
   // remainder may be obtained by dividing u[...] by d. If r is non-null we
   // compute the remainder (urem uses this).
@@ -1098,11 +1134,15 @@
     // multiplication by d by using a shift left. So, all we have to do is
     // shift right here. In order to mak
     uint32_t carry = 0;
+    DEBUG(cerr << "KnuthDiv: remainder:");
     for (int i = n-1; i >= 0; i--) {
       r[i] = (u[i] >> shift) | carry;
       carry = u[i] << shift;
+      DEBUG(cerr << " " << r[i]);
     }
+    DEBUG(cerr << '\n');
   }
+  DEBUG(cerr << std::setbase(10) << '\n');
 }
 
 // This function makes calling KnuthDiv a little more convenient. It uses






More information about the llvm-commits mailing list