Hi! The following testcase results in compiler UB as detected by ubsan. find_bswap_or_nop first checks is_bswap_or_nop_p and if that fails on the tmp_n value, tries some rotation of that if possible. The discovery what rotate count to use ignores zero bytes from the least significant end (those mean zero bytes and so can be masked away) and on the first non-zero non-0xff byte (0xff means don't know), 1-8 means some particular byte of the original computes count (the rotation count) from that byte + the byte index. Now, on the following testcase we have tmp_n 0x403020105060700, i.e. the least significant byte is zero, then the msb from the original value, byte below it, another one below it, then the low 32 bits of the original value. So, we stop at count 7 with i 1, it wraps around and we get count 0. Then we invoke UB on tmp_n = tmp_n >> count | tmp_n << (range - count); because count is 0 and range is 64. Now, of course I could fix it up by doing tmp_n << ((range - count) % range) or something similar, but that is just wasted compile time, if count is 0, we already know that is_bswap_or_nop_p failed on that tmp_n value and so it will fail again if the value is the same. So I think better just return NULL (i.e. punt).
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk and 15.2? 2025-07-31 Jakub Jelinek <ja...@redhat.com> PR middle-end/121322 * gimple-ssa-store-merging.cc (find_bswap_or_nop): Return NULL if count is 0. * gcc.dg/pr121322.c: New test. --- gcc/gimple-ssa-store-merging.cc.jj 2025-07-31 10:53:47.607180140 +0200 +++ gcc/gimple-ssa-store-merging.cc 2025-07-31 11:53:51.635997562 +0200 @@ -1055,6 +1055,8 @@ find_bswap_or_nop (gimple *stmt, struct if (count <= range / BITS_PER_MARKER) { count = (count + i) * BITS_PER_MARKER % range; + if (!count) + return NULL; break; } else --- gcc/testsuite/gcc.dg/pr121322.c.jj 2025-07-31 11:58:02.103718378 +0200 +++ gcc/testsuite/gcc.dg/pr121322.c 2025-07-31 11:57:44.136953600 +0200 @@ -0,0 +1,14 @@ +/* PR middle-end/121322 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +unsigned long long +foo (unsigned long long *p) +{ + unsigned long long a = *p; + unsigned long long b = __builtin_bswap64 (a); + return ((b << 32) + | ((b >> 8) & 0xff000000ULL) + | ((b >> 24) & 0xff0000ULL) + | ((b >> 40) & 0xff00ULL)); +} Jakub