Konstantinos Eleftheriou <konstantinos.elefther...@vrull.eu> 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

Reply via email to