From 79a84e00fad27bab2a4ca7a58ace1f68cc88be5c Mon Sep 17 00:00:00 2001 From: Sebastian Pop Date: Tue, 23 Apr 2019 20:18:39 +0000 Subject: [PATCH] speed up increment and decrement operators with overflow detection 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 | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 869f575efa0..1effdd6c674 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -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))) {