On 02/04/2013 01:50 PM, Dmitry Stogov wrote:
I can't remember if I did any special benchmarks except for bench.php when
I introduced fast math functions.
That time, I rearranged the code to allow inlining of the most probable
paths and added assembler code to catch overflow (C can't do it in optimal
way). As I remember the bench.php showed some visible improvement.


OK, in that case I would still recommend using fewer hardcoded numbers and offsets: please refer to the applied patch, it makes things a bit more robust.

However, as I don't expect any speedup for ARM in this area, I will not pursue this any further.

Are there any other optimizations involving inline assembler that you implemented for PHP? I would like to review them to see if I need to add an ARM version.

Cheers,

Ard.


>From 16f61b05b3911c91b52c5eff66c2274d5a7c817f Mon Sep 17 00:00:00 2001
From: Ard Biesheuvel <ard.biesheu...@linaro.org>
Date: Mon, 4 Feb 2013 17:56:11 +0100
Subject: [PATCH] Remove hardcoded constants and struct offsets from asm
 arithmetic

---
 Zend/zend_operators.h |   80 ++++++++++++++++++++++++++++++++-----------------
 1 file changed, 52 insertions(+), 28 deletions(-)

diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
index 20a5277..b51a000 100644
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@ -476,6 +476,10 @@ ZEND_API void zend_update_current_locale(void);
 #define zend_update_current_locale()
 #endif
 
+/* The offset in bytes between the value and type fields of a zval */
+#define ZVAL_OFFSETOF_TYPE	\
+	(__builtin_offsetof(zval,type) - __builtin_offsetof(zval,value))
+
 static zend_always_inline int fast_increment_function(zval *op1)
 {
 	if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
@@ -485,20 +489,24 @@ static zend_always_inline int fast_increment_function(zval *op1)
 			"jno  0f\n\t"
 			"movl $0x0, (%0)\n\t"
 			"movl $0x41e00000, 0x4(%0)\n\t"
-			"movb $0x2,0xc(%0)\n"
+			"movb %1, %c2(%0)\n"
 			"0:"
 			:
-			: "r"(op1));
+			: "r"(&op1->value),
+			  "n"(IS_DOUBLE),
+			  "n"(ZVAL_OFFSETOF_TYPE));
 #elif defined(__GNUC__) && defined(__x86_64__)
 		__asm__(
 			"incq (%0)\n\t"
 			"jno  0f\n\t"
 			"movl $0x0, (%0)\n\t"
 			"movl $0x43e00000, 0x4(%0)\n\t"
-			"movb $0x2,0x14(%0)\n"
+			"movb %1, %c2(%0)\n"
 			"0:"
 			:
-			: "r"(op1));
+			: "r"(&op1->value),
+			  "n"(IS_DOUBLE),
+			  "n"(ZVAL_OFFSETOF_TYPE));
 #else
 		if (UNEXPECTED(Z_LVAL_P(op1) == LONG_MAX)) {
 			/* switch to double */
@@ -522,20 +530,24 @@ static zend_always_inline int fast_decrement_function(zval *op1)
 			"jno  0f\n\t"
 			"movl $0x00200000, (%0)\n\t"
 			"movl $0xc1e00000, 0x4(%0)\n\t"
-			"movb $0x2,0xc(%0)\n"
+			"movb %1,%c2(%0)\n"
 			"0:"
 			:
-			: "r"(op1));
+			: "r"(&op1->value),
+			  "n"(IS_DOUBLE),
+			  "n"(ZVAL_OFFSETOF_TYPE));
 #elif defined(__GNUC__) && defined(__x86_64__)
 		__asm__(
 			"decq (%0)\n\t"
 			"jno  0f\n\t"
 			"movl $0x00000000, (%0)\n\t"
 			"movl $0xc3e00000, 0x4(%0)\n\t"
-			"movb $0x2,0x14(%0)\n"
+			"movb %1,%c2(%0)\n"
 			"0:"
 			:
-			: "r"(op1));
+			: "r"(&op1->value),
+			  "n"(IS_DOUBLE),
+			  "n"(ZVAL_OFFSETOF_TYPE));
 #else
 		if (UNEXPECTED(Z_LVAL_P(op1) == LONG_MIN)) {
 			/* switch to double */
@@ -560,19 +572,22 @@ static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *o
 			"addl   (%2), %%eax\n\t"
 			"jo     0f\n\t"     
 			"movl   %%eax, (%0)\n\t"
-			"movb   $0x1,0xc(%0)\n\t"
+			"movb   %3, %c5(%0)\n\t"
 			"jmp    1f\n"
 			"0:\n\t"
 			"fildl	(%1)\n\t"
 			"fildl	(%2)\n\t"
 			"faddp	%%st, %%st(1)\n\t"
-			"movb   $0x2,0xc(%0)\n\t"
+			"movb   %4, %c5(%0)\n\t"
 			"fstpl	(%0)\n"
 			"1:"
 			: 
-			: "r"(result),
-			  "r"(op1),
-			  "r"(op2)
+			: "r"(&result->value),
+			  "r"(&op1->value),
+			  "r"(&op2->value),
+			  "n"(IS_LONG),
+			  "n"(IS_DOUBLE),
+			  "n"(ZVAL_OFFSETOF_TYPE)
 			: "eax");
 #elif defined(__GNUC__) && defined(__x86_64__)
 		__asm__(
@@ -580,19 +595,22 @@ static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *o
 			"addq   (%2), %%rax\n\t"
 			"jo     0f\n\t"     
 			"movq   %%rax, (%0)\n\t"
-			"movb   $0x1,0x14(%0)\n\t"
+			"movb   %3, %c5(%0)\n\t"
 			"jmp    1f\n"
 			"0:\n\t"
 			"fildq	(%1)\n\t"
 			"fildq	(%2)\n\t"
 			"faddp	%%st, %%st(1)\n\t"
-			"movb   $0x2,0x14(%0)\n\t"
+			"movb   %4, %c5(%0)\n\t"
 			"fstpl	(%0)\n"
 			"1:"
 			: 
-			: "r"(result),
-			  "r"(op1),
-			  "r"(op2)
+			: "r"(&result->value),
+			  "r"(&op1->value),
+			  "r"(&op2->value),
+			  "n"(IS_LONG),
+			  "n"(IS_DOUBLE),
+			  "n"(ZVAL_OFFSETOF_TYPE)
 			: "rax");
 #else
 			Z_LVAL_P(result) = Z_LVAL_P(op1) + Z_LVAL_P(op2);
@@ -635,7 +653,7 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o
 			"subl   (%2), %%eax\n\t"
 			"jo     0f\n\t"     
 			"movl   %%eax, (%0)\n\t"
-			"movb   $0x1,0xc(%0)\n\t"
+			"movb   %3, %c5(%0)\n\t"
 			"jmp    1f\n"
 			"0:\n\t"
 			"fildl	(%2)\n\t"
@@ -645,13 +663,16 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o
 #else
 			"fsubp	%%st, %%st(1)\n\t"
 #endif
-			"movb   $0x2,0xc(%0)\n\t"
+			"movb   %4, %c5(%0)\n\t"
 			"fstpl	(%0)\n"
 			"1:"
 			: 
-			: "r"(result),
-			  "r"(op1),
-			  "r"(op2)
+			: "r"(&result->value),
+			  "r"(&op1->value),
+			  "r"(&op2->value),
+			  "n"(IS_LONG),
+			  "n"(IS_DOUBLE),
+			  "n"(ZVAL_OFFSETOF_TYPE)
 			: "eax");
 #elif defined(__GNUC__) && defined(__x86_64__)
 		__asm__(
@@ -659,7 +680,7 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o
 			"subq   (%2), %%rax\n\t"
 			"jo     0f\n\t"     
 			"movq   %%rax, (%0)\n\t"
-			"movb   $0x1,0x14(%0)\n\t"
+			"movb   %3, %c5(%0)\n\t"
 			"jmp    1f\n"
 			"0:\n\t"
 			"fildq	(%2)\n\t"
@@ -669,13 +690,16 @@ static zend_always_inline int fast_sub_function(zval *result, zval *op1, zval *o
 #else
 			"fsubp	%%st, %%st(1)\n\t"
 #endif
-			"movb   $0x2,0x14(%0)\n\t"
+			"movb   %4, %c5(%0)\n\t"
 			"fstpl	(%0)\n"
 			"1:"
 			: 
-			: "r"(result),
-			  "r"(op1),
-			  "r"(op2)
+			: "r"(&result->value),
+			  "r"(&op1->value),
+			  "r"(&op2->value),
+			  "n"(IS_LONG),
+			  "n"(IS_DOUBLE),
+			  "n"(ZVAL_OFFSETOF_TYPE)
 			: "rax");
 #else
 			Z_LVAL_P(result) = Z_LVAL_P(op1) - Z_LVAL_P(op2);
-- 
1.7.10.4


-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to