]> granicus.if.org Git - php/commitdiff
speed up increment and decrement operators with overflow detection
authorSebastian Pop <spop@amazon.com>
Tue, 23 Apr 2019 20:18:39 +0000 (20:18 +0000)
committerDmitry Stogov <dmitry@zend.com>
Tue, 7 May 2019 12:42:19 +0000 (15:42 +0300)
On A72, google-benchmark measure before and after the patch:
--------------------------------------------------------
Benchmark              Time             CPU   Iterations
--------------------------------------------------------
BM_inc_before       6.54 ns         6.54 ns    106985447
BM_dec_before       6.54 ns         6.54 ns    107011667
BM_inc_after        4.36 ns         4.36 ns    160525864
BM_dec_after        4.36 ns         4.36 ns    160524243

Before the patch:
fast_long_add_function:
ldr x0, [x1]
add x2, x0, 1
cmp x2, x0
blt .L11
str x2, [x1]
ret
.L11:
mov x0, 4890909195324358656
mov w2, 5
str x0, [x1]
str w2, [x1, 8]
ret

With the patch:
fast_long_add_function:
ldr x5, [x1]
adds x5,x5,1
bvs .L2
str x5, [x1]
ret
.L2:
mov x0, 4890909195324358656
mov w2, 5
str x0, [x1]
str w2, [x1, 8]
ret

    php$ ./sapi/cli/php Zend/bench.php

Base:                         Patch:
simple             0.091      simple             0.091
simplecall         0.014      simplecall         0.014
simpleucall        0.041      simpleucall        0.041
simpleudcall       0.045      simpleudcall       0.045
mandel             0.193      mandel             0.193
mandel2            0.229      mandel2            0.229
ackermann(7)       0.044      ackermann(7)       0.044
ary(50000)         0.010      ary(50000)         0.010
ary2(50000)        0.008      ary2(50000)        0.008
ary3(2000)         0.096      ary3(2000)         0.102
fibo(30)           0.149      fibo(30)           0.148
hash1(50000)       0.016      hash1(50000)       0.016
hash2(500)         0.020      hash2(500)         0.020
heapsort(20000)    0.055      heapsort(20000)    0.055
matrix(20)         0.057      matrix(20)         0.057
nestedloop(12)     0.091      nestedloop(12)     0.091
sieve(30)          0.032      sieve(30)          0.032
strcat(200000)     0.010      strcat(200000)     0.010
------------------------      ------------------------
Total              1.199      Total              1.204

    php$ ./sapi/cli/php Zend/micro_bench.php

Base:                                      Patch:
empty_loop         0.051                   empty_loop         0.050
func()             0.181    0.130          func()             0.181    0.131
undef_func()       0.186    0.135          undef_func()       0.186    0.136
int_func()         0.116    0.064          int_func()         0.116    0.065
$x = self::$x      0.235    0.183          $x = self::$x      0.229    0.179
self::$x = 0       0.198    0.147          self::$x = 0       0.199    0.148
isset(self::$x)    0.229    0.178          isset(self::$x)    0.225    0.174
empty(self::$x)    0.231    0.180          empty(self::$x)    0.227    0.177
$x = Foo::$x       0.144    0.093          $x = Foo::$x       0.142    0.092
Foo::$x = 0        0.107    0.056          Foo::$x = 0        0.105    0.054
isset(Foo::$x)     0.140    0.088          isset(Foo::$x)     0.140    0.089
empty(Foo::$x)     0.148    0.097          empty(Foo::$x)     0.144    0.094
self::f()          0.238    0.187          self::f()          0.240    0.190
Foo::f()           0.209    0.158          Foo::f()           0.201    0.150
$x = $this->x      0.123    0.072          $x = $this->x      0.120    0.070
$this->x = 0       0.124    0.073          $this->x = 0       0.124    0.074
$this->x += 2      0.151    0.099          $this->x += 2      0.151    0.101
++$this->x         0.137    0.086          ++$this->x         0.139    0.088
--$this->x         0.137    0.086          --$this->x         0.137    0.087
$this->x++         0.170    0.119          $this->x++         0.172    0.122
$this->x--         0.171    0.119          $this->x--         0.172    0.122
isset($this->x)    0.170    0.119          isset($this->x)    0.170    0.120
empty($this->x)    0.179    0.128          empty($this->x)    0.179    0.129
$this->f()         0.194    0.143          $this->f()         0.194    0.144
$x = Foo::TEST     0.188    0.137          $x = Foo::TEST     0.188    0.138
new Foo()          0.482    0.431          new Foo()          0.482    0.432
$x = TEST          0.109    0.058          $x = TEST          0.109    0.059
$x = $_GET         0.190    0.138          $x = $_GET         0.188    0.137
$x = $GLOBALS['v'] 0.242    0.191          $x = $GLOBALS['v'] 0.246    0.196
$x = $hash['v']    0.196    0.145          $x = $hash['v']    0.192    0.142
$x = $str[0]       0.146    0.094          $x = $str[0]       0.142    0.092
$x = $a ?: null    0.144    0.093          $x = $a ?: null    0.144    0.094
$x = $f ?: tmp     0.174    0.123          $x = $f ?: tmp     0.174    0.124
$x = $f ? $f : $a  0.153    0.101          $x = $f ? $f : $a  0.153    0.102
$x = $f ? $f : tmp 0.148    0.097          $x = $f ? $f : tmp 0.148    0.098
------------------------                   ------------------------
Total              6.143                   Total              6.108

Zend/zend_operators.h

index 869f575efa088a4d1d585a14255dce699be1df32..1effdd6c674be4f65c7b8f644078d2680074b2a9 100644 (file)
@@ -490,6 +490,19 @@ overflow: ZEND_ATTRIBUTE_COLD_LABEL
        return;
 overflow: ZEND_ATTRIBUTE_COLD_LABEL
        ZVAL_DOUBLE(op1, (double)ZEND_LONG_MAX + 1.0);
+#elif defined(HAVE_ASM_GOTO) && defined(__aarch64__)
+       __asm__ goto (
+               "ldr x5, [%0]\n\t"
+               "adds x5, x5, 1\n\t"
+               "bvs %l1\n"
+               "str x5, [%0]"
+               :
+               : "r"(&op1->value)
+               : "x5", "cc", "memory"
+               : overflow);
+       return;
+overflow: ZEND_ATTRIBUTE_COLD_LABEL
+       ZVAL_DOUBLE(op1, (double)ZEND_LONG_MAX + 1.0);
 #elif PHP_HAVE_BUILTIN_SADDL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
        long lresult;
        if (UNEXPECTED(__builtin_saddl_overflow(Z_LVAL_P(op1), 1, &lresult))) {
@@ -540,6 +553,19 @@ overflow: ZEND_ATTRIBUTE_COLD_LABEL
        return;
 overflow: ZEND_ATTRIBUTE_COLD_LABEL
        ZVAL_DOUBLE(op1, (double)ZEND_LONG_MIN - 1.0);
+#elif defined(HAVE_ASM_GOTO) && defined(__aarch64__)
+       __asm__ goto (
+               "ldr x5, [%0]\n\t"
+               "subs x5 ,x5, 1\n\t"
+               "bvs %l1\n"
+               "str x5, [%0]"
+               :
+               : "r"(&op1->value)
+               : "x5", "cc", "memory"
+               : overflow);
+       return;
+overflow: ZEND_ATTRIBUTE_COLD_LABEL
+       ZVAL_DOUBLE(op1, (double)ZEND_LONG_MIN - 1.0);
 #elif PHP_HAVE_BUILTIN_SSUBL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
        long lresult;
        if (UNEXPECTED(__builtin_ssubl_overflow(Z_LVAL_P(op1), 1, &lresult))) {