/* number of trailing set (1) bits */
static zend_always_inline int zend_mm_bitset_nts(zend_mm_bitset bitset)
{
-#if defined(__GNUC__)
-# if SIZEOF_ZEND_LONG == SIZEOF_LONG
+#if (defined(__GNUC__) || __has_builtin(__builtin_ctzl)) && SIZEOF_ZEND_LONG == SIZEOF_LONG
return __builtin_ctzl(~bitset);
-# else
+#elif defined(__GNUC__) || __has_builtin(__builtin_ctzll)
return __builtin_ctzll(~bitset);
-# endif
#elif defined(_WIN32)
unsigned long index;
/* number of trailing zero bits (0x01 -> 1; 0x40 -> 6; 0x00 -> LEN) */
static zend_always_inline int zend_mm_bitset_ntz(zend_mm_bitset bitset)
{
-#if defined(__GNUC__)
-# if SIZEOF_ZEND_LONG == SIZEOF_LONG
+#if (defined(__GNUC__) || __has_builtin(__builtin_ctzl)) && SIZEOF_ZEND_LONG == SIZEOF_LONG
return __builtin_ctzl(bitset);
-# else
+#elif defined(__GNUC__) || __has_builtin(__builtin_ctzll)
return __builtin_ctzll(bitset);
-# endif
#elif defined(_WIN32)
unsigned long index;
/* higher set bit number (0->N/A, 1->1, 2->2, 4->3, 8->4, 127->7, 128->8 etc) */
static zend_always_inline int zend_mm_small_size_to_bit(int size)
{
-#if defined(__GNUC__)
+#if defined(__GNUC__) || __has_builtin(__builtin_clz)
return (__builtin_clz(size) ^ 0x1f) + 1;
#elif defined(_WIN32)
unsigned long index;
# define ZEND_GCC_VERSION 0
#endif
+/* Compatibility with non-clang compilers */
+#ifndef __has_attribute
+# define __has_attribute(x) 0
+#endif
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+
#if defined(ZEND_WIN32)
# define ZEND_ASSUME(c) __assume(c)
-#elif defined(__GNUC__) && PHP_HAVE_BUILTIN_EXPECT && ZEND_GCC_VERSION >= 4005
+#elif ((defined(__GNUC__) && ZEND_GCC_VERSION >= 4005) || __has_builtin(__builtin_unreachable)) && PHP_HAVE_BUILTIN_EXPECT
# define ZEND_ASSUME(c) do { \
if (__builtin_expect(!(c), 0)) __builtin_unreachable(); \
} while (0)
# endif
#endif
-/* Compatibility with non-clang compilers */
-#ifndef __has_attribute
-# define __has_attribute(x) 0
-#endif
-
#if ZEND_GCC_VERSION >= 2096
# define ZEND_ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
#else