tree-ssa-dom.c (optimize_stmt): Make this a method within the dom_opt_dom_walker...
authorJeff Law <law@redhat.com>
Sun, 1 Oct 2017 15:22:39 +0000 (09:22 -0600)
committerJeff Law <law@gcc.gnu.org>
Sun, 1 Oct 2017 15:22:39 +0000 (09:22 -0600)
* tree-ssa-dom.c (optimize_stmt): Make this a method within the
dom_opt_dom_walker class with direct access to private members.
Add comments.  Call test_for_singularity.
(dom_opt_dom_walker::before_dom_children): Corresponding changes.
(dom_opt_dom_walker::after_dom_children): Do not lazily initialize
m_dummy_cond anymore.
(class dom_opt_dom_walker): Initialize m_dummy_cond member in the
class ctor.
(pass_dominator:execute): Build the dummy_cond here and pass it
to the dom_opt_dom_walker ctor.
(test_for_singularity): New function.

* gcc.dg/tree-ssa/ssa-dom-simplify-1.c: New test.

2017-09-30  Paolo Carlini  <paolo.carlini@oracle.com>

From-SVN: r253329

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-1.c [new file with mode: 0644]
gcc/tree-ssa-dom.c

index d1c3e9fa409b54fd4bb3cd121b17e0934cecf590..93dcaedbb4add7f4a0376b2e01158472119bc4fa 100644 (file)
@@ -1,3 +1,17 @@
+2017-10-01  Jeff Law  <law@redhat.com>
+
+       * tree-ssa-dom.c (optimize_stmt): Make this a method within the
+       dom_opt_dom_walker class with direct access to private members.
+       Add comments.  Call test_for_singularity.
+       (dom_opt_dom_walker::before_dom_children): Corresponding changes.
+       (dom_opt_dom_walker::after_dom_children): Do not lazily initialize
+       m_dummy_cond anymore.
+       (class dom_opt_dom_walker): Initialize m_dummy_cond member in the
+       class ctor.
+       (pass_dominator:execute): Build the dummy_cond here and pass it
+       to the dom_opt_dom_walker ctor. 
+       (test_for_singularity): New function.
+
 2017-09-30  Krister Walfridsson  <krister.walfridsson@gmail.com>
            Maya Rashish  <coypu@sdf.org>
 
index 40f59343fe1d67e7752faf7ac262ea5f8cc30ca7..d12fbdd86a5d51ba52f38036f008535877f45f85 100644 (file)
@@ -1,3 +1,7 @@
+2017-10-01  Jeff Law  <law@redhat.com>
+
+       * gcc.dg/tree-ssa/ssa-dom-simplify-1.c: New test.
+
 2017-10-01  Dominique d'Humieres  <dominiq@lps.ens.fr>
 
        PR fortran/61450
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-1.c
new file mode 100644 (file)
index 0000000..23741b6
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -w -fdump-tree-dom2" } */
+
+extern void frob (void);
+extern void frob (void);
+
+void
+rhs_to_tree (int x, int z)
+{
+  if (x >= 4)
+    frob ();
+  if (x >= 3)
+    frob ();
+}
+
+/* The second conditional should change into a simple equality test.  */
+/* { dg-final { scan-tree-dump-times "if \\(x_\[0-9\]+\\(D\\) == 3\\)" 1 "dom2"} } */
+
index d91766e902e4846383ab7e843a13ba5adc64e969..06be69a530cadb6c466d6cc6057e55f42ee8c214 100644 (file)
@@ -103,9 +103,6 @@ struct opt_stats_d
 static struct opt_stats_d opt_stats;
 
 /* Local functions.  */
-static edge optimize_stmt (basic_block, gimple_stmt_iterator,
-                          class const_and_copies *,
-                          class avail_exprs_stack *);
 static void record_equality (tree, tree, class const_and_copies *);
 static void record_equivalences_from_phis (basic_block);
 static void record_equivalences_from_incoming_edge (basic_block,
@@ -572,11 +569,12 @@ class dom_opt_dom_walker : public dom_walker
 public:
   dom_opt_dom_walker (cdi_direction direction,
                      class const_and_copies *const_and_copies,
-                     class avail_exprs_stack *avail_exprs_stack)
+                     class avail_exprs_stack *avail_exprs_stack,
+                     gcond *dummy_cond)
     : dom_walker (direction, true),
       m_const_and_copies (const_and_copies),
       m_avail_exprs_stack (avail_exprs_stack),
-      m_dummy_cond (NULL) {}
+      m_dummy_cond (dummy_cond) { }
 
   virtual edge before_dom_children (basic_block);
   virtual void after_dom_children (basic_block);
@@ -587,7 +585,14 @@ private:
   class const_and_copies *m_const_and_copies;
   class avail_exprs_stack *m_avail_exprs_stack;
 
+  /* Dummy condition to avoid creating lots of throw away statements.  */
   gcond *m_dummy_cond;
+
+  /* Optimize a single statement within a basic block using the
+     various tables mantained by DOM.  Returns the taken edge if
+     the statement is a conditional with a statically determined
+     value.  */
+  edge optimize_stmt (basic_block, gimple_stmt_iterator);
 };
 
 /* Jump threading, redundancy elimination and const/copy propagation.
@@ -684,10 +689,12 @@ pass_dominator::execute (function *fun)
   FOR_EACH_BB_FN (bb, fun)
     record_edge_info (bb);
 
+  gcond *dummy_cond = gimple_build_cond (NE_EXPR, integer_zero_node,
+                                        integer_zero_node, NULL, NULL);
+
   /* Recursively walk the dominator tree optimizing statements.  */
-  dom_opt_dom_walker walker (CDI_DOMINATORS,
-                            const_and_copies,
-                            avail_exprs_stack);
+  dom_opt_dom_walker walker (CDI_DOMINATORS, const_and_copies,
+                            avail_exprs_stack, dummy_cond);
   walker.walk (fun->cfg->x_entry_block_ptr);
 
   /* Look for blocks where we cleared EDGE_EXECUTABLE on an outgoing
@@ -1348,8 +1355,7 @@ dom_opt_dom_walker::before_dom_children (basic_block bb)
 
   edge taken_edge = NULL;
   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-    taken_edge
-      = optimize_stmt (bb, gsi, m_const_and_copies, m_avail_exprs_stack);
+    taken_edge = this->optimize_stmt (bb, gsi);
 
   /* Now prepare to process dominated blocks.  */
   record_edge_info (bb);
@@ -1367,10 +1373,6 @@ dom_opt_dom_walker::before_dom_children (basic_block bb)
 void
 dom_opt_dom_walker::after_dom_children (basic_block bb)
 {
-  if (! m_dummy_cond)
-    m_dummy_cond = gimple_build_cond (NE_EXPR, integer_zero_node,
-                                     integer_zero_node, NULL, NULL);
-
   thread_outgoing_edges (bb, m_dummy_cond, m_const_and_copies,
                         m_avail_exprs_stack,
                         simplify_stmt_for_jump_threading);
@@ -1700,8 +1702,99 @@ cprop_into_stmt (gimple *stmt)
     }
 }
 
-/* Optimize the statement in block BB pointed to by iterator SI
-   using equivalences from CONST_AND_COPIES and AVAIL_EXPRS_STACK.
+/* If STMT contains a relational test, try to convert it into an
+   equality test if there is only a single value which can ever
+   make the test true.
+
+   For example, if the expression hash table contains:
+
+    TRUE = (i <= 1)
+
+   And we have a test within statement of i >= 1, then we can safely
+   rewrite the test as i == 1 since there only a single value where
+   the test is true.
+
+   This is similar to code in VRP.  */
+
+static void
+test_for_singularity (gimple *stmt, gcond *dummy_cond,
+                     avail_exprs_stack *avail_exprs_stack)
+{
+  /* We want to support gimple conditionals as well as assignments
+     where the RHS contains a conditional.  */
+  if (is_gimple_assign (stmt) || gimple_code (stmt) == GIMPLE_COND)
+    {
+      enum tree_code code = ERROR_MARK;
+      tree lhs, rhs;
+
+      /* Extract the condition of interest from both forms we support.  */
+      if (is_gimple_assign (stmt))
+       {
+         code = gimple_assign_rhs_code (stmt);
+         lhs = gimple_assign_rhs1 (stmt);
+         rhs = gimple_assign_rhs2 (stmt);
+       }
+      else if (gimple_code (stmt) == GIMPLE_COND)
+       {
+         code = gimple_cond_code (as_a <gcond *> (stmt));
+         lhs = gimple_cond_lhs (as_a <gcond *> (stmt));
+         rhs = gimple_cond_rhs (as_a <gcond *> (stmt));
+       }
+
+      /* We're looking for a relational test using LE/GE.  Also note we can
+        canonicalize LT/GT tests against constants into LE/GT tests.  */
+      if (code == LE_EXPR || code == GE_EXPR
+         || ((code == LT_EXPR || code == GT_EXPR)
+              && TREE_CODE (rhs) == INTEGER_CST))
+       {
+         /* For LT_EXPR and GT_EXPR, canonicalize to LE_EXPR and GE_EXPR.  */
+         if (code == LT_EXPR)
+           rhs = fold_build2 (MINUS_EXPR, TREE_TYPE (rhs),
+                              rhs, build_int_cst (TREE_TYPE (rhs), 1));
+
+         if (code == GT_EXPR)
+           rhs = fold_build2 (PLUS_EXPR, TREE_TYPE (rhs),
+                              rhs, build_int_cst (TREE_TYPE (rhs), 1));
+
+         /* Determine the code we want to check for in the hash table.  */
+         enum tree_code test_code;
+         if (code == GE_EXPR || code == GT_EXPR)
+           test_code = LE_EXPR;
+         else
+           test_code = GE_EXPR;
+
+         /* Update the dummy statement so we can query the hash tables.  */
+         gimple_cond_set_code (dummy_cond, test_code);
+         gimple_cond_set_lhs (dummy_cond, lhs);
+         gimple_cond_set_rhs (dummy_cond, rhs);
+         tree cached_lhs
+           = avail_exprs_stack->lookup_avail_expr (dummy_cond, false, false);
+
+         /* If the lookup returned 1 (true), then the expression we
+            queried was in the hash table.  As a result there is only
+            one value that makes the original conditional true.  Update
+            STMT accordingly.  */
+         if (cached_lhs && integer_onep (cached_lhs))
+           {
+             if (is_gimple_assign (stmt))
+               {
+                 gimple_assign_set_rhs_code (stmt, EQ_EXPR);
+                 gimple_assign_set_rhs2 (stmt, rhs);
+                 gimple_set_modified (stmt, true);
+               }
+             else
+               {
+                 gimple_set_modified (stmt, true);
+                 gimple_cond_set_code (as_a <gcond *> (stmt), EQ_EXPR);
+                 gimple_cond_set_rhs (as_a <gcond *> (stmt), rhs);
+                 gimple_set_modified (stmt, true);
+               }
+           }
+       }
+    }
+}
+
+/* Optimize the statement in block BB pointed to by iterator SI.
 
    We try to perform some simplistic global redundancy elimination and
    constant propagation:
@@ -1714,12 +1807,15 @@ cprop_into_stmt (gimple *stmt)
    2- Constant values and copy assignments.  This is used to do very
       simplistic constant and copy propagation.  When a constant or copy
       assignment is found, we map the value on the RHS of the assignment to
-      the variable in the LHS in the CONST_AND_COPIES table.  */
+      the variable in the LHS in the CONST_AND_COPIES table.
 
-static edge
-optimize_stmt (basic_block bb, gimple_stmt_iterator si,
-              class const_and_copies *const_and_copies,
-              class avail_exprs_stack *avail_exprs_stack)
+   3- Very simple redundant store elimination is performed.
+
+   4- We can simpify a condition to a constant or from a relational
+      condition to an equality condition.  */
+
+edge
+dom_opt_dom_walker::optimize_stmt (basic_block bb, gimple_stmt_iterator si)
 {
   gimple *stmt, *old_stmt;
   bool may_optimize_p;
@@ -1832,8 +1928,8 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si,
        }
 
       update_stmt_if_modified (stmt);
-      eliminate_redundant_computations (&si, const_and_copies,
-                                       avail_exprs_stack);
+      eliminate_redundant_computations (&si, m_const_and_copies,
+                                       m_avail_exprs_stack);
       stmt = gsi_stmt (si);
 
       /* Perform simple redundant store elimination.  */
@@ -1855,8 +1951,8 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si,
          else
            new_stmt = gimple_build_assign (rhs, lhs);
          gimple_set_vuse (new_stmt, gimple_vuse (stmt));
-         cached_lhs = avail_exprs_stack->lookup_avail_expr (new_stmt, false,
-                                                            false);
+         cached_lhs = m_avail_exprs_stack->lookup_avail_expr (new_stmt, false,
+                                                              false);
          if (cached_lhs && operand_equal_p (rhs, cached_lhs, 0))
            {
              basic_block bb = gimple_bb (stmt);
@@ -1871,11 +1967,16 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si,
              return retval;
            }
        }
+
+      /* If this statement was not redundant, we may still be able to simplify
+        it, which may in turn allow other part of DOM or other passes to do
+        a better job.  */
+      test_for_singularity (stmt, m_dummy_cond, m_avail_exprs_stack);
     }
 
   /* Record any additional equivalences created by this statement.  */
   if (is_gimple_assign (stmt))
-    record_equivalences_from_stmt (stmt, may_optimize_p, avail_exprs_stack);
+    record_equivalences_from_stmt (stmt, may_optimize_p, m_avail_exprs_stack);
 
   /* If STMT is a COND_EXPR or SWITCH_EXPR and it was modified, then we may
      know where it goes.  */