https://gcc.gnu.org/g:0895e430b5e59e3ee18c4763c493ee05a0c363e8

commit r17-1974-g0895e430b5e59e3ee18c4763c493ee05a0c363e8
Author: Roger Sayle <[email protected]>
Date:   Mon Jun 29 14:07:08 2026 +0100

    PR target/94871: Simplify (not (eq x y)) as (ne x y) for vectors.
    
    This patch is my proposed fix for PR target/94871, a missed optimization
    for simplifying vector comparisons in the RTL optimizers (combine) that
    includes both middle-end and i386 backend changes.
    
    The testcase from the original bugzilla PR is:
    
    typedef long long int64_t;
    typedef signed char int8_t;
    
    typedef double v2df __attribute__((vector_size(16)));
    typedef int64_t v2di __attribute__((vector_size(16)));
    typedef int8_t v16qi __attribute__((vector_size(16)));
    
    inline v2di set1_epi8(int8_t a)
    {
        return (v2di)(v16qi){a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a};
    }
    
    v2di foo(v2df a, v2df b)
    {
        return ((v2di)__builtin_ia32_cmpeqpd(a, b) ^ set1_epi8(0xFF));
    }
    
    where GCC with -O2 currently generates:
    
    foo:    cmpeqpd %xmm1, %xmm0
            pcmpeqd %xmm1, %xmm1
            pxor    %xmm1, %xmm0
            ret
    
    where with this pair of changes, we instead generate:
    
    foo:    cmpneqpd        %xmm1, %xmm0
            ret
    
    Basically, the usual optimizations (not (eq x y)) -> (ne x y) and
    (not (ne x y)) -> (eq x y), but applied to vector mode comparisons
    (and in this case floating point vector comparisons).
    
    The first (i386 backend) part is to observe that the middle-end
    RTL optimizers enjoy canonicalizing floating point vector comparisons
    to return integer vector results.  Hence -fdump-rtl-combine-all
    contains the lines:
    
    Failed to match this instruction:
    (set (reg:V2DI 105)
        (eq:V2DI (reg:V2DF 106 [ aD.2972 ])
            (reg:V2DF 107 [ bD.2973 ])))
    
    Currently sse.md contains patterns for matching vector comparisons
    for comparing V2DFs returning a V2DF, but not the equivalent patterns
    for comparing V2DFs but returning a V2DI.  Very easily handled by
    cloning the existing define_insn but substituting <sseintvecmode> for
    the comparison result mode.
    
    The second (simplify-rtx.cc) part is to tweak the current
    (not (eq X Y)) -> (ne X Y) transformation in
    simplify_unary_operation_1 to allow/handle vector modes.
    In fact, this is a (latent) bug fix, as the current logic
    checks STORE_FLAG_VALUE even for modes where this isn't
    relevant.  The target's STORE_FLAG_VALUE is applicable for
    SCALAR_INT_MODE_P comparisons; VECTOR_STORE_FLAG_VALUE
    should be used for VECTOR integer modes.
    
    For symmetry, I've also added the equivalent optimization for
    targets with STORE_FLAG_VALUE == 1 or VECTOR_STORE_FLAG_VALUE
    == const1_rtx (such as aarch64), such that (not (neg (eq x y)))
    -> (neg (ne x y)).
    
    2026-06-29  Roger Sayle  <[email protected]>
    
    gcc/ChangeLog
            PR target/94871
            * simplify-rtx.cc (simplify_unary_operation_1) <case NOT>:
            Update (not (eq X Y)) -> (ne X Y) to support vector comparions
            using VECTOR_STORE_FLAG_VALUE, and check SCALAR_INT_MODE_P
            when checking STORE_FLAG_VALUE.  Add equivalent optimization
            (not (neg (eq X Y))) -> (neg (ne X Y)) for targets with
            STORE_FLAG_VALUE == 1 or VECTOR_STORE_FLAG_VALUE is const1_rtx.
    
            * config/i386/sse.md (*<sse>_imaskcmp<mode>3_comm): Clone
            of *<sse>_maskcmp<mode>3_comm pattern with integer vector
            result.
    
    gcc/testsuite/ChangeLog
            PR target/94871
            * gcc.target/i386/pr94871.c: New test case.

Diff:
---
 gcc/config/i386/sse.md                  | 17 +++++++++++++++++
 gcc/simplify-rtx.cc                     | 26 +++++++++++++++++++++++++-
 gcc/testsuite/gcc.target/i386/pr94871.c | 26 ++++++++++++++++++++++++++
 3 files changed, 68 insertions(+), 1 deletion(-)

diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index 7a0029ecedb4..65eff9a64082 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -4611,6 +4611,23 @@
    (set_attr "prefix" "orig,vex")
    (set_attr "mode" "<MODE>")])
 
+(define_insn "*<sse>_imaskcmp<mode>3_comm"
+  [(set (match_operand:<sseintvecmode> 0 "register_operand" "=x,x")
+       (match_operator:<sseintvecmode> 3 "sse_comparison_operator"
+         [(match_operand:VF_128_256 1 "register_operand" "%0,x")
+          (match_operand:VF_128_256 2 "vector_operand" "xBm,xjm")]))]
+  "TARGET_SSE
+   && GET_RTX_CLASS (GET_CODE (operands[3])) == RTX_COMM_COMPARE"
+  "@
+   cmp%D3<ssemodesuffix>\t{%2, %0|%0, %2}
+   vcmp%D3<ssemodesuffix>\t{%2, %1, %0|%0, %1, %2}"
+  [(set_attr "isa" "noavx,avx")
+   (set_attr "addr" "*,gpr16")
+   (set_attr "type" "ssecmp")
+   (set_attr "length_immediate" "1")
+   (set_attr "prefix" "orig,vex")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "<sse>_maskcmp<mode>3"
   [(set (match_operand:VF_128_256 0 "register_operand" "=x,x")
        (match_operator:VF_128_256 3 "sse_comparison_operator"
diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index 872ae0328691..e55cf0e0813c 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -941,11 +941,35 @@ simplify_context::simplify_unary_operation_1 (rtx_code 
code, machine_mode mode,
       /* (not (eq X Y)) == (ne X Y), etc. if BImode or the result of the
         comparison is all ones.   */
       if (COMPARISON_P (op)
-         && (mode == BImode || STORE_FLAG_VALUE == -1)
+         && ((SCALAR_INT_MODE_P (mode) && STORE_FLAG_VALUE == -1)
+#ifdef VECTOR_STORE_FLAG_VALUE
+             || (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+                 && VECTOR_STORE_FLAG_VALUE (mode) == constm1_rtx)
+#endif
+             || mode == BImode)
          && ((reversed = reversed_comparison_code (op, NULL)) != UNKNOWN))
        return simplify_gen_relational (reversed, mode, VOIDmode,
                                        XEXP (op, 0), XEXP (op, 1));
 
+      /* (not (neg (eq X Y))) is (neg (ne X Y)), etc. if the result of
+        the comparison is one.  */
+      if (GET_CODE (op) == NEG
+         && COMPARISON_P (XEXP (op, 0))
+         && ((SCALAR_INT_MODE_P (mode) && STORE_FLAG_VALUE == 1)
+#ifdef VECTOR_STORE_FLAG_VALUE
+             || (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+                 && VECTOR_STORE_FLAG_VALUE (mode) == const1_rtx)
+#endif
+            )
+         && ((reversed = reversed_comparison_code (XEXP (op, 0), NULL))
+             != UNKNOWN))
+       {
+         temp = simplify_gen_relational (reversed, mode, VOIDmode,
+                                         XEXP (XEXP (op, 0), 0),
+                                         XEXP (XEXP (op, 0), 1));
+         return simplify_gen_unary (NEG, mode, temp, mode);
+       }
+
       /* (not (plus X -1)) can become (neg X).  */
       if (GET_CODE (op) == PLUS
          && XEXP (op, 1) == constm1_rtx)
diff --git a/gcc/testsuite/gcc.target/i386/pr94871.c 
b/gcc/testsuite/gcc.target/i386/pr94871.c
new file mode 100644
index 000000000000..f218198647c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr94871.c
@@ -0,0 +1,26 @@
+/* PR target/94871 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mavx2 -march=skylake" } */
+
+typedef double v2df __attribute__((vector_size(16)));
+typedef long long v2di __attribute__((vector_size(16)));
+typedef char v16qi __attribute__((vector_size(16)));
+
+v2df p, q;
+v2di out;
+
+void foo()
+{
+  signed char a = 0xff;
+  v2di tmp = (v2di)(v16qi){a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a};
+  out = ((v2di)__builtin_ia32_cmpeqpd(p, q) ^ tmp);
+}
+
+void bar()
+{
+  signed char a = 0xff;
+  v2di tmp = (v2di)(v16qi){a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a};
+  out = ((v2di)__builtin_ia32_cmpneqpd(p, q) ^ tmp);
+}
+
+/* { dg-final { scan-assembler-not "xor" } } */

Reply via email to