diff options
author | Andi Gutmans <andi@php.net> | 2004-03-17 09:25:52 +0000 |
---|---|---|
committer | Andi Gutmans <andi@php.net> | 2004-03-17 09:25:52 +0000 |
commit | 29ee03aa55688ca9a6441c3aa1ed8be905830027 (patch) | |
tree | 3c6cf763687b89bb9d1d971d9dccad327058df70 | |
parent | 8aea19c345fa9f92a8fc7b6cedcb16c9f385e1c3 (diff) | |
download | php-git-29ee03aa55688ca9a6441c3aa1ed8be905830027.tar.gz |
- Apply Ard's patch to support multiplication & overflow on both 32bit
and 64bit machines
-rw-r--r-- | Zend/zend_multiply.h | 46 | ||||
-rw-r--r-- | Zend/zend_operators.c | 15 |
2 files changed, 24 insertions, 37 deletions
diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h index 2e6fe6a11a..eda4ca135e 100644 --- a/Zend/zend_multiply.h +++ b/Zend/zend_multiply.h @@ -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 | @@ -12,36 +12,28 @@ | 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 diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 412c3e529f..cbc1235659 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -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) |