]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-ssa-math-opts: Pattern recognize some further hand written forms of signed __bui...
authorJakub Jelinek <jakub@redhat.com>
Fri, 19 May 2023 10:58:32 +0000 (12:58 +0200)
committerJakub Jelinek <jakub@redhat.com>
Fri, 19 May 2023 10:58:32 +0000 (12:58 +0200)
In the pattern recognition of signed __builtin_mul_overflow{,_p} we
check for result of unsigned division (which follows unsigned
multiplication) being equality compared against one of the multiplication's
argument (the one not used in the division) and check for the comparison
to be done against same precision cast of the argument (because
division's result is unsigned and the argument is signed).
But as shown in this PR, one can write it equally as comparison done in
the signed type, i.e. compare division's result cast to corresponding
signed type against the argument.

The following patch handles even those cases.

2023-05-19  Jakub Jelinek  <jakub@redhat.com>

PR tree-optimization/105776
* tree-ssa-math-opts.cc (arith_overflow_check_p): If cast_stmt is
non-NULL, allow division statement to have a cast as single imm use
rather than comparison/condition.
(match_arith_overflow): In that case remove the cast stmt in addition
to the division statement.

* gcc.target/i386/pr105776.c: New test.

gcc/testsuite/gcc.target/i386/pr105776.c [new file with mode: 0644]
gcc/tree-ssa-math-opts.cc

diff --git a/gcc/testsuite/gcc.target/i386/pr105776.c b/gcc/testsuite/gcc.target/i386/pr105776.c
new file mode 100644 (file)
index 0000000..56878bd
--- /dev/null
@@ -0,0 +1,43 @@
+/* PR tree-optimization/105776 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -masm=att" } */
+/* { dg-final { scan-tree-dump-times " = \.MUL_OVERFLOW " 5 "optimized" } } */
+/* { dg-final { scan-assembler-times "\timull\t" 5 } } */
+/* { dg-final { scan-assembler-times "\tsetno\t" 5 } } */
+
+int
+foo (unsigned x, unsigned y)
+{
+  unsigned int r = x * y;
+  return !x || ((int) r / (int) x) == (int) y;
+}
+
+int
+bar (unsigned x, unsigned y)
+{
+  return !x || ((int) (x * y) / (int) x) == (int) y;
+}
+
+int
+baz (unsigned x, unsigned y)
+{
+  if (x == 0)
+    return 1;
+  return ((int) (x * y) / (int) x) == y;
+}
+
+int
+qux (unsigned x, unsigned y, unsigned *z)
+{
+  unsigned int r = x * y;
+  *z = r;
+  return !x || ((int) r / (int) x) == (int) y;
+}
+
+int
+corge (unsigned x, unsigned y, unsigned *z)
+{
+  unsigned int r = x * y;
+  *z = r;
+  return !x || ((int) r / (int) x) == y;
+}
index d80d53dee9288092b6f4cca80dc1933d961ab347..9c9ca571bcda10e9db80015b8e2d2d874ec7738c 100644 (file)
@@ -3802,6 +3802,21 @@ arith_overflow_check_p (gimple *stmt, gimple *cast_stmt, gimple *&use_stmt,
       use_operand_p use;
       if (!single_imm_use (divlhs, &use, &cur_use_stmt))
        return 0;
+      if (cast_stmt && gimple_assign_cast_p (cur_use_stmt))
+       {
+         tree cast_lhs = gimple_assign_lhs (cur_use_stmt);
+         if (INTEGRAL_TYPE_P (TREE_TYPE (cast_lhs))
+             && TYPE_UNSIGNED (TREE_TYPE (cast_lhs))
+             && (TYPE_PRECISION (TREE_TYPE (cast_lhs))
+                 == TYPE_PRECISION (TREE_TYPE (divlhs)))
+             && single_imm_use (cast_lhs, &use, &cur_use_stmt))
+           {
+             cast_stmt = NULL;
+             divlhs = cast_lhs;
+           }
+         else
+           return 0;
+       }
     }
   if (gimple_code (cur_use_stmt) == GIMPLE_COND)
     {
@@ -4390,6 +4405,16 @@ match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
          gimple_stmt_iterator gsi2 = gsi_for_stmt (orig_use_stmt);
          maybe_optimize_guarding_check (mul_stmts, use_stmt, orig_use_stmt,
                                         cfg_changed);
+         use_operand_p use;
+         gimple *cast_stmt;
+         if (single_imm_use (gimple_assign_lhs (orig_use_stmt), &use,
+                             &cast_stmt)
+             && gimple_assign_cast_p (cast_stmt))
+           {
+             gimple_stmt_iterator gsi3 = gsi_for_stmt (cast_stmt);
+             gsi_remove (&gsi3, true);
+             release_ssa_name (gimple_assign_lhs (cast_stmt));
+           }
          gsi_remove (&gsi2, true);
          release_ssa_name (gimple_assign_lhs (orig_use_stmt));
        }