start splitting out bigops
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Tue, 26 Apr 2022 12:41:35 +0000 (13:41 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Tue, 26 Apr 2022 12:41:35 +0000 (13:41 +0100)
openpower/sv/biginteger/divmnu64.c

index e193a59ed357949835e5a1a3d47c85f1929032f0..7906ce099b9bdd1c400d03689b7f05bf7908b1e0 100644 (file)
@@ -74,6 +74,63 @@ divrem_t divrem_64_by_32(uint64_t n, uint32_t d)
     }
 }
 
+bool bigmul(uint32_t qhat, unsigned product[], unsigned vn[], int m,
+            int n)
+{
+    long long t, k;
+    int s, i;
+    uint32_t carry = 0;
+    // VL = n + 1
+    // sv.madded product.v, vn.v, qhat.s, carry.s
+    for (int i = 0; i <= n; i++)
+    {
+        uint32_t vn_v = i < n ? vn[i] : 0;
+        uint64_t value = (uint64_t)vn_v * (uint64_t)qhat + carry;
+        carry = (uint32_t)(value >> 32);
+        product[i] = (uint32_t)value;
+    }
+    return carry != 0;
+}
+
+bool bigadd(unsigned result[], unsigned vn[], unsigned un[], int m, int n,
+            bool ca)
+{
+    // VL = n + 1
+    // sv.subfe un_j.v, product.v, un_j.v
+    for (int i = 0; i <= n; i++)
+    {
+        uint64_t value = (uint64_t)vn[i] + (uint64_t)un[i] + ca;
+        ca = value >> 32 != 0;
+        result[i] = value;
+    }
+    return ca;
+}
+
+bool bigsub(unsigned result[], unsigned vn[], unsigned un[], int m, int n,
+            bool ca)
+{
+    // VL = n + 1
+    // sv.subfe un_j.v, product.v, un_j.v
+    for (int i = 0; i <= n; i++)
+    {
+        uint64_t value = (uint64_t)~vn[i] + (uint64_t)un[i] + ca;
+        ca = value >> 32 != 0;
+        result[i] = value;
+    }
+    return ca;
+}
+
+bool bigmulsub(unsigned long long qhat, unsigned vn[], unsigned un[], int j,
+               int m, int n)
+{
+    // Multiply and subtract.
+    uint32_t product[n + 1];
+    bigmul(qhat, product, vn, m, n);
+    bool ca = bigsub(un, product, un, m, n, true);
+    bool need_fixup = !ca;
+    return need_fixup;
+}
+
 /* q[0], r[0], u[0], and v[0] contain the LEAST significant words.
 (The sequence is in little-endian order).
 
@@ -143,6 +200,7 @@ int divmnu(unsigned q[], unsigned r[], const unsigned u[], const unsigned v[],
 
     for (j = m - n; j >= 0; j--)
     { // Main loop.
+        uint32_t *un_j = &un[j];
         // Compute estimate qhat of q[j] from top 2 digits.
         uint64_t dig2 = ((uint64_t)un[j + n] << 32) | un[j + n - 1];
         divrem_t qr = divrem_64_by_32(dig2, vn[n - 1]);
@@ -333,7 +391,6 @@ int divmnu(unsigned q[], unsigned r[], const unsigned u[], const unsigned v[],
             product[i] = (uint32_t)value;
         }
         bool ca = true;
-        uint32_t *un_j = &un[j];
         // VL = n + 1
         // sv.subfe un_j.v, product.v, un_j.v
         for (int i = 0; i <= n; i++)
@@ -351,14 +408,7 @@ int divmnu(unsigned q[], unsigned r[], const unsigned u[], const unsigned v[],
         if (need_fixup)
         {                    // If we subtracted too
             q[j] = q[j] - 1; // much, add back.
-            k = 0;
-            for (i = 0; i < n; i++)
-            {
-                t = (unsigned long long)un[i + j] + vn[i] + k;
-                un[i + j] = t;
-                k = t >> 32;
-            }
-            un[j + n] = un[j + n] + k;
+            bigadd(un_j, vn, un_j, m, n, 0);
         }
     } // End j.
     // If the caller wants the remainder, unnormalize