https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125988
--- Comment #3 from Konstantinos Eleftheriou <konstantinos.eleftheriou at vrull
dot eu> ---
`store_bit_field_1` in `gcc/expmed.cc` may take the `gen_lowpart`
narrowing branch when its destination register's mode has no equal
integral mode (e.g. a multi-register vector tuple such as `V4x4BF`):
```
opt_scalar_int_mode op0_mode = int_mode_for_mode (GET_MODE (op0));
scalar_int_mode imode;
if (!op0_mode.exists (&imode) || imode != GET_MODE (op0))
{
if (MEM_P (op0))
op0 = adjust_bitfield_address_size (op0, op0_mode.else_blk (),
0, MEM_SIZE (op0));
else if (!op0_mode.exists ())
{
...
/* Stack-temp branch: result is copied back into op0. */
rtx temp = assign_stack_temp (GET_MODE (op0),
GET_MODE_SIZE (GET_MODE (op0)));
emit_move_insn (temp, op0);
store_bit_field_1 (temp, bitsize, bitnum, 0, 0, fieldmode, value,
reverse, fallback_p, undefined_p);
emit_move_insn (op0, temp); /* <-- copy back */
return true;
}
else
op0 = gen_lowpart (op0_mode.require (), op0); /* <-- no copy back */
}
return store_integral_bit_field (op0, op0_mode, ibitsize, ibitnum,
bitregion_start, bitregion_end,
fieldmode, value, reverse, fallback_p);
```
When `gen_lowpart` returns a fresh register (because the source mode
cannot be reinterpreted into the chosen integral mode via a valid
subreg), `store_integral_bit_field` writes the inserted value into
that fresh register. The caller's `str_rtx` is never updated, so the
insertion is silently dropped.
The sibling `!op0_mode.exists()` branch already performs the
analogous copy-back via the stack-temp pattern (the final
`emit_move_insn (op0, temp)`). The `gen_lowpart` branch is missing
that copy-back.
Suggested fix:
Mirror the stack-temp branch's copy-back at the end of
`store_bit_field_1`: after `store_integral_bit_field` returns, if the
register reached via `op0` differs from the one reached via
`str_rtx`, copy the value back into `str_rtx`.