On Mon, Jul 20, 2026 at 6:37 AM Roger Sayle <[email protected]> wrote:
>
>
> This patch teaches the x86 backend that the SSE4.1 insertps instruction
> can be used/abused to clear one or more elements of a V4SI or V4SF vector
> in a single instruction (i.e. without requiring xor to clear a second
> register).
>
> Consider the test case
>
> typedef int v4si __attribute__ ((__vector_size__ (16)));
> v4si foo(v4si x) { x[2]=0; return x; }
>
> Currently with -O2 -mavx2, we generate:
>
> foo:    xorl    %eax, %eax
>         vpinsrd $2, %eax, %xmm0, %xmm0
>         ret
>
> with this patch we now generate:
>
> foo:    vinsertps       $4, %xmm0, %xmm0, %xmm0
>         ret
>
> For the more complicated example:
>
> v4si bar(v4si x) { x[1]=0; x[3]=0; return x; }
>
> previously, we'd generate:
>
> bar:    xorl    %eax, %eax
>         vpinsrd $1, %eax, %xmm0, %xmm0
>         vpinsrd $3, %eax, %xmm0, %xmm0
>         ret
>
> with this patch we now generate:
>
> bar:    vinsertps       $10, %xmm0, %xmm0, %xmm0
>         ret
>
>
> One improvement that I'll leave to an i386/SSE expert, is that setting
> elements 1, 2 and 3 [i.e. zero extending element 0] still falls back
> to the existing patterns (and tests for this are commented out in the
> new test cases).  Tweaking sse_movss_v4si to consider using insertps
> requires expertise in register preferencing and instruction attributes
> that I'm happy to leave to someone else.
BTW, AVX10.2 support vmovd xmm0, xmm0 to zero extend element 0.

>
> This patch has been tested on x86_64-pc-linux-gnu with make bootstrap
> and make -k check, both with and without --target_board=unix{-m32}
> with no new failures.  Ok for mainline?
>
>
> 2026-07-19  Roger Sayle  <[email protected]>
>
> gcc/ChangeLog
>         * config/i386/i386-expand.cc (ix86_expand_vec_set_builtin): Don't
>         force op1 to a register when it is CONST0_RTX (mode1).
>         (ix86_expand_vector_set_var): For now, force VAL to a register.
>         (ix86_expand_vector_set): If val is CONST0_RTX, expand using
>         the new sse4_1_insertps_v4s[if]_zero patterns on TARGET_SSE4_1.
>         Otherwise, force val to a register (restoring previous behaviour).
>         * config/i386/sse.md (sse4_1_insertps_<mode>_zero): New insn
>         with using vec_merge to select which elements to clear.
>         (*sse4_1_insertps_<mode>_zero): Likewise, a variant with the
>         const0_operand second, and operand3 selecting elements to preserve.

VEC_MERGE canonicalization prefers the register first and zero second,
complementing the mask (gcc/simplify-rtx.cc:7808).
The final RTL always matches the second *sse4_1_insertps_*_zero pattern.
So just keep one named pattern in canonical form:
 (vec_merge reg const0 preserve_mask)
 Then make ix86_expand_vector_set emit (~(1 << elt) & 15) as the preserve mask.


+  if (TARGET_SSE4_1 && mode == V4SImode && val == const0_rtx)
+    {
+      emit_insn (gen_sse4_1_insertps_v4si_zero (target, target,
+                                               CONST0_RTX (V4SImode),
+                                               GEN_INT ((1 << elt) ^ 15)));
+      return;
+    }
+  if (TARGET_SSE4_1 && mode == V4SFmode && val == CONST0_RTX (SFmode))
+    {
+      emit_insn (gen_sse4_1_insertps_v4sf_zero (target, target,
+                                               CONST0_RTX (V4SFmode),
+                                               GEN_INT ((1 << elt) ^ 15)));
+      return;
+    }
+
+  val = force_reg (GET_MODE_INNER (mode), val);
+

...

+;; Use sse4_1_insertps_v4s[if] to zero values in a vector.
+;; Operands[3] indicates which bits to preserve.
+(define_insn "sse4_1_insertps_<mode>_zero"
+  [(set (match_operand:VI4F_128 0 "register_operand" "=x,v")
+       (vec_merge:VI4F_128
+         (match_operand:VI4F_128 1 "register_operand" "0,v")
+         (match_operand:VI4F_128 2 "const0_operand")
+         (match_operand:SI 3 "const_0_to_15_operand")))]
+  "TARGET_SSE4_1
+   && IN_RANGE (INTVAL (operands[3]), 1, 14)"
+{
+  operands[3] = GEN_INT (INTVAL (operands[3]) ^ 15);
+  return "%vinsertps\t{%3, %d1, %0|%0, %d1, %3}";
+}
+  [(set_attr "isa" "noavx,avx")
+   (set_attr "type" "sselog")
+   (set_attr "prefix_data16" "1,*")
+   (set_attr "prefix_extra" "1")
+   (set_attr "length_immediate" "1")
+   (set_attr "prefix" "orig,maybe_evex")
+   (set_attr "mode" "V4SF")])


-- 
BR,
Hongtao

Reply via email to