]> granicus.if.org Git - php/commitdiff
decbin/decoct/dechex optimization.
authorDmitry Stogov <dmitry@zend.com>
Tue, 8 Sep 2020 07:34:29 +0000 (10:34 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 8 Sep 2020 07:34:29 +0000 (10:34 +0300)
Zend/zend_bitset.h
build/php.m4
configure.ac
ext/standard/math.c

index 9e196713f06fe093b2511f3a868138aabf685923..b7c369c74979b839f5f873de5360c91fc13a0c1a 100644 (file)
@@ -75,6 +75,46 @@ static zend_always_inline int zend_ulong_ntz(zend_ulong num)
 #endif
 }
 
+/* Number of leading zero bits (Undefined for zero) */
+static zend_always_inline int zend_ulong_nlz(zend_ulong num)
+{
+#if (defined(__GNUC__) || __has_builtin(__builtin_clzl)) \
+       && SIZEOF_ZEND_LONG == SIZEOF_LONG && defined(PHP_HAVE_BUILTIN_CLZL)
+       return __builtin_clzl(num);
+#elif (defined(__GNUC__) || __has_builtin(__builtin_clzll)) && defined(PHP_HAVE_BUILTIN_CLZLL)
+       return __builtin_clzll(num);
+#elif defined(_WIN32)
+       unsigned long index;
+
+#if defined(_WIN64)
+       if (!BitScanReverse64(&index, num)) {
+#else
+       if (!BitScanReverse(&index, num)) {
+#endif
+               /* undefined behavior */
+               return SIZEOF_ZEND_LONG * 8;
+       }
+
+       return (int) (SIZEOF_ZEND_LONG * 8 - 1)- index;
+#else
+       zend_ulong x;
+       int n;
+
+#if SIZEOF_ZEND_LONG == 8
+       n = 64;
+       x = num >> 32; if (x != 0) {n -= 32; num = x;}
+#else
+       n = 32;
+#endif
+       x = num >> 16; if (x != 0) {n -= 16; num = x;}
+       x = num >> 8;  if (x != 0) {n -=  8; num = x;}
+       x = num >> 4;  if (x != 0) {n -=  4; num = x;}
+       x = num >> 2;  if (x != 0) {n -=  2; num = x;}
+       x = num >> 1;  if (x != 0) return n - 2;
+       return n - num;
+#endif
+}
+
 /* Returns the number of zend_ulong words needed to store a bitset that is N
    bits long.  */
 static inline uint32_t zend_bitset_len(uint32_t n)
index da1007ff4eaa36c71d4a14d49bcac6507dcd79f4..b0e3c424d18e41faa64fb1201cdeaaea0a847f0d 100644 (file)
@@ -2448,6 +2448,44 @@ AC_DEFUN([PHP_CHECK_BUILTIN_CLZ], [
   AC_DEFINE_UNQUOTED([PHP_HAVE_BUILTIN_CLZ], [$have_builtin_clz], [Whether the compiler supports __builtin_clz])
 ])
 
+dnl
+dnl PHP_CHECK_BUILTIN_CLZL
+dnl
+AC_DEFUN([PHP_CHECK_BUILTIN_CLZL], [
+  AC_MSG_CHECKING([for __builtin_clzl])
+
+  AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[
+    return __builtin_clzl(1) ? 1 : 0;
+  ]])], [
+    have_builtin_clzl=1
+    AC_MSG_RESULT([yes])
+  ], [
+    have_builtin_clzl=0
+    AC_MSG_RESULT([no])
+  ])
+
+  AC_DEFINE_UNQUOTED([PHP_HAVE_BUILTIN_CLZL], [$have_builtin_clzl], [Whether the compiler supports __builtin_clzl])
+])
+
+dnl
+dnl PHP_CHECK_BUILTIN_CLZLL
+dnl
+AC_DEFUN([PHP_CHECK_BUILTIN_CLZLL], [
+  AC_MSG_CHECKING([for __builtin_clzll])
+
+  AC_LINK_IFELSE([AC_LANG_PROGRAM([], [[
+    return __builtin_clzll(1) ? 1 : 0;
+  ]])], [
+    have_builtin_clzll=1
+    AC_MSG_RESULT([yes])
+  ], [
+    have_builtin_clzll=0
+    AC_MSG_RESULT([no])
+  ])
+
+  AC_DEFINE_UNQUOTED([PHP_HAVE_BUILTIN_CLZLL], [$have_builtin_clzll], [Whether the compiler supports __builtin_clzll])
+])
+
 dnl
 dnl PHP_CHECK_BUILTIN_CTZL
 dnl
index 3ff9a91bf9fb5c3fa015b6af07d766d08a98d7b1..f82783a03b04e96f6d1e98d82cc1e4d50b941efa 100644 (file)
@@ -465,6 +465,10 @@ dnl Check __builtin_expect
 PHP_CHECK_BUILTIN_EXPECT
 dnl Check __builtin_clz
 PHP_CHECK_BUILTIN_CLZ
+dnl Check __builtin_clzl
+PHP_CHECK_BUILTIN_CLZL
+dnl Check __builtin_clzll
+PHP_CHECK_BUILTIN_CLZLL
 dnl Check __builtin_ctzl
 PHP_CHECK_BUILTIN_CTZL
 dnl Check __builtin_ctzll
index 2aedcc259d2cc8a11b315592f1bc520d714af893..4f723be365dfac592048e79096889a1efc732076 100644 (file)
@@ -22,6 +22,7 @@
 #include "zend_multiply.h"
 #include "zend_exceptions.h"
 #include "zend_portability.h"
+#include "zend_bitset.h"
 
 #include <math.h>
 #include <float.h>
@@ -821,6 +822,41 @@ PHPAPI zend_string * _php_math_longtobase(zend_long arg, int base)
 }
 /* }}} */
 
+/* {{{ _php_math_longtobase_pwr2 */
+/*
+ * Convert a long to a string containing a base(2,4,6,16,32) representation of
+ * the number.
+ */
+static zend_always_inline zend_string * _php_math_longtobase_pwr2(zend_long arg, int base_log2)
+{
+       static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+       zend_ulong value;
+       size_t len;
+       zend_string *ret;
+       char *ptr;
+
+       value = arg;
+
+       if (value == 0) {
+               len = 1;
+       } else {
+               len = ((sizeof(value) * 8 - zend_ulong_nlz(value)) + (base_log2 - 1)) / base_log2;
+       }
+
+       ret = zend_string_alloc(len, 0);
+       ptr = ZSTR_VAL(ret) + len;
+       *ptr = '\0';
+
+       do {
+               ZEND_ASSERT(ptr > ZSTR_VAL(ret));
+               *--ptr = digits[value & ((1 << base_log2) - 1)];
+               value >>= base_log2;
+       } while (value);
+
+       return ret;
+}
+/* }}} */
+
 /* {{{ _php_math_zvaltobase */
 /*
  * Convert a zval to a string containing a base(2-36) representation of
@@ -908,7 +944,7 @@ PHP_FUNCTION(decbin)
                Z_PARAM_LONG(arg)
        ZEND_PARSE_PARAMETERS_END();
 
-       RETURN_STR(_php_math_longtobase(arg, 2));
+       RETURN_STR(_php_math_longtobase_pwr2(arg, 1));
 }
 /* }}} */
 
@@ -921,7 +957,7 @@ PHP_FUNCTION(decoct)
                Z_PARAM_LONG(arg)
        ZEND_PARSE_PARAMETERS_END();
 
-       RETURN_STR(_php_math_longtobase(arg, 8));
+       RETURN_STR(_php_math_longtobase_pwr2(arg, 3));
 }
 /* }}} */
 
@@ -934,7 +970,7 @@ PHP_FUNCTION(dechex)
                Z_PARAM_LONG(arg)
        ZEND_PARSE_PARAMETERS_END();
 
-       RETURN_STR(_php_math_longtobase(arg, 16));
+       RETURN_STR(_php_math_longtobase_pwr2(arg, 4));
 }
 /* }}} */