https://gcc.gnu.org/g:ae80ad655d514d7c275b21f5d1ad155793ae4cc0

commit r17-1923-gae80ad655d514d7c275b21f5d1ad155793ae4cc0
Author: Roger Sayle <[email protected]>
Date:   Fri Jun 26 16:20:05 2026 +0100

    i386: ix86_expand_sse_movcc improvements
    
    This patch implements Alexander Monakov's suggestion from PR 123238.
    Traditionally, the x86_64 backend implements VCOND_MASK using a three
    instruction sequence of pand, pandn and por (requiring three registers),
    however when op_true and op_false are both constant vectors, this can
    be done using just two instructions, pand and pxor (requiring only two
    registers).  This requires delaying forcing const_vector operands to
    memory (the constant pool) as late as possible, including changing the
    predicates on the define_expand patterns that call ix86_expand_sse_movcc
    to (consistently) accept vector_or_const_vector_operand.
    
    void f(char c[])
    {
        for (int i = 0; i < 8; i++)
            c[i] = c[i] ? 'a' : 'c';
    }
    
    Before with -O2 (12 instructions):
    f:      movq    (%rdi), %xmm0
            pxor    %xmm1, %xmm1
            movabsq $7016996765293437281, %rdx  // {'a','a','a'...}
            movabsq $7161677110969590627, %rax  // {'c','c','c'...}
            movq    %rdx, %xmm2
            pcmpeqb %xmm1, %xmm0
            movq    %rax, %xmm1
            pand    %xmm0, %xmm1
            pandn   %xmm2, %xmm0
            por     %xmm1, %xmm0
            movq    %xmm0, (%rdi)
            ret
    
    After with -O2 (11 instructions):
    f:      movq    (%rdi), %xmm0
            pxor    %xmm1, %xmm1
            movabsq $144680345676153346, %rdx  // {2,2,2...}
            movabsq $7016996765293437281, %rax  // {'a','a','a'...}
            pcmpeqb %xmm1, %xmm0
            movq    %rdx, %xmm1
            pand    %xmm1, %xmm0
            movq    %rax, %xmm1
            pxor    %xmm1, %xmm0
            movq    %xmm0, (%rdi)
            ret
    
    2026-06-26  Roger Sayle  <[email protected]>
                Hongtao Liu  <[email protected]>
    
    gcc/ChangeLog
            PR target/123238
            * config/i386/i386-expand.cc: Delay calling force_reg on
            op_true and op_false.  Generate an AND then XOR sequence
            if op_true and op_false are both CONST_VECTOR_P.
            * config/i386/mmx.md (vcond_mask_<mode>v4hi): Allow operands
            1 and 2 to be vector_or_const_vector_operand.
            (vcond_mask_<mode>v2hi): Likewise.
            (vcond_mask_<mode><mmxintvecmodelower>): Likewise.
            (vcond_mask_<mode><mode>): Likewise.
            * config/i386/sse.md (vcond_mask_<mode><sseintvecmodelower>):
            Likewise.
            (vcond_mask_<mode><sseintvecmodelower>): Likewise.
            (vcond_mask_v1tiv1ti): Likewise.
            (vcond_mask_<mode><sseintvecmodelower>): Likewise.
            (vcond_mask_<mode><sseintvecmodelower>): Likewise.
            * config/i386/predicates.md (vector_or_0_or_1s_operand): Delete
            predicate with no remaining uses.
    
    gcc/testsuite/ChangeLog
            PR target/123238
            * gcc.target/i386/pr123238-2.c: New test case.

Diff:
---
 gcc/config/i386/i386-expand.cc             | 30 +++++++++++++++++++-----------
 gcc/config/i386/mmx.md                     | 16 ++++++++--------
 gcc/config/i386/predicates.md              |  8 --------
 gcc/config/i386/sse.md                     | 20 ++++++++++----------
 gcc/testsuite/gcc.target/i386/pr123238-2.c | 10 ++++++++++
 5 files changed, 47 insertions(+), 37 deletions(-)

diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index 99b6343106a1..8e7b90c9744c 100644
--- a/gcc/config/i386/i386-expand.cc
+++ b/gcc/config/i386/i386-expand.cc
@@ -4462,12 +4462,6 @@ ix86_expand_sse_movcc (rtx dest, rtx cmp, rtx op_true, 
rtx op_false)
   rtx (*gen) (rtx, rtx, rtx, rtx) = NULL;
   machine_mode blend_mode = mode;
 
-  if (GET_MODE_SIZE (mode) < 16
-      || !vector_operand (op_true, mode))
-    op_true = force_reg (mode, op_true);
-
-  op_false = force_reg (mode, op_false);
-
   switch (mode)
     {
     case E_V2SFmode:
@@ -4580,6 +4574,11 @@ ix86_expand_sse_movcc (rtx dest, rtx cmp, rtx op_true, 
rtx op_false)
 
   if (gen != NULL)
     {
+      if (GET_MODE_SIZE (mode) < 16
+         || !vector_operand (op_true, mode))
+       op_true = force_reg (mode, op_true);
+      op_false = force_reg (mode, op_false);
+
       if (blend_mode == mode)
        x = dest;
       else
@@ -4595,15 +4594,24 @@ ix86_expand_sse_movcc (rtx dest, rtx cmp, rtx op_true, 
rtx op_false)
       if (x != dest)
        emit_move_insn (dest, gen_lowpart (mode, x));
     }
+  else if (CONST_VECTOR_P (op_true) && CONST_VECTOR_P (op_false))
+    {
+      rtx tmp = simplify_const_binary_operation (XOR, mode, op_true, op_false);
+      tmp = expand_simple_binop (mode, AND, cmp, tmp,
+                                NULL, 1, OPTAB_DIRECT);
+      tmp = expand_simple_binop (mode, XOR, tmp, op_false,
+                                dest, 1, OPTAB_DIRECT);
+      if (tmp != dest)
+       emit_move_insn (dest, tmp);
+    }
   else
     {
-      rtx t2, t3;
+      rtx t2 = expand_simple_binop (mode, AND, cmp, op_true,
+                                   NULL, 1, OPTAB_DIRECT);
 
-      t2 = expand_simple_binop (mode, AND, op_true, cmp,
-                               NULL, 1, OPTAB_DIRECT);
-
-      t3 = gen_reg_rtx (mode);
+      rtx t3 = gen_reg_rtx (mode);
       x = gen_rtx_NOT (mode, cmp);
+      op_false = force_reg (mode, op_false);
       ix86_emit_vec_binop (AND, mode, t3, x, op_false);
 
       x = expand_simple_binop (mode, IOR, t3, t2,
diff --git a/gcc/config/i386/mmx.md b/gcc/config/i386/mmx.md
index d747146776b8..f61335af0b9c 100644
--- a/gcc/config/i386/mmx.md
+++ b/gcc/config/i386/mmx.md
@@ -2313,8 +2313,8 @@
 (define_expand "vcond_mask_<mode>v4hi"
   [(set (match_operand:V4F_64 0 "register_operand")
        (vec_merge:V4F_64
-         (match_operand:V4F_64 1 "register_operand")
-         (match_operand:V4F_64 2 "register_operand")
+         (match_operand:V4F_64 1 "vector_or_const_vector_operand")
+         (match_operand:V4F_64 2 "vector_or_const_vector_operand")
          (match_operand:V4HI 3  "register_operand")))]
   "TARGET_MMX_WITH_SSE && TARGET_SSE4_1"
 {
@@ -2362,8 +2362,8 @@
 (define_expand "vcond_mask_<mode>v2hi"
   [(set (match_operand:V2F_32 0 "register_operand")
        (vec_merge:V2F_32
-         (match_operand:V2F_32 1 "register_operand")
-         (match_operand:V2F_32 2 "register_operand")
+         (match_operand:V2F_32 1 "vector_or_const_vector_operand")
+         (match_operand:V2F_32 2 "vector_or_const_vector_operand")
          (match_operand:V2HI 3 "register_operand")))]
   "TARGET_SSE4_1"
 {
@@ -4313,8 +4313,8 @@
 (define_expand "vcond_mask_<mode><mmxintvecmodelower>"
   [(set (match_operand:MMXMODE124 0 "register_operand")
        (vec_merge:MMXMODE124
-         (match_operand:MMXMODE124 1 "register_operand")
-         (match_operand:MMXMODE124 2 "register_operand")
+         (match_operand:MMXMODE124 1 "vector_or_const_vector_operand")
+         (match_operand:MMXMODE124 2 "vector_or_const_vector_operand")
          (match_operand:<mmxintvecmode> 3 "register_operand")))]
   "TARGET_MMX_WITH_SSE"
 {
@@ -4326,8 +4326,8 @@
 (define_expand "vcond_mask_<mode><mode>"
   [(set (match_operand:VI_16_32 0 "register_operand")
        (vec_merge:VI_16_32
-         (match_operand:VI_16_32 1 "register_operand")
-         (match_operand:VI_16_32 2 "register_operand")
+         (match_operand:VI_16_32 1 "vector_or_const_vector_operand")
+         (match_operand:VI_16_32 2 "vector_or_const_vector_operand")
          (match_operand:VI_16_32 3 "register_operand")))]
   "TARGET_SSE2"
 {
diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index 998a3eeac41a..6a2ced036044 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -1288,14 +1288,6 @@
        (match_operand 0 "vector_memory_operand")
        (match_code "const_vector")))
 
-; Return true when OP is register_operand, vector_memory_operand,
-; const_vector zero or const_vector all ones.
-(define_predicate "vector_or_0_or_1s_operand"
-  (ior (match_operand 0 "register_operand")
-       (match_operand 0 "vector_memory_operand")
-       (match_operand 0 "const0_operand")
-       (match_operand 0 "int_float_vector_all_ones_operand")))
-
 (define_predicate "bcst_mem_operand"
   (and (match_code "vec_duplicate")
        (and (match_test "TARGET_AVX512F")
diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index 3425baea3b62..7a0029ecedb4 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -5530,8 +5530,8 @@
 (define_expand "vcond_mask_<mode><sseintvecmodelower>"
   [(set (match_operand:VI_256_AVX2 0 "register_operand")
        (vec_merge:VI_256_AVX2
-         (match_operand:VI_256_AVX2 1 "nonimm_or_0_or_1s_operand")
-         (match_operand:VI_256_AVX2 2 "nonimm_or_0_operand")
+         (match_operand:VI_256_AVX2 1 "vector_or_const_vector_operand")
+         (match_operand:VI_256_AVX2 2 "vector_or_const_vector_operand")
          (match_operand:<sseintvecmode> 3 "register_operand")))]
   "TARGET_AVX"
 {
@@ -5543,8 +5543,8 @@
 (define_expand "vcond_mask_<mode><sseintvecmodelower>"
   [(set (match_operand:VI_128 0 "register_operand")
        (vec_merge:VI_128
-         (match_operand:VI_128 1 "vector_or_0_or_1s_operand")
-         (match_operand:VI_128 2 "nonimm_or_0_operand")
+         (match_operand:VI_128 1 "vector_or_const_vector_operand")
+         (match_operand:VI_128 2 "vector_or_const_vector_operand")
          (match_operand:<sseintvecmode> 3 "register_operand")))]
   "TARGET_SSE2"
 {
@@ -5556,8 +5556,8 @@
 (define_expand "vcond_mask_v1tiv1ti"
   [(set (match_operand:V1TI 0 "register_operand")
        (vec_merge:V1TI
-         (match_operand:V1TI 1 "vector_or_0_or_1s_operand")
-         (match_operand:V1TI 2 "nonimm_or_0_operand")
+         (match_operand:V1TI 1 "vector_or_const_vector_operand")
+         (match_operand:V1TI 2 "vector_or_const_vector_operand")
          (match_operand:V1TI 3 "register_operand")))]
   "TARGET_SSE2"
 {
@@ -5569,8 +5569,8 @@
 (define_expand "vcond_mask_<mode><sseintvecmodelower>"
   [(set (match_operand:VF_256 0 "register_operand")
        (vec_merge:VF_256
-         (match_operand:VF_256 1 "nonimm_or_0_or_1s_operand")
-         (match_operand:VF_256 2 "nonimm_or_0_operand")
+         (match_operand:VF_256 1 "vector_or_const_vector_operand")
+         (match_operand:VF_256 2 "vector_or_const_vector_operand")
          (match_operand:<sseintvecmode> 3 "register_operand")))]
   "TARGET_AVX"
 {
@@ -5582,8 +5582,8 @@
 (define_expand "vcond_mask_<mode><sseintvecmodelower>"
   [(set (match_operand:VF_128 0 "register_operand")
        (vec_merge:VF_128
-         (match_operand:VF_128 1 "vector_or_0_or_1s_operand")
-         (match_operand:VF_128 2 "nonimm_or_0_operand")
+         (match_operand:VF_128 1 "vector_or_const_vector_operand")
+         (match_operand:VF_128 2 "vector_or_const_vector_operand")
          (match_operand:<sseintvecmode> 3 "register_operand")))]
   "TARGET_SSE"
 {
diff --git a/gcc/testsuite/gcc.target/i386/pr123238-2.c 
b/gcc/testsuite/gcc.target/i386/pr123238-2.c
new file mode 100644
index 000000000000..6cf5b3e35c4d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr123238-2.c
@@ -0,0 +1,10 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2" } */
+
+void f(char c[])
+{
+    for (int i = 0; i < 8; i++)
+        c[i] = c[i] ? 'a' : 'c';
+}
+
+/* { dg-final { scan-assembler-not "pandn" } } */

Reply via email to