aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2019-10-19 14:46:57 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2019-10-19 14:46:57 +0200
commit15643a0dfc60e8e53d9b66165f4e2f4fcd8d98de (patch)
tree3f46d62c0e0d813672986e1e5292eaaeb307b3d7 /gcc
parent2366bf60c667d968c88e7bcec2eb9e2b84d0172d (diff)
downloadgcc-15643a0dfc60e8e53d9b66165f4e2f4fcd8d98de.zip
gcc-15643a0dfc60e8e53d9b66165f4e2f4fcd8d98de.tar.gz
gcc-15643a0dfc60e8e53d9b66165f4e2f4fcd8d98de.tar.bz2
re PR target/92140 (clang vs gcc optimizing with adc/sbb)
PR target/92140 * config/i386/predicates.md (int_nonimmediate_operand): New special predicate. * config/i386/i386.md (*add<mode>3_eq, *add<mode>3_ne, *add<mode>3_eq_0, *add<mode>3_ne_0, *sub<mode>3_eq, *sub<mode>3_ne, *sub<mode>3_eq_1, *sub<mode>3_eq_0, *sub<mode>3_ne_0): New define_insn_and_split patterns. * gcc.target/i386/pr92140.c: New test. * gcc.c-torture/execute/pr92140.c: New test. Co-Authored-By: Uros Bizjak <ubizjak@gmail.com> From-SVN: r277203
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/config/i386/i386.md222
-rw-r--r--gcc/config/i386/predicates.md9
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr92140.c83
-rw-r--r--gcc/testsuite/gcc.target/i386/pr92140.c38
6 files changed, 369 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7f77088..4919539 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2019-10-19 Jakub Jelinek <jakub@redhat.com>
+ Uroš Bizjak <ubizjak@gmail.com>
+
+ PR target/92140
+ * config/i386/predicates.md (int_nonimmediate_operand): New special
+ predicate.
+ * config/i386/i386.md (*add<mode>3_eq, *add<mode>3_ne,
+ *add<mode>3_eq_0, *add<mode>3_ne_0, *sub<mode>3_eq, *sub<mode>3_ne,
+ *sub<mode>3_eq_1, *sub<mode>3_eq_0, *sub<mode>3_ne_0): New
+ define_insn_and_split patterns.
+
2019-10-19 Iain Sandoe <iain@sandoe.co.uk>
* config/rs6000/rs6000.md: Delete out--of-date comment about
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index b7e7d12..a1b849e 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -6843,6 +6843,228 @@
[(set_attr "type" "alu")
(set_attr "mode" "SI")])
+;; x == 0 with zero flag test can be done also as x < 1U with carry flag
+;; test, where the latter is preferrable if we have some carry consuming
+;; instruction.
+;; For x != 0, we need to use x < 1U with negation of carry, i.e.
+;; + (1 - CF).
+(define_insn_and_split "*add<mode>3_eq"
+ [(set (match_operand:SWI 0 "nonimmediate_operand")
+ (plus:SWI
+ (plus:SWI
+ (eq:SWI (match_operand 3 "int_nonimmediate_operand") (const_int 0))
+ (match_operand:SWI 1 "nonimmediate_operand"))
+ (match_operand:SWI 2 "<general_operand>")))
+ (clobber (reg:CC FLAGS_REG))]
+ "ix86_binary_operator_ok (PLUS, <MODE>mode, operands)
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_dup 3) (const_int 1)))
+ (parallel [(set (match_dup 0)
+ (plus:SWI
+ (plus:SWI (ltu:SWI (reg:CC FLAGS_REG) (const_int 0))
+ (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:CC FLAGS_REG))])])
+
+(define_insn_and_split "*add<mode>3_ne"
+ [(set (match_operand:SWI 0 "nonimmediate_operand")
+ (plus:SWI
+ (plus:SWI
+ (ne:SWI (match_operand 3 "int_nonimmediate_operand") (const_int 0))
+ (match_operand:SWI 1 "nonimmediate_operand"))
+ (match_operand:SWI 2 "<immediate_operand>")))
+ (clobber (reg:CC FLAGS_REG))]
+ "CONST_INT_P (operands[2])
+ && (<MODE>mode != DImode
+ || INTVAL (operands[2]) != HOST_WIDE_INT_C (-0x80000000))
+ && ix86_binary_operator_ok (PLUS, <MODE>mode, operands)
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_dup 3) (const_int 1)))
+ (parallel [(set (match_dup 0)
+ (minus:SWI
+ (minus:SWI (match_dup 1)
+ (ltu:SWI (reg:CC FLAGS_REG) (const_int 0)))
+ (match_dup 2)))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ operands[2] = gen_int_mode (~INTVAL (operands[2]),
+ <MODE>mode == DImode ? SImode : <MODE>mode);
+})
+
+(define_insn_and_split "*add<mode>3_eq_0"
+ [(set (match_operand:SWI 0 "nonimmediate_operand")
+ (plus:SWI
+ (eq:SWI (match_operand 2 "int_nonimmediate_operand") (const_int 0))
+ (match_operand:SWI 1 "<general_operand>")))
+ (clobber (reg:CC FLAGS_REG))]
+ "ix86_unary_operator_ok (PLUS, <MODE>mode, operands)
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_dup 2) (const_int 1)))
+ (parallel [(set (match_dup 0)
+ (plus:SWI (ltu:SWI (reg:CC FLAGS_REG) (const_int 0))
+ (match_dup 1)))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ if (!nonimmediate_operand (operands[1], <MODE>mode))
+ operands[1] = force_reg (<MODE>mode, operands[1]);
+})
+
+(define_insn_and_split "*add<mode>3_ne_0"
+ [(set (match_operand:SWI 0 "nonimmediate_operand")
+ (plus:SWI
+ (ne:SWI (match_operand 2 "int_nonimmediate_operand") (const_int 0))
+ (match_operand:SWI 1 "<general_operand>")))
+ (clobber (reg:CC FLAGS_REG))]
+ "ix86_unary_operator_ok (PLUS, <MODE>mode, operands)
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_dup 2) (const_int 1)))
+ (parallel [(set (match_dup 0)
+ (minus:SWI (minus:SWI
+ (match_dup 1)
+ (ltu:SWI (reg:CC FLAGS_REG) (const_int 0)))
+ (const_int -1)))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ if (!nonimmediate_operand (operands[1], <MODE>mode))
+ operands[1] = force_reg (<MODE>mode, operands[1]);
+})
+
+(define_insn_and_split "*sub<mode>3_eq"
+ [(set (match_operand:SWI 0 "nonimmediate_operand")
+ (minus:SWI
+ (minus:SWI
+ (match_operand:SWI 1 "nonimmediate_operand")
+ (eq:SWI (match_operand 3 "int_nonimmediate_operand")
+ (const_int 0)))
+ (match_operand:SWI 2 "<general_operand>")))
+ (clobber (reg:CC FLAGS_REG))]
+ "ix86_binary_operator_ok (MINUS, <MODE>mode, operands)
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_dup 3) (const_int 1)))
+ (parallel [(set (match_dup 0)
+ (minus:SWI
+ (minus:SWI (match_dup 1)
+ (ltu:SWI (reg:CC FLAGS_REG) (const_int 0)))
+ (match_dup 2)))
+ (clobber (reg:CC FLAGS_REG))])])
+
+(define_insn_and_split "*sub<mode>3_ne"
+ [(set (match_operand:SWI 0 "nonimmediate_operand")
+ (plus:SWI
+ (minus:SWI
+ (match_operand:SWI 1 "nonimmediate_operand")
+ (ne:SWI (match_operand 3 "int_nonimmediate_operand")
+ (const_int 0)))
+ (match_operand:SWI 2 "<immediate_operand>")))
+ (clobber (reg:CC FLAGS_REG))]
+ "CONST_INT_P (operands[2])
+ && (<MODE>mode != DImode
+ || INTVAL (operands[2]) != HOST_WIDE_INT_C (-0x80000000))
+ && ix86_binary_operator_ok (MINUS, <MODE>mode, operands)
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_dup 3) (const_int 1)))
+ (parallel [(set (match_dup 0)
+ (plus:SWI
+ (plus:SWI (ltu:SWI (reg:CC FLAGS_REG) (const_int 0))
+ (match_dup 1))
+ (match_dup 2)))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ operands[2] = gen_int_mode (INTVAL (operands[2]) - 1,
+ <MODE>mode == DImode ? SImode : <MODE>mode);
+})
+
+(define_insn_and_split "*sub<mode>3_eq_1"
+ [(set (match_operand:SWI 0 "nonimmediate_operand")
+ (plus:SWI
+ (minus:SWI
+ (match_operand:SWI 1 "nonimmediate_operand")
+ (eq:SWI (match_operand 3 "int_nonimmediate_operand")
+ (const_int 0)))
+ (match_operand:SWI 2 "<immediate_operand>")))
+ (clobber (reg:CC FLAGS_REG))]
+ "CONST_INT_P (operands[2])
+ && (<MODE>mode != DImode
+ || INTVAL (operands[2]) != HOST_WIDE_INT_C (-0x80000000))
+ && ix86_binary_operator_ok (MINUS, <MODE>mode, operands)
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_dup 3) (const_int 1)))
+ (parallel [(set (match_dup 0)
+ (minus:SWI
+ (minus:SWI (match_dup 1)
+ (ltu:SWI (reg:CC FLAGS_REG) (const_int 0)))
+ (match_dup 2)))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ operands[2] = gen_int_mode (-INTVAL (operands[2]),
+ <MODE>mode == DImode ? SImode : <MODE>mode);
+})
+
+(define_insn_and_split "*sub<mode>3_eq_0"
+ [(set (match_operand:SWI 0 "nonimmediate_operand")
+ (minus:SWI
+ (match_operand:SWI 1 "<general_operand>")
+ (eq:SWI (match_operand 2 "int_nonimmediate_operand") (const_int 0))))
+ (clobber (reg:CC FLAGS_REG))]
+ "ix86_unary_operator_ok (MINUS, <MODE>mode, operands)
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_dup 2) (const_int 1)))
+ (parallel [(set (match_dup 0)
+ (minus:SWI (match_dup 1)
+ (ltu:SWI (reg:CC FLAGS_REG) (const_int 0))))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ if (!nonimmediate_operand (operands[1], <MODE>mode))
+ operands[1] = force_reg (<MODE>mode, operands[1]);
+})
+
+(define_insn_and_split "*sub<mode>3_ne_0"
+ [(set (match_operand:SWI 0 "nonimmediate_operand")
+ (minus:SWI
+ (match_operand:SWI 1 "<general_operand>")
+ (ne:SWI (match_operand 2 "int_nonimmediate_operand") (const_int 0))))
+ (clobber (reg:CC FLAGS_REG))]
+ "ix86_unary_operator_ok (MINUS, <MODE>mode, operands)
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_dup 2) (const_int 1)))
+ (parallel [(set (match_dup 0)
+ (plus:SWI (plus:SWI
+ (ltu:SWI (reg:CC FLAGS_REG) (const_int 0))
+ (match_dup 1))
+ (const_int -1)))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ if (!nonimmediate_operand (operands[1], <MODE>mode))
+ operands[1] = force_reg (<MODE>mode, operands[1]);
+})
+
;; The patterns that match these are at the end of this file.
(define_expand "<plusminus_insn>xf3"
diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index 31f1cea..279827f 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -100,6 +100,15 @@
(match_test "GET_MODE (op) == SImode")
(match_test "GET_MODE (op) == HImode"))))
+;; Match a DI, SI, HI or QImode nonimmediate_operand.
+(define_special_predicate "int_nonimmediate_operand"
+ (and (match_operand 0 "nonimmediate_operand")
+ (ior (and (match_test "TARGET_64BIT")
+ (match_test "GET_MODE (op) == DImode"))
+ (match_test "GET_MODE (op) == SImode")
+ (match_test "GET_MODE (op) == HImode")
+ (match_test "GET_MODE (op) == QImode"))))
+
;; Match register operands, but include memory operands for TARGET_SSE_MATH.
(define_predicate "register_ssemem_operand"
(if_then_else
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 6fc0c82..c22b137 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2019-10-19 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/92140
+ * gcc.target/i386/pr92140.c: New test.
+ * gcc.c-torture/execute/pr92140.c: New test.
+
2019-10-19 Iain Sandoe <iain@sandoe.co.uk>
* gcc.dg/Wnonnull.c: Add attributed function declarations for
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr92140.c b/gcc/testsuite/gcc.c-torture/execute/pr92140.c
new file mode 100644
index 0000000..1036fd8
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr92140.c
@@ -0,0 +1,83 @@
+/* PR target/92140 */
+
+char c;
+int v;
+
+__attribute__((noipa)) void f1 (void) { v += c != 0; }
+__attribute__((noipa)) void f2 (void) { v -= c != 0; }
+__attribute__((noipa)) void f3 (void) { v += c == 0; }
+__attribute__((noipa)) void f4 (void) { v -= c == 0; }
+__attribute__((noipa)) void f5 (void) { v += (c != 0) - 26; }
+__attribute__((noipa)) void f6 (void) { v -= (c != 0) - 26; }
+__attribute__((noipa)) void f7 (void) { v += (c == 0) - 26; }
+__attribute__((noipa)) void f8 (void) { v -= (c == 0) - 26; }
+__attribute__((noipa)) void f9 (void) { v += (c != 0) + 42; }
+__attribute__((noipa)) void f10 (void) { v -= (c != 0) + 42; }
+__attribute__((noipa)) void f11 (void) { v += (c == 0) + 42; }
+__attribute__((noipa)) void f12 (void) { v -= (c == 0) + 42; }
+__attribute__((noipa)) void f13 (int z) { v += (c == 0) + z; }
+__attribute__((noipa)) void f14 (int z) { v -= (c == 0) + z; }
+__attribute__((noipa)) unsigned int f15 (unsigned int n) { return n ? 2 : 1; }
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 2; i++)
+ {
+ v = 15;
+ if (i == 1)
+ c = 37;
+ f1 ();
+ if (v != 15 + i)
+ __builtin_abort ();
+ f2 ();
+ if (v != 15)
+ __builtin_abort ();
+ f3 ();
+ if (v != 16 - i)
+ __builtin_abort ();
+ f4 ();
+ if (v != 15)
+ __builtin_abort ();
+ f5 ();
+ if (v != 15 + i - 26)
+ __builtin_abort ();
+ f6 ();
+ if (v != 15)
+ __builtin_abort ();
+ f7 ();
+ if (v != 16 - i - 26)
+ __builtin_abort ();
+ f8 ();
+ if (v != 15)
+ __builtin_abort ();
+ f9 ();
+ if (v != 15 + i + 42)
+ __builtin_abort ();
+ f10 ();
+ if (v != 15)
+ __builtin_abort ();
+ f11 ();
+ if (v != 16 - i + 42)
+ __builtin_abort ();
+ f12 ();
+ if (v != 15)
+ __builtin_abort ();
+ f13 (173);
+ if (v != 16 - i + 173)
+ __builtin_abort ();
+ f14 (173);
+ if (v != 15)
+ __builtin_abort ();
+ f13 (-35);
+ if (v != 16 - i - 35)
+ __builtin_abort ();
+ f14 (-35);
+ if (v != 15)
+ __builtin_abort ();
+ }
+ if (f15 (0) != 1 || f15 (1) != 2 || f15 (371) != 2)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr92140.c b/gcc/testsuite/gcc.target/i386/pr92140.c
new file mode 100644
index 0000000..f21544e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr92140.c
@@ -0,0 +1,38 @@
+/* PR target/92140 */
+/* { dg-do compile { target nonpic } } */
+/* { dg-options "-O2 -mtune=generic -masm=att" } */
+/* { dg-additional-options "-mregparm=1" { target ia32 } } */
+/* { dg-final { scan-assembler-times "\tsbbl\t\\\$-1, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tadcl\t\\\$-1, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tadcl\t\\\$0, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tsbbl\t\\\$0, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tsbbl\t\\\$25, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tadcl\t\\\$25, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tadcl\t\\\$-26, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tsbbl\t\\\$-26, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tsbbl\t\\\$-43, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tadcl\t\\\$-43, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tadcl\t\\\$42, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tsbbl\t\\\$42, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tadcl\t%\[a-z0-9]*, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tsbbl\t%\[a-z0-9]*, v" 1 } } */
+/* { dg-final { scan-assembler-times "\tsbbl\t\\\$-1, %" 1 } } */
+
+char c;
+int v;
+
+__attribute__((noipa)) void f1 (void) { v += c != 0; }
+__attribute__((noipa)) void f2 (void) { v -= c != 0; }
+__attribute__((noipa)) void f3 (void) { v += c == 0; }
+__attribute__((noipa)) void f4 (void) { v -= c == 0; }
+__attribute__((noipa)) void f5 (void) { v += (c != 0) - 26; }
+__attribute__((noipa)) void f6 (void) { v -= (c != 0) - 26; }
+__attribute__((noipa)) void f7 (void) { v += (c == 0) - 26; }
+__attribute__((noipa)) void f8 (void) { v -= (c == 0) - 26; }
+__attribute__((noipa)) void f9 (void) { v += (c != 0) + 42; }
+__attribute__((noipa)) void f10 (void) { v -= (c != 0) + 42; }
+__attribute__((noipa)) void f11 (void) { v += (c == 0) + 42; }
+__attribute__((noipa)) void f12 (void) { v -= (c == 0) + 42; }
+__attribute__((noipa)) void f13 (int z) { v += (c == 0) + z; }
+__attribute__((noipa)) void f14 (int z) { v -= (c == 0) + z; }
+__attribute__((noipa)) unsigned int f15 (unsigned int n) { return n ? 2 : 1; }