tree-ssa-threadedge.c (simplify_control_stmt_condition): Split out into ...
authorPatrick Palka <ppalka@gcc.gnu.org>
Fri, 29 Apr 2016 19:15:25 +0000 (19:15 +0000)
committerJeff Law <law@gcc.gnu.org>
Fri, 29 Apr 2016 19:15:25 +0000 (13:15 -0600)
2016-04-29  Patrick Palka  <ppalka@gcc.gnu.org>

* tree-ssa-threadedge.c (simplify_control_stmt_condition): Split
out into ...
(simplify_control_stmt_condition_1): ... here.  Recurse into
BIT_AND_EXPRs and BIT_IOR_EXPRs.

* gcc.dg/tree-ssa/ssa-thread-14.c: New test.
* gcc.dg/tree-ssa/ssa-thread-11.c: Update expected output.

From-SVN: r235653

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-11.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-14.c [new file with mode: 0644]
gcc/tree-ssa-threadedge.c

index 1b06c04e430a72108760332ee5b8fa65effbd912..e3458cc732a90a620df51706ba568f9688905a4a 100644 (file)
@@ -1,3 +1,10 @@
+2016-04-29  Patrick Palka  <ppalka@gcc.gnu.org>
+
+       * tree-ssa-threadedge.c (simplify_control_stmt_condition): Split
+       out into ...
+       (simplify_control_stmt_condition_1): ... here.  Recurse into
+       BIT_AND_EXPRs and BIT_IOR_EXPRs.
+
 2016-04-29  David Edelsohn  <dje.gcc@gmail.com>
 
        PR target/69810
index addef50175a7810b504205e0e22089e514927292..0d0f252b4528e4b9604ee24bffcdac7c8c73f05f 100644 (file)
@@ -1,3 +1,8 @@
+2016-04-29  Patrick Palka  <ppalka@gcc.gnu.org>
+
+       * gcc.dg/tree-ssa/ssa-thread-14.c: New test.
+       * gcc.dg/tree-ssa/ssa-thread-11.c: Update expected output.
+
 2016-04-29  Cesar Philippidis  <cesar@codesourcery.com>
 
        PR middle-end/70626
index a729f5637a53238b33ed1ddbb6ded2de81486919..d28a0eb068923a9c9b78ccd4ca402c896ce0c0ea 100644 (file)
@@ -1,7 +1,6 @@
 /* { dg-do compile { target { ! { logical_op_short_circuit || { m68k*-*-* mep*-*-* bfin*-*-* v850*-*-* moxie*-*-* m32c*-*-* fr30*-*-* mcore*-*-* frv-*-* h8300-*-* m32r-*-* mn10300-*-* msp430-*-* pdp11-*-* rl78-*-* rx-*-* vax-*-*} } } } } */
 /* { dg-options "-O2 -fdump-tree-vrp2-details" } */
 /* { dg-final { scan-tree-dump-not "IRREDUCIBLE_LOOP" "vrp2" } } */
-/* { dg-final { scan-tree-dump "FSM" "vrp2" } } */
 
 void abort (void);
 typedef struct bitmap_head_def *bitmap;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-14.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-14.c
new file mode 100644 (file)
index 0000000..db9ed3b
--- /dev/null
@@ -0,0 +1,81 @@
+/* { dg-do compile }  */
+/* { dg-additional-options "-O2 -fdump-tree-vrp" }  */
+/* { dg-final { scan-tree-dump-times "Threaded jump" 8 "vrp1" } }  */
+
+void foo (void);
+void bar (void);
+void blah (void);
+
+/* One jump threaded here.  */
+
+void
+baz_1 (int a, int b, int c)
+{
+  if (a && b)
+    foo ();
+  if (!b && c)
+    bar ();
+}
+
+/* One jump threaded here.  */
+
+void
+baz_2 (int a, int b, int c)
+{
+  if (a && b)
+    foo ();
+  if (b || c)
+    bar ();
+}
+
+/* One jump threaded here.  */
+
+void
+baz_3 (int a, int b, int c)
+{
+  if (a && b > 10)
+    foo ();
+  if (b < 5 && c)
+    bar ();
+}
+
+/* Two jumps threaded here.  */
+
+void
+baz_4 (int a, int b, int c)
+{
+  if (a && b)
+    {
+      foo ();
+      if (c)
+        bar ();
+    }
+  if (b && c)
+    blah ();
+}
+
+/* Two jumps threaded here.  */
+
+void
+baz_5 (int a, int b, int c)
+{
+  if (a && b)
+    {
+      foo ();
+      if (c)
+        bar ();
+    }
+  if (!b || !c)
+    blah ();
+}
+
+/* One jump threaded here.  */
+
+void
+baz_6 (int a, int b, int c)
+{
+  if (a == 39 && b == 41)
+    foo ();
+  if (c == 12 || b == 41)
+    bar ();
+}
index f60be3882185f78dfdd3660c9e03cd5f4680553d..eca3812090f35c7d62504ca9e10239dcf0d80cd1 100644 (file)
@@ -376,6 +376,12 @@ record_temporary_equivalences_from_stmts_at_dest (edge e,
   return stmt;
 }
 
+static tree simplify_control_stmt_condition_1 (edge, gimple *,
+                                              class avail_exprs_stack *,
+                                              tree, enum tree_code, tree,
+                                              gcond *, pfn_simplify, bool,
+                                              unsigned);
+
 /* Simplify the control statement at the end of the block E->dest.
 
    To avoid allocating memory unnecessarily, a scratch GIMPLE_COND
@@ -436,52 +442,14 @@ simplify_control_stmt_condition (edge e,
            }
        }
 
-      if (handle_dominating_asserts)
-       {
-         /* Now see if the operand was consumed by an ASSERT_EXPR
-            which dominates E->src.  If so, we want to replace the
-            operand with the LHS of the ASSERT_EXPR.  */
-         if (TREE_CODE (op0) == SSA_NAME)
-           op0 = lhs_of_dominating_assert (op0, e->src, stmt);
-
-         if (TREE_CODE (op1) == SSA_NAME)
-           op1 = lhs_of_dominating_assert (op1, e->src, stmt);
-       }
-
-      /* We may need to canonicalize the comparison.  For
-        example, op0 might be a constant while op1 is an
-        SSA_NAME.  Failure to canonicalize will cause us to
-        miss threading opportunities.  */
-      if (tree_swap_operands_p (op0, op1, false))
-       {
-         cond_code = swap_tree_comparison (cond_code);
-         std::swap (op0, op1);
-       }
+      const unsigned recursion_limit = 4;
 
-      /* Stuff the operator and operands into our dummy conditional
-        expression.  */
-      gimple_cond_set_code (dummy_cond, cond_code);
-      gimple_cond_set_lhs (dummy_cond, op0);
-      gimple_cond_set_rhs (dummy_cond, op1);
-
-      /* We absolutely do not care about any type conversions
-         we only care about a zero/nonzero value.  */
-      fold_defer_overflow_warnings ();
-
-      cached_lhs = fold_binary (cond_code, boolean_type_node, op0, op1);
-      if (cached_lhs)
-       while (CONVERT_EXPR_P (cached_lhs))
-          cached_lhs = TREE_OPERAND (cached_lhs, 0);
-
-      fold_undefer_overflow_warnings ((cached_lhs
-                                       && is_gimple_min_invariant (cached_lhs)),
-                                     stmt, WARN_STRICT_OVERFLOW_CONDITIONAL);
-
-      /* If we have not simplified the condition down to an invariant,
-        then use the pass specific callback to simplify the condition.  */
-      if (!cached_lhs
-          || !is_gimple_min_invariant (cached_lhs))
-        cached_lhs = (*simplify) (dummy_cond, stmt, avail_exprs_stack);
+      cached_lhs
+       = simplify_control_stmt_condition_1 (e, stmt, avail_exprs_stack,
+                                            op0, cond_code, op1,
+                                            dummy_cond, simplify,
+                                            handle_dominating_asserts,
+                                            recursion_limit);
 
       /* If we were testing an integer/pointer against a constant, then
         we can use the FSM code to trace the value of the SSA_NAME.  If
@@ -560,6 +528,197 @@ simplify_control_stmt_condition (edge e,
   return cached_lhs;
 }
 
+/* Recursive helper for simplify_control_stmt_condition.  */
+
+static tree
+simplify_control_stmt_condition_1 (edge e,
+                                  gimple *stmt,
+                                  class avail_exprs_stack *avail_exprs_stack,
+                                  tree op0,
+                                  enum tree_code cond_code,
+                                  tree op1,
+                                  gcond *dummy_cond,
+                                  pfn_simplify simplify,
+                                  bool handle_dominating_asserts,
+                                  unsigned limit)
+{
+  if (limit == 0)
+    return NULL_TREE;
+
+  /* We may need to canonicalize the comparison.  For
+     example, op0 might be a constant while op1 is an
+     SSA_NAME.  Failure to canonicalize will cause us to
+     miss threading opportunities.  */
+  if (tree_swap_operands_p (op0, op1, false))
+    {
+      cond_code = swap_tree_comparison (cond_code);
+      std::swap (op0, op1);
+    }
+
+  /* If the condition has the form (A & B) CMP 0 or (A | B) CMP 0 then
+     recurse into the LHS to see if there is a dominating ASSERT_EXPR
+     of A or of B that makes this condition always true or always false
+     along the edge E.  */
+  if (handle_dominating_asserts
+      && (cond_code == EQ_EXPR || cond_code == NE_EXPR)
+      && TREE_CODE (op0) == SSA_NAME
+      && integer_zerop (op1))
+    {
+      gimple *def_stmt = SSA_NAME_DEF_STMT (op0);
+      if (gimple_code (def_stmt) != GIMPLE_ASSIGN)
+        ;
+      else if (gimple_assign_rhs_code (def_stmt) == BIT_AND_EXPR
+              || gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR)
+       {
+         enum tree_code rhs_code = gimple_assign_rhs_code (def_stmt);
+         const tree rhs1 = gimple_assign_rhs1 (def_stmt);
+         const tree rhs2 = gimple_assign_rhs2 (def_stmt);
+         const tree zero_cst = build_zero_cst (TREE_TYPE (op0));
+         const tree one_cst = build_one_cst (TREE_TYPE (op0));
+
+         /* Is A != 0 ?  */
+         const tree res1
+           = simplify_control_stmt_condition_1 (e, def_stmt, avail_exprs_stack,
+                                                rhs1, NE_EXPR, op1,
+                                                dummy_cond, simplify,
+                                                handle_dominating_asserts,
+                                                limit - 1);
+         if (res1 == NULL_TREE)
+           ;
+         else if (rhs_code == BIT_AND_EXPR && integer_zerop (res1))
+           {
+             /* If A == 0 then (A & B) != 0 is always false.  */
+             if (cond_code == NE_EXPR)
+               return zero_cst;
+             /* If A == 0 then (A & B) == 0 is always true.  */
+             if (cond_code == EQ_EXPR)
+               return one_cst;
+           }
+         else if (rhs_code == BIT_IOR_EXPR && integer_nonzerop (res1))
+           {
+             /* If A != 0 then (A | B) != 0 is always true.  */
+             if (cond_code == NE_EXPR)
+               return one_cst;
+             /* If A != 0 then (A | B) == 0 is always false.  */
+             if (cond_code == EQ_EXPR)
+               return zero_cst;
+           }
+
+         /* Is B != 0 ?  */
+         const tree res2
+           = simplify_control_stmt_condition_1 (e, def_stmt, avail_exprs_stack,
+                                                rhs2, NE_EXPR, op1,
+                                                dummy_cond, simplify,
+                                                handle_dominating_asserts,
+                                                limit - 1);
+         if (res2 == NULL_TREE)
+           ;
+         else if (rhs_code == BIT_AND_EXPR && integer_zerop (res2))
+           {
+             /* If B == 0 then (A & B) != 0 is always false.  */
+             if (cond_code == NE_EXPR)
+               return zero_cst;
+             /* If B == 0 then (A & B) == 0 is always true.  */
+             if (cond_code == EQ_EXPR)
+               return one_cst;
+           }
+         else if (rhs_code == BIT_IOR_EXPR && integer_nonzerop (res2))
+           {
+             /* If B != 0 then (A | B) != 0 is always true.  */
+             if (cond_code == NE_EXPR)
+               return one_cst;
+             /* If B != 0 then (A | B) == 0 is always false.  */
+             if (cond_code == EQ_EXPR)
+               return zero_cst;
+           }
+
+         if (res1 != NULL_TREE && res2 != NULL_TREE)
+           {
+             if (rhs_code == BIT_AND_EXPR
+                 && TYPE_PRECISION (TREE_TYPE (op0)) == 1
+                 && integer_nonzerop (res1)
+                 && integer_nonzerop (res2))
+               {
+                 /* If A != 0 and B != 0 then (bool)(A & B) != 0 is true.  */
+                 if (cond_code == NE_EXPR)
+                   return one_cst;
+                 /* If A != 0 and B != 0 then (bool)(A & B) == 0 is false.  */
+                 if (cond_code == EQ_EXPR)
+                   return zero_cst;
+               }
+
+             if (rhs_code == BIT_IOR_EXPR
+                 && integer_zerop (res1)
+                 && integer_zerop (res2))
+               {
+                 /* If A == 0 and B == 0 then (A | B) != 0 is false.  */
+                 if (cond_code == NE_EXPR)
+                   return zero_cst;
+                 /* If A == 0 and B == 0 then (A | B) == 0 is true.  */
+                 if (cond_code == EQ_EXPR)
+                   return one_cst;
+               }
+           }
+       }
+      /* Handle (A CMP B) CMP 0.  */
+      else if (TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt))
+              == tcc_comparison)
+       {
+         tree rhs1 = gimple_assign_rhs1 (def_stmt);
+         tree rhs2 = gimple_assign_rhs2 (def_stmt);
+
+         tree_code new_cond = gimple_assign_rhs_code (def_stmt);
+         if (cond_code == EQ_EXPR)
+           new_cond = invert_tree_comparison (new_cond, false);
+
+         tree res
+           = simplify_control_stmt_condition_1 (e, def_stmt, avail_exprs_stack,
+                                                rhs1, new_cond, rhs2,
+                                                dummy_cond, simplify,
+                                                handle_dominating_asserts,
+                                                limit - 1);
+         if (res != NULL_TREE && is_gimple_min_invariant (res))
+           return res;
+       }
+    }
+
+  if (handle_dominating_asserts)
+    {
+      /* Now see if the operand was consumed by an ASSERT_EXPR
+        which dominates E->src.  If so, we want to replace the
+        operand with the LHS of the ASSERT_EXPR.  */
+      if (TREE_CODE (op0) == SSA_NAME)
+       op0 = lhs_of_dominating_assert (op0, e->src, stmt);
+
+      if (TREE_CODE (op1) == SSA_NAME)
+       op1 = lhs_of_dominating_assert (op1, e->src, stmt);
+    }
+
+  gimple_cond_set_code (dummy_cond, cond_code);
+  gimple_cond_set_lhs (dummy_cond, op0);
+  gimple_cond_set_rhs (dummy_cond, op1);
+
+  /* We absolutely do not care about any type conversions
+     we only care about a zero/nonzero value.  */
+  fold_defer_overflow_warnings ();
+
+  tree res = fold_binary (cond_code, boolean_type_node, op0, op1);
+  if (res)
+    while (CONVERT_EXPR_P (res))
+      res = TREE_OPERAND (res, 0);
+
+  fold_undefer_overflow_warnings ((res && is_gimple_min_invariant (res)),
+                                 stmt, WARN_STRICT_OVERFLOW_CONDITIONAL);
+
+  /* If we have not simplified the condition down to an invariant,
+     then use the pass specific callback to simplify the condition.  */
+  if (!res
+      || !is_gimple_min_invariant (res))
+    res = (*simplify) (dummy_cond, stmt, avail_exprs_stack);
+
+  return res;
+}
+
 /* Copy debug stmts from DEST's chain of single predecessors up to
    SRC, so that we don't lose the bindings as PHI nodes are introduced
    when DEST gains new predecessors.  */