widening_mul: Fix a > ~b to .ADD_OVERFLOW optimization [PR98256]
authorJakub Jelinek <jakub@redhat.com>
Sun, 13 Dec 2020 18:25:33 +0000 (19:25 +0100)
committerJakub Jelinek <jakub@redhat.com>
Sun, 13 Dec 2020 18:28:07 +0000 (19:28 +0100)
Unfortunately, my latest tree-ssa-math-opts.c patch broke the following
testcase.  The problem is that the code is adding .ADD_OVERFLOW or
.SUB_OVERFLOW before or after the stmt on which the function has been
called, which is normally a addition or subtraction that has all the
operands.
But in the a > ~b optimization that stmt is the ~b stmt and the other
comparison operand might be defined only after that ~b stmt, so we can't
insert the .ADD_OVERFLOW next to ~b that we want to delete, but need to
insert it before the a > temp comparison that uses it; and in that case
when removing the BIT_NOT_EXPR stmt we need to ensure the caller doesn't do
gsi_next because gsi_remove already points the iterator to the next stmt.

2020-12-13  Jakub Jelinek  <jakub@redhat.com>

PR tree-optimization/98256
* tree-ssa-math-opts.c (match_uaddsub_overflow): For BIT_NOT_EXPR,
only handle a single use, and insert .ADD_OVERFLOW before the
comparison rather than after the BIT_NOT_EXPR.  Return true iff
it is BIT_NOT_EXPR and it has been removed.
(math_opts_dom_walker::after_dom_children) <case BIT_NOT_EXPR>:
If match_uaddsub_overflow returned true, continue instead of break.

* gcc.c-torture/compile/pr98256.c: New test.

gcc/testsuite/gcc.c-torture/compile/pr98256.c [new file with mode: 0644]
gcc/tree-ssa-math-opts.c

diff --git a/gcc/testsuite/gcc.c-torture/compile/pr98256.c b/gcc/testsuite/gcc.c-torture/compile/pr98256.c
new file mode 100644 (file)
index 0000000..44839c7
--- /dev/null
@@ -0,0 +1,9 @@
+/* PR tree-optimization/98256 */
+
+unsigned a, b;
+
+int
+foo (void)
+{
+  return !!(~a / b);
+}
index b8cdce94bff8b67f4514a4cc7aca4b5ddfc53ee0..c74b763d99a913fb3ae236137f7d78dd2929c38d 100644 (file)
@@ -3598,6 +3598,7 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
   gimple *use_stmt;
   gimple *add_stmt = NULL;
   bool add_first = false;
+  gimple *cond_stmt = NULL;
 
   gcc_checking_assert (code == PLUS_EXPR
                       || code == MINUS_EXPR
@@ -3628,8 +3629,9 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
                return false;
              if (rhs2 == NULL)
                rhs2 = other;
-             else if (rhs2 != other)
+             else
                return false;
+             cond_stmt = use_stmt;
            }
          ovf_use_seen = true;
        }
@@ -3818,6 +3820,9 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
        }
     }
 
+  if (code == BIT_NOT_EXPR)
+    *gsi = gsi_for_stmt (cond_stmt);
+
   tree ctype = build_complex_type (type);
   gcall *g = gimple_build_call_internal (code != MINUS_EXPR
                                         ? IFN_ADD_OVERFLOW : IFN_SUB_OVERFLOW,
@@ -3843,7 +3848,10 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
   tree ovf = make_ssa_name (type);
   g2 = gimple_build_assign (ovf, IMAGPART_EXPR,
                            build1 (IMAGPART_EXPR, type, ctmp));
-  gsi_insert_after (gsi, g2, GSI_NEW_STMT);
+  if (code != BIT_NOT_EXPR)
+    gsi_insert_after (gsi, g2, GSI_NEW_STMT);
+  else
+    gsi_insert_before (gsi, g2, GSI_SAME_STMT);
 
   FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
     {
@@ -3908,11 +3916,12 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
     }
   else if (code == BIT_NOT_EXPR)
     {
-      gimple_stmt_iterator gsi2 = gsi_for_stmt (stmt);
-      gsi_remove (&gsi2, true);
+      *gsi = gsi_for_stmt (stmt);
+      gsi_remove (gsi, true);
       release_ssa_name (lhs);
+      return true;
     }
-  return true;
+  return false;
 }
 
 /* Return true if target has support for divmod.  */
@@ -4238,7 +4247,8 @@ math_opts_dom_walker::after_dom_children (basic_block bb)
              break;
 
            case BIT_NOT_EXPR:
-             match_uaddsub_overflow (&gsi, stmt, code);
+             if (match_uaddsub_overflow (&gsi, stmt, code))
+               continue;
              break;
 
            case TRUNC_MOD_EXPR: