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)); }
