//===-- llvm/ADT/bit.h - C++20 ----------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// This file implements the C++20 header. /// //===----------------------------------------------------------------------===// #ifndef LLVM_ADT_BIT_H #define LLVM_ADT_BIT_H #include "llvm/Support/Compiler.h" #include #include #include #if !__has_builtin(__builtin_bit_cast) #include #endif #if defined(_MSC_VER) && !defined(_DEBUG) #include // for _byteswap_{ushort,ulong,uint64} #endif #ifdef _MSC_VER // Declare these intrinsics manually rather including intrin.h. It's very // expensive, and bit.h is popular via MathExtras.h. // #include extern "C" { unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask); unsigned char _BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask); unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask); unsigned char _BitScanReverse64(unsigned long *_Index, unsigned __int64 _Mask); } #endif namespace llvm { // This implementation of bit_cast is different from the C++20 one in two ways: // - It isn't constexpr because that requires compiler support. // - It requires trivially-constructible To, to avoid UB in the implementation. template < typename To, typename From, typename = std::enable_if_t, typename = std::enable_if_t::value>, typename = std::enable_if_t::value>, typename = std::enable_if_t::value>> [[nodiscard]] inline To bit_cast(const From &from) noexcept { #if __has_builtin(__builtin_bit_cast) return __builtin_bit_cast(To, from); #else To to; std::memcpy(&to, &from, sizeof(To)); return to; #endif } /// Reverses the bytes in the given integer value V. template >> [[nodiscard]] constexpr T byteswap(T V) noexcept { if constexpr (sizeof(T) == 1) { return V; } else if constexpr (sizeof(T) == 2) { uint16_t UV = V; #if defined(_MSC_VER) && !defined(_DEBUG) // The DLL version of the runtime lacks these functions (bug!?), but in a // release build they're replaced with BSWAP instructions anyway. return _byteswap_ushort(UV); #else uint16_t Hi = UV << 8; uint16_t Lo = UV >> 8; return Hi | Lo; #endif } else if constexpr (sizeof(T) == 4) { uint32_t UV = V; #if __has_builtin(__builtin_bswap32) return __builtin_bswap32(UV); #elif defined(_MSC_VER) && !defined(_DEBUG) return _byteswap_ulong(UV); #else uint32_t Byte0 = UV & 0x000000FF; uint32_t Byte1 = UV & 0x0000FF00; uint32_t Byte2 = UV & 0x00FF0000; uint32_t Byte3 = UV & 0xFF000000; return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24); #endif } else if constexpr (sizeof(T) == 8) { uint64_t UV = V; #if __has_builtin(__builtin_bswap64) return __builtin_bswap64(UV); #elif defined(_MSC_VER) && !defined(_DEBUG) return _byteswap_uint64(UV); #else uint64_t Hi = llvm::byteswap(UV); uint32_t Lo = llvm::byteswap(UV >> 32); return (Hi << 32) | Lo; #endif } else { static_assert(!sizeof(T *), "Don't know how to handle the given type."); return 0; } } template >> [[nodiscard]] constexpr inline bool has_single_bit(T Value) noexcept { return (Value != 0) && ((Value & (Value - 1)) == 0); } namespace detail { template struct TrailingZerosCounter { static unsigned count(T Val) { if (!Val) return std::numeric_limits::digits; if (Val & 0x1) return 0; // Bisection method. unsigned ZeroBits = 0; T Shift = std::numeric_limits::digits >> 1; T Mask = std::numeric_limits::max() >> Shift; while (Shift) { if ((Val & Mask) == 0) { Val >>= Shift; ZeroBits |= Shift; } Shift >>= 1; Mask >>= Shift; } return ZeroBits; } }; #if defined(__GNUC__) || defined(_MSC_VER) template struct TrailingZerosCounter { static unsigned count(T Val) { if (Val == 0) return 32; #if __has_builtin(__builtin_ctz) || defined(__GNUC__) return __builtin_ctz(Val); #elif defined(_MSC_VER) unsigned long Index; _BitScanForward(&Index, Val); return Index; #endif } }; #if !defined(_MSC_VER) || defined(_M_X64) template struct TrailingZerosCounter { static unsigned count(T Val) { if (Val == 0) return 64; #if __has_builtin(__builtin_ctzll) || defined(__GNUC__) return __builtin_ctzll(Val); #elif defined(_MSC_VER) unsigned long Index; _BitScanForward64(&Index, Val); return Index; #endif } }; #endif #endif } // namespace detail /// Count number of 0's from the least significant bit to the most /// stopping at the first 1. /// /// Only unsigned integral types are allowed. /// /// Returns std::numeric_limits::digits on an input of 0. template [[nodiscard]] int countr_zero(T Val) { static_assert(std::is_unsigned_v, "Only unsigned integral types are allowed."); return llvm::detail::TrailingZerosCounter::count(Val); } namespace detail { template struct LeadingZerosCounter { static unsigned count(T Val) { if (!Val) return std::numeric_limits::digits; // Bisection method. unsigned ZeroBits = 0; for (T Shift = std::numeric_limits::digits >> 1; Shift; Shift >>= 1) { T Tmp = Val >> Shift; if (Tmp) Val = Tmp; else ZeroBits |= Shift; } return ZeroBits; } }; #if defined(__GNUC__) || defined(_MSC_VER) template struct LeadingZerosCounter { static unsigned count(T Val) { if (Val == 0) return 32; #if __has_builtin(__builtin_clz) || defined(__GNUC__) return __builtin_clz(Val); #elif defined(_MSC_VER) unsigned long Index; _BitScanReverse(&Index, Val); return Index ^ 31; #endif } }; #if !defined(_MSC_VER) || defined(_M_X64) template struct LeadingZerosCounter { static unsigned count(T Val) { if (Val == 0) return 64; #if __has_builtin(__builtin_clzll) || defined(__GNUC__) return __builtin_clzll(Val); #elif defined(_MSC_VER) unsigned long Index; _BitScanReverse64(&Index, Val); return Index ^ 63; #endif } }; #endif #endif } // namespace detail /// Count number of 0's from the most significant bit to the least /// stopping at the first 1. /// /// Only unsigned integral types are allowed. /// /// Returns std::numeric_limits::digits on an input of 0. template [[nodiscard]] int countl_zero(T Val) { static_assert(std::is_unsigned_v, "Only unsigned integral types are allowed."); return llvm::detail::LeadingZerosCounter::count(Val); } /// Count the number of ones from the most significant bit to the first /// zero bit. /// /// Ex. countl_one(0xFF0FFF00) == 8. /// Only unsigned integral types are allowed. /// /// Returns std::numeric_limits::digits on an input of all ones. template [[nodiscard]] int countl_one(T Value) { static_assert(std::is_unsigned_v, "Only unsigned integral types are allowed."); return llvm::countl_zero(~Value); } /// Count the number of ones from the least significant bit to the first /// zero bit. /// /// Ex. countr_one(0x00FF00FF) == 8. /// Only unsigned integral types are allowed. /// /// Returns std::numeric_limits::digits on an input of all ones. template [[nodiscard]] int countr_one(T Value) { static_assert(std::is_unsigned_v, "Only unsigned integral types are allowed."); return llvm::countr_zero(~Value); } /// Returns the number of bits needed to represent Value if Value is nonzero. /// Returns 0 otherwise. /// /// Ex. bit_width(5) == 3. template [[nodiscard]] int bit_width(T Value) { static_assert(std::is_unsigned_v, "Only unsigned integral types are allowed."); return std::numeric_limits::digits - llvm::countl_zero(Value); } /// Returns the largest integral power of two no greater than Value if Value is /// nonzero. Returns 0 otherwise. /// /// Ex. bit_floor(5) == 4. template [[nodiscard]] T bit_floor(T Value) { static_assert(std::is_unsigned_v, "Only unsigned integral types are allowed."); if (!Value) return 0; return T(1) << (llvm::bit_width(Value) - 1); } /// Returns the smallest integral power of two no smaller than Value if Value is /// nonzero. Returns 0 otherwise. /// /// Ex. bit_ceil(5) == 8. /// /// The return value is undefined if the input is larger than the largest power /// of two representable in T. template [[nodiscard]] T bit_ceil(T Value) { static_assert(std::is_unsigned_v, "Only unsigned integral types are allowed."); if (Value < 2) return 1; return T(1) << llvm::bit_width(Value - 1u); } namespace detail { template struct PopulationCounter { static int count(T Value) { // Generic version, forward to 32 bits. static_assert(SizeOfT <= 4, "Not implemented!"); #if defined(__GNUC__) return (int)__builtin_popcount(Value); #else uint32_t v = Value; v = v - ((v >> 1) & 0x55555555); v = (v & 0x33333333) + ((v >> 2) & 0x33333333); return int(((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24); #endif } }; template struct PopulationCounter { static int count(T Value) { #if defined(__GNUC__) return (int)__builtin_popcountll(Value); #else uint64_t v = Value; v = v - ((v >> 1) & 0x5555555555555555ULL); v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL); v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL; return int((uint64_t)(v * 0x0101010101010101ULL) >> 56); #endif } }; } // namespace detail /// Count the number of set bits in a value. /// Ex. popcount(0xF000F000) = 8 /// Returns 0 if the word is zero. template >> [[nodiscard]] inline int popcount(T Value) noexcept { return detail::PopulationCounter::count(Value); } } // namespace llvm #endif