summaryrefslogtreecommitdiff
path: root/Zend/zend_operators.h
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2017-11-28 12:37:00 +0300
committerDmitry Stogov <dmitry@zend.com>2017-11-28 12:37:00 +0300
commit6acfade8a1084202229929ecb54c01f9ef1059d2 (patch)
tree04500851930e025c1b8921afe8c773efb05db5c7 /Zend/zend_operators.h
parent4a2ccd908be193fdc34a91306febb7153cc461eb (diff)
downloadphp-git-6acfade8a1084202229929ecb54c01f9ef1059d2.tar.gz
Prefer "GNU asm goto" to __builtin_saddl_overflow() for overflow detection. This allows generation of significantly better code.
Diffstat (limited to 'Zend/zend_operators.h')
-rw-r--r--Zend/zend_operators.h258
1 files changed, 108 insertions, 150 deletions
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
index 366fa1ed5e..44ef072862 100644
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@ -464,7 +464,29 @@ ZEND_API void zend_update_current_locale(void);
static zend_always_inline void fast_long_increment_function(zval *op1)
{
-#if PHP_HAVE_BUILTIN_SADDL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
+#if defined(__GNUC__) && defined(__i386__)
+ __asm__ goto(
+ "incl (%0)\n\t"
+ "jo %l1\n"
+ :
+ : "r"(&op1->value)
+ : "cc", "memory"
+ : overflow);
+ return;
+overflow: ZEND_ATTRIBUTE_COLD_LABEL
+ ZVAL_DOUBLE(op1, (double)ZEND_LONG_MAX + 1.0);
+#elif defined(__GNUC__) && defined(__x86_64__)
+ __asm__ goto(
+ "incq (%0)\n\t"
+ "jo %l1\n"
+ :
+ : "r"(&op1->value)
+ : "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))) {
/* switch to double */
@@ -480,32 +502,6 @@ static zend_always_inline void fast_long_increment_function(zval *op1)
} else {
Z_LVAL_P(op1) = llresult;
}
-#elif defined(__GNUC__) && defined(__i386__)
- __asm__(
- "incl (%0)\n\t"
- "jno 0f\n\t"
- "movl $0x0, (%0)\n\t"
- "movl $0x41e00000, 0x4(%0)\n\t"
- "movl %1, %c2(%0)\n"
- "0:"
- :
- : "r"(&op1->value),
- "n"(IS_DOUBLE),
- "n"(ZVAL_OFFSETOF_TYPE)
- : "cc", "memory");
-#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"
- "movl %1, %c2(%0)\n"
- "0:"
- :
- : "r"(&op1->value),
- "n"(IS_DOUBLE),
- "n"(ZVAL_OFFSETOF_TYPE)
- : "cc", "memory");
#else
if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MAX)) {
/* switch to double */
@@ -518,7 +514,29 @@ static zend_always_inline void fast_long_increment_function(zval *op1)
static zend_always_inline void fast_long_decrement_function(zval *op1)
{
-#if PHP_HAVE_BUILTIN_SSUBL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
+#if defined(__GNUC__) && defined(__i386__)
+ __asm__ goto(
+ "decl (%0)\n\t"
+ "jo %l1\n"
+ :
+ : "r"(&op1->value)
+ : "cc", "memory"
+ : overflow);
+ return;
+overflow: ZEND_ATTRIBUTE_COLD_LABEL
+ ZVAL_DOUBLE(op1, (double)ZEND_LONG_MIN - 1.0);
+#elif defined(__GNUC__) && defined(__x86_64__)
+ __asm__ goto(
+ "decq (%0)\n\t"
+ "jo %l1\n"
+ :
+ : "r"(&op1->value)
+ : "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))) {
/* switch to double */
@@ -534,32 +552,6 @@ static zend_always_inline void fast_long_decrement_function(zval *op1)
} else {
Z_LVAL_P(op1) = llresult;
}
-#elif defined(__GNUC__) && defined(__i386__)
- __asm__(
- "decl (%0)\n\t"
- "jno 0f\n\t"
- "movl $0x00200000, (%0)\n\t"
- "movl $0xc1e00000, 0x4(%0)\n\t"
- "movl %1,%c2(%0)\n"
- "0:"
- :
- : "r"(&op1->value),
- "n"(IS_DOUBLE),
- "n"(ZVAL_OFFSETOF_TYPE)
- : "cc", "memory");
-#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"
- "movl %1,%c2(%0)\n"
- "0:"
- :
- : "r"(&op1->value),
- "n"(IS_DOUBLE),
- "n"(ZVAL_OFFSETOF_TYPE)
- : "cc", "memory");
#else
if (UNEXPECTED(Z_LVAL_P(op1) == ZEND_LONG_MIN)) {
/* switch to double */
@@ -572,69 +564,56 @@ static zend_always_inline void fast_long_decrement_function(zval *op1)
static zend_always_inline void fast_long_add_function(zval *result, zval *op1, zval *op2)
{
-#if PHP_HAVE_BUILTIN_SADDL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
- long lresult;
- if (UNEXPECTED(__builtin_saddl_overflow(Z_LVAL_P(op1), Z_LVAL_P(op2), &lresult))) {
- ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
- } else {
- ZVAL_LONG(result, lresult);
- }
-#elif PHP_HAVE_BUILTIN_SADDLL_OVERFLOW && SIZEOF_LONG_LONG == SIZEOF_ZEND_LONG
- long long llresult;
- if (UNEXPECTED(__builtin_saddll_overflow(Z_LVAL_P(op1), Z_LVAL_P(op2), &llresult))) {
- ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
- } else {
- ZVAL_LONG(result, llresult);
- }
-#elif defined(__GNUC__) && defined(__i386__) \
- && !(4 == __GNUC__ && 8 == __GNUC_MINOR__) \
- && !(4 == __GNUC__ && 9 == __GNUC_MINOR__ && (defined(__PIC__) || defined(__PIE__)))
- /* Position-independent builds fail with gcc-4.9.x */
- __asm__(
+#if defined(__GNUC__) && defined(__i386__)
+ __asm__ goto(
"movl (%1), %%eax\n\t"
"addl (%2), %%eax\n\t"
- "jo 0f\n\t"
+ "jo %l5\n\t"
"movl %%eax, (%0)\n\t"
- "movl %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"
- "movl %4, %c5(%0)\n\t"
- "fstpl (%0)\n"
- "1:"
+ "movl %3, %c4(%0)\n"
:
: "r"(&result->value),
"r"(&op1->value),
"r"(&op2->value),
"n"(IS_LONG),
- "n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
- : "eax","cc", "memory");
+ : "eax","cc", "memory"
+ : overflow);
+ return;
+overflow: ZEND_ATTRIBUTE_COLD_LABEL
+ ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
#elif defined(__GNUC__) && defined(__x86_64__)
- __asm__(
+ __asm__ goto(
"movq (%1), %%rax\n\t"
"addq (%2), %%rax\n\t"
- "jo 0f\n\t"
+ "jo %l5\n\t"
"movq %%rax, (%0)\n\t"
- "movl %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"
- "movl %4, %c5(%0)\n\t"
- "fstpl (%0)\n"
- "1:"
+ "movl %3, %c4(%0)\n"
:
: "r"(&result->value),
"r"(&op1->value),
"r"(&op2->value),
"n"(IS_LONG),
- "n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
- : "rax","cc", "memory");
+ : "rax","cc", "memory"
+ : overflow);
+ return;
+overflow: ZEND_ATTRIBUTE_COLD_LABEL
+ ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
+#elif PHP_HAVE_BUILTIN_SADDL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
+ long lresult;
+ if (UNEXPECTED(__builtin_saddl_overflow(Z_LVAL_P(op1), Z_LVAL_P(op2), &lresult))) {
+ ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
+ } else {
+ ZVAL_LONG(result, lresult);
+ }
+#elif PHP_HAVE_BUILTIN_SADDLL_OVERFLOW && SIZEOF_LONG_LONG == SIZEOF_ZEND_LONG
+ long long llresult;
+ if (UNEXPECTED(__builtin_saddll_overflow(Z_LVAL_P(op1), Z_LVAL_P(op2), &llresult))) {
+ ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
+ } else {
+ ZVAL_LONG(result, llresult);
+ }
#else
/*
* 'result' may alias with op1 or op2, so we need to
@@ -675,77 +654,56 @@ static zend_always_inline int fast_add_function(zval *result, zval *op1, zval *o
static zend_always_inline void fast_long_sub_function(zval *result, zval *op1, zval *op2)
{
-#if PHP_HAVE_BUILTIN_SSUBL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
- long lresult;
- if (UNEXPECTED(__builtin_ssubl_overflow(Z_LVAL_P(op1), Z_LVAL_P(op2), &lresult))) {
- ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
- } else {
- ZVAL_LONG(result, lresult);
- }
-#elif PHP_HAVE_BUILTIN_SSUBLL_OVERFLOW && SIZEOF_LONG_LONG == SIZEOF_ZEND_LONG
- long long llresult;
- if (UNEXPECTED(__builtin_ssubll_overflow(Z_LVAL_P(op1), Z_LVAL_P(op2), &llresult))) {
- ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
- } else {
- ZVAL_LONG(result, llresult);
- }
-#elif defined(__GNUC__) && defined(__i386__) && \
- !(4 == __GNUC__ && 8 == __GNUC_MINOR__) && \
- !(4 == __GNUC__ && 9 == __GNUC_MINOR__ && (defined(__PIC__) || defined(__PIE__)))
- /* Position-independent builds fail with gcc-4.9.x */
- __asm__(
+#if defined(__GNUC__) && defined(__i386__)
+ __asm__ goto(
"movl (%1), %%eax\n\t"
"subl (%2), %%eax\n\t"
- "jo 0f\n\t"
+ "jo %l5\n\t"
"movl %%eax, (%0)\n\t"
- "movl %3, %c5(%0)\n\t"
- "jmp 1f\n"
- "0:\n\t"
- "fildl (%2)\n\t"
- "fildl (%1)\n\t"
-#if defined(__clang__) && (__clang_major__ < 2 || (__clang_major__ == 2 && __clang_minor__ < 10))
- "fsubp %%st(1), %%st\n\t" /* LLVM bug #9164 */
-#else
- "fsubp %%st, %%st(1)\n\t"
-#endif
- "movl %4, %c5(%0)\n\t"
- "fstpl (%0)\n"
- "1:"
+ "movl %3, %c4(%0)\n"
:
: "r"(&result->value),
"r"(&op1->value),
"r"(&op2->value),
"n"(IS_LONG),
- "n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
- : "eax","cc", "memory");
+ : "eax","cc", "memory"
+ : overflow);
+ return;
+overflow: ZEND_ATTRIBUTE_COLD_LABEL
+ ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
#elif defined(__GNUC__) && defined(__x86_64__)
- __asm__(
+ __asm__ goto(
"movq (%1), %%rax\n\t"
"subq (%2), %%rax\n\t"
- "jo 0f\n\t"
+ "jo %l5\n\t"
"movq %%rax, (%0)\n\t"
- "movl %3, %c5(%0)\n\t"
- "jmp 1f\n"
- "0:\n\t"
- "fildq (%2)\n\t"
- "fildq (%1)\n\t"
-#if defined(__clang__) && (__clang_major__ < 2 || (__clang_major__ == 2 && __clang_minor__ < 10))
- "fsubp %%st(1), %%st\n\t" /* LLVM bug #9164 */
-#else
- "fsubp %%st, %%st(1)\n\t"
-#endif
- "movl %4, %c5(%0)\n\t"
- "fstpl (%0)\n"
- "1:"
+ "movl %3, %c4(%0)\n"
:
: "r"(&result->value),
"r"(&op1->value),
"r"(&op2->value),
"n"(IS_LONG),
- "n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
- : "rax","cc", "memory");
+ : "rax","cc", "memory"
+ : overflow);
+ return;
+overflow: ZEND_ATTRIBUTE_COLD_LABEL
+ ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
+#elif PHP_HAVE_BUILTIN_SSUBL_OVERFLOW && SIZEOF_LONG == SIZEOF_ZEND_LONG
+ long lresult;
+ if (UNEXPECTED(__builtin_ssubl_overflow(Z_LVAL_P(op1), Z_LVAL_P(op2), &lresult))) {
+ ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
+ } else {
+ ZVAL_LONG(result, lresult);
+ }
+#elif PHP_HAVE_BUILTIN_SSUBLL_OVERFLOW && SIZEOF_LONG_LONG == SIZEOF_ZEND_LONG
+ long long llresult;
+ if (UNEXPECTED(__builtin_ssubll_overflow(Z_LVAL_P(op1), Z_LVAL_P(op2), &llresult))) {
+ ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2));
+ } else {
+ ZVAL_LONG(result, llresult);
+ }
#else
ZVAL_LONG(result, Z_LVAL_P(op1) - Z_LVAL_P(op2));