On Tue, Jun 23, 2026 at 8:42 PM Roger Sayle <[email protected]> wrote:
>
> 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 modes, and FLOAT_STORE_FLAG_VALUE
> for comparisons that yield floating point results.  In this
> patch I've split the logic into a helper function,
> comparison_all_ones_result_p to make things clearer.
>
> I notice aarch64 returns a vector of 1s, not -1s, for vector
> mode comparisons, so in theory similar RTL simplifications should
> be possible there for (vx == vy) ^ 1 -> vx != vy, and likewise
> 1 - (vx == yy) -> vx != vy.
>
>
> 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 (from middle-end and i386
> backend maintainers)?

+/* Test whether the result of a comparison in mode MODE is all ones.  */

of a elementwise comparison

+static bool
+comparison_all_ones_result_p (machine_mode mode)
+{
+  if (mode == BImode)
+    return true;
+  if (SCALAR_INT_MODE_P (mode) && STORE_FLAG_VALUE == -1)
+    return true;
+#ifdef VECTOR_STORE_FLAG_VALUE
+  if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT

why the check for MODE_VECTOR_INT?

+      && VECTOR_STORE_FLAG_VALUE (mode) == constm1_rtx)
+    return true;
+#else
+  if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
+    return true;
+#endif
+  return false;
+}

VECTOR_STORE_FLAG_VALUE documents
"If there are no such operations, do not define
this macro." which to me implies it's required to define the macro,
so the fallback handling for MODE_VECTOR_INT above looks wrong and we
should drop it?

The function does look incomplete (FLOAT_STORE_FLAG_VALUE),
so I wonder if amending the mode == BImode || STORE_FLAG_VALUE == -1
with the VECTOR_STORE_FLAG_VALUE case would be simpler
and less contentious?  IMO we'd want to have a store_flag_value (mode)
function that wraps all the macros and works on all modes, not
necessarily also checking for constm1_rtx.

Thanks,
Richard.

>
> 2026-06-23  Roger Sayle  <[email protected]>
>
> gcc/ChangeLog
>         PR target/94871
>         * config/i386/sse.md (*<sse>_imaskcmp<mode>3_comm): Clone
>         of *<sse>_maskcmp<mode>3_comm pattern with integer vector
>         result.
>
>         * simplify-rtx.cc (comparison_all_ones_result_p): New
>         helper function to check that the true result from a
>         comparison with result mode MODE is a mask of all ones.
>         (simplify_unary_operation_1): Use it when reversing
>         comparisons, i.e. (not (eq X Y)) -> (ne X Y).
>
> gcc/testsuite/ChangeLog
>         PR target/94871
>         * gcc.target/i386/pr94871.c: New test case.
>
>
> Thanks in advance (to you both),
> Roger
> --
>

Reply via email to