On Wed, Sep 9, 2026 at 7:27 AM Sun, Qin <[email protected]> wrote:
>
> This patch fixes a miss-optimization issue.
>
> Pattern `vec_concatv2df` has no alternative accepting a memory operand 1
> and a non-zero operand 2, but the old condition accepted it with an unclear
> condition `!(MEM_P (operands[1]) && MEM_P (operands[2]))`.
> Therefore, after combine resulted its folding with a MEM operand 1 and a
> REG operand 2, the old condition would wrongly advertise the unencodable
> form. A reload would be needed by LRA, which might result in one more
> instruction.
> To avoid such situations, we should reject MEM as operand 1 in the condition
> unless operand 2 is a CONST 0.
>
> Take this case as an example:
>
> v2df foo3 (double* a, double *b) { return __extension__(v2df) {*b, *a}; }
>
> Before with -O3 -march=znver5, we generated:
> foo3:
>         vmovsd  (%rdi), %xmm0
>         vmovsd  (%rsi), %xmm1
>         vunpcklpd       %xmm0, %xmm1, %xmm0
>         ret
>
> By narrowing the condition, now we generate:
> foo3:
>         vmovsd  (%rdi), %xmm0
>         vmovhpd (%rdi), %xmm0, %xmm0
>         ret
>
> gcc/ChangeLog:
>
>         * config/i386/sse.md (vec_concatv2df): Restrict the condition
>         to accept only CONST0_RTX as operand 2 when operand 1 is MEM.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.target/i386/vec-concatv2df-1.c: New test.

OK.

GCC 16 got it right by chance, because it expanded to:

    8: r106:DF=[r108:DI]
      REG_DEAD r108:DI
    9: r104:V2DF=vec_concat(r106:DF,[r107:DI])
      REG_DEAD r107:DI
      REG_DEAD r106:DF

while mainline expands to:

    8: r106:DF=[r107:DI]
      REG_DEAD r107:DI
    9: r104:V2DF=vec_concat([r108:DI],r106:DF)
      REG_DEAD r108:DI
      REG_DEAD r106:DF

Thanks,
Uros.

> ---
>  gcc/config/i386/sse.md                        |  2 +-
>  .../gcc.target/i386/vec-concatv2df.c          | 22 +++++++++++++++++++
>  2 files changed, 23 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/vec-concatv2df.c
>
> diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
> index e4bc746dacc..fe25d3cdce4 100644
> --- a/gcc/config/i386/sse.md
> +++ b/gcc/config/i386/sse.md
> @@ -15739,7 +15739,7 @@
>         (vec_concat:V2DF
>           (match_operand:DF 1 "nonimmediate_operand" " 0,x,v,0,x,vm,0,0")
>           (match_operand:DF 2 "nonimm_or_0_operand"  " x,x,v,m,m, C,x,m")))]
> -  "TARGET_SSE && !(MEM_P (operands[1]) && MEM_P (operands[2]))"
> +  "TARGET_SSE && (operands[2] == CONST0_RTX (DFmode) || !MEM_P 
> (operands[1]))"
>    "@
>     unpcklpd\t{%2, %0|%0, %2}
>     vunpcklpd\t{%2, %1, %0|%0, %1, %2}
> diff --git a/gcc/testsuite/gcc.target/i386/vec-concatv2df.c 
> b/gcc/testsuite/gcc.target/i386/vec-concatv2df.c
> new file mode 100644
> index 00000000000..1ae58b94602
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/vec-concatv2df.c
> @@ -0,0 +1,22 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -mavx -masm=att" } */
> +
> +typedef double v2df __attribute__((vector_size (16)));
> +
> +v2df
> +f1 (double *a, double *b)
> +{
> +  return (v2df) { *b, *a };
> +}
> +
> +/* { dg-final { scan-assembler-times "vmovhpd\[ \t]" 1 } } */
> +/* { dg-final { scan-assembler-not "vunpcklpd" } } */
> +
> +v2df
> +f2 (double *a)
> +{
> +  return (v2df) { *a, 0.0 };
> +}
> +
> +/* { dg-final { scan-assembler-times "vmovq\[ \t]" 1 } } */
> +/* { dg-final { scan-assembler-times "vmovsd\[ \t]" 1 } } */
> --
> 2.25.1
>

Reply via email to