Fix #times: for WIN32
authorStefan Vogel <sv@exept.de>
Tue, 31 Aug 2004 21:29:22 +0200
changeset 8506 ddd41df3dc0f
parent 8505 4456ffd20005
child 8507 9d392516725c
Fix #times: for WIN32
SmallInteger.st
--- a/SmallInteger.st	Tue Aug 31 16:26:30 2004 +0200
+++ b/SmallInteger.st	Tue Aug 31 21:29:22 2004 +0200
@@ -2998,19 +2998,156 @@
 
 %{  /* NOCONTEXT */
 
+    INT myValue, otherValue;
+    unsigned INT productLow, productHi;
+    int negative;
+
+#   define low16Bits(foo)  ((foo) & 0xFFFF)
+#   define hi16Bits(foo)   ((foo) >> 16)
+#   define low32Bits(foo)  ((foo) & 0xFFFFFFFFL)
+#   define hi32Bits(foo)   ((foo) >> 32)
+
+    /*
+     * can we use long long arithmetic ?
+     *
+     * long-long arithmetic seems to be buggy with some systems
+     * (took me a while to find this out :-(
+     * (try 10000 * 10000)
+     */
+#if defined(sparc) && defined(__GNUC__) && (__GNUC__ >= 2)
+# define USE_LONGLONG_FOR_MUL
+#endif
+
+#if defined(i386) && defined(__GNUC__) && (__GNUC__ >= 2)
+# define USE_LONGLONG_FOR_MUL
+#endif
+
     if (__isSmallInteger(aNumber)) {
+        myValue = __intVal(self);
+        otherValue = __intVal(aNumber);
+
+#if defined(USE_LONGLONG_FOR_MUL)
+        {
 # if defined(alpha) && !defined(alpha64)
 #  define LONGLONG      INT64
 # else
 #  define LONGLONG      long long
 # endif
-        LONGLONG product;
-
-        /* keep the sign */
-        product = ((LONGLONG)__intVal(self) * (LONGLONG)__intVal(aNumber)) % _MAX_INT;
-        RETURN ( __MKSMALLINT((INT)product));
+            LONGLONG product;
+
+            product = (LONGLONG)myValue * (LONGLONG)otherValue;
+            if (product < 0) {
+                RETURN ( __MKSMALLINT(-(INT)(-product & 0x3FFFFFFF)));
+            }
+            RETURN ( __MKSMALLINT((INT)(product & 0x3FFFFFFF)));
+        }
+#else /* no long-long */
+        negative = 1;
+        if (myValue < 0) {
+            negative = -1;
+            myValue = -myValue;
+        }
+        if (otherValue < 0) {
+            negative = -negative;
+            otherValue = -otherValue;
+        }
+
+# if defined(__GNUC__) && defined(mc68k)
+        asm ("mulu%.l %3,%1:%0"
+                : "=d"  ((unsigned long)(productLow)),
+                  "=d"  ((unsigned long)(productHi))
+                : "%0"  ((unsigned long)(myValue)),
+                  "dmi" ((unsigned long)(otherValue)));
+# else
+#  if defined (__GNUC__) && defined(i386)
+        asm ("mull %3"
+                : "=a"  ((unsigned long)(productLow)),
+                  "=d"  ((unsigned long)(productHi))
+                : "%0"  ((unsigned long)(myValue)),
+                  "rm"  ((unsigned long)(otherValue)));
+#  else
+#   if defined(WIN32)
+        asm {
+            mov   eax, myValue
+            mov   edx, otherValue
+            mul   edx
+            mov   productLow, eax
+            mov   productHi, edx
+        }
+#   else /* generic */
+        {
+            unsigned INT pHH, pHL, pLH, pLL;
+            unsigned INT low1, low2, hi1, hi2;
+            unsigned INT t;
+
+            /* unsigned multiply myValue * otherValue -> productHi, productLow
+             *
+             * this is too slow:
+             * since most machines can do 32*32 to 64 bit multiply,
+             * (or at least 32*32 with Overflow check)
+             * - need more assembler (inline) functions here 
+             */
+#    ifdef alpha64
+            low1 = low32Bits((unsigned INT)myValue);
+            hi1 = hi32Bits((unsigned INT)myValue);
+            low2 = low32Bits((unsigned INT)otherValue);
+            hi2 = hi32Bits((unsigned INT)otherValue);
+#     define LLMASK 0xC000000000000000L
+#    else
+            low1 = low16Bits((unsigned INT)myValue);
+            hi1 = hi16Bits((unsigned INT)myValue);
+            low2 = low16Bits((unsigned INT)otherValue);
+            hi2 = hi16Bits((unsigned INT)otherValue);
+#     define LLMASK 0xC0000000
+#    endif
+
+            pLH = low1 * hi2;
+            pHL = hi1 * low2;
+            pLL = low1 * low2;
+            pHH = hi1 * hi2;
+
+            /*
+             * the common case ...
+             */
+            if ((pHL == 0)
+             && (pLH == 0)
+             && (pHH == 0)
+             && ((pLL & LLMASK) == 0)) {
+                if (negative < 0) {
+                    RETURN ( __MKSMALLINT(- ((INT)pLL)) );
+                }
+                RETURN ( __MKSMALLINT((INT)pLL) );
+            }
+
+            /*
+             *   pHH |--------|--------|
+             *   pLH          |--------|--------|
+             *   pHL          |--------|--------|
+             *   pLL                   |--------|--------|
+             */
+
+#    ifdef alpha64
+            t = low32Bits(pLH) + low32Bits(pHL) + hi32Bits(pLL);
+            productLow = (t << 32) + low32Bits(pLL);
+            productHi = pHH + hi32Bits(t) + hi32Bits(pHL) + hi32Bits(pLH);
+#    else
+            t = low16Bits(pLH) + low16Bits(pHL) + hi16Bits(pLL);
+            productLow = (t << 16) + low16Bits(pLL);
+            productHi = pHH + hi16Bits(t) + hi16Bits(pHL) + hi16Bits(pLH);
+#    endif
+        }
+#   endif /* ! WIN32 */
+#  endif /* ! (__GNUC__ && i386) */
+# endif /* ! (__GNUC__ && mc68k) */
+
+        if (negative < 0) {
+            RETURN ( __MKSMALLINT(-(INT)(productLow & 0x3FFFFFFF)));
+        }
+        RETURN ( __MKSMALLINT((INT)(productLow & 0x3FFFFFFF)));
+#endif /* ! USE_LONGLONG */
     }
 %}.
+
     self primitiveFailed
 
     "
@@ -3018,7 +3155,7 @@
         5 times:1
         self maxVal-1 times:2
         self maxVal-1 times:-2
-        self maxVal-1 * 2
+        self maxVal-1 * 2  bitAnd:16r3fffffff
     "
 ! !
 
@@ -3447,5 +3584,5 @@
 !SmallInteger class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/SmallInteger.st,v 1.161 2004-08-30 16:44:27 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/SmallInteger.st,v 1.162 2004-08-31 19:29:22 stefan Exp $'
 ! !