aboutsummaryrefslogtreecommitdiff
path: root/src/compat/endian.h
diff options
context:
space:
mode:
authorfanquake <fanquake@gmail.com>2024-03-01 11:18:11 -0500
committerfanquake <fanquake@gmail.com>2024-03-01 11:19:58 -0500
commit8da62a1041bfaf8ce4e40a4b31c7281cbe8bb916 (patch)
tree0a4f62b24ce0bc9241b1d6e275aabd20fabe1ee2 /src/compat/endian.h
parentae4165f7bc395ffdfc0ff46371d539d29c54dfce (diff)
parent86b7f28d6c507155a9d3a15487ee883989b88943 (diff)
downloadbitcoin-8da62a1041bfaf8ce4e40a4b31c7281cbe8bb916.tar.xz
Merge bitcoin/bitcoin#29263: serialization: c++20 endian/byteswap/clz modernization
86b7f28d6c507155a9d3a15487ee883989b88943 serialization: use internal endian conversion functions (Cory Fields) 432b18ca8d0654318a8d882b28b20af2cb2d2e5d serialization: detect byteswap builtins without autoconf tests (Cory Fields) 297367b3bb062c57142747719ac9bf2e12717ce9 crypto: replace CountBits with std::bit_width (Cory Fields) 52f9bba889fd9b50a0543fd9fedc389592cdc7e5 crypto: replace non-standard CLZ builtins with c++20's bit_width (Cory Fields) Pull request description: This replaces #28674, #29036, and #29057. Now ready for testing and review. Replaces platform-specific endian and byteswap functions. This is especially useful for kernel, as it means that our deep serialization code no longer requires bitcoin-config.h. I apologize for the size of the last commit, but it's hard to avoid making those changes at once. All platforms now use our internal functions rather than libc or platform-specific ones, with the exception of MSVC. Sadly, benchmarking showed that not all compilers are capable of detecting and optimizing byteswap functions, so compiler builtins are instead used where possible. However, they're now detected via macros rather than autoconf checks. This[ matches how libc++ implements std::byteswap for c++23](https://github.com/llvm/llvm-project/blob/main/libcxx/include/__bit/byteswap.h#L26). I suggest we move/rename `compat/endian.h`, but I left that out of this PR to avoid bikeshedding. #29057 pointed out some irregularities in benchmarks. After messing with various compilers and configs for a few weeks with these changes, I'm of the opinion that we can't win on every platform every time, so we should take the code that makes sense going forward. That said, if any real-world slowdowns are caused here, we should obviously investigate. ACKs for top commit: maflcko: ACK 86b7f28d6c507155a9d3a15487ee883989b88943 📘 fanquake: ACK 86b7f28d6c507155a9d3a15487ee883989b88943 - we can finish pruning out the __builtin_clz* checks/usage once the minisketch code has been updated. This is more good cleanup pre-CMake & for the kernal. Tree-SHA512: 715a32ec190c70505ffbce70bfe81fc7b6aa33e376b60292e801f60cf17025aabfcab4e8c53ebb2e28ffc5cf4c20b74fe3dd8548371ad772085c13aec8b7970e
Diffstat (limited to 'src/compat/endian.h')
-rw-r--r--src/compat/endian.h241
1 files changed, 37 insertions, 204 deletions
diff --git a/src/compat/endian.h b/src/compat/endian.h
index 882de2dbf0..4f58428153 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -5,237 +5,70 @@
#ifndef BITCOIN_COMPAT_ENDIAN_H
#define BITCOIN_COMPAT_ENDIAN_H
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
#include <compat/byteswap.h>
+#include <bit>
#include <cstdint>
-#if defined(HAVE_ENDIAN_H)
-#include <endian.h>
-#elif defined(HAVE_SYS_ENDIAN_H)
-#include <sys/endian.h>
-#endif
-
-#ifndef HAVE_CONFIG_H
-// While not technically a supported configuration, defaulting to defining these
-// DECLs when we were compiled without autotools makes it easier for other build
-// systems to build things like libbitcoinconsensus for strange targets.
-#ifdef htobe16
-#define HAVE_DECL_HTOBE16 1
-#endif
-#ifdef htole16
-#define HAVE_DECL_HTOLE16 1
-#endif
-#ifdef be16toh
-#define HAVE_DECL_BE16TOH 1
-#endif
-#ifdef le16toh
-#define HAVE_DECL_LE16TOH 1
-#endif
-
-#ifdef htobe32
-#define HAVE_DECL_HTOBE32 1
-#endif
-#ifdef htole32
-#define HAVE_DECL_HTOLE32 1
-#endif
-#ifdef be32toh
-#define HAVE_DECL_BE32TOH 1
-#endif
-#ifdef le32toh
-#define HAVE_DECL_LE32TOH 1
-#endif
-
-#ifdef htobe64
-#define HAVE_DECL_HTOBE64 1
-#endif
-#ifdef htole64
-#define HAVE_DECL_HTOLE64 1
-#endif
-#ifdef be64toh
-#define HAVE_DECL_BE64TOH 1
-#endif
-#ifdef le64toh
-#define HAVE_DECL_LE64TOH 1
-#endif
-
-#endif // HAVE_CONFIG_H
-
-#if defined(WORDS_BIGENDIAN)
-
-#if HAVE_DECL_HTOBE16 == 0
-inline uint16_t htobe16(uint16_t host_16bits)
-{
- return host_16bits;
-}
-#endif // HAVE_DECL_HTOBE16
-
-#if HAVE_DECL_HTOLE16 == 0
-inline uint16_t htole16(uint16_t host_16bits)
-{
- return bswap_16(host_16bits);
-}
-#endif // HAVE_DECL_HTOLE16
-
-#if HAVE_DECL_BE16TOH == 0
-inline uint16_t be16toh(uint16_t big_endian_16bits)
-{
- return big_endian_16bits;
-}
-#endif // HAVE_DECL_BE16TOH
-
-#if HAVE_DECL_LE16TOH == 0
-inline uint16_t le16toh(uint16_t little_endian_16bits)
-{
- return bswap_16(little_endian_16bits);
-}
-#endif // HAVE_DECL_LE16TOH
-
-#if HAVE_DECL_HTOBE32 == 0
-inline uint32_t htobe32(uint32_t host_32bits)
-{
- return host_32bits;
-}
-#endif // HAVE_DECL_HTOBE32
-
-#if HAVE_DECL_HTOLE32 == 0
-inline uint32_t htole32(uint32_t host_32bits)
-{
- return bswap_32(host_32bits);
-}
-#endif // HAVE_DECL_HTOLE32
-
-#if HAVE_DECL_BE32TOH == 0
-inline uint32_t be32toh(uint32_t big_endian_32bits)
-{
- return big_endian_32bits;
-}
-#endif // HAVE_DECL_BE32TOH
-
-#if HAVE_DECL_LE32TOH == 0
-inline uint32_t le32toh(uint32_t little_endian_32bits)
+inline BSWAP_CONSTEXPR uint16_t htobe16_internal(uint16_t host_16bits)
{
- return bswap_32(little_endian_32bits);
+ if constexpr (std::endian::native == std::endian::little) return internal_bswap_16(host_16bits);
+ else return host_16bits;
}
-#endif // HAVE_DECL_LE32TOH
-
-#if HAVE_DECL_HTOBE64 == 0
-inline uint64_t htobe64(uint64_t host_64bits)
-{
- return host_64bits;
-}
-#endif // HAVE_DECL_HTOBE64
-
-#if HAVE_DECL_HTOLE64 == 0
-inline uint64_t htole64(uint64_t host_64bits)
-{
- return bswap_64(host_64bits);
-}
-#endif // HAVE_DECL_HTOLE64
-
-#if HAVE_DECL_BE64TOH == 0
-inline uint64_t be64toh(uint64_t big_endian_64bits)
-{
- return big_endian_64bits;
-}
-#endif // HAVE_DECL_BE64TOH
-
-#if HAVE_DECL_LE64TOH == 0
-inline uint64_t le64toh(uint64_t little_endian_64bits)
-{
- return bswap_64(little_endian_64bits);
-}
-#endif // HAVE_DECL_LE64TOH
-
-#else // WORDS_BIGENDIAN
-
-#if HAVE_DECL_HTOBE16 == 0
-inline uint16_t htobe16(uint16_t host_16bits)
+inline BSWAP_CONSTEXPR uint16_t htole16_internal(uint16_t host_16bits)
{
- return bswap_16(host_16bits);
+ if constexpr (std::endian::native == std::endian::big) return internal_bswap_16(host_16bits);
+ else return host_16bits;
}
-#endif // HAVE_DECL_HTOBE16
-
-#if HAVE_DECL_HTOLE16 == 0
-inline uint16_t htole16(uint16_t host_16bits)
+inline BSWAP_CONSTEXPR uint16_t be16toh_internal(uint16_t big_endian_16bits)
{
- return host_16bits;
+ if constexpr (std::endian::native == std::endian::little) return internal_bswap_16(big_endian_16bits);
+ else return big_endian_16bits;
}
-#endif // HAVE_DECL_HTOLE16
-
-#if HAVE_DECL_BE16TOH == 0
-inline uint16_t be16toh(uint16_t big_endian_16bits)
+inline BSWAP_CONSTEXPR uint16_t le16toh_internal(uint16_t little_endian_16bits)
{
- return bswap_16(big_endian_16bits);
+ if constexpr (std::endian::native == std::endian::big) return internal_bswap_16(little_endian_16bits);
+ else return little_endian_16bits;
}
-#endif // HAVE_DECL_BE16TOH
-
-#if HAVE_DECL_LE16TOH == 0
-inline uint16_t le16toh(uint16_t little_endian_16bits)
+inline BSWAP_CONSTEXPR uint32_t htobe32_internal(uint32_t host_32bits)
{
- return little_endian_16bits;
+ if constexpr (std::endian::native == std::endian::little) return internal_bswap_32(host_32bits);
+ else return host_32bits;
}
-#endif // HAVE_DECL_LE16TOH
-
-#if HAVE_DECL_HTOBE32 == 0
-inline uint32_t htobe32(uint32_t host_32bits)
-{
- return bswap_32(host_32bits);
-}
-#endif // HAVE_DECL_HTOBE32
-
-#if HAVE_DECL_HTOLE32 == 0
-inline uint32_t htole32(uint32_t host_32bits)
+inline BSWAP_CONSTEXPR uint32_t htole32_internal(uint32_t host_32bits)
{
- return host_32bits;
+ if constexpr (std::endian::native == std::endian::big) return internal_bswap_32(host_32bits);
+ else return host_32bits;
}
-#endif // HAVE_DECL_HTOLE32
-
-#if HAVE_DECL_BE32TOH == 0
-inline uint32_t be32toh(uint32_t big_endian_32bits)
+inline BSWAP_CONSTEXPR uint32_t be32toh_internal(uint32_t big_endian_32bits)
{
- return bswap_32(big_endian_32bits);
+ if constexpr (std::endian::native == std::endian::little) return internal_bswap_32(big_endian_32bits);
+ else return big_endian_32bits;
}
-#endif // HAVE_DECL_BE32TOH
-
-#if HAVE_DECL_LE32TOH == 0
-inline uint32_t le32toh(uint32_t little_endian_32bits)
+inline BSWAP_CONSTEXPR uint32_t le32toh_internal(uint32_t little_endian_32bits)
{
- return little_endian_32bits;
+ if constexpr (std::endian::native == std::endian::big) return internal_bswap_32(little_endian_32bits);
+ else return little_endian_32bits;
}
-#endif // HAVE_DECL_LE32TOH
-
-#if HAVE_DECL_HTOBE64 == 0
-inline uint64_t htobe64(uint64_t host_64bits)
+inline BSWAP_CONSTEXPR uint64_t htobe64_internal(uint64_t host_64bits)
{
- return bswap_64(host_64bits);
+ if constexpr (std::endian::native == std::endian::little) return internal_bswap_64(host_64bits);
+ else return host_64bits;
}
-#endif // HAVE_DECL_HTOBE64
-
-#if HAVE_DECL_HTOLE64 == 0
-inline uint64_t htole64(uint64_t host_64bits)
+inline BSWAP_CONSTEXPR uint64_t htole64_internal(uint64_t host_64bits)
{
- return host_64bits;
+ if constexpr (std::endian::native == std::endian::big) return internal_bswap_64(host_64bits);
+ else return host_64bits;
}
-#endif // HAVE_DECL_HTOLE64
-
-#if HAVE_DECL_BE64TOH == 0
-inline uint64_t be64toh(uint64_t big_endian_64bits)
+inline BSWAP_CONSTEXPR uint64_t be64toh_internal(uint64_t big_endian_64bits)
{
- return bswap_64(big_endian_64bits);
+ if constexpr (std::endian::native == std::endian::little) return internal_bswap_64(big_endian_64bits);
+ else return big_endian_64bits;
}
-#endif // HAVE_DECL_BE64TOH
-
-#if HAVE_DECL_LE64TOH == 0
-inline uint64_t le64toh(uint64_t little_endian_64bits)
+inline BSWAP_CONSTEXPR uint64_t le64toh_internal(uint64_t little_endian_64bits)
{
- return little_endian_64bits;
+ if constexpr (std::endian::native == std::endian::big) return internal_bswap_64(little_endian_64bits);
+ else return little_endian_64bits;
}
-#endif // HAVE_DECL_LE64TOH
-
-#endif // WORDS_BIGENDIAN
#endif // BITCOIN_COMPAT_ENDIAN_H