OSDN Git Service

2004-09-22 Frank Ch. Eigler <fche@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / dominance.c
index d080957..ef40b54 100644 (file)
@@ -1,5 +1,5 @@
 /* Calculate (post)dominators in slightly super-linear time.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2003, 2004 Free Software Foundation, Inc.
    Contributed by Michael Matz (matz@ifh.de).
 
    This file is part of GCC.
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
-#include "error.h"
+#include "errors.h"
 #include "et-forest.h"
 
-struct dominance_info
-{
-  et_forest_t forest;
-  varray_type varray;
-};
-
-#define BB_NODE(info, bb) \
-  ((et_forest_node_t)VARRAY_GENERIC_PTR ((info)->varray, (bb)->index + 2))
-#define SET_BB_NODE(info, bb, node) \
-  (VARRAY_GENERIC_PTR ((info)->varray, (bb)->index + 2) = (node))
+/* Whether the dominators and the postdominators are available.  */
+enum dom_state dom_computed[2];
 
 /* 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
@@ -101,31 +95,35 @@ struct dom_info
      number of that node in DFS order counted from 1.  This is an index
      into most of the other arrays in this structure.  */
   TBB *dfs_order;
-  /* If x is the DFS-index of a node which corresponds with an basic block,
+  /* If x is the DFS-index of a node which corresponds with a basic block,
      dfs_to_bb[x] is that basic block.  Note, that in our structure there are
      more nodes that basic blocks, so only dfs_to_bb[dfs_order[bb->index]]==bb
      is true for every basic block bb, but not the opposite.  */
   basic_block *dfs_to_bb;
 
-  /* This is the next free DFS number when creating the DFS tree or forest.  */
+  /* This is the next free DFS number when creating the DFS tree.  */
   unsigned int dfsnum;
   /* The number of nodes in the DFS tree (==dfsnum-1).  */
   unsigned int nodes;
+
+  /* Blocks with bits set here have a fake edge to EXIT.  These are used
+     to turn a DFS forest into a proper tree.  */
+  bitmap fake_exit_edge;
 };
 
-static void init_dom_info              PARAMS ((struct dom_info *));
-static void free_dom_info              PARAMS ((struct dom_info *));
-static void calc_dfs_tree_nonrec       PARAMS ((struct dom_info *,
-                                                basic_block,
-                                                enum cdi_direction));
-static void calc_dfs_tree              PARAMS ((struct dom_info *,
-                                                enum cdi_direction));
-static void compress                   PARAMS ((struct dom_info *, TBB));
-static TBB eval                                PARAMS ((struct dom_info *, TBB));
-static void link_roots                 PARAMS ((struct dom_info *, TBB, TBB));
-static void calc_idoms                 PARAMS ((struct dom_info *,
-                                                enum cdi_direction));
-void debug_dominance_info              PARAMS ((dominance_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 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);
+void debug_dominance_info (enum cdi_direction);
+
+/* Keeps track of the*/
+static unsigned n_bbs_in_dom_tree[2];
 
 /* Helper macro for allocating and initializing an array,
    for aesthetic reasons.  */
@@ -134,10 +132,10 @@ void debug_dominance_info         PARAMS ((dominance_info));
     {                                                          \
       unsigned int i = 1;    /* Catch content == i.  */                \
       if (! (content))                                         \
-       (var) = (type *) xcalloc ((num), sizeof (type));        \
+       (var) = xcalloc ((num), sizeof (type));                 \
       else                                                     \
        {                                                       \
-         (var) = (type *) xmalloc ((num) * sizeof (type));     \
+         (var) = xmalloc ((num) * sizeof (type));              \
          for (i = 0; i < num; i++)                             \
            (var)[i] = (content);                               \
        }                                                       \
@@ -145,11 +143,10 @@ void debug_dominance_info         PARAMS ((dominance_info));
   while (0)
 
 /* Allocate all needed memory in a pessimistic fashion (so we round up).
-   This initialises the contents of DI, which already must be allocated.  */
+   This initializes the contents of DI, which already must be allocated.  */
 
 static void
-init_dom_info (di)
-     struct dom_info *di;
+init_dom_info (struct dom_info *di, enum cdi_direction dir)
 {
   /* We need memory for n_basic_blocks nodes and the ENTRY_BLOCK or
      EXIT_BLOCK.  */
@@ -171,6 +168,8 @@ init_dom_info (di)
 
   di->dfsnum = 1;
   di->nodes = 0;
+
+  di->fake_exit_edge = dir ? BITMAP_XMALLOC () : NULL;
 }
 
 #undef init_ar
@@ -178,8 +177,7 @@ init_dom_info (di)
 /* Free all allocated memory in DI, but not DI itself.  */
 
 static void
-free_dom_info (di)
-     struct dom_info *di;
+free_dom_info (struct dom_info *di)
 {
   free (di->dfs_parent);
   free (di->path_min);
@@ -192,6 +190,7 @@ free_dom_info (di)
   free (di->set_child);
   free (di->dfs_order);
   free (di->dfs_to_bb);
+  BITMAP_XFREE (di->fake_exit_edge);
 }
 
 /* The nonrecursive variant of creating a DFS tree.  DI is our working
@@ -201,12 +200,9 @@ free_dom_info (di)
    assigned their dfs number and are linked together to form a tree.  */
 
 static void
-calc_dfs_tree_nonrec (di, bb, reverse)
-     struct dom_info *di;
-     basic_block bb;
-     enum cdi_direction reverse;
+calc_dfs_tree_nonrec (struct dom_info *di, basic_block bb,
+                     enum cdi_direction reverse)
 {
-  /* We never call this with bb==EXIT_BLOCK_PTR (ENTRY_BLOCK_PTR if REVERSE).  */
   /* We call this _only_ if bb is not already visited.  */
   edge e;
   TBB child_i, my_i = 0;
@@ -218,7 +214,7 @@ calc_dfs_tree_nonrec (di, bb, reverse)
   /* Ending block.  */
   basic_block ex_block;
 
-  stack = (edge *) xmalloc ((n_basic_blocks + 3) * sizeof (edge));
+  stack = xmalloc ((n_basic_blocks + 3) * sizeof (edge));
   sp = 0;
 
   /* Initialize our border blocks, and the first edge.  */
@@ -275,8 +271,7 @@ calc_dfs_tree_nonrec (di, bb, reverse)
              e_next = bn->succ;
            }
 
-         if (bn == en_block)
-           abort ();
+         gcc_assert (bn != en_block);
 
          /* Fill the DFS tree info calculatable _before_ recursing.  */
          if (bb != en_block)
@@ -319,9 +314,7 @@ calc_dfs_tree_nonrec (di, bb, reverse)
    because there may be nodes from which the EXIT_BLOCK is unreachable.  */
 
 static void
-calc_dfs_tree (di, reverse)
-     struct dom_info *di;
-     enum cdi_direction reverse;
+calc_dfs_tree (struct dom_info *di, enum cdi_direction reverse)
 {
   /* The first block is the ENTRY_BLOCK (or EXIT_BLOCK if REVERSE).  */
   basic_block begin = reverse ? EXIT_BLOCK_PTR : ENTRY_BLOCK_PTR;
@@ -335,25 +328,53 @@ calc_dfs_tree (di, reverse)
     {
       /* 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
-         nodes, but in post-dom we have to deal with them, so we simply
-         include them in the DFS tree which actually becomes a forest.  */
+         nodes, but in post-dom we have to deal with them.
+
+        There are two situations in which this occurs.  First, noreturn
+        functions.  Second, infinite loops.  In the first case we need to
+        pretend that there is an edge to the exit block.  In the second
+        case, we wind up with a forest.  We need to process all noreturn
+        blocks before we know if we've got any infinite loops.  */
+
       basic_block b;
+      bool saw_unconnected = false;
+
       FOR_EACH_BB_REVERSE (b)
        {
-         if (di->dfs_order[b->index])
-           continue;
+         if (b->succ)
+           {
+             if (di->dfs_order[b->index] == 0)
+               saw_unconnected = true;
+             continue;
+           }
+         bitmap_set_bit (di->fake_exit_edge, b->index);
          di->dfs_order[b->index] = di->dfsnum;
          di->dfs_to_bb[di->dfsnum] = b;
+         di->dfs_parent[di->dfsnum] = di->dfs_order[last_basic_block];
          di->dfsnum++;
          calc_dfs_tree_nonrec (di, b, reverse);
        }
+
+      if (saw_unconnected)
+       {
+         FOR_EACH_BB_REVERSE (b)
+           {
+             if (di->dfs_order[b->index])
+               continue;
+             bitmap_set_bit (di->fake_exit_edge, b->index);
+             di->dfs_order[b->index] = di->dfsnum;
+             di->dfs_to_bb[di->dfsnum] = b;
+             di->dfs_parent[di->dfsnum] = di->dfs_order[last_basic_block];
+             di->dfsnum++;
+             calc_dfs_tree_nonrec (di, b, reverse);
+           }
+       }
     }
 
   di->nodes = di->dfsnum - 1;
 
   /* This aborts e.g. when there is _no_ path from ENTRY to EXIT at all.  */
-  if (di->nodes != (unsigned int) n_basic_blocks + 1)
-    abort ();
+  gcc_assert (di->nodes == (unsigned int) n_basic_blocks + 1);
 }
 
 /* Compress the path from V to the root of its set and update path_min at the
@@ -362,9 +383,7 @@ calc_dfs_tree (di, reverse)
    from V to that root.  */
 
 static void
-compress (di, v)
-     struct dom_info *di;
-     TBB v;
+compress (struct dom_info *di, TBB v)
 {
   /* Btw. It's not worth to unrecurse compress() as the depth is usually not
      greater than 5 even for huge graphs (I've not seen call depth > 4).
@@ -384,9 +403,7 @@ compress (di, v)
    value on the path from V to the root.  */
 
 static inline TBB
-eval (di, v)
-     struct dom_info *di;
-     TBB v;
+eval (struct dom_info *di, TBB v)
 {
   /* The representant of the set V is in, also called root (as the set
      representation is a tree).  */
@@ -415,9 +432,7 @@ eval (di, v)
    of W.  */
 
 static void
-link_roots (di, v, w)
-     struct dom_info *di;
-     TBB v, w;
+link_roots (struct dom_info *di, TBB v, TBB w)
 {
   TBB s = w;
 
@@ -459,9 +474,7 @@ link_roots (di, v, w)
    On return the immediate dominator to node V is in di->dom[V].  */
 
 static void
-calc_idoms (di, reverse)
-     struct dom_info *di;
-     enum cdi_direction reverse;
+calc_idoms (struct dom_info *di, enum cdi_direction reverse)
 {
   TBB v, w, k, par;
   basic_block en_block;
@@ -480,7 +493,16 @@ calc_idoms (di, reverse)
       par = di->dfs_parent[v];
       k = v;
       if (reverse)
-       e = bb->succ;
+       {
+         e = bb->succ;
+
+         /* If this block has a fake edge to exit, process that first.  */
+         if (bitmap_bit_p (di->fake_exit_edge, bb->index))
+           {
+             e_next = e;
+             goto do_fake_exit_edge;
+           }
+       }
       else
        e = bb->pred;
 
@@ -488,7 +510,7 @@ calc_idoms (di, reverse)
          to them.  That way we have the smallest node with also a path to
          us only over nodes behind us.  In effect we search for our
          semidominator.  */
-      for (; e; e = e_next)
+      for (; e ; e = e_next)
        {
          TBB k1;
          basic_block b;
@@ -504,7 +526,10 @@ calc_idoms (di, reverse)
              e_next = e->pred_next;
            }
          if (b == en_block)
-           k1 = di->dfs_order[last_basic_block];
+           {
+           do_fake_exit_edge:
+             k1 = di->dfs_order[last_basic_block];
+           }
          else
            k1 = di->dfs_order[b->index];
 
@@ -542,271 +567,422 @@ calc_idoms (di, reverse)
       di->dom[v] = di->dom[di->dom[v]];
 }
 
-/* The main entry point into this module.  IDOM is an integer array with room
-   for last_basic_block integers, DOMS is a preallocated sbitmap array having
-   room for last_basic_block^2 bits, and POST is true if the caller wants to
-   know post-dominators.
+/* Assign dfs numbers starting from NUM to NODE and its sons.  */
+
+static void
+assign_dfs_numbers (struct et_node *node, int *num)
+{
+  struct et_node *son;
+
+  node->dfs_num_in = (*num)++;
+
+  if (node->son)
+    {
+      assign_dfs_numbers (node->son, num);
+      for (son = node->son->right; son != node->son; son = son->right)
+       assign_dfs_numbers (son, num);
+    }
+
+  node->dfs_num_out = (*num)++;
+}
+
+/* Compute the data necessary for fast resolving of dominator queries in a
+   static dominator tree.  */
+
+static void
+compute_dom_fast_query (enum cdi_direction dir)
+{
+  int num = 0;
+  basic_block bb;
 
-   On return IDOM[i] will be the BB->index of the immediate (post) dominator
-   of basic block i, and DOMS[i] will have set bit j if basic block j is a
-   (post)dominator for block i.
+  gcc_assert (dom_computed[dir] >= DOM_NO_FAST_QUERY);
 
-   Either IDOM or DOMS may be NULL (meaning the caller is not interested in
-   immediate resp. all dominators).  */
+  if (dom_computed[dir] == DOM_OK)
+    return;
 
-dominance_info
-calculate_dominance_info (reverse)
-     enum cdi_direction reverse;
+  FOR_ALL_BB (bb)
+    {
+      if (!bb->dom[dir]->father)
+       assign_dfs_numbers (bb->dom[dir], &num);
+    }
+
+  dom_computed[dir] = DOM_OK;
+}
+
+/* The main entry point into this module.  DIR is set depending on whether
+   we want to compute dominators or postdominators.  */
+
+void
+calculate_dominance_info (enum cdi_direction dir)
 {
   struct dom_info di;
-  dominance_info info;
   basic_block b;
 
-  /* allocate structure for dominance information.  */
-  info = xmalloc (sizeof (struct dominance_info));
-  info->forest = et_forest_create ();
-  VARRAY_GENERIC_PTR_INIT (info->varray, last_basic_block + 3, "dominance info");
+  if (dom_computed[dir] == DOM_OK)
+    return;
 
-  /* Add the two well-known basic blocks.  */
-  SET_BB_NODE (info, ENTRY_BLOCK_PTR, et_forest_add_node (info->forest,
-                                                         ENTRY_BLOCK_PTR));
-  SET_BB_NODE (info, EXIT_BLOCK_PTR, et_forest_add_node (info->forest,
-                                                        EXIT_BLOCK_PTR));
-  FOR_EACH_BB (b)
-    SET_BB_NODE (info, b, et_forest_add_node (info->forest, b));
+  if (dom_computed[dir] != DOM_NO_FAST_QUERY)
+    {
+      if (dom_computed[dir] != DOM_NONE)
+       free_dominance_info (dir);
 
-  init_dom_info (&di);
-  calc_dfs_tree (&di, reverse);
-  calc_idoms (&di, reverse);
+      gcc_assert (!n_bbs_in_dom_tree[dir]);
 
+      FOR_ALL_BB (b)
+       {
+         b->dom[dir] = et_new_tree (b);
+       }
+      n_bbs_in_dom_tree[dir] = n_basic_blocks + 2;
 
-  FOR_EACH_BB (b)
-    {
-      TBB d = di.dom[di.dfs_order[b->index]];
+      init_dom_info (&di, dir);
+      calc_dfs_tree (&di, dir);
+      calc_idoms (&di, dir);
 
-      if (di.dfs_to_bb[d])
-        et_forest_add_edge (info->forest, BB_NODE (info, di.dfs_to_bb[d]), BB_NODE (info, b));
+      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]);
+       }
+
+      free_dom_info (&di);
+      dom_computed[dir] = DOM_NO_FAST_QUERY;
     }
 
-  free_dom_info (&di);
-  return info;
+  compute_dom_fast_query (dir);
 }
 
-/* Free dominance information.  */
+/* Free dominance information for direction DIR.  */
 void
-free_dominance_info (info)
-     dominance_info info;
+free_dominance_info (enum cdi_direction dir)
 {
   basic_block bb;
 
-  /* Allow users to create new basic block without setting up the dominance
-     information for them.  */
-  FOR_EACH_BB (bb)
-    if (bb->index < (int)(info->varray->num_elements - 2)
-       && BB_NODE (info, bb))
-      delete_from_dominance_info (info, bb);
-  delete_from_dominance_info (info, ENTRY_BLOCK_PTR);
-  delete_from_dominance_info (info, EXIT_BLOCK_PTR);
-  et_forest_delete (info->forest);
-  VARRAY_GROW (info->varray, 0);
-  free (info);
+  if (!dom_computed[dir])
+    return;
+
+  FOR_ALL_BB (bb)
+    {
+      delete_from_dominance_info (dir, bb);
+    }
+
+  /* If there are any nodes left, something is wrong.  */
+  gcc_assert (!n_bbs_in_dom_tree[dir]);
+
+  dom_computed[dir] = DOM_NONE;
 }
 
 /* Return the immediate dominator of basic block BB.  */
 basic_block
-get_immediate_dominator (dom, bb)
-     dominance_info dom;
-     basic_block bb;
+get_immediate_dominator (enum cdi_direction dir, basic_block bb)
 {
-  return et_forest_node_value (dom->forest,
-                              et_forest_parent (dom->forest,
-                                                BB_NODE (dom, bb)));
+  struct et_node *node = bb->dom[dir];
+
+  gcc_assert (dom_computed[dir]);
+
+  if (!node->father)
+    return NULL;
+
+  return node->father->data;
 }
 
 /* Set the immediate dominator of the block possibly removing
    existing edge.  NULL can be used to remove any edge.  */
 inline void
-set_immediate_dominator (dom, bb, dominated_by)
-     dominance_info dom;
-     basic_block bb, dominated_by;
+set_immediate_dominator (enum cdi_direction dir, basic_block bb,
+                        basic_block dominated_by)
 {
-  void *aux_bb_node;
-  et_forest_node_t bb_node = BB_NODE (dom, bb);
+  struct et_node *node = bb->dom[dir];
 
-  aux_bb_node = et_forest_parent (dom->forest, bb_node);
-  if (aux_bb_node)
-    et_forest_remove_edge (dom->forest, aux_bb_node, bb_node);
-  if (dominated_by != NULL)
+  gcc_assert (dom_computed[dir]);
+
+  if (node->father)
     {
-      if (bb == dominated_by)
-       abort ();
-      if (!et_forest_add_edge (dom->forest, BB_NODE (dom, dominated_by), bb_node))
-       abort ();
+      if (node->father->data == dominated_by)
+       return;
+      et_split (node);
     }
+
+  if (dominated_by)
+    et_set_father (node, dominated_by->dom[dir]);
+
+  if (dom_computed[dir] == DOM_OK)
+    dom_computed[dir] = DOM_NO_FAST_QUERY;
 }
 
-/* Store all basic blocks dominated by BB into BBS and return their number.  */
+/* Store all basic blocks immediately dominated by BB into BBS and return
+   their number.  */
 int
-get_dominated_by (dom, bb, bbs)
-     dominance_info dom;
-     basic_block bb;
-     basic_block **bbs;
+get_dominated_by (enum cdi_direction dir, basic_block bb, basic_block **bbs)
 {
-  int n, i;
+  int n;
+  struct et_node *node = bb->dom[dir], *son = node->son, *ason;
+
+  gcc_assert (dom_computed[dir]);
+
+  if (!son)
+    {
+      *bbs = NULL;
+      return 0;
+    }
+
+  for (ason = son->right, n = 1; ason != son; ason = ason->right)
+    n++;
+
+  *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;
 
-  *bbs = xmalloc (n_basic_blocks * sizeof (basic_block));
-  n = et_forest_enumerate_sons (dom->forest, BB_NODE (dom, bb), (et_forest_node_t *)*bbs);
-  for (i = 0; i < n; i++)
-   (*bbs)[i] = et_forest_node_value (dom->forest, (et_forest_node_t)(*bbs)[i]);
   return n;
 }
 
+/* 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.  */
+
+unsigned
+get_dominated_by_region (enum cdi_direction dir, basic_block *region,
+                        unsigned n_region, basic_block *doms)
+{
+  unsigned n_doms = 0, i;
+  basic_block dom;
+
+  for (i = 0; i < n_region; i++)
+    region[i]->rbi->duplicated = 1;
+  for (i = 0; i < n_region; i++)
+    for (dom = first_dom_son (dir, region[i]);
+        dom;
+        dom = next_dom_son (dir, dom))
+      if (!dom->rbi->duplicated)
+       doms[n_doms++] = dom;
+  for (i = 0; i < n_region; i++)
+    region[i]->rbi->duplicated = 0;
+
+  return n_doms;
+}
+
 /* Redirect all edges pointing to BB to TO.  */
 void
-redirect_immediate_dominators (dom, bb, to)
-     dominance_info dom;
-     basic_block bb;
-     basic_block to;
+redirect_immediate_dominators (enum cdi_direction dir, basic_block bb,
+                              basic_block to)
 {
-  et_forest_node_t *bbs = xmalloc (n_basic_blocks * sizeof (basic_block));
-  et_forest_node_t node = BB_NODE (dom, bb);
-  et_forest_node_t node2 = BB_NODE (dom, to);
-  int n = et_forest_enumerate_sons (dom->forest, node, bbs);
-  int i;
+  struct et_node *bb_node = bb->dom[dir], *to_node = to->dom[dir], *son;
 
-  for (i = 0; i < n; i++)
+  gcc_assert (dom_computed[dir]);
+
+  if (!bb_node->son)
+    return;
+
+  while (bb_node->son)
     {
-      et_forest_remove_edge (dom->forest, node, bbs[i]);
-      et_forest_add_edge (dom->forest, node2, bbs[i]);
+      son = bb_node->son;
+
+      et_split (son);
+      et_set_father (son, to_node);
     }
-  free (bbs);
+
+  if (dom_computed[dir] == DOM_OK)
+    dom_computed[dir] = DOM_NO_FAST_QUERY;
 }
 
 /* Find first basic block in the tree dominating both BB1 and BB2.  */
 basic_block
-nearest_common_dominator (dom, bb1, bb2)
-     dominance_info dom;
-     basic_block bb1;
-     basic_block bb2;
+nearest_common_dominator (enum cdi_direction dir, basic_block bb1, basic_block bb2)
 {
+  gcc_assert (dom_computed[dir]);
+
   if (!bb1)
     return bb2;
   if (!bb2)
     return bb1;
-  return et_forest_node_value (dom->forest,
-                              et_forest_common_ancestor (dom->forest,
-                                                         BB_NODE (dom, bb1),
-                                                         BB_NODE (dom,
-                                                                  bb2)));
+
+  return et_nca (bb1->dom[dir], bb2->dom[dir])->data;
 }
 
 /* Return TRUE in case BB1 is dominated by BB2.  */
 bool
-dominated_by_p (dom, bb1, bb2)
-     dominance_info dom;
-     basic_block bb1;
-     basic_block bb2;
-{
-  return nearest_common_dominator (dom, bb1, bb2) == bb2;
+dominated_by_p (enum cdi_direction dir, basic_block bb1, basic_block bb2)
+{ 
+  struct et_node *n1 = bb1->dom[dir], *n2 = bb2->dom[dir];
+
+  gcc_assert (dom_computed[dir]);
+
+  if (dom_computed[dir] == DOM_OK)
+    return (n1->dfs_num_in >= n2->dfs_num_in
+           && n1->dfs_num_out <= n2->dfs_num_out);
+
+  return et_below (n1, n2);
 }
 
 /* Verify invariants of dominator structure.  */
 void
-verify_dominators (dom)
-     dominance_info dom;
+verify_dominators (enum cdi_direction dir)
 {
   int err = 0;
   basic_block bb;
 
+  gcc_assert (dom_computed[dir]);
+
   FOR_EACH_BB (bb)
     {
       basic_block dom_bb;
 
-      dom_bb = recount_dominator (dom, bb);
-      if (dom_bb != get_immediate_dominator (dom, bb))
+      dom_bb = recount_dominator (dir, bb);
+      if (dom_bb != get_immediate_dominator (dir, bb))
        {
-         error ("dominator of %d should be %d, not %d",
-          bb->index, dom_bb->index, get_immediate_dominator(dom, bb)->index);
+         if (dom_bb == NULL)
+           error ("dominator of %d should be (unknown), not %d",
+                  bb->index, get_immediate_dominator(dir, bb)->index);
+         else
+           error ("dominator of %d should be %d, not %d",
+                  bb->index, dom_bb->index, get_immediate_dominator(dir, bb)->index);
          err = 1;
        }
     }
-  if (err)
-    abort ();
+
+  if (dir == CDI_DOMINATORS
+      && dom_computed[dir] >= DOM_NO_FAST_QUERY)
+    {
+      FOR_EACH_BB (bb)
+       {
+         if (!dominated_by_p (dir, bb, ENTRY_BLOCK_PTR))
+           {
+             error ("ENTRY does not dominate bb %d", bb->index);
+             err = 1;
+           }
+       }
+    }
+
+  gcc_assert (!err);
 }
 
-/* Recount dominator of BB.  */
+/* Determine immediate dominator (or postdominator, according to DIR) of BB,
+   assuming that dominators of other blocks are correct.  We also use it to
+   recompute the dominators in a restricted area, by iterating it until it
+   reaches a fixed point.  */
+
 basic_block
-recount_dominator (dom, bb)
-     dominance_info dom;
-     basic_block bb;
+recount_dominator (enum cdi_direction dir, basic_block bb)
 {
-   basic_block dom_bb = NULL;
-   edge e;
+  basic_block dom_bb = NULL;
+  edge e;
 
-   for (e = bb->pred; e; e = e->pred_next)
-     {
-       if (!dominated_by_p (dom, e->src, bb))
-         dom_bb = nearest_common_dominator (dom, dom_bb, e->src);
-     }
+  gcc_assert (dom_computed[dir]);
 
-   return dom_bb;
+  if (dir == CDI_DOMINATORS)
+    {
+      for (e = bb->pred; e; e = e->pred_next)
+       {
+         /* 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);
+       }
+    }
+  else
+    {
+      for (e = bb->succ; e; e = e->succ_next)
+       {
+         if (!dominated_by_p (dir, e->dest, bb))
+           dom_bb = nearest_common_dominator (dir, dom_bb, e->dest);
+       }
+    }
+
+  return dom_bb;
 }
 
 /* Iteratively recount dominators of BBS. The change is supposed to be local
    and not to grow further.  */
 void
-iterate_fix_dominators (dom, bbs, n)
-     dominance_info dom;
-     basic_block *bbs;
-     int n;
+iterate_fix_dominators (enum cdi_direction dir, basic_block *bbs, int n)
 {
   int i, changed = 1;
   basic_block old_dom, new_dom;
 
+  gcc_assert (dom_computed[dir]);
+
+  for (i = 0; i < n; i++)
+    set_immediate_dominator (dir, bbs[i], NULL);
+
   while (changed)
     {
       changed = 0;
       for (i = 0; i < n; i++)
        {
-         old_dom = get_immediate_dominator (dom, bbs[i]);
-         new_dom = recount_dominator (dom, bbs[i]);
+         old_dom = get_immediate_dominator (dir, bbs[i]);
+         new_dom = recount_dominator (dir, bbs[i]);
          if (old_dom != new_dom)
            {
              changed = 1;
-             set_immediate_dominator (dom, bbs[i], new_dom);
+             set_immediate_dominator (dir, bbs[i], new_dom);
            }
        }
     }
+
+  for (i = 0; i < n; i++)
+    gcc_assert (get_immediate_dominator (dir, bbs[i]));
 }
 
 void
-add_to_dominance_info (dom, bb)
-     dominance_info dom;
-     basic_block bb;
+add_to_dominance_info (enum cdi_direction dir, basic_block bb)
 {
-  VARRAY_GROW (dom->varray, last_basic_block + 3);
-#ifdef ENABLE_CHECKING
-  if (BB_NODE (dom, bb))
-    abort ();
-#endif
-  SET_BB_NODE (dom, bb, et_forest_add_node (dom->forest, bb));
+  gcc_assert (dom_computed[dir]);
+  gcc_assert (!bb->dom[dir]);
+
+  n_bbs_in_dom_tree[dir]++;
+  
+  bb->dom[dir] = et_new_tree (bb);
+
+  if (dom_computed[dir] == DOM_OK)
+    dom_computed[dir] = DOM_NO_FAST_QUERY;
 }
 
 void
-delete_from_dominance_info (dom, bb)
-     dominance_info dom;
-     basic_block bb;
+delete_from_dominance_info (enum cdi_direction dir, basic_block bb)
+{
+  gcc_assert (dom_computed[dir]);
+
+  et_free_tree (bb->dom[dir]);
+  bb->dom[dir] = NULL;
+  n_bbs_in_dom_tree[dir]--;
+
+  if (dom_computed[dir] == DOM_OK)
+    dom_computed[dir] = DOM_NO_FAST_QUERY;
+}
+
+/* Returns the first son of BB in the dominator or postdominator tree
+   as determined by DIR.  */
+
+basic_block
+first_dom_son (enum cdi_direction dir, basic_block bb)
+{
+  struct et_node *son = bb->dom[dir]->son;
+
+  return son ? son->data : NULL;
+}
+
+/* Returns the next dominance son after BB in the dominator or postdominator
+   tree as determined by DIR, or NULL if it was the last one.  */
+
+basic_block
+next_dom_son (enum cdi_direction dir, basic_block bb)
 {
-  et_forest_remove_node (dom->forest, BB_NODE (dom, bb));
-  SET_BB_NODE (dom, bb, NULL);
+  struct et_node *next = bb->dom[dir]->right;
+
+  return next->father->son == next ? NULL : next->data;
 }
 
 void
-debug_dominance_info (dom)
-  dominance_info dom;
+debug_dominance_info (enum cdi_direction dir)
 {
   basic_block bb, bb2;
   FOR_EACH_BB (bb)
-    if ((bb2 = get_immediate_dominator (dom, bb)))
+    if ((bb2 = get_immediate_dominator (dir, bb)))
       fprintf (stderr, "%i %i\n", bb->index, bb2->index);
 }