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.
Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.
Uros.
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 4a2232e4023..3ea2439526b 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -8860,6 +8860,35 @@ (define_peephole2
(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
@@ -8874,6 +8903,26 @@ (define_insn "*add<mode>3_carry_0"
(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
@@ -8888,6 +8937,26 @@ (define_insn "*add<mode>3_carry_0r"
(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
@@ -9456,6 +9525,35 @@ (define_peephole2
(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
@@ -9470,6 +9568,26 @@ (define_insn "*sub<mode>3_carry_0"
(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
@@ -9484,6 +9602,26 @@ (define_insn "*sub<mode>3_carry_0r"
(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
index 00000000000..9120dd440e4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr122390-1.c
@@ -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
index 00000000000..a12849a4700
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr122390.c
@@ -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" } } */