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.

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

Reply via email to