Hi!

As mentioned by Linus, we can't optimize comparison of otherwise unused
result of plus with CONST_INT second operand, compared against zero.
This can be done using just cmp instruction with negated constant and say
js/jns/je/jne etc. conditional jumps (or setcc).
We already have *cmp<mode>_minus_1 instruction which handles it when
(as shown in foo in the testcase) the IL has MINUS rather than PLUS,
but for constants except for the minimum value the canonical form is
with PLUS.

The following patch adds a new pattern to handle this.

I'm not really sure about the flag_cf_protection stuff in there,
in other spots we just don't care and can sometimes emit immediates
with endbr64 or endbr32 in them.
E.g. *add<mode>_1<nf_name> when x86_maybe_negate_const_int
returns true, or in *subborrow<mode>_1 or *sub<mode>3_eq_1 at least.
So, I can drop that part.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2025-05-20  Jakub Jelinek  <ja...@redhat.com>

        PR target/120360
        * config/i386/i386.md (*cmp<mode>_plus_1): New pattern.

        * gcc.target/i386/pr120360.c: New test.

--- gcc/config/i386/i386.md.jj  2025-05-20 08:14:05.036425035 +0200
+++ gcc/config/i386/i386.md     2025-05-20 20:21:39.294358658 +0200
@@ -1599,6 +1599,25 @@ (define_insn "*cmp<mode>_minus_1"
   [(set_attr "type" "icmp")
    (set_attr "mode" "<MODE>")])
 
+(define_insn "*cmp<mode>_plus_1"
+  [(set (reg FLAGS_REG)
+       (compare
+         (plus:SWI (match_operand:SWI 0 "nonimmediate_operand" "<r>m")
+                   (match_operand:SWI 1 "<immediate_operand>" "<i>"))
+         (const_int 0)))]
+  "CONST_INT_P (operands[1])
+   && ix86_match_ccmode (insn, CCGOCmode)
+   && (<MODE>mode != DImode || !mode_signbit_p (SImode, operands[1]))
+   && ((flag_cf_protection & CF_BRANCH) == 0
+       || ((-INTVAL (operands[1]) & 0xffffffffUL)
+          != (TARGET_64BIT ? 0xfa1e0ff3UL : 0xfb1e0ff3UL)))"
+{
+  operands[1] = gen_int_mode (-INTVAL (operands[1]), <MODE>mode);
+  return "cmp{<imodesuffix>}\t{%1, %0|%0, %1}";
+}
+  [(set_attr "type" "icmp")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "*cmpqi_ext<mode>_1"
   [(set (reg FLAGS_REG)
        (compare
--- gcc/testsuite/gcc.target/i386/pr120360.c.jj 2025-05-20 20:40:32.194962716 
+0200
+++ gcc/testsuite/gcc.target/i386/pr120360.c    2025-05-20 20:43:03.910930990 
+0200
@@ -0,0 +1,36 @@
+/* PR target/120360 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-stack-protector -masm=att" } */
+/* { dg-additional-options "-fno-pic" { target { ! *-*-darwin* } } } */
+/* { dg-final { scan-assembler-times "\tjn*s\t" 3 } } */
+/* { dg-final { scan-assembler-times "\tcmp\[lq]\t%" 1 } } */
+/* { dg-final { scan-assembler-times "\tcmp\[lq]\t\\\$-1234," 1 } } */
+/* { dg-final { scan-assembler-times "\tcmp\[lq]\t\\\$2345," 1 } } */
+/* { dg-final { scan-assembler-not "\tadd\[lq]\t" { target { ! *-*-darwin* } } 
} } */
+/* { dg-final { scan-assembler-not "\tsub\[lq]\t" { target { ! *-*-darwin* } } 
} } */
+
+void qux (unsigned long);
+
+void
+foo (unsigned long x, unsigned long y)
+{
+  unsigned long z = x - y;
+  if ((long) z < 0)
+    qux (x);
+}
+
+void
+bar (unsigned long x)
+{
+  unsigned long z = x + 1234;
+  if ((long) z < 0)
+    qux (x);
+}
+
+void
+baz (unsigned long x)
+{
+  unsigned long z = x - 2345;
+  if ((long) z < 0)
+    qux (x);
+}

        Jakub

Reply via email to