OSDN Git Service

* cp-tree.h (struct tinst_level): Add chain_next GTY
[pf3gnuchains/gcc-fork.git] / gcc / dominance.c
index f89b6f6..03511e2 100644 (file)
@@ -1,12 +1,13 @@
 /* Calculate (post)dominators in slightly super-linear time.
-   Copyright (C) 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
    Contributed by Michael Matz (matz@ifh.de).
 
    This file is part of GCC.
 
    GCC is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GCC is distributed in the hope that it will be useful, but WITHOUT
@@ -15,9 +16,8 @@
    License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GCC; see the file COPYING.  If not, write to the Free
-   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 /* This file implements the well known algorithm from Lengauer and Tarjan
    to compute the dominators in a control flow graph.  A basic block D is said
 #include "hard-reg-set.h"
 #include "obstack.h"
 #include "basic-block.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "et-forest.h"
-
-/* Whether the dominators and the postdominators are available.  */
-enum dom_state dom_computed[2];
+#include "timevar.h"
+#include "vecprim.h"
+#include "pointer-set.h"
+#include "graphds.h"
+#include "bitmap.h"
 
 /* We name our nodes with integers, beginning with 1.  Zero is reserved for
    'undefined' or 'end of list'.  The name of each node is given by the dfs
@@ -82,7 +84,7 @@ struct dom_info
 
   /* The following few fields implement the structures needed for disjoint
      sets.  */
-  /* set_chain[x] is the next node on the path from x to the representant
+  /* set_chain[x] is the next node on the path from x to the representative
      of the set containing x.  If set_chain[x]==0 then x is a root.  */
   TBB *set_chain;
   /* set_size[x] is the number of elements in the set named by x.  */
@@ -113,17 +115,14 @@ struct dom_info
 
 static void init_dom_info (struct dom_info *, enum cdi_direction);
 static void free_dom_info (struct dom_info *);
-static void calc_dfs_tree_nonrec (struct dom_info *, basic_block,
-                                 enum cdi_direction);
-static void calc_dfs_tree (struct dom_info *, enum cdi_direction);
+static void calc_dfs_tree_nonrec (struct dom_info *, basic_block, bool);
+static void calc_dfs_tree (struct dom_info *, bool);
 static void compress (struct dom_info *, TBB);
 static TBB eval (struct dom_info *, TBB);
 static void link_roots (struct dom_info *, TBB, TBB);
-static void calc_idoms (struct dom_info *, enum cdi_direction);
+static void calc_idoms (struct dom_info *, bool);
 void debug_dominance_info (enum cdi_direction);
-
-/* Keeps track of the*/
-static unsigned n_bbs_in_dom_tree[2];
+void debug_dominance_tree (enum cdi_direction, basic_block);
 
 /* Helper macro for allocating and initializing an array,
    for aesthetic reasons.  */
@@ -132,10 +131,10 @@ static unsigned n_bbs_in_dom_tree[2];
     {                                                          \
       unsigned int i = 1;    /* Catch content == i.  */                \
       if (! (content))                                         \
-       (var) = xcalloc ((num), sizeof (type));                 \
+       (var) = XCNEWVEC (type, num);                           \
       else                                                     \
        {                                                       \
-         (var) = xmalloc ((num) * sizeof (type));              \
+         (var) = XNEWVEC (type, (num));                        \
          for (i = 0; i < num; i++)                             \
            (var)[i] = (content);                               \
        }                                                       \
@@ -148,6 +147,7 @@ static unsigned n_bbs_in_dom_tree[2];
 static void
 init_dom_info (struct dom_info *di, enum cdi_direction dir)
 {
+  /* We need memory for n_basic_blocks nodes.  */
   unsigned int num = n_basic_blocks;
   init_ar (di->dfs_parent, TBB, num, 0);
   init_ar (di->path_min, TBB, num, i);
@@ -167,11 +167,34 @@ init_dom_info (struct dom_info *di, enum cdi_direction dir)
   di->dfsnum = 1;
   di->nodes = 0;
 
-  di->fake_exit_edge = dir ? BITMAP_ALLOC (NULL) : NULL;
+  switch (dir)
+    {
+      case CDI_DOMINATORS:
+       di->fake_exit_edge = NULL;
+       break;
+      case CDI_POST_DOMINATORS:
+       di->fake_exit_edge = BITMAP_ALLOC (NULL);
+       break;
+      default:
+       gcc_unreachable ();
+       break;
+    }
 }
 
 #undef init_ar
 
+/* Map dominance calculation type to array index used for various
+   dominance information arrays.  This version is simple -- it will need
+   to be modified, obviously, if additional values are added to
+   cdi_direction.  */
+
+static unsigned int
+dom_convert_dir_to_idx (enum cdi_direction dir)
+{
+  gcc_assert (dir == CDI_DOMINATORS || dir == CDI_POST_DOMINATORS);
+  return dir - 1;
+}
+
 /* Free all allocated memory in DI, but not DI itself.  */
 
 static void
@@ -198,8 +221,7 @@ free_dom_info (struct dom_info *di)
    assigned their dfs number and are linked together to form a tree.  */
 
 static void
-calc_dfs_tree_nonrec (struct dom_info *di, basic_block bb,
-                     enum cdi_direction reverse)
+calc_dfs_tree_nonrec (struct dom_info *di, basic_block bb, bool reverse)
 {
   /* We call this _only_ if bb is not already visited.  */
   edge e;
@@ -213,7 +235,7 @@ calc_dfs_tree_nonrec (struct dom_info *di, basic_block bb,
   /* Ending block.  */
   basic_block ex_block;
 
-  stack = xmalloc ((n_basic_blocks + 1) * sizeof (edge_iterator));
+  stack = XNEWVEC (edge_iterator, n_basic_blocks + 1);
   sp = 0;
 
   /* Initialize our border blocks, and the first edge.  */
@@ -310,7 +332,7 @@ calc_dfs_tree_nonrec (struct dom_info *di, basic_block bb,
    because there may be nodes from which the EXIT_BLOCK is unreachable.  */
 
 static void
-calc_dfs_tree (struct dom_info *di, enum cdi_direction reverse)
+calc_dfs_tree (struct dom_info *di, bool reverse)
 {
   /* The first block is the ENTRY_BLOCK (or EXIT_BLOCK if REVERSE).  */
   basic_block begin = reverse ? EXIT_BLOCK_PTR : ENTRY_BLOCK_PTR;
@@ -401,7 +423,7 @@ compress (struct dom_info *di, TBB v)
 static inline TBB
 eval (struct dom_info *di, TBB v)
 {
-  /* The representant of the set V is in, also called root (as the set
+  /* The representative of the set V is in, also called root (as the set
      representation is a tree).  */
   TBB rep = di->set_chain[v];
 
@@ -470,7 +492,7 @@ link_roots (struct dom_info *di, TBB v, TBB w)
    On return the immediate dominator to node V is in di->dom[V].  */
 
 static void
-calc_idoms (struct dom_info *di, enum cdi_direction reverse)
+calc_idoms (struct dom_info *di, bool reverse)
 {
   TBB v, w, k, par;
   basic_block en_block;
@@ -589,19 +611,20 @@ compute_dom_fast_query (enum cdi_direction dir)
 {
   int num = 0;
   basic_block bb;
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
 
   gcc_assert (dom_info_available_p (dir));
 
-  if (dom_computed[dir] == DOM_OK)
+  if (dom_computed[dir_index] == DOM_OK)
     return;
 
   FOR_ALL_BB (bb)
     {
-      if (!bb->dom[dir]->father)
-       assign_dfs_numbers (bb->dom[dir], &num);
+      if (!bb->dom[dir_index]->father)
+       assign_dfs_numbers (bb->dom[dir_index], &num);
     }
 
-  dom_computed[dir] = DOM_OK;
+  dom_computed[dir_index] = DOM_OK;
 }
 
 /* The main entry point into this module.  DIR is set depending on whether
@@ -612,37 +635,42 @@ calculate_dominance_info (enum cdi_direction dir)
 {
   struct dom_info di;
   basic_block b;
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+  bool reverse = (dir == CDI_POST_DOMINATORS) ? true : false;
 
-  if (dom_computed[dir] == DOM_OK)
+  if (dom_computed[dir_index] == DOM_OK)
     return;
 
+  timevar_push (TV_DOMINANCE);
   if (!dom_info_available_p (dir))
     {
-      gcc_assert (!n_bbs_in_dom_tree[dir]);
+      gcc_assert (!n_bbs_in_dom_tree[dir_index]);
 
       FOR_ALL_BB (b)
        {
-         b->dom[dir] = et_new_tree (b);
+         b->dom[dir_index] = et_new_tree (b);
        }
-      n_bbs_in_dom_tree[dir] = n_basic_blocks;
+      n_bbs_in_dom_tree[dir_index] = n_basic_blocks;
 
       init_dom_info (&di, dir);
-      calc_dfs_tree (&di, dir);
-      calc_idoms (&di, dir);
+      calc_dfs_tree (&di, reverse);
+      calc_idoms (&di, reverse);
 
       FOR_EACH_BB (b)
        {
          TBB d = di.dom[di.dfs_order[b->index]];
 
          if (di.dfs_to_bb[d])
-           et_set_father (b->dom[dir], di.dfs_to_bb[d]->dom[dir]);
+           et_set_father (b->dom[dir_index], di.dfs_to_bb[d]->dom[dir_index]);
        }
 
       free_dom_info (&di);
-      dom_computed[dir] = DOM_NO_FAST_QUERY;
+      dom_computed[dir_index] = DOM_NO_FAST_QUERY;
     }
 
   compute_dom_fast_query (dir);
+
+  timevar_pop (TV_DOMINANCE);
 }
 
 /* Free dominance information for direction DIR.  */
@@ -650,44 +678,48 @@ void
 free_dominance_info (enum cdi_direction dir)
 {
   basic_block bb;
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
 
   if (!dom_info_available_p (dir))
     return;
 
   FOR_ALL_BB (bb)
     {
-      et_free_tree_force (bb->dom[dir]);
-      bb->dom[dir] = NULL;
+      et_free_tree_force (bb->dom[dir_index]);
+      bb->dom[dir_index] = NULL;
     }
+  et_free_pools ();
 
-  n_bbs_in_dom_tree[dir] = 0;
+  n_bbs_in_dom_tree[dir_index] = 0;
 
-  dom_computed[dir] = DOM_NONE;
+  dom_computed[dir_index] = DOM_NONE;
 }
 
 /* Return the immediate dominator of basic block BB.  */
 basic_block
 get_immediate_dominator (enum cdi_direction dir, basic_block bb)
 {
-  struct et_node *node = bb->dom[dir];
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+  struct et_node *node = bb->dom[dir_index];
 
-  gcc_assert (dom_computed[dir]);
+  gcc_assert (dom_computed[dir_index]);
 
   if (!node->father)
     return NULL;
 
-  return node->father->data;
+  return (basic_block) node->father->data;
 }
 
 /* Set the immediate dominator of the block possibly removing
    existing edge.  NULL can be used to remove any edge.  */
-inline void
+void
 set_immediate_dominator (enum cdi_direction dir, basic_block bb,
                         basic_block dominated_by)
 {
-  struct et_node *node = bb->dom[dir];
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+  struct et_node *node = bb->dom[dir_index];
 
-  gcc_assert (dom_computed[dir]);
+  gcc_assert (dom_computed[dir_index]);
 
   if (node->father)
     {
@@ -697,50 +729,44 @@ set_immediate_dominator (enum cdi_direction dir, basic_block bb,
     }
 
   if (dominated_by)
-    et_set_father (node, dominated_by->dom[dir]);
+    et_set_father (node, dominated_by->dom[dir_index]);
 
-  if (dom_computed[dir] == DOM_OK)
-    dom_computed[dir] = DOM_NO_FAST_QUERY;
+  if (dom_computed[dir_index] == DOM_OK)
+    dom_computed[dir_index] = DOM_NO_FAST_QUERY;
 }
 
-/* Store all basic blocks immediately dominated by BB into BBS and return
-   their number.  */
-int
-get_dominated_by (enum cdi_direction dir, basic_block bb, basic_block **bbs)
+/* Returns the list of basic blocks immediately dominated by BB, in the
+   direction DIR.  */
+VEC (basic_block, heap) *
+get_dominated_by (enum cdi_direction dir, basic_block bb)
 {
-  int n;
-  struct et_node *node = bb->dom[dir], *son = node->son, *ason;
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+  struct et_node *node = bb->dom[dir_index], *son = node->son, *ason;
+  VEC (basic_block, heap) *bbs = NULL;
 
-  gcc_assert (dom_computed[dir]);
+  gcc_assert (dom_computed[dir_index]);
 
   if (!son)
-    {
-      *bbs = NULL;
-      return 0;
-    }
-
-  for (ason = son->right, n = 1; ason != son; ason = ason->right)
-    n++;
+    return NULL;
 
-  *bbs = xmalloc (n * sizeof (basic_block));
-  (*bbs)[0] = son->data;
-  for (ason = son->right, n = 1; ason != son; ason = ason->right)
-    (*bbs)[n++] = ason->data;
+  VEC_safe_push (basic_block, heap, bbs, (basic_block) son->data);
+  for (ason = son->right; ason != son; ason = ason->right)
+    VEC_safe_push (basic_block, heap, bbs, (basic_block) ason->data);
 
-  return n;
+  return bbs;
 }
 
-/* Find all basic blocks that are immediately dominated (in direction DIR)
-   by some block between N_REGION ones stored in REGION, except for blocks
-   in the REGION itself.  The found blocks are stored to DOMS and their number
-   is returned.  */
+/* Returns the list of basic blocks that are immediately dominated (in
+   direction DIR) by some block between N_REGION ones stored in REGION,
+   except for blocks in the REGION itself.  */
 
-unsigned
+VEC (basic_block, heap) *
 get_dominated_by_region (enum cdi_direction dir, basic_block *region,
-                        unsigned n_region, basic_block *doms)
+                        unsigned n_region)
 {
-  unsigned n_doms = 0, i;
+  unsigned i;
   basic_block dom;
+  VEC (basic_block, heap) *doms = NULL;
 
   for (i = 0; i < n_region; i++)
     region[i]->flags |= BB_DUPLICATED;
@@ -749,11 +775,54 @@ get_dominated_by_region (enum cdi_direction dir, basic_block *region,
         dom;
         dom = next_dom_son (dir, dom))
       if (!(dom->flags & BB_DUPLICATED))
-       doms[n_doms++] = dom;
+       VEC_safe_push (basic_block, heap, doms, dom);
   for (i = 0; i < n_region; i++)
     region[i]->flags &= ~BB_DUPLICATED;
 
-  return n_doms;
+  return doms;
+}
+
+/* Returns the list of basic blocks including BB dominated by BB, in the
+   direction DIR up to DEPTH in the dominator tree.  The DEPTH of zero will
+   produce a vector containing all dominated blocks.  The vector will be sorted
+   in preorder.  */
+
+VEC (basic_block, heap) *
+get_dominated_to_depth (enum cdi_direction dir, basic_block bb, int depth)
+{
+  VEC(basic_block, heap) *bbs = NULL;
+  unsigned i;
+  unsigned next_level_start;
+
+  i = 0;
+  VEC_safe_push (basic_block, heap, bbs, bb);
+  next_level_start = 1; /* = VEC_length (basic_block, bbs); */
+
+  do
+    {
+      basic_block son;
+
+      bb = VEC_index (basic_block, bbs, i++);
+      for (son = first_dom_son (dir, bb);
+          son;
+          son = next_dom_son (dir, son))
+       VEC_safe_push (basic_block, heap, bbs, son);
+
+      if (i == next_level_start && --depth)
+       next_level_start = VEC_length (basic_block, bbs);
+    }
+  while (i < next_level_start);
+
+  return bbs;
+}
+
+/* Returns the list of basic blocks including BB dominated by BB, in the
+   direction DIR.  The vector will be sorted in preorder.  */
+
+VEC (basic_block, heap) *
+get_all_dominated_blocks (enum cdi_direction dir, basic_block bb)
+{
+  return get_dominated_to_depth (dir, bb, 0);
 }
 
 /* Redirect all edges pointing to BB to TO.  */
@@ -761,9 +830,13 @@ void
 redirect_immediate_dominators (enum cdi_direction dir, basic_block bb,
                               basic_block to)
 {
-  struct et_node *bb_node = bb->dom[dir], *to_node = to->dom[dir], *son;
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+  struct et_node *bb_node, *to_node, *son;
+
+  bb_node = bb->dom[dir_index];
+  to_node = to->dom[dir_index];
 
-  gcc_assert (dom_computed[dir]);
+  gcc_assert (dom_computed[dir_index]);
 
   if (!bb_node->son)
     return;
@@ -776,22 +849,24 @@ redirect_immediate_dominators (enum cdi_direction dir, basic_block bb,
       et_set_father (son, to_node);
     }
 
-  if (dom_computed[dir] == DOM_OK)
-    dom_computed[dir] = DOM_NO_FAST_QUERY;
+  if (dom_computed[dir_index] == DOM_OK)
+    dom_computed[dir_index] = DOM_NO_FAST_QUERY;
 }
 
 /* Find first basic block in the tree dominating both BB1 and BB2.  */
 basic_block
 nearest_common_dominator (enum cdi_direction dir, basic_block bb1, basic_block bb2)
 {
-  gcc_assert (dom_computed[dir]);
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+
+  gcc_assert (dom_computed[dir_index]);
 
   if (!bb1)
     return bb2;
   if (!bb2)
     return bb1;
 
-  return et_nca (bb1->dom[dir], bb2->dom[dir])->data;
+  return (basic_block) et_nca (bb1->dom[dir_index], bb2->dom[dir_index])->data;
 }
 
 
@@ -804,7 +879,7 @@ nearest_common_dominator_for_set (enum cdi_direction dir, bitmap blocks)
   unsigned i, first;
   bitmap_iterator bi;
   basic_block dom;
-  
+
   first = bitmap_first_set_bit (blocks);
   dom = BASIC_BLOCK (first);
   EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, bi)
@@ -814,61 +889,155 @@ nearest_common_dominator_for_set (enum cdi_direction dir, bitmap blocks)
   return dom;
 }
 
+/*  Given a dominator tree, we can determine whether one thing
+    dominates another in constant time by using two DFS numbers:
+
+    1. The number for when we visit a node on the way down the tree
+    2. The number for when we visit a node on the way back up the tree
+
+    You can view these as bounds for the range of dfs numbers the
+    nodes in the subtree of the dominator tree rooted at that node
+    will contain.
+
+    The dominator tree is always a simple acyclic tree, so there are
+    only three possible relations two nodes in the dominator tree have
+    to each other:
+
+    1. Node A is above Node B (and thus, Node A dominates node B)
+
+     A
+     |
+     C
+    / \
+   B   D
+
+
+   In the above case, DFS_Number_In of A will be <= DFS_Number_In of
+   B, and DFS_Number_Out of A will be >= DFS_Number_Out of B.  This is
+   because we must hit A in the dominator tree *before* B on the walk
+   down, and we will hit A *after* B on the walk back up
+
+   2. Node A is below node B (and thus, node B dominates node A)
+
+
+     B
+     |
+     A
+    / \
+   C   D
+
+   In the above case, DFS_Number_In of A will be >= DFS_Number_In of
+   B, and DFS_Number_Out of A will be <= DFS_Number_Out of B.
+
+   This is because we must hit A in the dominator tree *after* B on
+   the walk down, and we will hit A *before* B on the walk back up
+
+   3. Node A and B are siblings (and thus, neither dominates the other)
+
+     C
+     |
+     D
+    / \
+   A   B
+
+   In the above case, DFS_Number_In of A will *always* be <=
+   DFS_Number_In of B, and DFS_Number_Out of A will *always* be <=
+   DFS_Number_Out of B.  This is because we will always finish the dfs
+   walk of one of the subtrees before the other, and thus, the dfs
+   numbers for one subtree can't intersect with the range of dfs
+   numbers for the other subtree.  If you swap A and B's position in
+   the dominator tree, the comparison changes direction, but the point
+   is that both comparisons will always go the same way if there is no
+   dominance relationship.
+
+   Thus, it is sufficient to write
+
+   A_Dominates_B (node A, node B)
+   {
+     return DFS_Number_In(A) <= DFS_Number_In(B)
+            && DFS_Number_Out (A) >= DFS_Number_Out(B);
+   }
+
+   A_Dominated_by_B (node A, node B)
+   {
+     return DFS_Number_In(A) >= DFS_Number_In(A)
+            && DFS_Number_Out (A) <= DFS_Number_Out(B);
+   }  */
 
 /* Return TRUE in case BB1 is dominated by BB2.  */
 bool
-dominated_by_p (enum cdi_direction dir, basic_block bb1, basic_block bb2)
-{ 
-  struct et_node *n1 = bb1->dom[dir], *n2 = bb2->dom[dir];
+dominated_by_p (enum cdi_direction dir, const_basic_block bb1, const_basic_block bb2)
+{
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+  struct et_node *n1 = bb1->dom[dir_index], *n2 = bb2->dom[dir_index];
 
-  gcc_assert (dom_computed[dir]);
+  gcc_assert (dom_computed[dir_index]);
 
-  if (dom_computed[dir] == DOM_OK)
+  if (dom_computed[dir_index] == DOM_OK)
     return (n1->dfs_num_in >= n2->dfs_num_in
            && n1->dfs_num_out <= n2->dfs_num_out);
 
   return et_below (n1, n2);
 }
 
+/* Returns the entry dfs number for basic block BB, in the direction DIR.  */
+
+unsigned
+bb_dom_dfs_in (enum cdi_direction dir, basic_block bb)
+{
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+  struct et_node *n = bb->dom[dir_index];
+
+  gcc_assert (dom_computed[dir_index] == DOM_OK);
+  return n->dfs_num_in;
+}
+
+/* Returns the exit dfs number for basic block BB, in the direction DIR.  */
+
+unsigned
+bb_dom_dfs_out (enum cdi_direction dir, basic_block bb)
+{
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+  struct et_node *n = bb->dom[dir_index];
+
+  gcc_assert (dom_computed[dir_index] == DOM_OK);
+  return n->dfs_num_out;
+}
+
 /* Verify invariants of dominator structure.  */
-void
+DEBUG_FUNCTION void
 verify_dominators (enum cdi_direction dir)
 {
   int err = 0;
-  basic_block bb;
+  basic_block bb, imm_bb, imm_bb_correct;
+  struct dom_info di;
+  bool reverse = (dir == CDI_POST_DOMINATORS) ? true : false;
 
   gcc_assert (dom_info_available_p (dir));
 
+  init_dom_info (&di, dir);
+  calc_dfs_tree (&di, reverse);
+  calc_idoms (&di, reverse);
+
   FOR_EACH_BB (bb)
     {
-      basic_block dom_bb;
-      basic_block imm_bb;
-
-      dom_bb = recount_dominator (dir, bb);
       imm_bb = get_immediate_dominator (dir, bb);
-      if (dom_bb != imm_bb)
+      if (!imm_bb)
        {
-         if ((dom_bb == NULL) || (imm_bb == NULL))
-           error ("dominator of %d status unknown", bb->index);
-         else
-           error ("dominator of %d should be %d, not %d",
-                  bb->index, dom_bb->index, imm_bb->index);
+         error ("dominator of %d status unknown", bb->index);
          err = 1;
        }
-    }
 
-  if (dir == CDI_DOMINATORS)
-    {
-      FOR_EACH_BB (bb)
+      imm_bb_correct = di.dfs_to_bb[di.dom[di.dfs_order[bb->index]]];
+      if (imm_bb != imm_bb_correct)
        {
-         if (!dominated_by_p (dir, bb, ENTRY_BLOCK_PTR))
-           {
-             error ("ENTRY does not dominate bb %d", bb->index);
-             err = 1;
-           }
+         error ("dominator of %d should be %d, not %d",
+                bb->index, imm_bb_correct->index, imm_bb->index);
+         err = 1;
        }
     }
 
+  free_dom_info (&di);
   gcc_assert (!err);
 }
 
@@ -878,23 +1047,19 @@ verify_dominators (enum cdi_direction dir)
    reaches a fixed point.  */
 
 basic_block
-recount_dominator (enum cdi_direction dir, basic_block bb)
+recompute_dominator (enum cdi_direction dir, basic_block bb)
 {
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
   basic_block dom_bb = NULL;
   edge e;
   edge_iterator ei;
 
-  gcc_assert (dom_computed[dir]);
+  gcc_assert (dom_computed[dir_index]);
 
   if (dir == CDI_DOMINATORS)
     {
       FOR_EACH_EDGE (e, ei, bb->preds)
        {
-         /* Ignore the predecessors that either are not reachable from
-            the entry block, or whose dominator was not determined yet.  */
-         if (!dominated_by_p (dir, e->src, ENTRY_BLOCK_PTR))
-           continue;
-
          if (!dominated_by_p (dir, e->src, bb))
            dom_bb = nearest_common_dominator (dir, dom_bb, e->src);
        }
@@ -911,63 +1076,355 @@ recount_dominator (enum cdi_direction dir, basic_block bb)
   return dom_bb;
 }
 
-/* Iteratively recount dominators of BBS. The change is supposed to be local
-   and not to grow further.  */
-void
-iterate_fix_dominators (enum cdi_direction dir, basic_block *bbs, int n)
+/* Use simple heuristics (see iterate_fix_dominators) to determine dominators
+   of BBS.  We assume that all the immediate dominators except for those of the
+   blocks in BBS are correct.  If CONSERVATIVE is true, we also assume that the
+   currently recorded immediate dominators of blocks in BBS really dominate the
+   blocks.  The basic blocks for that we determine the dominator are removed
+   from BBS.  */
+
+static void
+prune_bbs_to_update_dominators (VEC (basic_block, heap) *bbs,
+                               bool conservative)
 {
-  int i, changed = 1;
-  basic_block old_dom, new_dom;
+  unsigned i;
+  bool single;
+  basic_block bb, dom = NULL;
+  edge_iterator ei;
+  edge e;
+
+  for (i = 0; VEC_iterate (basic_block, bbs, i, bb);)
+    {
+      if (bb == ENTRY_BLOCK_PTR)
+       goto succeed;
+
+      if (single_pred_p (bb))
+       {
+         set_immediate_dominator (CDI_DOMINATORS, bb, single_pred (bb));
+         goto succeed;
+       }
+
+      if (!conservative)
+       goto fail;
 
-  gcc_assert (dom_computed[dir]);
+      single = true;
+      dom = NULL;
+      FOR_EACH_EDGE (e, ei, bb->preds)
+       {
+         if (dominated_by_p (CDI_DOMINATORS, e->src, bb))
+           continue;
 
-  for (i = 0; i < n; i++)
-    set_immediate_dominator (dir, bbs[i], NULL);
+         if (!dom)
+           dom = e->src;
+         else
+           {
+             single = false;
+             dom = nearest_common_dominator (CDI_DOMINATORS, dom, e->src);
+           }
+       }
 
-  while (changed)
+      gcc_assert (dom != NULL);
+      if (single
+         || find_edge (dom, bb))
+       {
+         set_immediate_dominator (CDI_DOMINATORS, bb, dom);
+         goto succeed;
+       }
+
+fail:
+      i++;
+      continue;
+
+succeed:
+      VEC_unordered_remove (basic_block, bbs, i);
+    }
+}
+
+/* Returns root of the dominance tree in the direction DIR that contains
+   BB.  */
+
+static basic_block
+root_of_dom_tree (enum cdi_direction dir, basic_block bb)
+{
+  return (basic_block) et_root (bb->dom[dom_convert_dir_to_idx (dir)])->data;
+}
+
+/* See the comment in iterate_fix_dominators.  Finds the immediate dominators
+   for the sons of Y, found using the SON and BROTHER arrays representing
+   the dominance tree of graph G.  BBS maps the vertices of G to the basic
+   blocks.  */
+
+static void
+determine_dominators_for_sons (struct graph *g, VEC (basic_block, heap) *bbs,
+                              int y, int *son, int *brother)
+{
+  bitmap gprime;
+  int i, a, nc;
+  VEC (int, heap) **sccs;
+  basic_block bb, dom, ybb;
+  unsigned si;
+  edge e;
+  edge_iterator ei;
+
+  if (son[y] == -1)
+    return;
+  if (y == (int) VEC_length (basic_block, bbs))
+    ybb = ENTRY_BLOCK_PTR;
+  else
+    ybb = VEC_index (basic_block, bbs, y);
+
+  if (brother[son[y]] == -1)
     {
-      changed = 0;
-      for (i = 0; i < n; i++)
+      /* Handle the common case Y has just one son specially.  */
+      bb = VEC_index (basic_block, bbs, son[y]);
+      set_immediate_dominator (CDI_DOMINATORS, bb,
+                              recompute_dominator (CDI_DOMINATORS, bb));
+      identify_vertices (g, y, son[y]);
+      return;
+    }
+
+  gprime = BITMAP_ALLOC (NULL);
+  for (a = son[y]; a != -1; a = brother[a])
+    bitmap_set_bit (gprime, a);
+
+  nc = graphds_scc (g, gprime);
+  BITMAP_FREE (gprime);
+
+  sccs = XCNEWVEC (VEC (int, heap) *, nc);
+  for (a = son[y]; a != -1; a = brother[a])
+    VEC_safe_push (int, heap, sccs[g->vertices[a].component], a);
+
+  for (i = nc - 1; i >= 0; i--)
+    {
+      dom = NULL;
+      FOR_EACH_VEC_ELT (int, sccs[i], si, a)
        {
-         old_dom = get_immediate_dominator (dir, bbs[i]);
-         new_dom = recount_dominator (dir, bbs[i]);
-         if (old_dom != new_dom)
+         bb = VEC_index (basic_block, bbs, a);
+         FOR_EACH_EDGE (e, ei, bb->preds)
            {
-             changed = 1;
-             set_immediate_dominator (dir, bbs[i], new_dom);
+             if (root_of_dom_tree (CDI_DOMINATORS, e->src) != ybb)
+               continue;
+
+             dom = nearest_common_dominator (CDI_DOMINATORS, dom, e->src);
            }
        }
+
+      gcc_assert (dom != NULL);
+      FOR_EACH_VEC_ELT (int, sccs[i], si, a)
+       {
+         bb = VEC_index (basic_block, bbs, a);
+         set_immediate_dominator (CDI_DOMINATORS, bb, dom);
+       }
+    }
+
+  for (i = 0; i < nc; i++)
+    VEC_free (int, heap, sccs[i]);
+  free (sccs);
+
+  for (a = son[y]; a != -1; a = brother[a])
+    identify_vertices (g, y, a);
+}
+
+/* Recompute dominance information for basic blocks in the set BBS.  The
+   function assumes that the immediate dominators of all the other blocks
+   in CFG are correct, and that there are no unreachable blocks.
+
+   If CONSERVATIVE is true, we additionally assume that all the ancestors of
+   a block of BBS in the current dominance tree dominate it.  */
+
+void
+iterate_fix_dominators (enum cdi_direction dir, VEC (basic_block, heap) *bbs,
+                       bool conservative)
+{
+  unsigned i;
+  basic_block bb, dom;
+  struct graph *g;
+  int n, y;
+  size_t dom_i;
+  edge e;
+  edge_iterator ei;
+  struct pointer_map_t *map;
+  int *parent, *son, *brother;
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+
+  /* We only support updating dominators.  There are some problems with
+     updating postdominators (need to add fake edges from infinite loops
+     and noreturn functions), and since we do not currently use
+     iterate_fix_dominators for postdominators, any attempt to handle these
+     problems would be unused, untested, and almost surely buggy.  We keep
+     the DIR argument for consistency with the rest of the dominator analysis
+     interface.  */
+  gcc_assert (dir == CDI_DOMINATORS);
+  gcc_assert (dom_computed[dir_index]);
+
+  /* The algorithm we use takes inspiration from the following papers, although
+     the details are quite different from any of them:
+
+     [1] G. Ramalingam, T. Reps, An Incremental Algorithm for Maintaining the
+        Dominator Tree of a Reducible Flowgraph
+     [2]  V. C. Sreedhar, G. R. Gao, Y.-F. Lee: Incremental computation of
+         dominator trees
+     [3]  K. D. Cooper, T. J. Harvey and K. Kennedy: A Simple, Fast Dominance
+         Algorithm
+
+     First, we use the following heuristics to decrease the size of the BBS
+     set:
+       a) if BB has a single predecessor, then its immediate dominator is this
+         predecessor
+       additionally, if CONSERVATIVE is true:
+       b) if all the predecessors of BB except for one (X) are dominated by BB,
+         then X is the immediate dominator of BB
+       c) if the nearest common ancestor of the predecessors of BB is X and
+         X -> BB is an edge in CFG, then X is the immediate dominator of BB
+
+     Then, we need to establish the dominance relation among the basic blocks
+     in BBS.  We split the dominance tree by removing the immediate dominator
+     edges from BBS, creating a forest F.  We form a graph G whose vertices
+     are BBS and ENTRY and X -> Y is an edge of G if there exists an edge
+     X' -> Y in CFG such that X' belongs to the tree of the dominance forest
+     whose root is X.  We then determine dominance tree of G.  Note that
+     for X, Y in BBS, X dominates Y in CFG if and only if X dominates Y in G.
+     In this step, we can use arbitrary algorithm to determine dominators.
+     We decided to prefer the algorithm [3] to the algorithm of
+     Lengauer and Tarjan, since the set BBS is usually small (rarely exceeding
+     10 during gcc bootstrap), and [3] should perform better in this case.
+
+     Finally, we need to determine the immediate dominators for the basic
+     blocks of BBS.  If the immediate dominator of X in G is Y, then
+     the immediate dominator of X in CFG belongs to the tree of F rooted in
+     Y.  We process the dominator tree T of G recursively, starting from leaves.
+     Suppose that X_1, X_2, ..., X_k are the sons of Y in T, and that the
+     subtrees of the dominance tree of CFG rooted in X_i are already correct.
+     Let G' be the subgraph of G induced by {X_1, X_2, ..., X_k}.  We make
+     the following observations:
+       (i) the immediate dominator of all blocks in a strongly connected
+          component of G' is the same
+       (ii) if X has no predecessors in G', then the immediate dominator of X
+           is the nearest common ancestor of the predecessors of X in the
+           subtree of F rooted in Y
+     Therefore, it suffices to find the topological ordering of G', and
+     process the nodes X_i in this order using the rules (i) and (ii).
+     Then, we contract all the nodes X_i with Y in G, so that the further
+     steps work correctly.  */
+
+  if (!conservative)
+    {
+      /* Split the tree now.  If the idoms of blocks in BBS are not
+        conservatively correct, setting the dominators using the
+        heuristics in prune_bbs_to_update_dominators could
+        create cycles in the dominance "tree", and cause ICE.  */
+      FOR_EACH_VEC_ELT (basic_block, bbs, i, bb)
+       set_immediate_dominator (CDI_DOMINATORS, bb, NULL);
+    }
+
+  prune_bbs_to_update_dominators (bbs, conservative);
+  n = VEC_length (basic_block, bbs);
+
+  if (n == 0)
+    return;
+
+  if (n == 1)
+    {
+      bb = VEC_index (basic_block, bbs, 0);
+      set_immediate_dominator (CDI_DOMINATORS, bb,
+                              recompute_dominator (CDI_DOMINATORS, bb));
+      return;
+    }
+
+  /* Construct the graph G.  */
+  map = pointer_map_create ();
+  FOR_EACH_VEC_ELT (basic_block, bbs, i, bb)
+    {
+      /* If the dominance tree is conservatively correct, split it now.  */
+      if (conservative)
+       set_immediate_dominator (CDI_DOMINATORS, bb, NULL);
+      *pointer_map_insert (map, bb) = (void *) (size_t) i;
+    }
+  *pointer_map_insert (map, ENTRY_BLOCK_PTR) = (void *) (size_t) n;
+
+  g = new_graph (n + 1);
+  for (y = 0; y < g->n_vertices; y++)
+    g->vertices[y].data = BITMAP_ALLOC (NULL);
+  FOR_EACH_VEC_ELT (basic_block, bbs, i, bb)
+    {
+      FOR_EACH_EDGE (e, ei, bb->preds)
+       {
+         dom = root_of_dom_tree (CDI_DOMINATORS, e->src);
+         if (dom == bb)
+           continue;
+
+         dom_i = (size_t) *pointer_map_contains (map, dom);
+
+         /* Do not include parallel edges to G.  */
+         if (!bitmap_set_bit ((bitmap) g->vertices[dom_i].data, i))
+           continue;
+
+         add_edge (g, dom_i, i);
+       }
+    }
+  for (y = 0; y < g->n_vertices; y++)
+    BITMAP_FREE (g->vertices[y].data);
+  pointer_map_destroy (map);
+
+  /* Find the dominator tree of G.  */
+  son = XNEWVEC (int, n + 1);
+  brother = XNEWVEC (int, n + 1);
+  parent = XNEWVEC (int, n + 1);
+  graphds_domtree (g, n, parent, son, brother);
+
+  /* Finally, traverse the tree and find the immediate dominators.  */
+  for (y = n; son[y] != -1; y = son[y])
+    continue;
+  while (y != -1)
+    {
+      determine_dominators_for_sons (g, bbs, y, son, brother);
+
+      if (brother[y] != -1)
+       {
+         y = brother[y];
+         while (son[y] != -1)
+           y = son[y];
+       }
+      else
+       y = parent[y];
     }
 
-  for (i = 0; i < n; i++)
-    gcc_assert (get_immediate_dominator (dir, bbs[i]));
+  free (son);
+  free (brother);
+  free (parent);
+
+  free_graph (g);
 }
 
 void
 add_to_dominance_info (enum cdi_direction dir, basic_block bb)
 {
-  gcc_assert (dom_computed[dir]);
-  gcc_assert (!bb->dom[dir]);
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+
+  gcc_assert (dom_computed[dir_index]);
+  gcc_assert (!bb->dom[dir_index]);
 
-  n_bbs_in_dom_tree[dir]++;
-  
-  bb->dom[dir] = et_new_tree (bb);
+  n_bbs_in_dom_tree[dir_index]++;
 
-  if (dom_computed[dir] == DOM_OK)
-    dom_computed[dir] = DOM_NO_FAST_QUERY;
+  bb->dom[dir_index] = et_new_tree (bb);
+
+  if (dom_computed[dir_index] == DOM_OK)
+    dom_computed[dir_index] = DOM_NO_FAST_QUERY;
 }
 
 void
 delete_from_dominance_info (enum cdi_direction dir, basic_block bb)
 {
-  gcc_assert (dom_computed[dir]);
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+
+  gcc_assert (dom_computed[dir_index]);
 
-  et_free_tree (bb->dom[dir]);
-  bb->dom[dir] = NULL;
-  n_bbs_in_dom_tree[dir]--;
+  et_free_tree (bb->dom[dir_index]);
+  bb->dom[dir_index] = NULL;
+  n_bbs_in_dom_tree[dir_index]--;
 
-  if (dom_computed[dir] == DOM_OK)
-    dom_computed[dir] = DOM_NO_FAST_QUERY;
+  if (dom_computed[dir_index] == DOM_OK)
+    dom_computed[dir_index] = DOM_NO_FAST_QUERY;
 }
 
 /* Returns the first son of BB in the dominator or postdominator tree
@@ -976,9 +1433,10 @@ delete_from_dominance_info (enum cdi_direction dir, basic_block bb)
 basic_block
 first_dom_son (enum cdi_direction dir, basic_block bb)
 {
-  struct et_node *son = bb->dom[dir]->son;
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+  struct et_node *son = bb->dom[dir_index]->son;
 
-  return son ? son->data : NULL;
+  return (basic_block) (son ? son->data : NULL);
 }
 
 /* Returns the next dominance son after BB in the dominator or postdominator
@@ -987,9 +1445,30 @@ first_dom_son (enum cdi_direction dir, basic_block bb)
 basic_block
 next_dom_son (enum cdi_direction dir, basic_block bb)
 {
-  struct et_node *next = bb->dom[dir]->right;
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+  struct et_node *next = bb->dom[dir_index]->right;
 
-  return next->father->son == next ? NULL : next->data;
+  return (basic_block) (next->father->son == next ? NULL : next->data);
+}
+
+/* Return dominance availability for dominance info DIR.  */
+
+enum dom_state
+dom_info_state (enum cdi_direction dir)
+{
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+
+  return dom_computed[dir_index];
+}
+
+/* Set the dominance availability for dominance info DIR to NEW_STATE.  */
+
+void
+set_dom_info_availability (enum cdi_direction dir, enum dom_state new_state)
+{
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+
+  dom_computed[dir_index] = new_state;
 }
 
 /* Returns true if dominance information for direction DIR is available.  */
@@ -997,10 +1476,12 @@ next_dom_son (enum cdi_direction dir, basic_block bb)
 bool
 dom_info_available_p (enum cdi_direction dir)
 {
-  return dom_computed[dir] != DOM_NONE;
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+
+  return dom_computed[dir_index] != DOM_NONE;
 }
 
-void
+DEBUG_FUNCTION void
 debug_dominance_info (enum cdi_direction dir)
 {
   basic_block bb, bb2;
@@ -1008,3 +1489,41 @@ debug_dominance_info (enum cdi_direction dir)
     if ((bb2 = get_immediate_dominator (dir, bb)))
       fprintf (stderr, "%i %i\n", bb->index, bb2->index);
 }
+
+/* Prints to stderr representation of the dominance tree (for direction DIR)
+   rooted in ROOT, indented by INDENT tabulators.  If INDENT_FIRST is false,
+   the first line of the output is not indented.  */
+
+static void
+debug_dominance_tree_1 (enum cdi_direction dir, basic_block root,
+                       unsigned indent, bool indent_first)
+{
+  basic_block son;
+  unsigned i;
+  bool first = true;
+
+  if (indent_first)
+    for (i = 0; i < indent; i++)
+      fprintf (stderr, "\t");
+  fprintf (stderr, "%d\t", root->index);
+
+  for (son = first_dom_son (dir, root);
+       son;
+       son = next_dom_son (dir, son))
+    {
+      debug_dominance_tree_1 (dir, son, indent + 1, !first);
+      first = false;
+    }
+
+  if (first)
+    fprintf (stderr, "\n");
+}
+
+/* Prints to stderr representation of the dominance tree (for direction DIR)
+   rooted in ROOT.  */
+
+DEBUG_FUNCTION void
+debug_dominance_tree (enum cdi_direction dir, basic_block root)
+{
+  debug_dominance_tree_1 (dir, root, 0, false);
+}