https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127921
Bug ID: 127921
Summary: Signed large _BitInt rotate is lowered with an
arithmetic right shift
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: middle-end
Assignee: unassigned at gcc dot gnu.org
Reporter: kyuwoncho18 at gmail dot com
Target Milestone: ---
godbolt: https://godbolt.org/z/T1d53xbqr
GCC trunk miscompiles a `__ROTATE_LEFT` of a signed `_BitInt(257)` (GIMPLE FE
input) when the rotate is not constant-folded:
```c
#include <stdio.h>
signed _BitInt(257) result;
int __GIMPLE
foo (signed _BitInt(257) x)
{
signed _BitInt(257) y;
y = x __ROTATE_LEFT 1;
result = y;
return 0;
}
int main(void) {
signed _BitInt(257) x = -2;
foo(x);
printf("%lld\n", (long long)result);
return 0;
}
```
```console
$ gcc -O0 -fgimple t.c && ./a.out
-1
$ gcc -O1 -fgimple t.c && ./a.out
-3
```
Expected `-3`: a rotate permutes the bits of the 257-bit two's-complement
value, so `-2` (`1...10`) rotated left by 1 is `1...101`, i.e. `-3`. At -O1
`foo` is inlined and the rotate is constant-folded to the correct `-3`; with
`-O1 -fno-inline` the lowering runs and the output is again `-1`. The same
program with `unsigned _BitInt(257)` prints `-3`.
In `gimple_lower_bitint`, the `LROTATE_EXPR`/`RROTATE_EXPR` case for a signed
type creates the conversion temporary with the signed `type` instead of
`utype`, and never replaces `rhs1` with it. Both shifts therefore use the
signed operand, and the `RSHIFT_EXPR` by `257 - 1` sign-fills, so the OR gives
`-1`.
This code dates from the original `_BitInt` lowering (r14-3746-ga9d6c7fbeb3);
the testcase needs the GIMPLE FE rotate syntax from r16-240-gbfc31543757
(PR119432). It fails with GCC 16.1, 16.2 and trunk (17.0.0 20261009).
Disclaimer: This test case was generated by a fuzzer, and the report was
written with LLM assistance.