[libcxx-commits] [libcxx] a6db20f - [libcxx] Use generic builtins for popcount, clz and ctz (#86563)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Apr 11 05:15:20 PDT 2024
Author: Marc Auberer
Date: 2024-04-11T14:15:16+02:00
New Revision: a6db20f2c39ecb5939890317068d5398c760746d
URL: https://github.com/llvm/llvm-project/commit/a6db20f2c39ecb5939890317068d5398c760746d
DIFF: https://github.com/llvm/llvm-project/commit/a6db20f2c39ecb5939890317068d5398c760746d.diff
LOG: [libcxx] Use generic builtins for popcount, clz and ctz (#86563)
Fixes #86556
Use `__builtin_popcountg` instead of `__buildin_popcount{l|ll}`
Use `__builtin_clzg instead` of `__buildin_clz{l|ll}`
Use `__builtin_ctzg instead` of `__builtin_ctz{l|ll}`
The generic variant of the builtins can be used to simplify some logic
with >= Clang 19 or >= GCC 14, where these generic variants are
available. As for backwards compatibility reasons, we can't completely
remove the old logic. Therefore, I left ToDo comments to address this,
as soon as support for pre Clang 19 as well as pre GCC 14 is dropped.
---------
Co-authored-by: Nick Desaulniers <nickdesaulniers at users.noreply.github.com>
Added:
Modified:
libcxx/include/__bit/countl.h
libcxx/include/__bit/countr.h
libcxx/include/__bit/popcount.h
Removed:
################################################################################
diff --git a/libcxx/include/__bit/countl.h b/libcxx/include/__bit/countl.h
index 396cfc2c3f4064..13df8d4e66c402 100644
--- a/libcxx/include/__bit/countl.h
+++ b/libcxx/include/__bit/countl.h
@@ -6,6 +6,9 @@
//
//===----------------------------------------------------------------------===//
+// TODO: __builtin_clzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can
+// refactor this code to exclusively use __builtin_clzg.
+
#ifndef _LIBCPP___BIT_COUNTL_H
#define _LIBCPP___BIT_COUNTL_H
@@ -38,6 +41,9 @@ _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_cl
#ifndef _LIBCPP_HAS_NO_INT128
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(__uint128_t __x) _NOEXCEPT {
+# if __has_builtin(__builtin_clzg)
+ return __builtin_clzg(__x);
+# else
// The function is written in this form due to C++ constexpr limitations.
// The algorithm:
// - Test whether any bit in the high 64-bits is set
@@ -49,12 +55,16 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(__uint128_t __x)
// zeros in the high 64-bits.
return ((__x >> 64) == 0) ? (64 + __builtin_clzll(static_cast<unsigned long long>(__x)))
: __builtin_clzll(static_cast<unsigned long long>(__x >> 64));
+# endif
}
#endif // _LIBCPP_HAS_NO_INT128
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countl_zero(_Tp __t) _NOEXCEPT {
static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__countl_zero requires an unsigned integer type");
+#if __has_builtin(__builtin_clzg)
+ return __builtin_clzg(__t, numeric_limits<_Tp>::digits);
+#else // __has_builtin(__builtin_clzg)
if (__t == 0)
return numeric_limits<_Tp>::digits;
@@ -79,6 +89,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countl_zero(_Tp __t) _
}
return __ret + __iter;
}
+#endif // __has_builtin(__builtin_clzg)
}
#if _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__bit/countr.h b/libcxx/include/__bit/countr.h
index b6b3ac52ca4e47..724a0bc23801c4 100644
--- a/libcxx/include/__bit/countr.h
+++ b/libcxx/include/__bit/countr.h
@@ -6,6 +6,9 @@
//
//===----------------------------------------------------------------------===//
+// TODO: __builtin_ctzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can
+// refactor this code to exclusively use __builtin_ctzg.
+
#ifndef _LIBCPP___BIT_COUNTR_H
#define _LIBCPP___BIT_COUNTR_H
@@ -37,9 +40,11 @@ _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ct
template <class _Tp>
_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero(_Tp __t) _NOEXCEPT {
+#if __has_builtin(__builtin_ctzg)
+ return __builtin_ctzg(__t, numeric_limits<_Tp>::digits);
+#else // __has_builtin(__builtin_ctzg)
if (__t == 0)
return numeric_limits<_Tp>::digits;
-
if (sizeof(_Tp) <= sizeof(unsigned int))
return std::__libcpp_ctz(static_cast<unsigned int>(__t));
else if (sizeof(_Tp) <= sizeof(unsigned long))
@@ -55,6 +60,7 @@ _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __coun
}
return __ret + std::__libcpp_ctz(static_cast<unsigned long long>(__t));
}
+#endif // __has_builtin(__builtin_ctzg)
}
#if _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/__bit/popcount.h b/libcxx/include/__bit/popcount.h
index b0319cef251894..37b3a3e1f3f2b9 100644
--- a/libcxx/include/__bit/popcount.h
+++ b/libcxx/include/__bit/popcount.h
@@ -6,6 +6,9 @@
//
//===----------------------------------------------------------------------===//
+// TODO: __builtin_popcountg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can
+// refactor this code to exclusively use __builtin_popcountg.
+
#ifndef _LIBCPP___BIT_POPCOUNT_H
#define _LIBCPP___BIT_POPCOUNT_H
@@ -39,6 +42,9 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned lo
template <__libcpp_unsigned_integer _Tp>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr int popcount(_Tp __t) noexcept {
+# if __has_builtin(__builtin_popcountg)
+ return __builtin_popcountg(__t);
+# else // __has_builtin(__builtin_popcountg)
if (sizeof(_Tp) <= sizeof(unsigned int))
return std::__libcpp_popcount(static_cast<unsigned int>(__t));
else if (sizeof(_Tp) <= sizeof(unsigned long))
@@ -53,6 +59,7 @@ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr int popcount(_Tp __t) noex
}
return __ret;
}
+# endif // __has_builtin(__builtin_popcountg)
}
#endif // _LIBCPP_STD_VER >= 20
More information about the libcxx-commits
mailing list