summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndi Gutmans <andi@php.net>2004-03-17 09:25:52 +0000
committerAndi Gutmans <andi@php.net>2004-03-17 09:25:52 +0000
commit29ee03aa55688ca9a6441c3aa1ed8be905830027 (patch)
tree3c6cf763687b89bb9d1d971d9dccad327058df70
parent8aea19c345fa9f92a8fc7b6cedcb16c9f385e1c3 (diff)
downloadphp-git-29ee03aa55688ca9a6441c3aa1ed8be905830027.tar.gz
- Apply Ard's patch to support multiplication & overflow on both 32bit
and 64bit machines
-rw-r--r--Zend/zend_multiply.h46
-rw-r--r--Zend/zend_operators.c15
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)