]> granicus.if.org Git - php/commitdiff
Prefer "GNU asm goto" to __builtin_saddl_overflow() for overflow detection. This...
authorDmitry Stogov <dmitry@zend.com>
Tue, 28 Nov 2017 09:37:00 +0000 (12:37 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 28 Nov 2017 09:37:00 +0000 (12:37 +0300)
Zend/zend_operators.h
Zend/zend_portability.h

index 366fa1ed5ea3a728e2bfa55463993139e9f9f5da..44ef072862a5331aebb79f4adbbccc7dacdf020a 100644 (file)
@@ -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));
 
index 0b5e8fa0a7362599fda00ae07d09aeb2de8a8fb2..2003734f0cd764cbd9ff5b9a091988c18e61b217 100644 (file)
@@ -220,11 +220,15 @@ char *alloca();
 #if defined(__GNUC__) && ZEND_GCC_VERSION >= 4003
 # define ZEND_ATTRIBUTE_UNUSED __attribute__((unused))
 # define ZEND_ATTRIBUTE_UNUSED_LABEL __attribute__((cold, unused));
+# define ZEND_ATTRIBUTE_COLD_LABEL __attribute__((cold));
+# define ZEND_ATTRIBUTE_HOT_LABEL __attribute__((hot));
 # define ZEND_COLD __attribute__((cold))
 # define ZEND_HOT __attribute__((hot))
 #else
 # define ZEND_ATTRIBUTE_UNUSED
 # define ZEND_ATTRIBUTE_UNUSED_LABEL
+# define ZEND_ATTRIBUTE_COLD_LABEL
+# define ZEND_ATTRIBUTE_HOT_LABEL
 # define ZEND_COLD
 # define ZEND_HOT
 #endif