From 3ecc7798749c254bb4ea7243eb3ec12d33325021 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 17 May 2024 15:48:33 -0700 Subject: [PATCH] byteswap: port better to limited platforms MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit POSIX does not require uint64_t, and the C standard does not require uint16_t or uint32_t either, so port to platforms that lack these types. The POSIX limitation is the only significant one in practice. I ran into this issue when updating Emacs, which still ports to platforms lacking 64-bit types. * lib/byteswap.in.h (bswap_16, bswap_32, bswap_64): Accept and return uint_leastN_t instead of uintN_t, for portability to non-POSIX hosts that lack uintN_t. Almost no platforms these days lack the types, but it’s easy to port so let’s do that. Also, redo to avoid unnecssary parentheses, as these are now functions not macros. (bswap_64): Define only if UINT_LEAST64_MAX, for benefit of not-quite-C99 platforms. This is similar to what bitrotate.h does. * tests/test-byteswap.c (test_bswap_constant) (test_bswap_eval_once, test_bswap_double) [!UINT_LEAST64_MAX]: Do not test 64-bit swaps. --- ChangeLog | 22 +++++++++++++++++++++ lib/byteswap.in.h | 45 ++++++++++++++++++++++++------------------- tests/test-byteswap.c | 20 ++++++++++++------- 3 files changed, 60 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5207f25b3a..078aea49cf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2024-05-17 Paul Eggert + + byteswap: port better to limited platforms + POSIX does not require uint64_t, and the C standard + does not require uint16_t or uint32_t either, so port + to platforms that lack these types. The POSIX limitation + is the only significant one in practice. I ran into this + issue when updating Emacs, which still ports to platforms + lacking 64-bit types. + * lib/byteswap.in.h (bswap_16, bswap_32, bswap_64): + Accept and return uint_leastN_t instead of uintN_t, + for portability to non-POSIX hosts that lack uintN_t. + Almost no platforms these days lack the types, but + it’s easy to port so let’s do that. Also, redo to avoid + unnecssary parentheses, as these are now functions not macros. + (bswap_64): Define only if UINT_LEAST64_MAX, for benefit + of not-quite-C99 platforms. This is similar to what + bitrotate.h does. + * tests/test-byteswap.c (test_bswap_constant) + (test_bswap_eval_once, test_bswap_double) [!UINT_LEAST64_MAX]: + Do not test 64-bit swaps. + 2024-05-17 Bruno Haible stdbit-h: Fix leading-zeros/ones functions on 64-bit MSVC. diff --git a/lib/byteswap.in.h b/lib/byteswap.in.h index ae05d59441..0e760005c2 100644 --- a/lib/byteswap.in.h +++ b/lib/byteswap.in.h @@ -56,47 +56,52 @@ extern "C" { /* Given an unsigned 16-bit argument X, return the value corresponding to X with reversed byte order. */ -_GL_BYTESWAP_INLINE uint16_t -bswap_16 (uint16_t x) +_GL_BYTESWAP_INLINE uint_least16_t +bswap_16 (uint_least16_t x) { #ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP16 return __builtin_bswap16 (x); #else - return (((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))); + return ( (x & 0xff00) >> 8 + | (x & 0x00ff) << 8); #endif } /* Given an unsigned 32-bit argument X, return the value corresponding to X with reversed byte order. */ -_GL_BYTESWAP_INLINE uint32_t -bswap_32 (uint32_t x) +_GL_BYTESWAP_INLINE uint_least32_t +bswap_32 (uint_least32_t x) { #ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP32 return __builtin_bswap32 (x); #else - return ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) - | (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24)); + return ( (x & 0xff000000) >> 24 + | (x & 0x00ff0000) >> 8 + | (x & 0x0000ff00) << 8 + | (x & 0x000000ff) << 24); #endif } +#ifdef UINT_LEAST64_MAX /* Given an unsigned 64-bit argument X, return the value corresponding to X with reversed byte order. */ -_GL_BYTESWAP_INLINE uint64_t -bswap_64 (uint64_t x) +_GL_BYTESWAP_INLINE uint_least64_t +bswap_64 (uint_least64_t x) { -#ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP64 +# ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP64 return __builtin_bswap64 (x); -#else - return ((((x) & 0xff00000000000000ull) >> 56) - | (((x) & 0x00ff000000000000ull) >> 40) - | (((x) & 0x0000ff0000000000ull) >> 24) - | (((x) & 0x000000ff00000000ull) >> 8) - | (((x) & 0x00000000ff000000ull) << 8) - | (((x) & 0x0000000000ff0000ull) << 24) - | (((x) & 0x000000000000ff00ull) << 40) - | (((x) & 0x00000000000000ffull) << 56)); -#endif +# else + return ( (x & 0xff00000000000000) >> 56 + | (x & 0x00ff000000000000) >> 40 + | (x & 0x0000ff0000000000) >> 24 + | (x & 0x000000ff00000000) >> 8 + | (x & 0x00000000ff000000) << 8 + | (x & 0x0000000000ff0000) << 24 + | (x & 0x000000000000ff00) << 40 + | (x & 0x00000000000000ff) << 56); +# endif } +#endif #ifdef __cplusplus } diff --git a/tests/test-byteswap.c b/tests/test-byteswap.c index 60b3ea31e2..475a655a13 100644 --- a/tests/test-byteswap.c +++ b/tests/test-byteswap.c @@ -29,25 +29,29 @@ test_bswap_constant (void) { ASSERT (bswap_16 (UINT16_C (0x1234)) == UINT16_C (0x3412)); ASSERT (bswap_32 (UINT32_C (0x12345678)) == UINT32_C (0x78563412)); +#ifdef UINT_LEAST64_MAX ASSERT (bswap_64 (UINT64_C (0x1234567890ABCDEF)) == UINT64_C (0xEFCDAB9078563412)); +#endif } /* Test that the bswap functions evaluate their arguments once. */ static void test_bswap_eval_once (void) { - uint16_t value_1 = 0; - uint32_t value_2 = 0; - uint64_t value_3 = 0; - + uint_least16_t value_1 = 0; ASSERT (bswap_16 (value_1++) == 0); - ASSERT (bswap_32 (value_2++) == 0); - ASSERT (bswap_64 (value_3++) == 0); - ASSERT (value_1 == 1); + + uint_least32_t value_2 = 0; + ASSERT (bswap_32 (value_2++) == 0); ASSERT (value_2 == 1); + +#ifdef UINT_LEAST64_MAX + uint_least64_t value_3 = 0; + ASSERT (bswap_64 (value_3++) == 0); ASSERT (value_3 == 1); +#endif } /* Test that the bswap functions accept floating-point arguments. */ @@ -56,7 +60,9 @@ test_bswap_double (void) { ASSERT (bswap_16 (0.0) == 0); ASSERT (bswap_32 (0.0) == 0); +#ifdef UINT_LEAST64_MAX ASSERT (bswap_64 (0.0) == 0); +#endif } int -- 2.39.5