Jacek Caban : ntdll: Reimplement _aulldiv using 32-bit arithmetic.

Alexandre Julliard julliard at winehq.org
Tue Jun 9 15:27:46 CDT 2020


Module: wine
Branch: master
Commit: d53672c6ecc8f1f1a0b883475028871c9e003431
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=d53672c6ecc8f1f1a0b883475028871c9e003431

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Mon Jun  8 18:12:01 2020 +0200

ntdll: Reimplement _aulldiv using 32-bit arithmetic.

Based on compiler-rt.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/large_int.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 178 insertions(+), 1 deletion(-)

diff --git a/dlls/ntdll/large_int.c b/dlls/ntdll/large_int.c
index e7b71c9385..6b63fb87ee 100644
--- a/dlls/ntdll/large_int.c
+++ b/dlls/ntdll/large_int.c
@@ -545,6 +545,183 @@ NTSTATUS WINAPI RtlInt64ToUnicodeString(
 
 #ifdef __i386__
 
+static ULONGLONG udivmod(ULONGLONG a, ULONGLONG b, ULONGLONG *rem)
+{
+    const ULARGE_INTEGER n = { .QuadPart = a };
+    const ULARGE_INTEGER d = { .QuadPart = b };
+    DWORD sr, carry, index;
+    ULARGE_INTEGER q, r;
+
+    const unsigned n_uword_bits  = 32;
+    const unsigned n_udword_bits = 64;
+
+    /* special cases, X is unknown, K != 0 */
+    if (n.u.HighPart == 0)
+    {
+        if (d.u.HighPart == 0)
+        {
+            /* 0 X / 0 X */
+            if (rem) *rem = n.u.LowPart % d.u.LowPart;
+            return n.u.LowPart / d.u.LowPart;
+        }
+        /* 0 X / K X */
+        if (rem) *rem = n.u.LowPart;
+        return 0;
+    }
+
+    /* n.u.HighPart != 0 */
+    if (d.u.LowPart == 0)
+    {
+        if (d.u.HighPart == 0)
+        {
+            /* K X / 0 0 */
+            if (rem) *rem = n.u.HighPart % d.u.LowPart;
+            return n.u.HighPart / d.u.LowPart;
+        }
+        /* d.u.HighPart != 0 */
+        if (n.u.LowPart == 0) {
+            /* K 0 / K 0 */
+            if (rem)
+            {
+                r.u.HighPart = n.u.HighPart % d.u.HighPart;
+                r.u.LowPart = 0;
+                *rem = r.QuadPart;
+            }
+            return n.u.HighPart / d.u.HighPart;
+        }
+        /* K K / K 0 */
+        if ((d.u.HighPart & (d.u.HighPart - 1)) == 0) /* if d is a power of 2 */
+        {
+            if (rem)
+            {
+                r.u.LowPart = n.u.LowPart;
+                r.u.HighPart = n.u.HighPart & (d.u.HighPart - 1);
+                *rem = r.QuadPart;
+            }
+            BitScanForward(&index, d.u.HighPart);
+            return n.u.HighPart >> index;
+        }
+        /* K K / K 0 */
+        BitScanReverse(&index, d.u.HighPart);
+        BitScanReverse(&sr, n.u.HighPart);
+        sr -= index;
+        /* 0 <= sr <= n_uword_bits - 2 or sr large */
+        if (sr > n_uword_bits - 2)
+        {
+            if (rem) *rem = n.QuadPart;
+            return 0;
+        }
+        ++sr;
+        /* 1 <= sr <= n_uword_bits - 1 */
+        /* q.QuadPart = n.QuadPart << (n_udword_bits - sr); */
+        q.u.LowPart = 0;
+        q.u.HighPart = n.u.LowPart << (n_uword_bits - sr);
+        /* r.QuadPart = n.QuadPart >> sr; */
+        r.u.HighPart = n.u.HighPart >> sr;
+        r.u.LowPart = (n.u.HighPart << (n_uword_bits - sr)) | (n.u.LowPart >> sr);
+    }
+    else /* d.u.LowPart != 0 */
+    {
+        if (d.u.HighPart == 0)
+        {
+            /* K X / 0 K */
+            if ((d.u.LowPart & (d.u.LowPart - 1)) == 0) /* if d is a power of 2 */
+            {
+                if (rem) *rem = n.u.LowPart & (d.u.LowPart - 1);
+                if (d.u.LowPart == 1) return n.QuadPart;
+                BitScanForward(&sr, d.u.LowPart);
+                q.u.HighPart = n.u.HighPart >> sr;
+                q.u.LowPart = (n.u.HighPart << (n_uword_bits - sr)) | (n.u.LowPart >> sr);
+                return q.QuadPart;
+            }
+            BitScanReverse(&index, d.u.LowPart);
+            BitScanReverse(&sr, n.u.HighPart);
+            sr = 1 + n_uword_bits + sr - index;
+            /* 2 <= sr <= n_udword_bits - 1
+             * q.QuadPart = n.QuadPart << (n_udword_bits - sr);
+             * r.QuadPart = n.QuadPart >> sr; */
+            if (sr == n_uword_bits)
+            {
+                q.u.LowPart = 0;
+                q.u.HighPart = n.u.LowPart;
+                r.u.HighPart = 0;
+                r.u.LowPart = n.u.HighPart;
+            }
+            else if (sr < n_uword_bits) /* 2 <= sr <= n_uword_bits - 1 */
+            {
+                q.u.LowPart = 0;
+                q.u.HighPart = n.u.LowPart << (n_uword_bits - sr);
+                r.u.HighPart = n.u.HighPart >> sr;
+                r.u.LowPart = (n.u.HighPart << (n_uword_bits - sr)) | (n.u.LowPart >> sr);
+            }
+            else /* n_uword_bits + 1 <= sr <= n_udword_bits - 1 */
+            {
+                q.u.LowPart = n.u.LowPart << (n_udword_bits - sr);
+                q.u.HighPart = (n.u.HighPart << (n_udword_bits - sr)) |
+                    (n.u.LowPart >> (sr - n_uword_bits));
+                r.u.HighPart = 0;
+                r.u.LowPart = n.u.HighPart >> (sr - n_uword_bits);
+            }
+        }
+        else
+        {
+            /* K X / K K */
+            BitScanReverse(&index, d.u.HighPart);
+            BitScanReverse(&sr, n.u.HighPart);
+            sr -= index;
+            /* 0 <= sr <= n_uword_bits - 1 or sr large */
+            if (sr > n_uword_bits - 1)
+            {
+                if (rem) *rem = n.QuadPart;
+                return 0;
+            }
+            ++sr;
+            /* 1 <= sr <= n_uword_bits
+             * q.QuadPart = n.QuadPart << (n_udword_bits - sr); */
+            q.u.LowPart = 0;
+            if (sr == n_uword_bits)
+            {
+                q.u.HighPart = n.u.LowPart;
+                r.u.HighPart = 0;
+                r.u.LowPart = n.u.HighPart;
+            }
+            else
+            {
+                q.u.HighPart = n.u.LowPart << (n_uword_bits - sr);
+                r.u.HighPart = n.u.HighPart >> sr;
+                r.u.LowPart = (n.u.HighPart << (n_uword_bits - sr)) | (n.u.LowPart >> sr);
+            }
+        }
+    }
+    /* Not a special case
+     * q and r are initialized with:
+     * q.QuadPart = n.QuadPart << (n_udword_bits - sr);
+     * r.QuadPart = n.QuadPart >> sr;
+     * 1 <= sr <= n_udword_bits - 1 */
+    carry = 0;
+    for (; sr > 0; --sr)
+    {
+        LONGLONG s;
+        /* r:q = ((r:q)  << 1) | carry */
+        r.u.HighPart = (r.u.HighPart << 1) | (r.u.LowPart >> (n_uword_bits - 1));
+        r.u.LowPart = (r.u.LowPart << 1) | (q.u.HighPart >> (n_uword_bits - 1));
+        q.u.HighPart = (q.u.HighPart << 1) | (q.u.LowPart >> (n_uword_bits - 1));
+        q.u.LowPart = (q.u.LowPart << 1) | carry;
+        /* if (r.QuadPart >= d.QuadPart)
+         * {
+         *      r.QuadPart -= d.QuadPart;
+         *      carry = 1;
+         * }
+         */
+        s = (LONGLONG)(d.QuadPart - r.QuadPart - 1) >> (n_udword_bits - 1);
+        carry = s & 1;
+        r.QuadPart -= d.QuadPart & s;
+    }
+    q.QuadPart = (q.QuadPart << 1) | carry;
+    if (rem) *rem = r.QuadPart;
+    return q.QuadPart;
+}
+
 /******************************************************************************
  *        _alldiv   (NTDLL.@)
  *
@@ -613,7 +790,7 @@ LONGLONG WINAPI _allrem( LONGLONG a, LONGLONG b )
  */
 ULONGLONG WINAPI _aulldiv( ULONGLONG a, ULONGLONG b )
 {
-    return a / b;
+    return udivmod(a, b, NULL);
 }
 
 /******************************************************************************




More information about the wine-cvs mailing list