diff --git a/include/bitops-emulated/generic-bswap.h b/include/bitops-emulated/generic-bswap.h new file mode 100644 index 0000000..4e5b3c5 --- /dev/null +++ b/include/bitops-emulated/generic-bswap.h @@ -0,0 +1,38 @@ +/* generic-bswap.h - generic bswap implementations. + * + * Copyright (C) 2024 Bruno Raoult ("br") + * Licensed under the GNU General Public License v3.0 or later. + * Some rights reserved. See COPYING. + * + * You should have received a copy of the GNU General Public License along with this + * program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ +#ifndef _GENERIC_BSWAP_H_ +#define _GENERIC_BSWAP_H_ + +#include "brlib.h" + +/* Adapted from: http://www-graphics.stanford.edu/%7Eseander/bithacks.html + */ +static __always_inline u32 __bswap32_emulated(u32 n) +{ + const u32 k = 0x00FF00FF; + n = ((n >> 8) & k) | ((n & k) << 8); + n = ( n >> 16) | ( n << 16); + return n; +} + +static __always_inline u64 __bswap64_emulated(u64 n) +{ + const u64 k1 = 0x00FF00FF00FF00FFull; + const u64 k2 = 0x0000FFFF0000FFFFull; + n = ((n >> 8) & k1) | ((n & k1) << 8); + n = ((n >> 16) & k2) | ((n & k2) << 16); + n = ( n >> 32) | ( n << 32); + return n; +} + +#endif /* _GENERIC_BSWAP_H_ */ diff --git a/include/bitops.h b/include/bitops.h index 752cd81..7e0f080 100644 --- a/include/bitops.h +++ b/include/bitops.h @@ -16,6 +16,7 @@ #include "brlib.h" #include "bitops-emulated/generic-ctz.h" #include "bitops-emulated/generic-clz.h" +#include "bitops-emulated/generic-bswap.h" #ifndef __has_builtin #define __has_builtin(x) 0 @@ -35,7 +36,9 @@ #if __has_builtin(__builtin_ffs) # define HAS_FFS #endif - +#if __has_builtin(__builtin_bswap32) +# define HAS_BSWAP +#endif /** * print_bitops_impl() - print bitops implementation. @@ -174,6 +177,24 @@ void print_bitops_impl(void); #define ffz32(n) ffs32(~(n)) #define ffz64(n) ffs64(~(n)) +/** + * bswap32, bswap64 - reverse bytes: 0x01020304 -> 0x04030201 + * @n: unsigned 32 or 64 bits integer. + * + * ffs(n) is similar to ctz(n) + 1, but returns 0 if n == 0 (except + * for ctz version, where ffs(0) is undefined). + * ffz(n) is ffz(~n), with undefine value if n = 0. + */ +#if defined(HAS_BSWAP) +# define __bswap32_native(n) __builtin_bswap32(n) +# define __bswap64_native(n) __builtin_bswap64(n) +# define bswap32(n) __bswap32_native(n) +# define bswap64(n) __bswap64_native(n) +#else +# define bswap32(n) __bswap32_emulated(n) +# define bswap64(n) __bswap64_emulated(n) +#endif + /** * fls32, fls64 - return one plus MSB index: 00101000 -> 6 * @n: unsigned 32 or 64 bits integer. diff --git a/test/bitops-test.c b/test/bitops-test.c index d320fc8..ef3b36c 100644 --- a/test/bitops-test.c +++ b/test/bitops-test.c @@ -14,12 +14,13 @@ #include #include -#include "br.h" +#include "brlib.h" #include "bitops.h" #include "cutest/CuTest.h" static const struct test32_1 { u32 t32; /* input */ + u32 bswap; int popc; int ctz; int clz; @@ -32,19 +33,19 @@ static const struct test32_1 { uchar bfe[32]; }; } test32_1[] = { - { 0x00000000, 0, 32, 32, 0, 1, 0, 0, /* sometimes undefined */ + { 0x00000000, 0x00000000, 0, 32, 32, 0, 1, 0, 0, /* sometimes undefined */ { 0, { 0 } } }, - { 0xffffffff, 32, 0, 0, 1, 0, 32, 31, + { 0xffffffff, 0xffffffff, 32, 0, 0, 1, 0, 32, 31, { 32, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 } } }, - { 0x00000001, 1, 0, 31, 1, 2, 1, 0, + { 0x00000001, 0x01000000, 1, 0, 31, 1, 2, 1, 0, { 1, { 0 } } }, - { 0x80000000, 1, 31, 0, 32, 1, 32, 31, + { 0x80000000, 0x00000080, 1, 31, 0, 32, 1, 32, 31, { 1, { 31 } } }, - { 0x71800718, 10, 3, 1, 4, 1, 31, 30, + { 0x71800718, 0x18078071, 10, 3, 1, 4, 1, 31, 30, /* 0111 0001 1000 0000 0000 0111 0001 1000 */ { 10, { 3, 4, 8, 9, 10, 23, 24, 28, 29, 30 } } }, - { 0x07eeeef7, 22, 0, 5, 1, 4, 27, 26, + { 0x07eeeef7, 0xf7eeee07, 22, 0, 5, 1, 4, 27, 26, /* 0000 0111 1110 1110 1110 1110 0111 1111*/ { 22, { 0, 1, 2, 4, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 18, 19, 21, 22, 23, 24, 25, 26 } } }, @@ -52,7 +53,8 @@ static const struct test32_1 { static const struct test64_1 { u64 t64; /* input */ - int popc; + u64 bswap; + int popc; /* some values may be undefined */ int ctz; int clz; int ffs; @@ -64,22 +66,22 @@ static const struct test64_1 { uchar bfe[64]; }; } test64_1[] = { - { 0x0000000000000000, 0, 64, 64, 0, 1, 0, 0, /* sometimes undefined */ + { 0x0000000000000000, 0x0000000000000000, 0, 64, 64, 0, 1, 0, 0, { 0, { 0 } } }, - { 0xffffffffffffffff, 64, 0, 0, 1, 0, 64, 63, + { 0xffffffffffffffff, 0xffffffffffffffff, 64, 0, 0, 1, 0, 64, 63, { 64, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 } } }, - { 0x0000000100000001, 2, 0, 31, 1, 2, 33, 32, + { 0x0000000100000001, 0x0100000001000000, 2, 0, 31, 1, 2, 33, 32, { 2, { 0, 32 } } }, - { 0x8000000000000000, 1, 63, 0, 64, 1, 64, 63, + { 0x8000000000000000, 0x0000000000000080, 1, 63, 0, 64, 1, 64, 63, { 1, { 63 } } }, - { 0x7180071871800718, 20, 3, 1, 4, 1, 63, 62, + { 0x7180071871800718, 0x1807807118078071, 20, 3, 1, 4, 1, 63, 62, /* 2 x 0111 0001 1000 0000 0000 0111 0001 1000 */ { 20, { 3, 4, 8, 9, 10, 23, 24, 28, 29, 30, 35, 36, 40, 41, 42, 55, 56, 60, 61, 62 } } }, - { 0x07eeeef707eeeef7, 44, 0, 5, 1, 4, 59, 58 , + { 0x07eeeef707eeeef7, 0xf7eeee07f7eeee07, 44, 0, 5, 1, 4, 59, 58 , /* 2 x 0000 0111 1110 1110 1110 1110 0111 1111*/ { 44, { 0, 1, 2, 4, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 18, 19, 21, 22, 23, 24, 25, 26, @@ -167,6 +169,20 @@ static void cutest_fls(CuTest *tc) } } +static void cutest_bswap(CuTest *tc) +{ + for (uint i = 0; i < ARRAY_SIZE(test32_1); ++i) { + int res = bswap32(test32_1[i].t32); + //printf("fls32 t=%#x r=%d e=%d\n", test32_1[i].t32, res, test32_1[i].fls); + CuAssertIntEquals(tc, test32_1[i].bswap, res); + } + for (uint i = 0; i < ARRAY_SIZE(test64_1); ++i) { + int res = bswap64(test64_1[i].t64); + //printf("fls64 t=%#llx r=%d e=%d\n", test64_1[i].t64, res, test64_1[i].fls); + CuAssertIntEquals(tc, test64_1[i].bswap, res); + } +} + static void cutest_ilog(CuTest *tc) { for (uint i = 0; i < ARRAY_SIZE(test32_1); ++i) { @@ -322,6 +338,7 @@ static CuSuite *bitops_GetSuite() SUITE_ADD_TEST(suite, cutest_fls); SUITE_ADD_TEST(suite, cutest_ilog); SUITE_ADD_TEST(suite, cutest_bfe); + SUITE_ADD_TEST(suite, cutest_bswap); SUITE_ADD_TEST(suite, cutest_rol); SUITE_ADD_TEST(suite, cutest_ror); diff --git a/test/pool-test.c b/test/pool-test.c index 66209c7..bbab8a1 100644 --- a/test/pool-test.c +++ b/test/pool-test.c @@ -1,7 +1,7 @@ #include #include -#include "br.h" +#include "brlib.h" #include "pool.h" #include "debug.h"