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" } } */
