https://gcc.gnu.org/g:dbc6b5266eb17638ca1d5b22ab35364e0b2e0d48

commit r17-1768-gdbc6b5266eb17638ca1d5b22ab35364e0b2e0d48
Author: Sarvesh Chandra <[email protected]>
Date:   Tue Jun 23 12:20:01 2026 +0530

    i386: Emit vunpcklpd for register V4DF/V8DF movddup [PR107057]
    
    The avx512f_movddup512 and avx_movddup256 patterns only accepted a
    memory source operand, so an even-lane duplicate of a value already in
    a register forced that register to be spilled to the stack and
    reloaded with vmovddup.
    
    Add a register source alternative that emits vunpcklpd, which performs
    the same even-lane interleave directly on a register operand.  A
    genuine memory source still selects vmovddup.
    
    The register alternative duplicates a single source operand
    (vunpcklpd %1, %1, %0), so it is typed sselog1, the single-source SSE
    logical type, while the memory alternative keeps ssemov.
    
    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]>

Diff:
---
 gcc/config/i386/sse.md                         | 20 ++++++++++++--------
 gcc/testsuite/gcc.target/i386/avx512-movedup.c | 14 ++++++++++++++
 2 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index 531d35175fc2..bb150f6b5f92 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -13810,18 +13810,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")])
 
@@ -13843,16 +13845,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 000000000000..3b2943bb67de
--- /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)); }

Reply via email to