https://gcc.gnu.org/g:96ce4939706066bccad5da441c9a96ae5c3fbcb0
commit r17-1161-g96ce4939706066bccad5da441c9a96ae5c3fbcb0 Author: Jakub Jelinek <[email protected]> Date: Tue Jun 2 08:52:44 2026 +0200 wide-int: Fix up wi::bitreverse_large [PR125517] The following testcase shows wi::bitreverse_large is buggy. In particular, it uses the len argument (i.e. number of limbs the xval wide_int has) to decide how much to clear, but it should be using BLOCKS_NEEDED (precision) for that and for canonize argument similarly to wi::bswap_large, because it behaves similarly to that. If xval is say len 1 but precision 512, we want to clear all 512 bits in the result limbs and the loop then sets the most significant one in there and canonize with len (512 + 63) / 64, not initialize just the least significant limb, set various bits in the uninitialized ones and then only care about the least significant 64 bits anyway. 2026-06-02 Jakub Jelinek <[email protected]> PR middle-end/125517 * wide-int.cc (wi::bitreverse_large): Rename LEN argument to XLEN and use it as safe_uhwi argument. Add LEN automatic variable set to BLOCKS_NEEDED (precision). Replace loop clearing val with memset. Remove I automatic variable. * gcc.dg/builtin-bitreverse-9.c: New test. Reviewed-by: Andrew Pinski <[email protected]> Diff: --- gcc/testsuite/gcc.dg/builtin-bitreverse-9.c | 17 +++++++++++++++++ gcc/wide-int.cc | 11 +++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/gcc/testsuite/gcc.dg/builtin-bitreverse-9.c b/gcc/testsuite/gcc.dg/builtin-bitreverse-9.c new file mode 100644 index 000000000000..c53ef34f9c1f --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-bitreverse-9.c @@ -0,0 +1,17 @@ +/* PR middle-end/125517 */ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2" } */ + +#if __SIZEOF_INT128__ == 16 +static_assert (__builtin_bitreverse128 (((unsigned __int128) + 0x6132fc885cb8cf0cULL << 64) + | 0xeaa7649b043ae77bULL) + == (((unsigned __int128) 0xdee75c20d926e557ULL << 64) + | 0x30f31d3a113f4c86ULL), "bitreverse128 1"); +static_assert (__builtin_bitreverse128 (0xeaa7649b043ae77bULL) + == ((unsigned __int128) 0xdee75c20d926e557ULL << 64), + "bitreverse128 2"); +static_assert (__builtin_bitreverse128 (0xaa7649b043ae77bULL) + == ((unsigned __int128) 0xdee75c20d926e550ULL << 64), + "bitreverse128 3"); +#endif diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc index 64d7ecfac9c9..c2c424344a24 100644 --- a/gcc/wide-int.cc +++ b/gcc/wide-int.cc @@ -763,22 +763,21 @@ wi::bswap_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval, return canonize (val, len, precision); } -/* Bitreverse the integer represented by XVAL and LEN into VAL. Return +/* Bitreverse the integer represented by XVAL and XLEN into VAL. Return the number of blocks in VAL. Both XVAL and VAL have PRECISION bits. */ unsigned int wi::bitreverse_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval, - unsigned int len, unsigned int precision) + unsigned int xlen, unsigned int precision) { - unsigned int i, s; + unsigned int s, len = BLOCKS_NEEDED (precision); - for (i = 0; i < len; i++) - val[i] = 0; + memset (val, 0, sizeof (unsigned HOST_WIDE_INT) * len); for (s = 0; s < precision; s++) { unsigned int block = s / HOST_BITS_PER_WIDE_INT; unsigned int offset = s & (HOST_BITS_PER_WIDE_INT - 1); - if (((safe_uhwi (xval, len, block) >> offset) & 1) != 0) + if (((safe_uhwi (xval, xlen, block) >> offset) & 1) != 0) { unsigned int d = (precision - 1) - s; block = d / HOST_BITS_PER_WIDE_INT;
