> -----Original Message-----
> From: Sarvesh Chandra <[email protected]>
> Sent: Tuesday, June 23, 2026 3:17 PM
> To: [email protected]
> Cc: Liu, Hongtao <[email protected]>; Ashwin Godbole
> <[email protected]>; Sarvesh Chandra
> <[email protected]>; Richard Biener <[email protected]>; Uros
> Bizjak <[email protected]>; Venkataramanan Kumar
> <[email protected]>
> Subject: [PATCH v2] i386: Emit vunpcklpd for register V4DF/V8DF movddup
> [PR107057]
>
> These movddup patterns only accepted a memory source, so duplicating the
> even lanes of a register value spilled it to the stack. Add a register
> alternative
> that emits vunpcklpd; a memory source still uses vmovddup.
Ok.
>
> gcc/ChangeLog:
>
> PR target/107057
> * config/i386/sse.md (avx512f_movddup512<mask_name>): Add a
> register source alternative that emits vunpcklpd.
> (avx_movddup256<mask_name>): Likewise.
>
> gcc/testsuite/ChangeLog:
>
> PR target/107057
> * gcc.target/i386/avx512-movedup.c: New test.
>
> Co-authored-by: Ashwin Godbole <[email protected]>
> Signed-off-by: Sarvesh Chandra <[email protected]>
> ---
> Bootstrapped and regression-tested on x86_64-pc-linux-gnu.
>
> v2: add a register alternative instead of reordering the patterns.
>
> Note: the register alternative is typed sselog1 rather than sselog, as GCC
> uses
> the sselog1 type for single-source-operand SSE logical insns.
>
> gcc/config/i386/sse.md | 20 +++++++++++--------
> .../gcc.target/i386/avx512-movedup.c | 14 +++++++++++++
> 2 files changed, 26 insertions(+), 8 deletions(-) create mode 100644
> gcc/testsuite/gcc.target/i386/avx512-movedup.c
>
> diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index
> 5d9ab8b14eb..74078a772a7 100644
> --- a/gcc/config/i386/sse.md
> +++ b/gcc/config/i386/sse.md
> @@ -13917,18 +13917,20 @@
> (set_attr "mode" "V2DF,V2DF,V1DF,V1DF,V1DF")])
>
> (define_insn "avx512f_movddup512<mask_name>"
> - [(set (match_operand:V8DF 0 "register_operand" "=v")
> + [(set (match_operand:V8DF 0 "register_operand" "=v,v")
> (vec_select:V8DF
> (vec_concat:V16DF
> - (match_operand:V8DF 1 "nonimmediate_operand" "m")
> + (match_operand:V8DF 1 "nonimmediate_operand" "v,m")
> (match_dup 1))
> (parallel [(const_int 0) (const_int 8)
> (const_int 2) (const_int 10)
> (const_int 4) (const_int 12)
> (const_int 6) (const_int 14)])))]
> "TARGET_AVX512F"
> - "vmovddup\t{%1, %0<mask_operand2>|%0<mask_operand2>, %1}"
> - [(set_attr "type" "ssemov")
> + "@
> +
> vunpcklpd\t{%1, %1, %0<mask_operand2>|%0<mask_operand2>, %1, %1}
> + vmovddup\t{%1, %0<mask_operand2>|%0<mask_operand2>, %1}"
> + [(set_attr "type" "sselog1,ssemov")
> (set_attr "prefix" "evex")
> (set_attr "mode" "V8DF")])
>
> @@ -13950,16 +13952,18 @@
>
> ;; Recall that the 256-bit unpck insns only shuffle within their lanes.
> (define_insn "avx_movddup256<mask_name>"
> - [(set (match_operand:V4DF 0 "register_operand" "=v")
> + [(set (match_operand:V4DF 0 "register_operand" "=v,v")
> (vec_select:V4DF
> (vec_concat:V8DF
> - (match_operand:V4DF 1 "nonimmediate_operand" "m")
> + (match_operand:V4DF 1 "nonimmediate_operand" "v,m")
> (match_dup 1))
> (parallel [(const_int 0) (const_int 4)
> (const_int 2) (const_int 6)])))]
> "TARGET_AVX && <mask_avx512vl_condition>"
> - "vmovddup\t{%1, %0<mask_operand2>|%0<mask_operand2>, %1}"
> - [(set_attr "type" "ssemov")
> + "@
> +
> vunpcklpd\t{%1, %1, %0<mask_operand2>|%0<mask_operand2>, %1, %1}
> + vmovddup\t{%1, %0<mask_operand2>|%0<mask_operand2>, %1}"
> + [(set_attr "type" "sselog1,ssemov")
> (set_attr "prefix" "<mask_prefix>")
> (set_attr "mode" "V4DF")])
>
> diff --git a/gcc/testsuite/gcc.target/i386/avx512-movedup.c
> b/gcc/testsuite/gcc.target/i386/avx512-movedup.c
> new file mode 100644
> index 00000000000..3b2943bb67d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/avx512-movedup.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -mavx512f" } */
> +/* { dg-final { scan-assembler "vunpcklpd\[ \\t\]+%zmm\[0-9\]+,
> +%zmm\[0-9\]+" } } */
> +/* { dg-final { scan-assembler "vunpcklpd\[ \\t\]+%ymm\[0-9\]+,
> +%ymm\[0-9\]+" } } */
> +/* { dg-final { scan-assembler "vmovddup\[ \\t\]+\\(" } } */
> +/* { dg-final { scan-assembler-not "vmovddup\[^\\n\]*\\(%\[er\]sp\\)" }
> +} */
> +
> +#include <immintrin.h>
> +
> +__m512d dup512 (__m512d x) { return _mm512_movedup_pd (x); }
> __m256d
> +dup256 (__m256d x) { return _mm256_movedup_pd (x); } __m512d
> +interleave512 (__m512d x) { return _mm512_unpacklo_pd (x, x); } __m256d
> +interleave256 (__m256d x) { return _mm256_unpacklo_pd (x, x); } __m512d
> +load512 (double *p) { return _mm512_movedup_pd (_mm512_loadu_pd
> (p)); }
> --
> 2.34.1