@@ -6854,6 +6854,20 @@ (define_insn "add<mode>3_carry"
(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
+ (match_operator:SWI 3 "ix86_carry_flag_operator"
+ [(match_operand 2 "flags_reg_operand") (const_int 0)])
+ (match_operand:SWI 1 "nonimmediate_operand" "0")))
+ (clobber (reg:CC FLAGS_REG))]
+ "ix86_unary_operator_ok (PLUS, <MODE>mode, operands)"
+ "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 "*addsi3_carry_zext"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI
@@ -6870,6 +6884,20 @@ (define_insn "*addsi3_carry_zext"
(set_attr "pent_pair" "pu")
(set_attr "mode" "SI")])
+(define_insn "*addsi3_carry_zext_0"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI
+ (plus:SI (match_operator:SI 2 "ix86_carry_flag_operator"
+ [(reg FLAGS_REG) (const_int 0)])
+ (match_operand:SI 1 "register_operand" "0"))))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "adc{l}\t{$0, %k0|%k0, 0}"
+ [(set_attr "type" "alu")
+ (set_attr "use_carry" "1")
+ (set_attr "pent_pair" "pu")
+ (set_attr "mode" "SI")])
+
;; There is no point to generate ADCX instruction. ADC is shorter and faster.
(define_insn "addcarry<mode>"
@@ -6926,6 +6954,20 @@ (define_insn "sub<mode>3_carry"
(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
+ (match_operand:SWI 1 "nonimmediate_operand" "0")
+ (match_operator:SWI 3 "ix86_carry_flag_operator"
+ [(match_operand 2 "flags_reg_operand") (const_int 0)])))
+ (clobber (reg:CC FLAGS_REG))]
+ "ix86_unary_operator_ok (MINUS, <MODE>mode, operands)"
+ "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 "*subsi3_carry_zext"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI
@@ -6941,6 +6983,21 @@ (define_insn "*subsi3_carry_zext"
[(set_attr "type" "alu")
(set_attr "use_carry" "1")
(set_attr "pent_pair" "pu")
+ (set_attr "mode" "SI")])
+
+(define_insn "*subsi3_carry_zext_0"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI
+ (minus:SI
+ (match_operand:SI 1 "register_operand" "0")
+ (match_operator:SI 2 "ix86_carry_flag_operator"
+ [(reg FLAGS_REG) (const_int 0)]))))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "sbb{l}\t{$0, %k0|%k0, 0}"
+ [(set_attr "type" "alu")
+ (set_attr "use_carry" "1")
+ (set_attr "pent_pair" "pu")
(set_attr "mode" "SI")])
(define_insn "sub<mode>3_carry_ccc"
@@ -0,0 +1,33 @@
+/* PR target/85095 *
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+
+unsigned int
+foo (unsigned int a, unsigned int b)
+{
+ a += b;
+ if (a < b) a++;
+ return a;
+}
+
+#ifdef __x86_64__
+unsigned long long
+bar (unsigned long long a, unsigned long long b)
+{
+ a += b;
+ if (a < b) a++;
+ return a;
+}
+
+unsigned long long
+baz (unsigned int a, unsigned int b)
+{
+ a += b;
+ if (a < b) a++;
+ return a;
+}
+#endif
+
+/* { dg-final { scan-assembler-times "adcl\t\\\$0," 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "adcl\t\\\$0," 2 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "adcq\t\\\$0," 1 { target { ! ia32 } } } } */
@@ -0,0 +1,54 @@
+/* PR target/85095 *
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+
+unsigned int
+f1 (unsigned int a, unsigned int b)
+{
+ unsigned int i = __builtin_add_overflow (a, b, &a);
+ return a + i;
+}
+
+unsigned int
+f2 (unsigned int a, unsigned int b)
+{
+ unsigned int i = __builtin_add_overflow (a, b, &a);
+ return a - i;
+}
+
+#ifdef __x86_64__
+unsigned long long
+f3 (unsigned long long a, unsigned long long b)
+{
+ unsigned long long i = __builtin_add_overflow (a, b, &a);
+ return a + i;
+}
+
+unsigned long long
+f4 (unsigned long long a, unsigned long long b)
+{
+ unsigned long long i = __builtin_add_overflow (a, b, &a);
+ return a - i;
+}
+
+unsigned long long
+f5 (unsigned int a, unsigned int b)
+{
+ unsigned int i = __builtin_add_overflow (a, b, &a);
+ return a + i;
+}
+
+unsigned long long
+f6 (unsigned int a, unsigned int b)
+{
+ unsigned int i = __builtin_add_overflow (a, b, &a);
+ return a - i;
+}
+#endif
+
+/* { dg-final { scan-assembler-times "adcl\t\\\$0," 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "sbbl\t\\\$0," 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "adcl\t\\\$0," 2 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "sbbl\t\\\$0," 2 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "adcq\t\\\$0," 1 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "sbbq\t\\\$0," 1 { target { ! ia32 } } } } */
@@ -0,0 +1,52 @@
+/* PR target/85095 */
+
+__attribute__((noipa)) unsigned long
+f1 (unsigned long a, unsigned long b)
+{
+ unsigned long i = __builtin_add_overflow (a, b, &a);
+ return a + i;
+}
+
+__attribute__((noipa)) unsigned long
+f2 (unsigned long a, unsigned long b)
+{
+ unsigned long i = __builtin_add_overflow (a, b, &a);
+ return a - i;
+}
+
+__attribute__((noipa)) unsigned long
+f3 (unsigned int a, unsigned int b)
+{
+ unsigned int i = __builtin_add_overflow (a, b, &a);
+ return a + i;
+}
+
+__attribute__((noipa)) unsigned long
+f4 (unsigned int a, unsigned int b)
+{
+ unsigned int i = __builtin_add_overflow (a, b, &a);
+ return a - i;
+}
+
+int
+main ()
+{
+ if (f1 (16UL, -18UL) != -2UL
+ || f1 (16UL, -17UL) != -1UL
+ || f1 (16UL, -16UL) != 1UL
+ || f1 (16UL, -15UL) != 2UL
+ || f2 (24UL, -26UL) != -2UL
+ || f2 (24UL, -25UL) != -1UL
+ || f2 (24UL, -24UL) != -1UL
+ || f2 (24UL, -23UL) != 0UL
+ || f3 (32U, -34U) != -2U
+ || f3 (32U, -33U) != -1U
+ || f3 (32U, -32U) != 1U
+ || f3 (32U, -31U) != 2U
+ || f4 (35U, -37U) != -2U
+ || f4 (35U, -36U) != -1U
+ || f4 (35U, -35U) != -1U
+ || f4 (35U, -34U) != 0U)
+ __builtin_abort ();
+ return 0;
+}