Konstantinos Eleftheriou <[email protected]> writes:
> During the base register initialization, when we are eliminating the load
> instruction, we were calling `emit_move_insn` on registers of the same
> size but of different mode in some cases, causing an ICE.
>
> This patch fixes this, by adding a check for the modes to match before
> calling `emit_move_insn`.
>
> Bootstrapped/regtested on AArch64 and x86_64.
>
> PR rtl-optimization/119884
>
> gcc/ChangeLog:
>
> * avoid-store-forwarding.cc (process_store_forwarding):
> Added check to ensure that the register modes match
> before calling `emit_move_insn`.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/i386/pr119884.c: New test.
> ---
> gcc/avoid-store-forwarding.cc | 3 ++-
> gcc/testsuite/gcc.target/i386/pr119884.c | 13 +++++++++++++
> 2 files changed, 15 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/gcc.target/i386/pr119884.c
>
> diff --git a/gcc/avoid-store-forwarding.cc b/gcc/avoid-store-forwarding.cc
> index ded8d7e596e0..aec05c22ac37 100644
> --- a/gcc/avoid-store-forwarding.cc
> +++ b/gcc/avoid-store-forwarding.cc
> @@ -244,7 +244,8 @@ process_store_forwarding (vec<store_fwd_info> &stores,
> rtx_insn *load_insn,
> GET_MODE_BITSIZE (GET_MODE (it->mov_reg))))
> base_reg = gen_rtx_ZERO_EXTEND (dest_mode, it->mov_reg);
>
> - if (base_reg)
> + /* Generate a move instruction, only when the modes match. */
> + if (base_reg && dest_mode == GET_MODE (base_reg))
> {
> rtx_insn *move0 = emit_move_insn (dest, base_reg);
> if (recog_memoized (move0) >= 0)
Is this a complete fix though? It looks like:
rtx base_reg = it->mov_reg;
if (known_gt (GET_MODE_BITSIZE (dest_mode),
GET_MODE_BITSIZE (GET_MODE (it->mov_reg))))
base_reg = gen_rtx_ZERO_EXTEND (dest_mode, it->mov_reg);
implicitly assumes that dest_mode and GET_MODE (it->mov_reg) are both
integer modes.
Given that this code only triggers if we're going to eliminate the load,
and thus presumably define all the other bytes of DEST_MODE later,
couldn't we just use lowpart_subreg? That way we can cope with different
like-sized modes and with "extensions" from one mode to another. Of course,
there might be cases where doing this for different modes would trigger
unwanted cross-file register transfers, but that seems like a general
risk with forwarding.
Not related to this PR, but on the same piece of code:
/* If we're eliminating the load then find the store with zero offset
and use it as the base register to avoid a bit insert if possible. */
if (load_elim && it->offset == 0)
Doesn't this offset check need to take endianness into account?
Byte 0 would normally be the msb for big-endian targets.
Thanks,
Richard
> diff --git a/gcc/testsuite/gcc.target/i386/pr119884.c
> b/gcc/testsuite/gcc.target/i386/pr119884.c
> new file mode 100644
> index 000000000000..34d5b689244d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr119884.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fno-dse -favoid-store-forwarding" } */
> +
> +typedef __attribute__((__vector_size__(64))) char V;
> +char c;
> +V v;
> +
> +char
> +foo()
> +{
> + v *= c;
> + return v[0];
> +}
> \ No newline at end of file