On Sun, Aug 2, 2026 at 11:06 AM H.J. Lu <[email protected]> wrote:
>
> On Wed, Jul 22, 2026 at 4:05 PM Hongtao Liu <[email protected]> wrote:
> >
> > On Tue, Jul 21, 2026 at 5:11 PM Roger Sayle <[email protected]>
> > wrote:
> > >
> > >
> > > This patch is a reorganization of x86's vector initialization (vec_init)
> > > functionality to generate more efficient implementations in most/many
> > > cases. Previously, for most (128-bit and 256-bit) vectors types,
> > > i386-expand.cc made use of "concat" recursion to divide-and-conquor;
> > > splitting each vector into upper and lower halves, initializing them,
> > > then concatenating the results together. Simple and orthogonal, but
> > > alas inefficient. This idiom is unable to take advantage of SSE's
> > > zero extension semantics, shuffle/permutation instructions, byte-level
> > > shifts, element insertion instructions nor vector-mode logic operations.
> > > Unfortunately the reality is that these ISAs are irregular, as are the
> > > patterns provided by the backend expose their instructions (which are
> > > often available in one mode but not another).
> > >
> > > The patch below recognizes/accepts these asymmetries, and provides
> > > "custom" vector initialization functions for most 128-bit and 256-bit
> > > vector modes. There are too many optimization/improvements to list
> > > them all, but some examples are given below:
> > >
> > > v4si f1(int x, int y) { return (v4si){x,y,0,0}; }
> > >
> > > Before with -O2:
> > > f1_old: movd %edi, %xmm0
> > > movd %esi, %xmm1
> > > punpckldq %xmm1, %xmm0
> > > movq %xmm0, %xmm0
> > > ret
> > >
> > > After with -O2:
> > > f1_new: movd %edi, %xmm0
> > > movd %esi, %xmm1
> > > punpckldq %xmm1, %xmm0
> > > ret
> > >
> > > v4si f2(int x) { return (v4si){0,x,x,0}; }
> > >
> > > Before with -O2:
> > > f2_old: movd %edi, %xmm2
> > > pxor %xmm0, %xmm0
> > > movd %edi, %xmm1
> > > punpckldq %xmm2, %xmm0
> > > punpcklqdq %xmm1, %xmm0
> > > ret
> > >
> > > f2_new: movd %edi, %xmm0
> > > shufps $65, %xmm0, %xmm0
> > > ret
> > >
> > > v4si f3(int x) { return (v4si){x,1,x,2}; }
> > >
> > > Before with -O2:
> > > f3_old: movl $2, %eax
> > > movd %edi, %xmm0
> > > movd %eax, %xmm2
> > > movl $1, %eax
> > > movdqa %xmm0, %xmm1
> > > movd %eax, %xmm3
> > > punpckldq %xmm2, %xmm1
> > > punpckldq %xmm3, %xmm0
> > > punpcklqdq %xmm1, %xmm0
> > > ret
> > >
> > > After with -O2:
> > > f3_new: movd %edi, %xmm0
> > > shufps $68, %xmm0, %xmm0
> > > por .LC0(%rip), %xmm0
> > > ret
> > >
> > > v16qi f4(char x) { return (v16qi){x,0,0,0,0,0,0,0,0,x,0,0,0,0,0,0}; }
> > >
> > > Before with -O2 -mavx2:
> > > f4_old: vmovd %edi, %xmm0
> > > xorl %eax, %eax
> > > vpxor %xmm1, %xmm1, %xmm1
> > > vpinsrb $1, %eax, %xmm0, %xmm0
> > > vpinsrb $1, %edi, %xmm1, %xmm1
> > > vpmovzxwd %xmm0, %xmm0
> > > vpmovzxwd %xmm1, %xmm1
> > > vpmovzxdq %xmm1, %xmm1
> > > vpmovzxdq %xmm0, %xmm0
> > > vpunpcklqdq %xmm1, %xmm0, %xmm0
> > > ret
> > >
> > > After with -O2 -mavx2:
> > > f4_new: movzbl %dil, %eax
> > > vmovd %eax, %xmm0
> > > vpinsrb $9, %edi, %xmm0, %xmm0
> > > ret
> > >
> > > Unfortunately, despite all of the goodness there remains one testsuite
> > > regression: avx512vl-concatv4si-1.c whose f2 function currently expects
> > > 3 instructions before the return:
> > >
> > > orig: vmovd (%rdi), %xmm2
> > > vpinsrd $1, 4(%rdi), %xmm2, %xmm1
> > > vpunpcklqdq %xmm1, %xmm0, %xmm16
> > > ret
> > >
> > > where actually an optimal implementation should require only two:
> > >
> > > ideal: vpinsrd $2, (%rdi), %xmm0, %xmm0
> > > vpinsrd $3, 4(%rdi), %xmm0, %xmm0
> > > ret
> > >
> > > but unfortunately with this patch we currently (for now) generate:
> > >
> > > curr: vmovd %xmm0, %eax
> > > vpextrd $1, %xmm0, %edx
> > > vmovd %eax, %xmm0
> > > vpinsrd $1, %edx, %xmm0, %xmm0
> > > vpinsrd $2, (%rdi), %xmm0, %xmm0
> > > vpinsrd $3, 4(%rdi), %xmm0, %xmm0
> > > vmovdqa32 %xmm0, %xmm16
> > > ret
> > >
> > > which actually contains our two optimal instructions, but between
> > > combine, simplify-rtx and sse.md's define_insn_and_splits, we fail
> > > to notice that the remaining operations (converting V2SI to V4SI)
> > > are a no-op. I beg the reviewers'/maintainers' indulgence to allow
> > > this to FAIL for the time being, to be solved in a follow-up patch.
> > > This current patch is large enough already, and this remaining quirk
> > > needs to be resolved outside the RTL expansion pass, in the later
> > > RTL optimizers (where it is currently a missed optimization).
> > >
> >
> >
> > + else if (TARGET_SSE2)
> > + {
> > + rtx tmp2 = gen_reg_rtx (V2DImode);
> > + emit_move_insn (tmp2, gen_lowpart (V2DImode, tmp));
> > + emit_insn (gen_vec_shl_v2di (target, tmp, GEN_INT (64)));
> >
> > Looks like a typo, should be tmp2 instead of tmp?
> >
> > + case E_V2DFmode:
> > + if (!REG_P (var) || !MEM_P (var))
> > + var = force_reg (DFmode, var);
> > + x = gen_rtx_VEC_CONCAT (V2DFmode, var, CONST0_RTX (DFmode));
> > + if (!one_var)
> > + emit_insn (gen_rtx_SET (target, x));
> > + else if (TARGET_SSE2)
> > + {
> > + tmp = gen_reg_rtx (V2DFmode);
> > + emit_insn (gen_rtx_SET (tmp, x));
> > + emit_insn (gen_vec_shl_v2df (target, tmp, GEN_INT (64)));
> > + }
> > + else
> > + {
> > + rtx tmp1 = gen_reg_rtx (V2DFmode);
> > + emit_insn (gen_rtx_SET (tmp1, x));
> > + rtx tmp2 = gen_reg_rtx (V4SImode);
> > + emit_move_insn (tmp2, gen_lowpart (V4SImode, tmp1));
> > + emit_insn (gen_sse_shufps_v4si (tmp2, tmp2, tmp2,
> > + GEN_INT (2), GEN_INT (3),
> > + GEN_INT (4), GEN_INT (5)));
> > + emit_move_insn (target, gen_lowpart (V2DFmode, tmp2));
> > + }
> >
> > vec_initv2df is guarded under TARGET_SSE2, so I think the else part is
> > redundant.
> >
> > +static int
> > +nonzero_int_const_count (rtx *ops, int n)
> > +{
> > + int result = 0;
> > + int i;
> > + for (i = 0; i < n; i++)
> > + if (CONST_INT_P (ops[i]) && ops[i] != const0_rtx) ---- here
> > check CONST_INT_P (ops[i])
> > + result++;
> > + return result;
> > +}
> >
> > ...
> > + else if (nonzero_int_const_count (ops, 4) >= 2)
> > + {
> > + rtx csts[4];
> > + int i;
> > + for (i = 0; i < 4; i++)
> > + if (CONST_DOUBLE_P (ops[i])) ---- here check
> > CONST_DOUBLE_P (ops[i]))
> > + {
> > + csts[i] = ops[i];
> > + vars[i] = CONST0_RTX (SFmode);
> > + }
> > + else
> > + {
> > + csts[i] = CONST0_RTX (SFmode);
> > + vars[i] = ops[i];
> > + }
> >
> > nonzero_int_const_count check CONST_INT_P, but in the float cases, it
> > should be CONST_DOUBLE_P? it's always 0 the float helpers(v4sf/v8f)?
> >
> >
> > + case E_V4DImode:
> > + if (TARGET_AVX2 && (TARGET_64BIT || MEM_P (var)))
> > + {
> > + if (!REG_P (var) || !MEM_P (var))
> > + var = force_reg (DImode, var);
> >
> > !REG_P (var) && !MEM_P (var)?
> >
> > + case E_V4DFmode:
> > + if (TARGET_AVX2)
> > + {
> > + if (!REG_P (var) || !MEM_P (var))
> > + var = force_reg (DFmode, var);
> > Ditto
> >
> > + return true;
> > + case E_V2DFmode:
> > + if (!REG_P (var) || !MEM_P (var))
> > + var = force_reg (DFmode, var);
> > + x = gen_rtx_VEC_CONCAT (V2DFmode, var, CONST0_RTX (DFmode));
> > Ditto.
> >
> > + if (TARGET_64BIT || MEM_P (var))
> > + {
> > + if (!REG_P (var) || !MEM_P (var))
> > + var = force_reg (DImode, var);
> > + x = gen_rtx_VEC_CONCAT (V2DImode, var, CONST0_RTX (DImode));
> > Ditto.
> >
> > +/* Helper function. Determine if the given OPS array of size N
> > + contains only zeros and one other value (possible repeated).
> > + If TRUE, *VAR returns the value, PERM[i] contains 0 for for
> >
> > Double *for* in the comments.
> >
> > +/* Helper function. Determine if the given OPS array of size N
> > + contains only zeros and two other values (possible repeated).
> > + If TRUE, VARS returns the values, PERM[i] contains 0 for for
> >
> > Ditto.
> >
> > Could you also add some testcases to cover your changes, it can be in
> > a separate commit.
> >
>
> With
>
> commit f0bd50e831792692ffcedf288b312167a9339260
> Author: Roger Sayle <[email protected]>
> Date: Sat Aug 1 17:51:02 2026 +0100
>
> x86 SSE: Improved vector initialization/construction.
>
> I got
>
> FAIL: gcc.target/i386/sse-init-v2df-1.c scan-assembler-times movq 10
I don't see how movq can be generated with only SSE.
> I also got
>
> FAIL: gcc.target/i386/sse2-init-v2df-1.c scan-assembler-times movsd 2
> FAIL: gcc.target/i386/sse2-init-v2df-1.c scan-assembler-times unpcklpd 3
> FAIL: gcc.target/i386/sse2-init-v2df-2.c scan-assembler-times movsd 3
> FAIL: gcc.target/i386/sse2-init-v2df-2.c scan-assembler-times unpcklpd 2
> FAIL: gcc.target/i386/sse2-init-v2di-3.c scan-assembler-times movq 9
> FAIL: gcc.target/i386/sse2-init-v2di-3.c scan-assembler-times punpcklqdq 3
> FAIL: gcc.target/i386/sse2-init-v2di-4.c scan-assembler-times movd 4
> FAIL: gcc.target/i386/sse2-init-v2di-4.c scan-assembler-times movq 6
> FAIL: gcc.target/i386/sse2-init-v2di-4.c scan-assembler-times punpcklqdq 2
Here is the patch to fix these failures.
> with
>
> $ make check-gcc RUNTESTFLAGS="--target_board='unix{-m32\
> -march=x86-64-v2,-march=x86-64-v2}' i386.exp=sse2-init-*.c"
>
>
> --
> H.J.
--
H.J.
---
commit f0bd50e831792692ffcedf288b312167a9339260
Author: Roger Sayle <[email protected]>
Date: Sat Aug 1 17:51:02 2026 +0100
x86 SSE: Improved vector initialization/construction.
improved vector initialization/construction. But some tests failed with
SSE3. For expample, with SSE3, we generate better codes:
fmm:
movddup m(%rip), %xmm0
ret
than with SSE2:
fmm:
movsd m(%rip), %xmm0
unpcklpd %xmm0, %xmm0
ret
for fmm in gcc.target/i386/sse2-init-v2df-1.c. Replace -mno-sse4.1 with
-mno-sse3 to disable SSE3 in these tests.
* gcc.target/i386/sse2-init-v2df-1.c: Replace -mno-sse4.1 with
-mno-sse3.
* gcc.target/i386/sse2-init-v2df-2.c: Likewise.
* gcc.target/i386/sse2-init-v2di-1.c: Likewise.
* gcc.target/i386/sse2-init-v2di-2.c: Likewise.
From 390049f52db616393244f2aa893276b0e54428c3 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <[email protected]>
Date: Sun, 2 Aug 2026 11:42:24 +0800
Subject: [PATCH] x86: Replace -mno-sse4.1 with -mno-sse3 in commit f0bd50e8317
tests
commit f0bd50e831792692ffcedf288b312167a9339260
Author: Roger Sayle <[email protected]>
Date: Sat Aug 1 17:51:02 2026 +0100
x86 SSE: Improved vector initialization/construction.
improved vector initialization/construction. But some tests failed with
SSE3. For expample, with SSE3, we generate better codes:
fmm:
movddup m(%rip), %xmm0
ret
than with SSE2:
fmm:
movsd m(%rip), %xmm0
unpcklpd %xmm0, %xmm0
ret
for fmm in gcc.target/i386/sse2-init-v2df-1.c. Replace -mno-sse4.1 with
-mno-sse3 to disable SSE3 in these tests.
* gcc.target/i386/sse2-init-v2df-1.c: Replace -mno-sse4.1 with
-mno-sse3.
* gcc.target/i386/sse2-init-v2df-2.c: Likewise.
* gcc.target/i386/sse2-init-v2di-1.c: Likewise.
* gcc.target/i386/sse2-init-v2di-2.c: Likewise.
Signed-off-by: H.J. Lu <[email protected]>
---
gcc/testsuite/gcc.target/i386/sse2-init-v2df-1.c | 2 +-
gcc/testsuite/gcc.target/i386/sse2-init-v2df-2.c | 2 +-
gcc/testsuite/gcc.target/i386/sse2-init-v2di-3.c | 2 +-
gcc/testsuite/gcc.target/i386/sse2-init-v2di-4.c | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/gcc/testsuite/gcc.target/i386/sse2-init-v2df-1.c b/gcc/testsuite/gcc.target/i386/sse2-init-v2df-1.c
index d73a32e9e88..293d7db2d09 100644
--- a/gcc/testsuite/gcc.target/i386/sse2-init-v2df-1.c
+++ b/gcc/testsuite/gcc.target/i386/sse2-init-v2df-1.c
@@ -1,5 +1,5 @@
/* { dg-do compile { target { ! ia32 } } } */
-/* { dg-options "-O2 -msse2 -mno-sse4.1" } */
+/* { dg-options "-O2 -msse2 -mno-sse3" } */
typedef double v2df __attribute__ ((__vector_size__ (16)));
diff --git a/gcc/testsuite/gcc.target/i386/sse2-init-v2df-2.c b/gcc/testsuite/gcc.target/i386/sse2-init-v2df-2.c
index 2e091eeabf6..3f58098af8d 100644
--- a/gcc/testsuite/gcc.target/i386/sse2-init-v2df-2.c
+++ b/gcc/testsuite/gcc.target/i386/sse2-init-v2df-2.c
@@ -1,5 +1,5 @@
/* { dg-do compile { target ia32 } } */
-/* { dg-options "-O2 -msse2 -mno-sse4.1" } */
+/* { dg-options "-O2 -msse2 -mno-sse3" } */
typedef double v2df __attribute__ ((__vector_size__ (16)));
diff --git a/gcc/testsuite/gcc.target/i386/sse2-init-v2di-3.c b/gcc/testsuite/gcc.target/i386/sse2-init-v2di-3.c
index b054daad119..15c6b9c4d63 100644
--- a/gcc/testsuite/gcc.target/i386/sse2-init-v2di-3.c
+++ b/gcc/testsuite/gcc.target/i386/sse2-init-v2di-3.c
@@ -1,5 +1,5 @@
/* { dg-do compile { target { ! ia32 } } } */
-/* { dg-options "-O2 -msse2 -mno-sse4.1" } */
+/* { dg-options "-O2 -msse2 -mno-sse3" } */
typedef long long v2di __attribute__ ((__vector_size__ (16)));
diff --git a/gcc/testsuite/gcc.target/i386/sse2-init-v2di-4.c b/gcc/testsuite/gcc.target/i386/sse2-init-v2di-4.c
index 272b6b23039..133115ab4f8 100644
--- a/gcc/testsuite/gcc.target/i386/sse2-init-v2di-4.c
+++ b/gcc/testsuite/gcc.target/i386/sse2-init-v2di-4.c
@@ -1,5 +1,5 @@
/* { dg-do compile { target ia32 } } */
-/* { dg-options "-O2 -msse2 -mno-sse4.1" } */
+/* { dg-options "-O2 -msse2 -mno-sse3" } */
typedef long long v2di __attribute__ ((__vector_size__ (16)));
--
2.55.0