https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127669
Jakub Jelinek <jakub at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Ever confirmed|0 |1
Status|UNCONFIRMED |NEW
Last reconfirmed| |2026-09-30
--- Comment #1 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Slightly reduced:
typedef unsigned _BitInt(129) T;
[[gnu::noipa]] static T
foo (T v)
{
return v;
}
static T
bar ()
{
return 1;
}
int
main ()
{
T x = __builtin_bitreverseg ((T) 1);
T y = __builtin_bitreverseg (bar ());
T z = __builtin_bitreverseg (foo (1));
if (x != y || x != z)
__builtin_abort ();
}
x and z are correctly ((T) 1) << 128, and y should be too, but instead is x |
1.
Note, before bitint lowering x is folded to the right constant (already since
generic),
and the z computation is also correct.
The y case is about .BITREVERSE (1); appearing only later on and somehow
fold_stmt not folding that into constant.
So, one bug (missed optimization) is that fold_stmt_1 doesn't do
fold_const_call for internal fns with constant arguments.
And another bug is that when we actually lower large/huge .BITREVERSE (or
.BSWAP?) ifn call with INTEGER_CST argument, we choose wrong size of the
constant.
The lowering of
y_6 = .BITREVERSE (1);
is
_32 = 1 & 1;
MEM[(unsigned long *)&bitint.13 + 16B] = _32;
<bb 3> [local count: 1073741824]:
# _33 = PHI <1(2), _34(3)>
_35 = 2 - _33;
_36 = VIEW_CONVERT_EXPR<unsigned long[2]>(*.LC0)[_35];
_37 = _36 << 63;
_38 = _35 + 18446744073709551615;
_39 = VIEW_CONVERT_EXPR<unsigned long[2]>(*.LC0)[_38];
_40 = _39 >> 1;
_41 = _37 | _40;
_42 = __builtin_bitreverse64 (_41);
bitint.13[_33] = _42;
_34 = _33 + 18446744073709551615;
if (_33 != 0)
goto <bb 3>; [0.05%]
else
goto <bb 4>; [99.95%]
which would be correct if .LC0 was an unsigned _BitInt(129) constant.
But the assembly shows
.LC0:
.quad 1
.quad 0
i.e. only 128-bit one. The loop first accesses limbs 2-1 and 2-1-1 and in the
second iteration 2-0 and 2-0-1. So, it reads one bit out of bounds...