File indexing completed on 2026-11-07 10:36:57
0001
0002
0003
0004
0005 #ifndef XSIMD_BIT_HPP
0006 #define XSIMD_BIT_HPP
0007
0008 #include "../../config/xsimd_config.hpp"
0009
0010 #if XSIMD_CPP_VERSION > 202002L
0011
0012 #include <version>
0013
0014 #if __cpp_lib_bitops >= 201907L
0015
0016 #include <bit>
0017
0018 namespace xsimd
0019 {
0020 namespace detail
0021 {
0022 using std::countl_one;
0023 using std::countl_zero;
0024 using std::countr_one;
0025 using std::countr_zero;
0026 using std::popcount;
0027 }
0028 }
0029
0030 #endif
0031
0032 #else
0033
0034 #include <climits>
0035 #include <type_traits>
0036
0037 #ifdef __has_builtin
0038 #define XSIMD_HAS_BUILTIN(x) __has_builtin(x)
0039 #else
0040 #define XSIMD_HAS_BUILTIN(x) 0
0041 #endif
0042
0043 #ifdef _MSC_VER
0044 #include <intrin.h>
0045 #endif
0046
0047 namespace xsimd
0048 {
0049 namespace detail
0050 {
0051
0052
0053
0054 template <class T, class = std::enable_if_t<std::is_unsigned<T>::value>>
0055 XSIMD_INLINE int popcount(T x) noexcept
0056 {
0057 #if XSIMD_HAS_BUILTIN(__builtin_popcountg)
0058 return __builtin_popcountg(x);
0059 #else
0060 XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
0061 {
0062 #if XSIMD_HAS_BUILTIN(__builtin_popcount)
0063 return __builtin_popcount(x);
0064 #elif defined(_MSC_VER)
0065 return __popcnt(x);
0066 #else
0067
0068 return ((uint64_t)x * 0x200040008001ULL & 0x111111111111111ULL) % 0xf;
0069 #endif
0070 }
0071 else XSIMD_IF_CONSTEXPR(sizeof(T) == 2)
0072 {
0073 #if XSIMD_HAS_BUILTIN(__builtin_popcount)
0074 return __builtin_popcount(x);
0075 #elif defined(_MSC_VER)
0076 return __popcnt16(x);
0077 #else
0078
0079 constexpr unsigned long long msb12 = 0x1001001001001ULL;
0080 constexpr unsigned long long mask5 = 0x84210842108421ULL;
0081
0082 unsigned int v = (unsigned int)x;
0083
0084 return ((v & 0xfff) * msb12 & mask5) % 0x1f
0085 + (((v & 0xfff000) >> 12) * msb12 & mask5) % 0x1f;
0086 #endif
0087 }
0088 else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
0089 {
0090 #if XSIMD_HAS_BUILTIN(__builtin_popcount)
0091 return __builtin_popcount(x);
0092 #elif defined(_MSC_VER)
0093 return __popcnt(x);
0094 #else
0095
0096 x = x - ((x >> 1) & (T) ~(T)0 / 3);
0097 x = (x & (T) ~(T)0 / 15 * 3) + ((x >> 2) & (T) ~(T)0 / 15 * 3);
0098 x = (x + (x >> 4)) & (T) ~(T)0 / 255 * 15;
0099 return (x * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * CHAR_BIT;
0100 #endif
0101 }
0102 else
0103 {
0104
0105 #if XSIMD_HAS_BUILTIN(__builtin_popcountll)
0106 return __builtin_popcountll(x);
0107 #elif XSIMD_HAS_BUILTIN(__builtin_popcount)
0108 return __builtin_popcount((unsigned int)x) + __builtin_popcount((unsigned int)(x >> 32));
0109 #elif defined(_MSC_VER)
0110 #ifdef _M_X64
0111 return (int)__popcnt64(x);
0112 #else
0113 return (int)(__popcnt((unsigned int)x) + __popcnt((unsigned int)(x >> 32)));
0114 #endif
0115 #else
0116
0117 x = x - ((x >> 1) & (T) ~(T)0 / 3);
0118 x = (x & (T) ~(T)0 / 15 * 3) + ((x >> 2) & (T) ~(T)0 / 15 * 3);
0119 x = (x + (x >> 4)) & (T) ~(T)0 / 255 * 15;
0120 return (x * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * CHAR_BIT;
0121 #endif
0122 }
0123 #endif
0124 }
0125
0126 template <class T, class = std::enable_if_t<std::is_unsigned<T>::value>>
0127 XSIMD_INLINE int countl_zero(T x) noexcept
0128 {
0129 #if XSIMD_HAS_BUILTIN(__builtin_clzg)
0130 return __builtin_clzg(x, (int)(sizeof(T) * CHAR_BIT));
0131 #else
0132 if (x == 0)
0133 return sizeof(T) * CHAR_BIT;
0134
0135 XSIMD_IF_CONSTEXPR(sizeof(T) <= 4)
0136 {
0137 #if XSIMD_HAS_BUILTIN(__builtin_clz)
0138 return __builtin_clz((unsigned int)x) - (4 - sizeof(T)) * CHAR_BIT;
0139 #elif defined(_MSC_VER)
0140 unsigned long index;
0141 _BitScanReverse(&index, (unsigned long)x);
0142 return sizeof(T) * CHAR_BIT - index - 1;
0143 #else
0144 x |= x >> 1;
0145 x |= x >> 2;
0146 x |= x >> 4;
0147 XSIMD_IF_CONSTEXPR(sizeof(T) >= 2)
0148 {
0149 x |= x >> 8;
0150 }
0151 XSIMD_IF_CONSTEXPR(sizeof(T) >= 4)
0152 {
0153 x |= x >> 16;
0154 }
0155 return sizeof(T) * CHAR_BIT - popcount(x);
0156 #endif
0157 }
0158 else
0159 {
0160
0161 #if XSIMD_HAS_BUILTIN(__builtin_clzll)
0162 return __builtin_clzll((unsigned long long)x);
0163 #elif defined(_MSC_VER) && defined(_M_X64)
0164 unsigned long index;
0165 _BitScanReverse64(&index, (unsigned long long)x);
0166 return sizeof(T) * CHAR_BIT - index - 1;
0167 #else
0168 x |= x >> 1;
0169 x |= x >> 2;
0170 x |= x >> 4;
0171 x |= x >> 8;
0172 x |= x >> 16;
0173 x |= x >> 32;
0174 return sizeof(T) * CHAR_BIT - popcount(x);
0175 #endif
0176 }
0177 #endif
0178 }
0179
0180 template <class T, class = std::enable_if_t<std::is_unsigned<T>::value>>
0181 XSIMD_INLINE int countl_one(T x) noexcept
0182 {
0183 return countl_zero(T(~x));
0184 }
0185
0186 template <class T, class = std::enable_if_t<std::is_unsigned<T>::value>>
0187 XSIMD_INLINE int countr_zero(T x) noexcept
0188 {
0189 #if XSIMD_HAS_BUILTIN(__builtin_ctzg)
0190 return __builtin_ctzg(x, (int)(sizeof(T) * CHAR_BIT));
0191 #else
0192 if (x == 0)
0193 return sizeof(T) * CHAR_BIT;
0194
0195 XSIMD_IF_CONSTEXPR(sizeof(T) <= 4)
0196 {
0197 #if XSIMD_HAS_BUILTIN(__builtin_ctz)
0198 return __builtin_ctz((unsigned int)x);
0199 #elif defined(_MSC_VER)
0200 unsigned long index;
0201 _BitScanForward(&index, (unsigned long)x);
0202 return index;
0203 #endif
0204 }
0205 else
0206 {
0207
0208 #if XSIMD_HAS_BUILTIN(__builtin_ctzll)
0209 return __builtin_ctzll((unsigned long long)x);
0210 #elif defined(_MSC_VER) && defined(_M_X64)
0211 unsigned long index;
0212 _BitScanForward64(&index, (unsigned long long)x);
0213 return index;
0214 #endif
0215 }
0216
0217
0218 return popcount((T)((x & -x) - 1));
0219 #endif
0220 }
0221
0222 template <class T, class = std::enable_if_t<std::is_unsigned<T>::value>>
0223 XSIMD_INLINE int countr_one(T x) noexcept
0224 {
0225 return countr_zero(T(~x));
0226 }
0227
0228 }
0229 }
0230
0231 #endif
0232 #endif