]> granicus.if.org Git - php/commitdiff
- Apply Ard's patch to support multiplication & overflow on both 32bit
authorAndi Gutmans <andi@php.net>
Wed, 17 Mar 2004 09:25:52 +0000 (09:25 +0000)
committerAndi Gutmans <andi@php.net>
Wed, 17 Mar 2004 09:25:52 +0000 (09:25 +0000)
  and 64bit machines

Zend/zend_multiply.h
Zend/zend_operators.c

index 2e6fe6a11aa527a706a48e55152a22c854ac9ac5..eda4ca135ec56a01defb3bffc71baa6fd43a7bfc 100644 (file)
@@ -2,7 +2,7 @@
    +----------------------------------------------------------------------+
    | Zend Engine                                                          |
    +----------------------------------------------------------------------+
-   | Copyright (c) 2003-2004 Sascha Schumann                              |
+   | Copyright (c) 1998-2004 Zend Technologies Ltd. (http://www.zend.com) |
    +----------------------------------------------------------------------+
    | This source file is subject to version 2.00 of the Zend license,     |
    | that is bundled with this package in the file LICENSE, and is        |
    | obtain it through the world-wide-web, please send a note to          |
    | license@zend.com so we can mail you a copy immediately.              |
    +----------------------------------------------------------------------+
-   | Author: Sascha Schumann <sascha@schumann.cx>                         |
+   | Author: Ard Biesheuvel <ard@ard.nu>                                  |
    +----------------------------------------------------------------------+
 */
 
 /* $Id$ */
 
-#if defined(__i386__) && defined(__GNUC__)
+#define HALF   (4*sizeof(long))
+#define UH(b)  ((b) >> HALF)
+#define LH(a)  ((a) & ~(-1L << HALF))
 
-#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do {      \
-       long __tmpvar;                                                                                                  \
-       __asm__ ("imul %3,%0\n"                                                                                 \
-               "adc $0,%1"                                                                                             \
-                       : "=r"(__tmpvar),"=r"(usedval)                                                  \
-                       : "0"(a), "r"(b), "1"(0));                                                              \
-       if (usedval) (dval) = (double) (a) * (double) (b);                              \
-       else (lval) = __tmpvar;                                                                                 \
+#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do {              \
+       long __mid,__upr,__res = (a) * (b);                                                                     \
+       if (-(long)(a) > 0 && -(long)(b) > 0) { /* overflow intended */         \
+               __mid = UH(-(a))*LH(-(b)) + LH(-(a))*UH(-(b));                                  \
+               __upr = UH(-(a))*UH(-(b)) + UH(__mid);                                                  \
+       } else {                                                                                                                        \
+               __mid = UH(a)*LH(b) + LH(a)*UH(b);                                                              \
+               __upr = UH(a)*UH(b) + UH(__mid);                                                                \
+       }                                                                                                                                       \
+       if (((usedval) = !((__upr==-1&&__res<0)||(!__upr&&__res>=0)))) {        \
+               (dval) = (double)(a)*(double)(b);                                                               \
+       } else {                                                                                                                        \
+               (lval) = __res;                                                                                                 \
+       }                                                                                                                                       \
 } while (0)
-
-#else
-
-#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do {      \
-       double __tmpvar = (double) (a) * (double) (b);                                  \
-                                                                                                                                       \
-       if (__tmpvar >= LONG_MAX || __tmpvar <= LONG_MIN) {                             \
-               (dval) = __tmpvar;                                                                                      \
-               (usedval) = 1;                                                                                          \
-       } else {                                                                                                                \
-               (lval) = (a) * (b);                                                                                     \
-               (usedval) = 0;                                                                                          \
-       }                                                                                                                               \
-} while (0)
-
-#endif
index 412c3e529f34c9611b9ca012bca8d6db873ae424..cbc12356593ac87f5954b6710888412cca04a9ea 100644 (file)
@@ -28,6 +28,7 @@
 #include "zend_list.h"
 #include "zend_fast_cache.h"
 #include "zend_API.h"
+#include "zend_multiply.h"
 
 #if 0&&HAVE_BCMATH
 #include "ext/bcmath/number.h"
@@ -803,16 +804,10 @@ ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
        zendi_convert_scalar_to_number(op2, op2_copy, result);
 
        if (op1->type == IS_LONG && op2->type == IS_LONG) {
-               long lval = op1->value.lval * op2->value.lval;
-               
-               /* check for overflow by applying the reverse calculation */
-               if (op1->value.lval != 0 && lval / op1->value.lval != op2->value.lval) {
-                       result->value.dval = (double) op1->value.lval * (double) op2->value.lval;
-                       result->type = IS_DOUBLE;
-               } else {
-                       result->value.lval = lval;
-                       result->type = IS_LONG;
-               }
+               long overflow;
+
+               ZEND_SIGNED_MULTIPLY_LONG(op1->value.lval,op2->value.lval, result->value.lval,result->value.dval,overflow);
+               result->type = overflow ? IS_DOUBLE : IS_LONG;  
                return SUCCESS;
        }
        if ((op1->type == IS_DOUBLE && op2->type == IS_LONG)