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.  */

Reply via email to