]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
i386: TEST insn should be merged with ADC/SBB insn [PR122390]
authorUros Bizjak <ubizjak@gmail.com>
Tue, 4 Nov 2025 09:18:03 +0000 (10:18 +0100)
committerUros Bizjak <ubizjak@gmail.com>
Tue, 4 Nov 2025 16:22:25 +0000 (17:22 +0100)
The attached testcase is currently compiled to:

f1:
        cmpl    %esi, %edi
        adcl    %esi, %edi
        testl   %edi, %edi
        js      .L4
...

TEST insn should be merged with ADC/SBB insn.  The patch provides missing
combined insn patterns.

PR target/122390

gcc/ChangeLog:

* config/i386/i386.md (*add<mode>3_carry_2): New insn pattern.
(*add<mode>3_carry_0_cc): Ditto.
(*add<mode>3_carry_0r_cc): Ditto.
(*sub<mode>3_carry_2): Ditto.
(*sub<mode>3_carry_0_cc): Ditto.
(*sub<mode>3_carry_0r_cc): Ditt.

gcc/testsuite/ChangeLog:

* gcc.target/i386/pr122390.c: New test.
* gcc.target/i386/pr122390-1.c: New test.

gcc/config/i386/i386.md
gcc/testsuite/gcc.target/i386/pr122390-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr122390.c [new file with mode: 0644]

index 4a2232e402394141757cb576fb79393c12ec6c42..3ea2439526bef1a8f9a0347318de7aafbb137ae3 100644 (file)
                             (match_dup 0)))
              (clobber (reg:CC FLAGS_REG))])])
 
+(define_insn "*add<mode>3_carry_2"
+  [(set (reg FLAGS_REG)
+       (compare
+         (plus:SWI
+           (plus:SWI
+             (match_operator:SWI 4 "ix86_carry_flag_operator"
+              [(match_operand 3 "flags_reg_operand") (const_int 0)])
+             (match_operand:SWI 1 "nonimmediate_operand" "%0,0,rm,r"))
+           (match_operand:SWI 2 "<general_operand>" "<r><i>,<m>,r<i>,<m>"))
+         (const_int 0)))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m,<r>,r,r")
+       (plus:SWI
+         (plus:SWI
+           (match_op_dup 4 [(match_dup 3) (const_int 0)])
+           (match_dup 1))
+         (match_dup 2)))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (PLUS, <MODE>mode, operands, TARGET_APX_NDD)"
+  "@
+   adc{<imodesuffix>}\t{%2, %0|%0, %2}
+   adc{<imodesuffix>}\t{%2, %0|%0, %2}
+   adc{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}
+   adc{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}"
+  [(set_attr "isa" "*,*,apx_ndd,apx_ndd")
+   (set_attr "type" "alu")
+   (set_attr "use_carry" "1")
+   (set_attr "pent_pair" "pu")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "*add<mode>3_carry_0"
   [(set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m")
        (plus:SWI
    (set_attr "pent_pair" "pu")
    (set_attr "mode" "<MODE>")])
 
+(define_insn "*add<mode>3_carry_0_cc"
+  [(set (reg FLAGS_REG)
+       (compare
+         (plus:SWI
+           (match_operator:SWI 2 "ix86_carry_flag_operator"
+             [(match_operand 3 "flags_reg_operand") (const_int 0)])
+           (match_operand:SWI 1 "nonimmediate_operand" "0"))
+         (const_int 0)))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m")
+       (plus:SWI
+         (match_op_dup 2 [(match_dup 3) (const_int 0)])
+         (match_dup 1)))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && (!MEM_P (operands[0]) || rtx_equal_p (operands[0], operands[1]))"
+  "adc{<imodesuffix>}\t{$0, %0|%0, 0}"
+  [(set_attr "type" "alu")
+   (set_attr "use_carry" "1")
+   (set_attr "pent_pair" "pu")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "*add<mode>3_carry_0r"
   [(set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m")
        (plus:SWI
    (set_attr "pent_pair" "pu")
    (set_attr "mode" "<MODE>")])
 
+(define_insn "*add<mode>3_carry_0r_cc"
+  [(set (reg FLAGS_REG)
+       (compare
+         (plus:SWI
+           (match_operator:SWI 2 "ix86_carry_flag_unset_operator"
+             [(match_operand 3 "flags_reg_operand") (const_int 0)])
+           (match_operand:SWI 1 "nonimmediate_operand" "0"))
+         (const_int 0)))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m")
+       (plus:SWI
+         (match_op_dup 2 [(match_dup 3) (const_int 0)])
+         (match_dup 1)))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && (!MEM_P (operands[0]) || rtx_equal_p (operands[0], operands[1]))"
+  "sbb{<imodesuffix>}\t{$-1, %0|%0, -1}"
+  [(set_attr "type" "alu")
+   (set_attr "use_carry" "1")
+   (set_attr "pent_pair" "pu")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "*addqi3_carry_zext<mode>"
   [(set (match_operand:SWI248x 0 "register_operand" "=r,r")
        (zero_extend:SWI248x
                              (match_dup 0)))
              (clobber (reg:CC FLAGS_REG))])])
 
+(define_insn "*sub<mode>3_carry_2"
+  [(set (reg FLAGS_REG)
+       (compare
+         (minus:SWI
+           (minus:SWI
+             (match_operand:SWI 1 "nonimmediate_operand" "0,0,rm,r")
+             (match_operator:SWI 4 "ix86_carry_flag_operator"
+              [(match_operand 3 "flags_reg_operand") (const_int 0)]))
+           (match_operand:SWI 2 "<general_operand>" "<r><i>,<m>,r<i>,<m>"))
+         (const_int 0)))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m,<r>,r,r")
+       (minus:SWI
+         (minus:SWI
+           (match_dup 1)
+           (match_op_dup 4 [(match_dup 3) (const_int 0)]))
+         (match_dup 2)))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (MINUS, <MODE>mode, operands, TARGET_APX_NDD)"
+  "@
+  sbb{<imodesuffix>}\t{%2, %0|%0, %2}
+  sbb{<imodesuffix>}\t{%2, %0|%0, %2}
+  sbb{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}
+  sbb{<imodesuffix>}\t{%2, %1, %0|%0, %1, %2}"
+  [(set_attr "isa" "*,*,apx_ndd,apx_ndd")
+   (set_attr "type" "alu")
+   (set_attr "use_carry" "1")
+   (set_attr "pent_pair" "pu")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "*sub<mode>3_carry_0"
   [(set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m")
        (minus:SWI
    (set_attr "pent_pair" "pu")
    (set_attr "mode" "<MODE>")])
 
+(define_insn "*sub<mode>3_carry_0_cc"
+  [(set (reg FLAGS_REG)
+       (compare
+         (minus:SWI
+           (match_operand:SWI 1 "nonimmediate_operand" "0")
+           (match_operator:SWI 2 "ix86_carry_flag_operator"
+             [(match_operand 3 "flags_reg_operand") (const_int 0)]))
+         (const_int 0)))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m")
+       (minus:SWI
+         (match_dup 1)
+         (match_op_dup 2 [(match_dup 3) (const_int 0)])))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && (!MEM_P (operands[0]) || rtx_equal_p (operands[0], operands[1]))"
+  "sbb{<imodesuffix>}\t{$0, %0|%0, 0}"
+  [(set_attr "type" "alu")
+   (set_attr "use_carry" "1")
+   (set_attr "pent_pair" "pu")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "*sub<mode>3_carry_0r"
   [(set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m")
        (minus:SWI
    (set_attr "pent_pair" "pu")
    (set_attr "mode" "<MODE>")])
 
+(define_insn "*sub<mode>3_carry_0r_cc"
+  [(set (reg FLAGS_REG)
+       (compare
+         (minus:SWI
+           (match_operand:SWI 1 "nonimmediate_operand" "0")
+           (match_operator:SWI 2 "ix86_carry_flag_unset_operator"
+             [(match_operand 3 "flags_reg_operand") (const_int 0)]))
+         (const_int 0)))
+   (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m")
+       (minus:SWI
+         (match_dup 1)
+         (match_op_dup 2 [(match_dup 3) (const_int 0)])))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && (!MEM_P (operands[0]) || rtx_equal_p (operands[0], operands[1]))"
+  "adc{<imodesuffix>}\t{$-1, %0|%0, -1}"
+  [(set_attr "type" "alu")
+   (set_attr "use_carry" "1")
+   (set_attr "pent_pair" "pu")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "*subqi3_carry_zext<mode>"
   [(set (match_operand:SWI248x 0 "register_operand" "=r,r")
        (zero_extend:SWI248x
diff --git a/gcc/testsuite/gcc.target/i386/pr122390-1.c b/gcc/testsuite/gcc.target/i386/pr122390-1.c
new file mode 100644 (file)
index 0000000..9120dd4
--- /dev/null
@@ -0,0 +1,26 @@
+/* PR target/122390 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int f (int);
+int g (int);
+
+int f1 (unsigned a, unsigned b)
+{
+  unsigned t = a < b;
+  int tt = a + b + t;
+  if (tt < 0)
+    return f(tt);
+  return g(tt);
+}
+
+int f2 (unsigned a, unsigned b)
+{
+  unsigned t = a < b;
+  int tt = a - b - t;
+  if (tt < 0)
+    return f(tt);
+  return g(tt);
+}
+
+/* { dg-final { scan-assembler-not "test" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr122390.c b/gcc/testsuite/gcc.target/i386/pr122390.c
new file mode 100644 (file)
index 0000000..a12849a
--- /dev/null
@@ -0,0 +1,44 @@
+/* PR target/122390 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int f (int);
+int g (int);
+
+int f1 (unsigned a, unsigned b)
+{
+  unsigned t = a < b;
+  int tt = a + t;
+  if (tt == 0)
+    return f(tt);
+  return g(tt);
+}
+
+int f2 (unsigned a, unsigned b)
+{
+  unsigned t = a <= b;
+  int tt = a + t;
+  if (tt < 0)
+    return f(tt);
+  return g(tt);
+}
+
+int f3 (unsigned a, unsigned b)
+{
+  unsigned t = a > b;
+  int tt = a - t;
+  if (tt == 0)
+    return f(tt);
+  return g(tt);
+}
+
+int f4 (unsigned a, unsigned b)
+{
+  unsigned t = a >= b;
+  int tt = a - t;
+  if (tt < 0)
+    return f(tt);
+  return g(tt);
+}
+
+/* { dg-final { scan-assembler-not "test" } } */