Update dom_info
authorYuri Rumyantsev <ysrumyan@gmail.com>
Mon, 17 Oct 2016 18:05:12 +0000 (18:05 +0000)
committerH.J. Lu <hjl@gcc.gnu.org>
Mon, 17 Oct 2016 18:05:12 +0000 (11:05 -0700)
2016-10-17  Yuri Rumyantsev  <ysrumyan@gmail.com>

* dominance.c (dom_info::dom_info): Add new constructor for region
which is vector of basic blocks.
(dom_init): New method to initialize members common for both
constructors.
(dom_info::dom_info): Invoke dom_init for partial initialization.
(dom_info::get_idom): Add check to corner cases on basic blocks which
are not in region.
(dom_info::calc_dfs_tree): Check M_FAKE_EXIT_EDGE instead of M_REVERSE
to detect unreachable bbs.
(dom_info::calc_idoms): Likewise.
(compute_dom_fast_query_in_region): New function.
(calculate_dominance_info_for_region): Likewise.
(free_dominance_info_for_region): Likewise.
* dominance.h: Add prototypes for introduced region-based functions
tree-if-conv.c: (build_region): New function.
(if_convertible_loop_p_1): Invoke local version of post-dominators
calculation before basic block predication with subsequent freeing
post-dominator info.
(tree_if_conversion): Remove free of post-dominator info
(pass_if_conversion::execute): Delete detection of infinite loops
and fake edges to exit block since post-dominator calculation is
performed per if-converted loop only.

From-SVN: r241275

gcc/ChangeLog
gcc/dominance.c
gcc/dominance.h
gcc/tree-if-conv.c

index 3cad7bb512c7c0c3a6deacb6840c67d157f1355a..b512e4b9bbcf481df99a9d2761522edba398229d 100644 (file)
@@ -1,3 +1,28 @@
+2016-10-17  Yuri Rumyantsev  <ysrumyan@gmail.com>
+
+       * dominance.c (dom_info::dom_info): Add new constructor for region
+       which is vector of basic blocks.
+       (dom_init): New method to initialize members common for both
+       constructors.
+       (dom_info::dom_info): Invoke dom_init for partial initialization.
+       (dom_info::get_idom): Add check to corner cases on basic blocks which
+       are not in region.
+       (dom_info::calc_dfs_tree): Check M_FAKE_EXIT_EDGE instead of M_REVERSE
+       to detect unreachable bbs.
+       (dom_info::calc_idoms): Likewise.
+       (compute_dom_fast_query_in_region): New function.
+       (calculate_dominance_info_for_region): Likewise.
+       (free_dominance_info_for_region): Likewise.
+       * dominance.h: Add prototypes for introduced region-based functions
+       tree-if-conv.c: (build_region): New function.
+       (if_convertible_loop_p_1): Invoke local version of post-dominators
+       calculation before basic block predication with subsequent freeing
+       post-dominator info.
+       (tree_if_conversion): Remove free of post-dominator info
+       (pass_if_conversion::execute): Delete detection of infinite loops
+       and fake edges to exit block since post-dominator calculation is
+       performed per if-converted loop only.
+
 2016-10-17  Bernd Edlinger  <bernd.edlinger@hotmail.de>
 
        PR target/77308
index e3308cc19277402fa53a9e77b512bcee2428772c..90bd00dab1555001f3336d78ddfb1ff934c6f5fb 100644 (file)
@@ -60,6 +60,7 @@ class dom_info
 {
 public:
   dom_info (function *, cdi_direction);
+  dom_info (vec <basic_block>, cdi_direction);
   ~dom_info ();
   void calc_dfs_tree ();
   void calc_idoms ();
@@ -68,6 +69,7 @@ public:
 private:
   void calc_dfs_tree_nonrec (basic_block);
   void compress (TBB);
+  void dom_init (void);
   TBB eval (TBB);
   void link_roots (TBB, TBB);
 
@@ -153,12 +155,12 @@ inline T *new_zero_array (size_t num)
   return result;
 }
 
-/* Allocate all needed memory in a pessimistic fashion (so we round up).  */
+/* Helper function for constructors to initialize a part of class members.  */
 
-dom_info::dom_info (function *fn, cdi_direction dir)
+void
+dom_info::dom_init (void)
 {
-  /* We need memory for n_basic_blocks nodes.  */
-  size_t num = m_n_basic_blocks = n_basic_blocks_for_fn (fn);
+  size_t num = m_n_basic_blocks;
   m_dfs_parent = new_zero_array <TBB> (num);
   m_dom = new_zero_array <TBB> (num);
 
@@ -177,13 +179,23 @@ dom_info::dom_info (function *fn, cdi_direction dir)
   m_set_chain = new_zero_array <TBB> (num);
   m_set_child = new_zero_array <TBB> (num);
 
-  unsigned last_bb_index = last_basic_block_for_fn (fn);
-  m_dfs_order = new_zero_array <TBB> (last_bb_index + 1);
-  m_dfs_last = &m_dfs_order[last_bb_index];
   m_dfs_to_bb = new_zero_array <basic_block> (num);
 
   m_dfsnum = 1;
   m_nodes = 0;
+}
+
+/* Allocate all needed memory in a pessimistic fashion (so we round up).  */
+
+dom_info::dom_info (function *fn, cdi_direction dir)
+{
+  m_n_basic_blocks = n_basic_blocks_for_fn (fn);
+
+  dom_init ();
+
+  unsigned last_bb_index = last_basic_block_for_fn (fn);
+  m_dfs_order = new_zero_array <TBB> (last_bb_index + 1);
+  m_dfs_last = &m_dfs_order[last_bb_index];
 
   switch (dir)
     {
@@ -204,6 +216,44 @@ dom_info::dom_info (function *fn, cdi_direction dir)
     }
 }
 
+/* Constructor for reducible region REGION.  */
+
+dom_info::dom_info (vec<basic_block> region, cdi_direction dir)
+{
+  m_n_basic_blocks = region.length ();
+  unsigned int nm1 = m_n_basic_blocks - 1;
+
+  dom_init ();
+
+  /* Determine max basic block index in region.  */
+  int max_index = region[0]->index;
+  for (size_t i = 1; i <= nm1; i++)
+    if (region[i]->index > max_index)
+      max_index = region[i]->index;
+  max_index += 1;  /* set index on the first bb out of region.  */
+
+  m_dfs_order = new_zero_array <TBB> (max_index + 1);
+  m_dfs_last = &m_dfs_order[max_index];
+
+  m_fake_exit_edge = NULL; /* Assume that region is reducible.  */
+
+  switch (dir)
+    {
+      case CDI_DOMINATORS:
+       m_reverse = false;
+       m_start_block = region[0];
+       m_end_block = region[nm1];
+       break;
+      case CDI_POST_DOMINATORS:
+       m_reverse = true;
+       m_start_block = region[nm1];
+       m_end_block = region[0];
+       break;
+      default:
+       gcc_unreachable ();
+    }
+}
+
 inline basic_block
 dom_info::get_idom (basic_block bb)
 {
@@ -252,6 +302,8 @@ dom_info::calc_dfs_tree_nonrec (basic_block bb)
 {
   edge_iterator *stack = new edge_iterator[m_n_basic_blocks + 1];
   int sp = 0;
+  unsigned d_i = dom_convert_dir_to_idx (m_reverse ? CDI_POST_DOMINATORS
+                                        : CDI_DOMINATORS);
 
   /* Initialize the first edge.  */
   edge_iterator ei = m_reverse ? ei_start (bb->preds)
@@ -276,9 +328,10 @@ dom_info::calc_dfs_tree_nonrec (basic_block bb)
              bn = e->src;
 
              /* If the next node BN is either already visited or a border
-                block the current edge is useless, and simply overwritten
-                with the next edge out of the current node.  */
-             if (bn == m_end_block || m_dfs_order[bn->index])
+                block or out of region the current edge is useless, and simply
+                overwritten with the next edge out of the current node.  */
+             if (bn == m_end_block || bn->dom[d_i] == NULL
+                 || m_dfs_order[bn->index])
                {
                  ei_next (&ei);
                  continue;
@@ -289,7 +342,8 @@ dom_info::calc_dfs_tree_nonrec (basic_block bb)
          else
            {
              bn = e->dest;
-             if (bn == m_end_block || m_dfs_order[bn->index])
+             if (bn == m_end_block || bn->dom[d_i] == NULL
+                 || m_dfs_order[bn->index])
                {
                  ei_next (&ei);
                  continue;
@@ -347,7 +401,7 @@ dom_info::calc_dfs_tree ()
 
   calc_dfs_tree_nonrec (m_start_block);
 
-  if (m_reverse)
+  if (m_fake_exit_edge)
     {
       /* In the post-dom case we may have nodes without a path to EXIT_BLOCK.
          They are reverse-unreachable.  In the dom-case we disallow such
@@ -511,7 +565,7 @@ dom_info::calc_idoms ()
                                   : ei_start (bb->preds);
       edge_iterator einext;
 
-      if (m_reverse)
+      if (m_fake_exit_edge)
        {
          /* If this block has a fake edge to exit, process that first.  */
          if (bitmap_bit_p (m_fake_exit_edge, bb->index))
@@ -622,6 +676,33 @@ compute_dom_fast_query (enum cdi_direction dir)
   dom_computed[dir_index] = DOM_OK;
 }
 
+/* Analogous to the previous function but compute the data for reducible
+   region REGION.  */
+
+static void
+compute_dom_fast_query_in_region (enum cdi_direction dir,
+                                 vec<basic_block> region)
+{
+  int num = 0;
+  basic_block bb;
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+
+  gcc_checking_assert (dom_info_available_p (dir));
+
+  if (dom_computed[dir_index] == DOM_OK)
+    return;
+
+  /* Assign dfs numbers for region nodes except for entry and exit nodes.  */
+  for (unsigned int i = 1; i < region.length () - 1; i++)
+    {
+      bb = region[i];
+      if (!bb->dom[dir_index]->father)
+       assign_dfs_numbers (bb->dom[dir_index], &num);
+    }
+
+  dom_computed[dir_index] = DOM_OK;
+}
+
 /* The main entry point into this module.  DIR is set depending on whether
    we want to compute dominators or postdominators.  */
 
@@ -668,6 +749,43 @@ calculate_dominance_info (cdi_direction dir)
   timevar_pop (TV_DOMINANCE);
 }
 
+/* Analogous to the previous function but compute dominance info for regions
+   which are single entry, multiple exit regions for CDI_DOMINATORs and
+   multiple entry, single exit regions for CDI_POST_DOMINATORs.  */
+
+void
+calculate_dominance_info_for_region (cdi_direction dir,
+                                    vec<basic_block> region)
+{
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+  basic_block bb;
+  unsigned int i;
+
+  if (dom_computed[dir_index] == DOM_OK)
+    return;
+
+  timevar_push (TV_DOMINANCE);
+  /* Assume that dom info is not partially computed.  */
+  gcc_assert (!dom_info_available_p (dir));
+
+  FOR_EACH_VEC_ELT (region, i, bb)
+    {
+      bb->dom[dir_index] = et_new_tree (bb);
+    }
+  dom_info di (region, dir);
+  di.calc_dfs_tree ();
+  di.calc_idoms ();
+
+  FOR_EACH_VEC_ELT (region, i, bb)
+    if (basic_block d = di.get_idom (bb))
+      et_set_father (bb->dom[dir_index], d->dom[dir_index]);
+
+  dom_computed[dir_index] = DOM_NO_FAST_QUERY;
+  compute_dom_fast_query_in_region (dir, region);
+
+  timevar_pop (TV_DOMINANCE);
+}
+
 /* Free dominance information for direction DIR.  */
 void
 free_dominance_info (function *fn, enum cdi_direction dir)
@@ -696,6 +814,32 @@ free_dominance_info (enum cdi_direction dir)
   free_dominance_info (cfun, dir);
 }
 
+/* Free dominance information for direction DIR in region REGION.  */
+
+void
+free_dominance_info_for_region (function *fn,
+                               enum cdi_direction dir,
+                               vec<basic_block> region)
+{
+  basic_block bb;
+  unsigned int i;
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+
+  if (!dom_info_available_p (dir))
+    return;
+
+  FOR_EACH_VEC_ELT (region, i, bb)
+    {
+      et_free_tree_force (bb->dom[dir_index]);
+      bb->dom[dir_index] = NULL;
+    }
+  et_free_pools ();
+
+  fn->cfg->x_dom_computed[dir_index] = DOM_NONE;
+
+  fn->cfg->x_n_bbs_in_dom_tree[dir_index] = 0;
+}
+
 /* Return the immediate dominator of basic block BB.  */
 basic_block
 get_immediate_dominator (enum cdi_direction dir, basic_block bb)
index 961c4e2bdd90225618e854de5667f93c883d4745..ddbfa003662044ebbdb7a68f0ddf6a18ef051fda 100644 (file)
@@ -36,8 +36,13 @@ enum dom_state
 };
 
 extern void calculate_dominance_info (enum cdi_direction);
+extern void calculate_dominance_info_for_region (enum cdi_direction,
+                                                vec<basic_block>);
 extern void free_dominance_info (function *, enum cdi_direction);
 extern void free_dominance_info (enum cdi_direction);
+extern void free_dominance_info_for_region (function *,
+                                           enum cdi_direction,
+                                           vec<basic_block>);
 extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
 extern void set_immediate_dominator (enum cdi_direction, basic_block,
                                     basic_block);
index eec431e6a4fbdd791d9dd7b0d07584ca4ac6ca1a..0a201898177a812e12ed04b9498e11f340b1c8b4 100644 (file)
@@ -1309,6 +1309,38 @@ predicate_bbs (loop_p loop)
              && bb_predicate_gimplified_stmts (loop->latch) == NULL);
 }
 
+/* Build region by adding loop pre-header and post-header blocks.  */
+
+static vec<basic_block>
+build_region (struct loop *loop)
+{
+  vec<basic_block> region = vNULL;
+  basic_block exit_bb = NULL;
+
+  gcc_assert (ifc_bbs);
+  /* The first element is loop pre-header.  */
+  region.safe_push (loop_preheader_edge (loop)->src);
+
+  for (unsigned int i = 0; i < loop->num_nodes; i++)
+    {
+      basic_block bb = ifc_bbs[i];
+      region.safe_push (bb);
+      /* Find loop postheader.  */
+      edge e;
+      edge_iterator ei;
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       if (loop_exit_edge_p (loop, e))
+         {
+             exit_bb = e->dest;
+             break;
+         }
+    }
+  /* The last element is loop post-header.  */
+  gcc_assert (exit_bb);
+  region.safe_push (exit_bb);
+  return region;
+}
+
 /* Return true when LOOP is if-convertible.  This is a helper function
    for if_convertible_loop_p.  REFS and DDRS are initialized and freed
    in if_convertible_loop_p.  */
@@ -1318,6 +1350,7 @@ if_convertible_loop_p_1 (struct loop *loop, vec<data_reference_p> *refs)
 {
   unsigned int i;
   basic_block exit_bb = NULL;
+  vec<basic_block> region;
 
   if (find_data_references_in_loop (loop, refs) == chrec_dont_know)
     return false;
@@ -1370,9 +1403,16 @@ if_convertible_loop_p_1 (struct loop *loop, vec<data_reference_p> *refs)
          = new hash_map<innermost_loop_behavior_hash, data_reference_p>;
   baseref_DR_map = new hash_map<tree_operand_hash, data_reference_p>;
 
-  calculate_dominance_info (CDI_POST_DOMINATORS);
+  /* Compute post-dominator tree locally.  */
+  region = build_region (loop);
+  calculate_dominance_info_for_region (CDI_POST_DOMINATORS, region);
+
   predicate_bbs (loop);
 
+  /* Free post-dominator tree since it is not used after predication.  */
+  free_dominance_info_for_region (cfun, CDI_POST_DOMINATORS, region);
+  region.release ();
+
   for (i = 0; refs->iterate (i, &dr); i++)
     {
       tree ref = DR_REF (dr);
@@ -2752,7 +2792,6 @@ tree_if_conversion (struct loop *loop)
       free (ifc_bbs);
       ifc_bbs = NULL;
     }
-  free_dominance_info (CDI_POST_DOMINATORS);
 
   return todo;
 }
@@ -2805,14 +2844,6 @@ pass_if_conversion::execute (function *fun)
   if (number_of_loops (fun) <= 1)
     return 0;
 
-  /* If there are infinite loops, during CDI_POST_DOMINATORS computation
-     we can pick pretty much random bb inside of the infinite loop that
-     has the fake edge.  If we are unlucky enough, this can confuse the
-     add_to_predicate_list post-dominator check to optimize as if that
-     bb or some other one is a join block when it actually is not.
-     See PR70916.  */
-  connect_infinite_loops_to_exit ();
-
   FOR_EACH_LOOP (loop, 0)
     if (flag_tree_loop_if_convert == 1
        || flag_tree_loop_if_convert_stores == 1
@@ -2820,8 +2851,6 @@ pass_if_conversion::execute (function *fun)
            && !loop->dont_vectorize))
       todo |= tree_if_conversion (loop);
 
-  remove_fake_exit_edges ();
-
   if (flag_checking)
     {
       basic_block bb;