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

Reid Spencer reid at x10sys.com
Wed Feb 28 21:40:15 PST 2007



Changes in directory llvm/lib/Support:

APInt.cpp updated: 1.59 -> 1.60
---
Log message:

Add a square root function.


---
Diffs of the changes:  (+87 -6)

 APInt.cpp |   93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 87 insertions(+), 6 deletions(-)


Index: llvm/lib/Support/APInt.cpp
diff -u llvm/lib/Support/APInt.cpp:1.59 llvm/lib/Support/APInt.cpp:1.60
--- llvm/lib/Support/APInt.cpp:1.59	Wed Feb 28 11:34:32 2007
+++ llvm/lib/Support/APInt.cpp	Wed Feb 28 23:39:56 2007
@@ -1015,7 +1015,7 @@
   if (shiftAmt < APINT_BITS_PER_WORD) {
     uint64_t carry = 0;
     for (int i = getNumWords()-1; i >= 0; --i) {
-      val[i] = pVal[i] >> shiftAmt | carry;
+      val[i] = (pVal[i] >> shiftAmt) | carry;
       carry = pVal[i] << (APINT_BITS_PER_WORD - shiftAmt);
     }
     return APInt(val, BitWidth).clearUnusedBits();
@@ -1037,8 +1037,8 @@
   // Shift the low order words 
   uint32_t breakWord = getNumWords() - offset -1;
   for (uint32_t i = 0; i < breakWord; ++i)
-    val[i] = pVal[i+offset] >> wordShift |
-             pVal[i+offset+1] << (APINT_BITS_PER_WORD - wordShift);
+    val[i] = (pVal[i+offset] >> wordShift) |
+             (pVal[i+offset+1] << (APINT_BITS_PER_WORD - wordShift));
   // Shift the break word.
   uint32_t SignBit = APINT_BITS_PER_WORD - (BitWidth % APINT_BITS_PER_WORD);
   val[breakWord] = uint64_t(
@@ -1072,7 +1072,7 @@
   if (shiftAmt < APINT_BITS_PER_WORD) {
     uint64_t carry = 0;
     for (int i = getNumWords()-1; i >= 0; --i) {
-      val[i] = pVal[i] >> shiftAmt | carry;
+      val[i] = (pVal[i] >> shiftAmt) | carry;
       carry = pVal[i] << (APINT_BITS_PER_WORD - shiftAmt);
     }
     return APInt(val, BitWidth).clearUnusedBits();
@@ -1094,8 +1094,8 @@
   // Shift the low order words 
   uint32_t breakWord = getNumWords() - offset -1;
   for (uint32_t i = 0; i < breakWord; ++i)
-    val[i] = pVal[i+offset] >> wordShift |
-             pVal[i+offset+1] << (APINT_BITS_PER_WORD - wordShift);
+    val[i] = (pVal[i+offset] >> wordShift) |
+             (pVal[i+offset+1] << (APINT_BITS_PER_WORD - wordShift));
   // Shift the break word.
   val[breakWord] = pVal[breakWord+offset] >> wordShift;
 
@@ -1158,6 +1158,87 @@
   return APInt(val, BitWidth).clearUnusedBits();
 }
 
+
+// Square Root - this method computes and returns the square root of "this".
+// Three mechanisms are used for computation. For small values (<= 5 bits),
+// a table lookup is done. This gets some performance for common cases. For
+// values using less than 52 bits, the value is converted to double and then
+// the libc sqrt function is called. The result is rounded and then converted
+// back to a uint64_t which is then used to construct the result. Finally,
+// the Babylonian method for computing square roots is used. 
+APInt APInt::sqrt() const {
+
+  // Determine the magnitude of the value.
+  uint32_t magnitude = getActiveBits();
+
+  // Use a fast table for some small values. This also gets rid of some
+  // rounding errors in libc sqrt for small values.
+  if (magnitude <= 5) {
+    uint64_t result = 0;
+    switch (isSingleWord() ? VAL : pVal[0]) {
+      case 0 : break;
+      case 1 : case 2 : result = 1; break;
+      case 3 : case 4 : case 5: case 6: result = 2; break;
+      case 7 : case 8 : case 9: case 10: case 11: case 12: 
+        result = 3; break;
+      case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20:
+        result = 4; break;
+      case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28:
+      case 29: case 30: result = 5; break;
+      case 31: result = 6; break;
+    }
+    return APInt(BitWidth, result);
+  }
+
+  // If the magnitude of the value fits in less than 52 bits (the precision of
+  // an IEEE double precision floating point value), then we can use the
+  // libc sqrt function which will probably use a hardware sqrt computation.
+  // This should be faster than the algorithm below.
+  if (magnitude < 52)
+    return APInt(BitWidth, 
+                 uint64_t(::round(::sqrt(double(isSingleWord()?VAL:pVal[0])))));
+
+  // Okay, all the short cuts are exhausted. We must compute it. The following
+  // is a classical Babylonian method for computing the square root. This code
+  // was adapted to APINt from a wikipedia article on such computations.
+  // See http://www.wikipedia.org/ and go to the page named
+  // Calculate_an_integer_square_root. 
+  uint32_t nbits = BitWidth, i = 4;
+  APInt testy(BitWidth, 16);
+  APInt x_old(BitWidth, 1);
+  APInt x_new(BitWidth, 0);
+  APInt two(BitWidth, 2);
+
+  // Select a good starting value using binary logarithms.
+  for (;; i += 2, testy = testy.shl(2)) 
+    if (i >= nbits || this->ule(testy)) {
+      x_old = x_old.shl(i / 2);
+      break;
+    }
+
+  // Use the Babylonian method to arrive at the integer square root: 
+  for (;;) {
+    x_new = (this->udiv(x_old) + x_old).udiv(two);
+    if (x_old.ule(x_new))
+      break;
+    x_old = x_new;
+  }
+
+  // Make sure we return the closest approximation
+  APInt square(x_old * x_old);
+  APInt nextSquare((x_old + 1) * (x_old +1));
+  if (this->ult(square))
+    return x_old;
+  else if (this->ule(nextSquare))
+    if ((nextSquare - *this).ult(*this - square))
+      return x_old + 1;
+    else
+      return x_old;
+  else
+    assert(0 && "Error in APInt::sqrt computation");
+  return x_old + 1;
+}
+
 /// Implementation of Knuth's Algorithm D (Division of nonnegative integers)
 /// from "Art of Computer Programming, Volume 2", section 4.3.1, p. 272. The
 /// variables here have the same names as in the algorithm. Comments explain






More information about the llvm-commits mailing list