2018-03-28 Jakub Jelinek <jakub@redhat.com>
+ PR target/85095
+ * config/i386/i386.md (*add<mode>3_carry_0, *addsi3_carry_zext_0,
+ *sub<mode>3_carry_0, *subsi3_carry_zext_0): New patterns.
+
PR tree-optimization/82004
* gimple-match-head.c (optimize_pow_to_exp): New function.
* match.pd (pow(C,x) -> exp(log(C)*x)): Wrap with #if GIMPLE.
(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
(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>"
(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
(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"
[(set (reg:CCC FLAGS_REG)
(compare:CCC
2018-03-28 Jakub Jelinek <jakub@redhat.com>
+ PR target/85095
+ * gcc.target/i386/pr85095-1.c: New test.
+ * gcc.target/i386/pr85095-2.c: New test.
+ * gcc.c-torture/execute/pr85095.c: New test.
+
PR tree-optimization/82004
* gcc.dg/pr82004.c: New test.
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 } } } } */
--- /dev/null
+/* 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 } } } } */