]> granicus.if.org Git - php/commitdiff
Improve performance of PowerPC64 ZEND_SIGNED_MULTIPLY_LONG
authorAnton Blanchard <anton@samba.org>
Tue, 26 May 2015 12:42:13 +0000 (22:42 +1000)
committerRemi Collet <remi@php.net>
Tue, 28 Jul 2015 16:38:23 +0000 (18:38 +0200)
Detecting overflow with the XER is slow, partially because we have to
clear it before use. We can do better by using a trick where we compare
the high 64 bits of the result with the low 64 bits shifted right
63 bits.

This is 7% faster on a POWER8 running a simple testcase:

<?php
        function testcase($count = 100000000) {
                for ($i = 0; $i < $count; $i++) {
                        $x = 1;
                        $x = $x * 2;
                        $x = $x * 2;
                        $x = $x * 2;
                        $x = $x * 2;
                }
        }

        testcase();
?>

Zend/zend_multiply.h

index b12c1e23b30e9d26d28581bdfe63fbe7b8cbba96..fc053d0e3583e21dfa93e4b1a299dea5d6cf51f3 100644 (file)
 
 #elif defined(__powerpc64__) && defined(__GNUC__)
 
-#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do {  \
-   long __tmpvar;                          \
-   __asm__("li 14, 0\n\t"                          \
-       "mtxer 14\n\t"                                          \
-       "mulldo. %0, %2,%3\n\t"                 \
-       "xor %1, %1, %1\n\t"                    \
-       "bns+ 0f\n\t"                       \
-        "li %1, 1\n\t"                     \
-        "0:\n"                         \
-           : "=r"(__tmpvar),"=r"(usedval)          \
-           : "r"(a), "r"(b)                \
-           : "r14", "cc");                 \
-   if (usedval) (dval) = (double) (a) * (double) (b);      \
-   else (lval) = __tmpvar;                     \
+#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do {      \
+       long __low, __high;                                             \
+       __asm__("mulld %0,%2,%3\n\t"                                    \
+               "mulhd %1,%2,%3\n"                                      \
+               : "=&r"(__low), "=&r"(__high)                           \
+               : "r"(a), "r"(b));                                      \
+       if ((__low >> 63) != __high) {                                  \
+               (dval) = (double) (a) * (double) (b);                   \
+               (usedval) = 1;                                          \
+       } else {                                                        \
+               (lval) = __low;                                         \
+               (usedval) = 0;                                          \
+       }                                                               \
 } while (0)
 
 #elif SIZEOF_ZEND_LONG == 4