Codechange: introduce own std::byteswap implementation

This is only available from C++23, but the implementation is fairly trivial
and the old variants of BSWAP32/BSWAP16 were not constexpr on MSVC. This was
due to all kinds of intrinsics that were added to get better code. However,
recent compilers with reasonable optimisation settings see the naive code and
will inject the appropriate optimised code (bswap op on x86-64).

For x86-64 recent is: Clang 6+ -O1, GCC 6+ -O2, MSVC 19.34+ /O1.
This commit is contained in:
Rubidium 2025-01-27 22:55:16 +01:00 committed by rubidium42
parent 37a2d97c64
commit 2481f2e085

View File

@ -344,42 +344,23 @@ private:
Tbitset bitset;
};
#if defined(__APPLE__)
/* Make endian swapping use Apple's macros to increase speed
* (since it will use hardware swapping if available).
* Even though they should return uint16_t and uint32_t, we get
* warnings if we don't cast those (why?) */
# define BSWAP32(x) (static_cast<uint32_t>(CFSwapInt32(x)))
# define BSWAP16(x) (static_cast<uint16_t>(CFSwapInt16(x)))
#elif defined(_MSC_VER)
/* MSVC has intrinsics for swapping, resulting in faster code */
# define BSWAP32(x) (_byteswap_ulong(x))
# define BSWAP16(x) (_byteswap_ushort(x))
#else
namespace std {
/**
* Perform a 32 bits endianness bitswap on x.
* Custom implementation of std::byteswap; remove once we build with C++23.
* Perform an endianness bitswap on x.
* @param x the variable to bitswap
* @return the bitswapped value.
*/
static inline uint32_t BSWAP32(uint32_t x)
template <typename T>
[[nodiscard]] constexpr enable_if_t<is_integral_v<T>, T> byteswap(T x) noexcept
{
#if !defined(__ICC) && defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ >= 3))
/* GCC >= 4.3 provides a builtin, resulting in faster code */
return static_cast<uint32_t>(__builtin_bswap32(static_cast<int32_t>(x)));
#else
return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000);
#endif /* defined(__GNUC__) */
if constexpr (sizeof(T) == 1) return x;
if constexpr (sizeof(T) == 2) return (x >> 8) | (x << 8);
if constexpr (sizeof(T) == 4) return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000);
}
}
/**
* Perform a 16 bits endianness bitswap on x.
* @param x the variable to bitswap
* @return the bitswapped value.
*/
static inline uint16_t BSWAP16(uint16_t x)
{
return (x >> 8) | (x << 8);
}
#endif /* __APPLE__ */
constexpr uint32_t BSWAP32(uint32_t x) { return std::byteswap(x); }
constexpr uint16_t BSWAP16(uint16_t x) { return std::byteswap(x); }
#endif /* BITMATH_FUNC_HPP */