[Bug middle-end/85344] constants with the sign bit set causes sign extension which is unexpected but not documented in the user documentation
pinskia at gcc dot gnu.org
gcc-bugzilla@gcc.gnu.org
Sat Aug 9 00:46:17 GMT 2025
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85344
--- Comment #21 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
(In reply to Segher Boessenkool from comment #20)
> (In reply to Andrew Pinski from comment #18)
> > Simple answer:
> > When the INTEGER_CST (unsigned short) is expanded into a const_int, the sign
> > extend happens due to the rules of const_int.
>
> What does that mean?!
```
case INTEGER_CST:
{
if (TREE_CODE (type) == BITINT_TYPE)
{
...
}
/* Given that TYPE_PRECISION (type) is not always equal to
GET_MODE_PRECISION (TYPE_MODE (type)), we need to extend from
the former to the latter according to the signedness of the
type. */
scalar_int_mode int_mode = SCALAR_INT_TYPE_MODE (type);
temp = immed_wide_int_const
(wi::to_wide (exp, GET_MODE_PRECISION (int_mode)), int_mode);
return temp;
```
immed_wide_int_const:
```
rtx
immed_wide_int_const (const poly_wide_int_ref &c, machine_mode mode)
{
if (c.is_constant ())
return immed_wide_int_const_1 (c.coeffs[0], mode);
```
immed_wide_int_const_1:
```
/* Return an rtx constant for V, given that the constant has mode MODE.
The returned rtx will be a CONST_INT if V fits, otherwise it will be
a CONST_DOUBLE (if !TARGET_SUPPORTS_WIDE_INT) or a CONST_WIDE_INT
(if TARGET_SUPPORTS_WIDE_INT). */
static rtx
immed_wide_int_const_1 (const wide_int_ref &v, machine_mode mode)
{
unsigned int len = v.get_len ();
/* Not scalar_int_mode because we also allow pointer bound modes. */
unsigned int prec = GET_MODE_PRECISION (as_a <scalar_mode> (mode));
/* Allow truncation but not extension since we do not know if the
number is signed or unsigned. */
gcc_assert (prec <= v.get_precision ());
if (len < 2 || prec <= HOST_BITS_PER_WIDE_INT)
return gen_int_mode (v.elt (0), mode);
```
gen_int_mode does the extension:
```
rtx
gen_int_mode (poly_int64 c, machine_mode mode)
{
c = trunc_int_for_mode (c, mode);
if (c.is_constant ())
return GEN_INT (c.coeffs[0]);
```
```
/* Truncate and perhaps sign-extend C as appropriate for MODE. */
HOST_WIDE_INT
trunc_int_for_mode (HOST_WIDE_INT c, machine_mode mode)
{
/* Not scalar_int_mode because we also allow pointer bound modes. */
scalar_mode smode = as_a <scalar_mode> (mode);
int width = GET_MODE_PRECISION (smode);
/* You want to truncate to a _what_? */
gcc_assert (SCALAR_INT_MODE_P (mode));
/* Canonicalize BImode to 0 and STORE_FLAG_VALUE. */
if (smode == BImode)
return c & 1 ? STORE_FLAG_VALUE : 0;
/* Sign-extend for the requested mode. */
if (width < HOST_BITS_PER_WIDE_INT)
{
HOST_WIDE_INT sign = 1;
sign <<= width - 1;
c &= (sign << 1) - 1;
c ^= sign;
c -= sign;
}
return c;
}
/* Likewise for polynomial values, using the sign-extended representation
for each individual coefficient. */
poly_int64
trunc_int_for_mode (poly_int64 x, machine_mode mode)
{
for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
x.coeffs[i] = trunc_int_for_mode (x.coeffs[i], mode);
return x;
}
```
Note NUM_POLY_INT_COEFFS is 1 most of the time (except for aarch64 and riscv).
Notice:
/* Sign-extend for the requested mode. */
More information about the Gcc-bugs
mailing list