summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnatol Belski <ab@php.net>2016-12-03 15:44:36 +0100
committerAnatol Belski <ab@php.net>2016-12-03 15:50:21 +0100
commitc5af4b25851d2a38b6dc84bfa2b2131f6bbc02f8 (patch)
tree155798ddaafa246dbfca60cd5c942a5b5ee036f7
parent143ee76fe4ad26041174caad32ed239fb0e28275 (diff)
downloadphp-git-c5af4b25851d2a38b6dc84bfa2b2131f6bbc02f8.tar.gz
Improve multiplication on x64.
Thanks Bob for the spot.
-rw-r--r--Zend/tests/zend_signed_multiply-64bit-2.phpt149
-rw-r--r--Zend/tests/zend_signed_multiply-64bit.phpt2
-rw-r--r--Zend/zend_multiply.h16
3 files changed, 165 insertions, 2 deletions
diff --git a/Zend/tests/zend_signed_multiply-64bit-2.phpt b/Zend/tests/zend_signed_multiply-64bit-2.phpt
new file mode 100644
index 0000000000..f0a3bafa5e
--- /dev/null
+++ b/Zend/tests/zend_signed_multiply-64bit-2.phpt
@@ -0,0 +1,149 @@
+--TEST--
+Zend signed multiply 64-bit, variation 2
+--SKIPIF--
+<?php if ((1 << 31) < 0) print "skip Running on 32-bit target"; ?>
+--FILE--
+<?php
+for($c = -16; $c < 0; $c++) {
+ var_dump($c, intdiv(PHP_INT_MIN, 10), intdiv(PHP_INT_MIN, 10) * $c);
+ echo "-----------\n";
+}
+for($c = 0; $c <= 16; $c++) {
+ var_dump($c, intdiv(PHP_INT_MAX, 10), intdiv(PHP_INT_MAX, 10) * $c);
+ echo "-----------\n";
+}
+?>
+--EXPECTF--
+int(-16)
+int(-922337203685477580)
+float(1.4757395258968E+19)
+-----------
+int(-15)
+int(-922337203685477580)
+float(1.3835058055282E+19)
+-----------
+int(-14)
+int(-922337203685477580)
+float(1.2912720851597E+19)
+-----------
+int(-13)
+int(-922337203685477580)
+float(1.1990383647911E+19)
+-----------
+int(-12)
+int(-922337203685477580)
+float(1.1068046444226E+19)
+-----------
+int(-11)
+int(-922337203685477580)
+float(1.014570924054E+19)
+-----------
+int(-10)
+int(-922337203685477580)
+int(9223372036854775800)
+-----------
+int(-9)
+int(-922337203685477580)
+int(8301034833169298220)
+-----------
+int(-8)
+int(-922337203685477580)
+int(7378697629483820640)
+-----------
+int(-7)
+int(-922337203685477580)
+int(6456360425798343060)
+-----------
+int(-6)
+int(-922337203685477580)
+int(5534023222112865480)
+-----------
+int(-5)
+int(-922337203685477580)
+int(4611686018427387900)
+-----------
+int(-4)
+int(-922337203685477580)
+int(3689348814741910320)
+-----------
+int(-3)
+int(-922337203685477580)
+int(2767011611056432740)
+-----------
+int(-2)
+int(-922337203685477580)
+int(1844674407370955160)
+-----------
+int(-1)
+int(-922337203685477580)
+int(922337203685477580)
+-----------
+int(0)
+int(922337203685477580)
+int(0)
+-----------
+int(1)
+int(922337203685477580)
+int(922337203685477580)
+-----------
+int(2)
+int(922337203685477580)
+int(1844674407370955160)
+-----------
+int(3)
+int(922337203685477580)
+int(2767011611056432740)
+-----------
+int(4)
+int(922337203685477580)
+int(3689348814741910320)
+-----------
+int(5)
+int(922337203685477580)
+int(4611686018427387900)
+-----------
+int(6)
+int(922337203685477580)
+int(5534023222112865480)
+-----------
+int(7)
+int(922337203685477580)
+int(6456360425798343060)
+-----------
+int(8)
+int(922337203685477580)
+int(7378697629483820640)
+-----------
+int(9)
+int(922337203685477580)
+int(8301034833169298220)
+-----------
+int(10)
+int(922337203685477580)
+int(9223372036854775800)
+-----------
+int(11)
+int(922337203685477580)
+float(1.014570924054E+19)
+-----------
+int(12)
+int(922337203685477580)
+float(1.1068046444226E+19)
+-----------
+int(13)
+int(922337203685477580)
+float(1.1990383647911E+19)
+-----------
+int(14)
+int(922337203685477580)
+float(1.2912720851597E+19)
+-----------
+int(15)
+int(922337203685477580)
+float(1.3835058055282E+19)
+-----------
+int(16)
+int(922337203685477580)
+float(1.4757395258968E+19)
+-----------
+
diff --git a/Zend/tests/zend_signed_multiply-64bit.phpt b/Zend/tests/zend_signed_multiply-64bit.phpt
index 94a6e035fa..d392b2e78a 100644
--- a/Zend/tests/zend_signed_multiply-64bit.phpt
+++ b/Zend/tests/zend_signed_multiply-64bit.phpt
@@ -1,5 +1,5 @@
--TEST--
-Zend signed multiply 64-bit
+Zend signed multiply 64-bit, variation 1
--SKIPIF--
<?php if ((1 << 31) < 0) print "skip Running on 32-bit target"; ?>
--FILE--
diff --git a/Zend/zend_multiply.h b/Zend/zend_multiply.h
index 9790c1faa3..7a600f8296 100644
--- a/Zend/zend_multiply.h
+++ b/Zend/zend_multiply.h
@@ -83,7 +83,20 @@
#elif defined(ZEND_WIN32)
-#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do { \
+# ifdef _M_X64
+# define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do { \
+ __int64 __high; \
+ __int64 __low = _mul128((a), (b), &__high); \
+ if ((__low >> 63i64) == __high) { \
+ (usedval) = 0; \
+ (lval) = __low; \
+ } else { \
+ (usedval) = 1; \
+ (dval) = (double)(a) * (double)(b); \
+ } \
+} while (0)
+# else
+# define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do { \
zend_long __lres = (a) * (b); \
long double __dres = (long double)(a) * (long double)(b); \
long double __delta = (long double) __lres - __dres; \
@@ -93,6 +106,7 @@
(lval) = __lres; \
} \
} while (0)
+# endif
#elif defined(__powerpc64__) && defined(__GNUC__)