Re: [x86 SSE PATCH] PR target/126619: Improve V4SF vector initialization.

Hongtao Liu <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <CAMZc-bzwVxj_6ay4JLhKzYk0_YpdoWadHyrG2qw9YO8iH9xXpA@mail.gmail.com>
On Sun, Aug 9, 2026 at 6:42 PM Roger Sayle <[email protected]> wrote:
>
>
> This patch addresses PR target/126619, a performance regression caused by
> my recent update of SSE vector initialization on x86_64.  The new idiom
> attempts to benefit from the implicit zero extension provided by movss
> and movd, but this causes problems for (V4SF) cases were the (SFmode)
> value is already in a register.  Without newer extensions, GCC's approach
> to zero extension (i.e. vec_init of (V4SF){ x, 0, 0, 0 }) is to perform
> an interunit transfer to a general purpose integer register, and then
> transfer the value back again.  Inter-unit moves are expensive, especially
> on older microarchitectures.
>
> The problem is fixed in several ways.  The first is to tweak register
> preferencing in vec_set<mode>_0's define_insn, so that general registers
> are only used if the source/destination is already an integer GPR.
> This changes reload from generating (two instructions):
>
>         movd %xmm0, %eax
>         movd %eax, %xmm0
>
> to instead using:
>
>         pxor %xmm1, %xmm1
>         movss %xmm0, %xmm1
>         movaps %xmm1, %xmm0
>
> which requires 3 instructions, and 1 extra register, but requires
> no inter-unit moves.  This matches what clang/llvm does.
>
> However, it's possible to do better, borrowing an idiom from
> the middle-end's expansion of integer zero-extensions.
>
>         pslldq  $12, %xmm0
>         psrldq  $12, %xmm0
>
> uses two instructions, and doesn't require an extra register.
> Indeed, initializing the vector (V4SF){ 0, 0, 0, x } can be
> done in a single instruction, as it doesn't require a "right"
> shift.
>
> Additionally, for cases such as (V4SF){ a, b, c, d }, where
> there is no benefit from zero extension, we should continue
> using GCC's original CONCAT of V2SF idiom, avoiding any overhead
> of zero extension (Hongtao's suggestion in the Bugzilla PR).
>
> Additionally, there are some additional V4SF initialization
> tweaks.  When loading from memory, where zero extension is
> free "onevar_perm"s should construct { x, 0, 0, 0 } then
> perform a shuffle using shufps, but when the source is a
> register, it should construct { 0, 0, 0, x } (using the
> single shift instruction described above), and perform a
> modified shuffle using shufps from there.
>
> With TARGET_SSE4_1, the first insertps can be used to clear
> (initialize) all the other elements to zero, and the remaining
> non-zero elements can be inserted with regular insertps.
>
I think even with sse4.1 and above we should still use the original
ix86_expand_vector_concat solution since insertps have sequential
dependence with depth of 4, but vec_concat only with depth 2.
so the vector_concat solution should still be faster(including the
4-memory case), maybe for optimization for size, insertps is prefered.

>-  else
>+  else if (TARGET_SSE4_1)

So may just
 else if (TARGET_SSE4_1 && optimize_insn_for_size_p ())
  {
    ......
  }
else
  ix86_expand_vector_init_concat (V4SFmode, target, ops, 4);

>+    {
>+      int i;
>+      rtx tmp = gen_reg_rtx (V4SFmode);
>+      bool first_p = true;
>...
>+  else
>+    ix86_expand_vector_init_concat (V4SFmode, target, ops, 4);
>}

> ;; see comment above inline_secondary_memory_needed function in i386.cc
> (define_insn "vec_set<mode>_0"
>   [(set (match_operand:VI4F_128 0 "nonimmediate_operand"
>-          "=Yr,*x,v,v,v,v,x,x,v,Yr ,?x ,x  ,m ,m   ,m")
>+          "=Yr,*x,v,v,v,!v,x,x,v,Yr ,?x ,x  ,m ,m   ,m")
         (vec_merge:VI4F_128

Add *?* to the corresponding alternative *r* of operands[2] instead of
add *!* to *v* of operands[0]?
my experience is ?r is better to help LRA for register allocation choice.

>+;; Use sse4_1_insertps_v4s[if] to vector_init one non-zero value.
>+(define_insn "sse4_1_insertps_<mode>_init"
>+  [(set (match_operand:VI4F_128 0 "register_operand" "=Yr,*x,v")
>+        (vec_merge:VI4F_128
>+          (vec_duplicate:VI4F_128
>+            (match_operand:<ssescalarmode> 1 "nonimmediate_operand" "Yrjm,*xjm,vm")
>+          (match_operand:VI4F_128 2 "const0_operand")
>+          (match_operand:SI 3 "const248_operand")))]
>+  "TARGET_SSE4_1"
>+{
>+  int op3 = INTVAL (operands[3]);
>+  operands[3] = GEN_INT ((exact_log2 (op3) << 4) + (op3 ^ 15));
>+  switch (which_alternative)
>+    {
>+    case 0:
>+    case 1:
>+      return "insertps\t{%3, %1, %0|%0, %1, %3}";
>+    case 2:
>+      return "vinsertps\t{%3, %1, %0, %0|%0, %0, %1, %3}";

Split alternative 2 into v,m and use {%3, %1, %1, %0|%0, %1, %1, %3}
for alternative *v*, it can avoid false dependence for operands[0].
Also for the new *m* alternative, can we only enable it when not
preferred_for_speed since there's false dependence.
   (set (attr "preferred_for_speed")
    (cond [(eq_attr "alternative" "3")
             (symbol_ref "false")]
          (symbol_ref "true")))

>+    default:
>+      gcc_unreachable ();
>+    }

>+      if (TARGET_SSE4_1)
>+        {
>+          if (!REG_P (var) && !MEM_P (var))
>+            var = force_reg (SFmode, var);

-      rtx tmp1 = gen_reg_rtx (V4SFmode);
-      vars[0] = ops[0];
-      vars[1] = CONST0_RTX (SFmode);
-      vars[2] = CONST0_RTX (SFmode);
-      vars[3] = CONST0_RTX (SFmode);
-      ix86_expand_vector_init_v4sf (tmp1, vars);
+      if (TARGET_SSE4_1)
+        {
+          rtx tmp = gen_reg_rtx (V4SFmode);
+          rtx val = ops[0];
+          if (!REG_P (val) && !MEM_P (val))
+            val = force_reg (SFmode, val);
+          emit_insn (gen_vec_setv4sf_0 (tmp, CONST0_RTX (V4SFmode), val));
+          val = ops[1];
+          if (!REG_P (val) && !MEM_P (val))
+            val = force_reg (SFmode, val);
+          emit_insn (gen_vec_setv4sf_sse4_1 (target, tmp, val, GEN_INT (2)));
+        }

I think we can generate 1 insertps for {a,b,0,0} {a, 0, b,0}, {a, 0,
0, b}, here still generates 2 insertps,  maybe we can directy
gen_sse4_1_insertps_v4sf, use subreg to convert SFmode to V4SFmode?


BR,
Hongtao
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.