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