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