https://gcc.gnu.org/g:6b1ffdc831718b1e7639d25c37ea1cdef48e1b53
commit r17-4566-g6b1ffdc831718b1e7639d25c37ea1cdef48e1b53 Author: Roger Sayle <[email protected]> Date: Tue Sep 22 15:57:40 2026 +0100 x86_64: Improved 128-bit TImode moves from SSE to GPRs with SSE2. This patch improves TImode moves on x86_64 between SSE and general registers with SSE2. This is a partial solution for PR target/114544. Consider the following simple function: typedef __int128 v1ti __attribute__((vector_size(16))); __int128 foo(v1ti x) { return x[0]; } Currently, with default -O2 (-msse2) the 128-bit value is moved via the stack: foo: movaps %xmm0, -24(%rsp) // 5 bytes movq -24(%rsp), %rax // 5 bytes movq -16(%rsp), %rdx // 5 bytes ret Though with -O2 -msse4.1, the transfers can be done directly. foo: movq %xmm0, %rax pextrq $1, %xmm0, %rdx ret With this patch, we make use of SSE2's shuffle functionality to avoid the transfers to and from memory: foo: movq %xmm0, %rax // 5 bytes shufpd $1, %xmm0, %xmm0 // 5 bytes movq %xmm0, %rdx // 5 bytes ret Technically, to avoid using a second register we swap/rotate the high and low lanes between movq instructions, and (not shown above) also swap/rotate the lanes back again (so the source register remains unchanged if the value is still live). This second (restoring) shufpd is eliminated by later RTL passes if it's discovered to be dead code. To make this possible, the Yd constraint that enables allows *movti_internal to match on SSE4_1, is tweaked to form a new YD constraint that allows *movti_internal to match on SSE2. 2026-09-22 Roger Sayle <[email protected]> Hongtao Liu <[email protected]> gcc/ChangeLog PR target/114544 * config/i386/constraints.md (YD): New constraint, like Yd but allows SSE_REGS on TARGET_SSE2. * config/i386/i386.cc (inline_secondary_memory_needed): Update that TImode moves to GENERAL_REGS don't need to use memory. * config/i386/i386.md (*movti_internal): Change Yd constraint to YD. (define_split): On TARGET_64BIT && TARGET_SSE2 && !TARGET_SSE4_1, split *movti_internal into movq+shufpd+movq+shufpd. gcc/testsuite/ChangeLog * gcc.target/i386/pr126293-15.c: Update test case. * gcc.target/i386/pr126293-5.c: Likewise. Diff: --- gcc/config/i386/constraints.md | 6 ++++++ gcc/config/i386/i386.cc | 5 +++++ gcc/config/i386/i386.md | 18 +++++++++++++++++- gcc/testsuite/gcc.target/i386/pr126293-15.c | 6 +++--- gcc/testsuite/gcc.target/i386/pr126293-5.c | 6 +++--- 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md index e7dec9cc0c0d..af7ebb7670b6 100644 --- a/gcc/config/i386/constraints.md +++ b/gcc/config/i386/constraints.md @@ -98,6 +98,8 @@ ;; z First SSE register. ;; d any EVEX encodable SSE register for AVX512DQ target or ;; any SSE register for SSE4_1 target. +;; D any EVEX encodable SSE register for AVX512DQ target or +;; any SSE register for SSE2 target. ;; p Integer register when TARGET_PARTIAL_REG_STALL is disabled ;; a Integer register when zero extensions with AND are disabled ;; b Any register that can be used as the GOT base when calling @@ -121,6 +123,10 @@ "TARGET_AVX512DQ ? ALL_SSE_REGS : TARGET_SSE4_1 ? SSE_REGS : NO_REGS" "@internal Any EVEX encodable SSE register (@code{%xmm0-%xmm31}) for AVX512DQ target or any SSE register for SSE4_1 target.") +(define_register_constraint "YD" + "TARGET_AVX512DQ ? ALL_SSE_REGS : TARGET_SSE2 ? SSE_REGS : NO_REGS" + "@internal Any EVEX encodable SSE register (@code{%xmm0-%xmm31}) for AVX512DQ target or any SSE register for SSE2 target.") + (define_register_constraint "Yp" "TARGET_PARTIAL_REG_STALL ? NO_REGS : GENERAL_REGS" "@internal Any integer register when TARGET_PARTIAL_REG_STALL is disabled.") diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 915a2d8385df..705ebb6c014c 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -21436,6 +21436,11 @@ inline_secondary_memory_needed (machine_mode mode, reg_class_t class1, && (TARGET_64BIT ? mode == TImode : mode == DImode)) return false; + /* Moves from SSE_REGS to GENERAL_REGS need only SSE2: + *movti_internal splits them into movq + shufpd + movq. */ + if (TARGET_64BIT && mode == TImode && SSE_CLASS_P (class1)) + return false; + int msize = GET_MODE_SIZE (mode); /* Between SSE and general, we have moves no larger than word size. */ diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 9888644ed91c..0d4749e6e091 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -2553,7 +2553,7 @@ (define_insn "*movti_internal" [(set (match_operand:TI 0 "nonimmediate_operand" "=!r ,o ,v,v ,v ,m,?jc,?Yd") - (match_operand:TI 1 "general_operand" "riFo,re,C,BC,vm,v,Yd,jc"))] + (match_operand:TI 1 "general_operand" "riFo,re,C,BC,vm,v,YD,jc"))] "(TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))) || (TARGET_SSE @@ -2831,6 +2831,22 @@ gen_lowpart (<MODE>mode, operands[1])); }) +(define_split + [(set (match_operand:TI 0 "general_reg_operand") + (match_operand:TI 1 "sse_reg_operand"))] + "TARGET_64BIT && TARGET_SSE2 && !TARGET_SSE4_1 + && reload_completed" + [(const_int 0)] +{ + rtx lo = gen_lowpart (DImode, operands[1]); + rtx tmp = gen_rtx_REG (V2DImode, REGNO (operands[1])); + emit_move_insn (gen_lowpart (DImode, operands[0]), lo); + emit_insn (gen_sse2_shufpd_v2di (tmp, tmp, tmp, const1_rtx, GEN_INT (2))); + emit_move_insn (gen_highpart (DImode, operands[0]), lo); + emit_insn (gen_sse2_shufpd_v2di (tmp, tmp, tmp, const1_rtx, GEN_INT (2))); + DONE; +}) + (define_split [(set (match_operand:DWI 0 "nonimmediate_gr_operand") (match_operand:DWI 1 "general_gr_operand"))] diff --git a/gcc/testsuite/gcc.target/i386/pr126293-15.c b/gcc/testsuite/gcc.target/i386/pr126293-15.c index 058e432058d8..b791a7aa2c75 100644 --- a/gcc/testsuite/gcc.target/i386/pr126293-15.c +++ b/gcc/testsuite/gcc.target/i386/pr126293-15.c @@ -8,9 +8,9 @@ **.LFB0: ** .cfi_startproc ** movdqa load\(%rip\), %xmm0 -** movaps %xmm0, -24\(%rsp\) -** movq -24\(%rsp\), %rax -** movq -16\(%rsp\), %rdx +** movq %xmm0, %rax +** shufpd \$1, %xmm0, %xmm0 +** movq %xmm0, %rdx ** ret ** .cfi_endproc **... diff --git a/gcc/testsuite/gcc.target/i386/pr126293-5.c b/gcc/testsuite/gcc.target/i386/pr126293-5.c index 2f0794132c9b..f5e4a57ed28b 100644 --- a/gcc/testsuite/gcc.target/i386/pr126293-5.c +++ b/gcc/testsuite/gcc.target/i386/pr126293-5.c @@ -8,9 +8,9 @@ **.LFB0: ** .cfi_startproc ** movdqa load\(%rip\), %xmm0 -** movaps %xmm0, -24\(%rsp\) -** movq -24\(%rsp\), %rax -** movq -16\(%rsp\), %rdx +** movq %xmm0, %rax +** shufpd \$1, %xmm0, %xmm0 +** movq %xmm0, %rdx ** ret ** .cfi_endproc **...
