OSDN Git Service

* config/ia64/ia64.c (ia64_expand_call): Force function address
[pf3gnuchains/gcc-fork.git] / gcc / dominance.c
index 3c35268..38182ef 100644 (file)
@@ -1,23 +1,23 @@
 /* Calculate (post)dominators in slightly super-linear time.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2003 Free Software Foundation, Inc.
    Contributed by Michael Matz (matz@ifh.de).
-  
-   This file is part of GNU CC.
-   GNU CC is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
+
+   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)
    any later version.
 
-   GNU CC is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GNU CC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 /* 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
    block I(X), called the immediate dominator of X, which is the parent of X
    in the dominator tree.
 
-   The algorithm computes this dominator tree implicitely by computing for
+   The algorithm computes this dominator tree implicitly by computing for
    each block its immediate dominator.  We use tree balancing and path
    compression, so its the O(e*a(e,v)) variant, where a(e,v) is the very
    slowly growing functional inverse of the Ackerman function.  */
 
 #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 "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))
 
 /* 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
    number of the corresponding basic block.  Please note, that we include the
    artificial ENTRY_BLOCK (or EXIT_BLOCK in the post-dom case) in our lists to
    support multiple entry points.  As it has no real basic block index we use
-   'n_basic_blocks' for that.  Its dfs number is of course 1.  */
+   'last_basic_block' for that.  Its dfs number is of course 1.  */
 
 /* Type of Basic Block aka. TBB */
 typedef unsigned int TBB;
@@ -89,7 +103,7 @@ 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 correspondends 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.  */
@@ -101,42 +115,39 @@ struct dom_info
   unsigned int nodes;
 };
 
-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));
-static void idoms_to_doms              PARAMS ((struct dom_info *,
-                                                sbitmap *));
+static void init_dom_info (struct dom_info *);
+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 (dominance_info);
 
 /* Helper macro for allocating and initializing an array,
    for aesthetic reasons.  */
 #define init_ar(var, type, num, content)                       \
-  do {                                                         \
-    unsigned int i = 1;    /* Catch content == i.  */          \
-    if (! (content))                                           \
-      (var) = (type *) xcalloc ((num), sizeof (type));         \
-    else                                                       \
-      {                                                                \
-        (var) = (type *) xmalloc ((num) * sizeof (type));      \
-       for (i = 0; i < num; i++)                               \
-         (var)[i] = (content);                                 \
-      }                                                                \
-  } while (0)
+  do                                                           \
+    {                                                          \
+      unsigned int i = 1;    /* Catch content == i.  */                \
+      if (! (content))                                         \
+       (var) = xcalloc ((num), sizeof (type));                 \
+      else                                                     \
+       {                                                       \
+         (var) = xmalloc ((num) * sizeof (type));              \
+         for (i = 0; i < num; i++)                             \
+           (var)[i] = (content);                               \
+       }                                                       \
+    }                                                          \
+  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)
 {
   /* We need memory for n_basic_blocks nodes and the ENTRY_BLOCK or
      EXIT_BLOCK.  */
@@ -153,7 +164,7 @@ init_dom_info (di)
   init_ar (di->set_size, unsigned int, num, 1);
   init_ar (di->set_child, TBB, num, 0);
 
-  init_ar (di->dfs_order, TBB, (unsigned int) n_basic_blocks + 1, 0);
+  init_ar (di->dfs_order, TBB, (unsigned int) last_basic_block + 1, 0);
   init_ar (di->dfs_to_bb, basic_block, num, 0);
 
   di->dfsnum = 1;
@@ -165,8 +176,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);
@@ -188,10 +198,7 @@ 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.  */
@@ -205,7 +212,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.  */
@@ -269,7 +276,7 @@ calc_dfs_tree_nonrec (di, bb, reverse)
          if (bb != en_block)
            my_i = di->dfs_order[bb->index];
          else
-           my_i = di->dfs_order[n_basic_blocks];
+           my_i = di->dfs_order[last_basic_block];
          child_i = di->dfs_order[bn->index] = di->dfsnum++;
          di->dfs_to_bb[child_i] = bn;
          di->dfs_parent[child_i] = my_i;
@@ -306,13 +313,11 @@ 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;
-  di->dfs_order[n_basic_blocks] = di->dfsnum;
+  di->dfs_order[last_basic_block] = di->dfsnum;
   di->dfs_to_bb[di->dfsnum] = begin;
   di->dfsnum++;
 
@@ -324,10 +329,9 @@ calc_dfs_tree (di, reverse)
          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.  */
-      int i;
-      for (i = n_basic_blocks - 1; i >= 0; i--)
+      basic_block b;
+      FOR_EACH_BB_REVERSE (b)
        {
-         basic_block b = BASIC_BLOCK (i);
          if (di->dfs_order[b->index])
            continue;
          di->dfs_order[b->index] = di->dfsnum;
@@ -350,9 +354,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).
@@ -372,9 +374,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).  */
@@ -403,9 +403,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;
 
@@ -447,9 +445,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;
@@ -492,7 +488,7 @@ calc_idoms (di, reverse)
              e_next = e->pred_next;
            }
          if (b == en_block)
-           k1 = di->dfs_order[n_basic_blocks];
+           k1 = di->dfs_order[last_basic_block];
          else
            k1 = di->dfs_order[b->index];
 
@@ -523,60 +519,16 @@ calc_idoms (di, reverse)
       v--;
     }
 
-  /* Explicitely define the dominators.  */
+  /* Explicitly define the dominators.  */
   di->dom[1] = 0;
   for (v = 2; v <= di->nodes; v++)
     if (di->dom[v] != di->key[v])
       di->dom[v] = di->dom[di->dom[v]];
 }
 
-/* Convert the information about immediate dominators (in DI) to sets of all
-   dominators (in DOMINATORS).  */
-
-static void
-idoms_to_doms (di, dominators)
-     struct dom_info *di;
-     sbitmap *dominators;
-{
-  TBB i, e_index;
-  int bb, bb_idom;
-  sbitmap_vector_zero (dominators, n_basic_blocks);
-  /* We have to be careful, to not include the ENTRY_BLOCK or EXIT_BLOCK
-     in the list of (post)-doms, so remember that in e_index.  */
-  e_index = di->dfs_order[n_basic_blocks];
-
-  for (i = 1; i <= di->nodes; i++)
-    {
-      if (i == e_index)
-       continue;
-      bb = di->dfs_to_bb[i]->index;
-
-      if (di->dom[i] && (di->dom[i] != e_index))
-       {
-         bb_idom = di->dfs_to_bb[di->dom[i]]->index;
-         sbitmap_copy (dominators[bb], dominators[bb_idom]);
-       }
-      else
-       {
-         /* It has no immediate dom or only ENTRY_BLOCK or EXIT_BLOCK.
-            If it is a child of ENTRY_BLOCK that's OK, and it's only
-            dominated by itself; if it's _not_ a child of ENTRY_BLOCK, it
-            means, it is unreachable.  That case has been disallowed in the
-            building of the DFS tree, so we are save here.  For the reverse
-            flow graph it means, it has no children, so, to be compatible
-            with the old code, we set the post_dominators to all one.  */
-         if (!di->dom[i])
-           {
-             sbitmap_ones (dominators[bb]);
-           }
-       }
-      SET_BIT (dominators[bb], bb);
-    }
-}
-
 /* The main entry point into this module.  IDOM is an integer array with room
-   for n_basic_blocks integers, DOMS is a preallocated sbitmap array having
-   room for n_basic_blocks^2 bits, and POST is true if the caller wants to
+   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.
 
    On return IDOM[i] will be the BB->index of the immediate (post) dominator
@@ -586,37 +538,230 @@ idoms_to_doms (di, dominators)
    Either IDOM or DOMS may be NULL (meaning the caller is not interested in
    immediate resp. all dominators).  */
 
-void
-calculate_dominance_info (idom, doms, reverse)
-     int *idom;
-     sbitmap *doms;
-     enum cdi_direction reverse;
+dominance_info
+calculate_dominance_info (enum cdi_direction reverse)
 {
   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");
+
+  /* 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 (!doms && !idom)
-    return;
   init_dom_info (&di);
   calc_dfs_tree (&di, reverse);
   calc_idoms (&di, reverse);
 
-  if (idom)
+
+  FOR_EACH_BB (b)
     {
-      int i;
-      for (i = 0; i < n_basic_blocks; i++)
+      TBB d = di.dom[di.dfs_order[b->index]];
+
+      if (di.dfs_to_bb[d])
+        et_forest_add_edge (info->forest, BB_NODE (info, di.dfs_to_bb[d]), BB_NODE (info, b));
+    }
+
+  free_dom_info (&di);
+  return info;
+}
+
+/* Free dominance information.  */
+void
+free_dominance_info (dominance_info info)
+{
+  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);
+}
+
+/* Return the immediate dominator of basic block BB.  */
+basic_block
+get_immediate_dominator (dominance_info dom, basic_block bb)
+{
+  return et_forest_node_value (dom->forest,
+                              et_forest_parent (dom->forest,
+                                                BB_NODE (dom, bb)));
+}
+
+/* Set the immediate dominator of the block possibly removing
+   existing edge.  NULL can be used to remove any edge.  */
+inline void
+set_immediate_dominator (dominance_info dom, basic_block bb, basic_block dominated_by)
+{
+  void *aux_bb_node;
+  et_forest_node_t bb_node = BB_NODE (dom, bb);
+
+  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)
+    {
+      if (bb == dominated_by)
+       abort ();
+      if (!et_forest_add_edge (dom->forest, BB_NODE (dom, dominated_by), bb_node))
+       abort ();
+    }
+}
+
+/* Store all basic blocks dominated by BB into BBS and return their number.  */
+int
+get_dominated_by (dominance_info dom, basic_block bb, basic_block **bbs)
+{
+  int n, i;
+
+  *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;
+}
+
+/* Redirect all edges pointing to BB to TO.  */
+void
+redirect_immediate_dominators (dominance_info dom, 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;
+
+  for (i = 0; i < n; i++)
+    {
+      et_forest_remove_edge (dom->forest, node, bbs[i]);
+      et_forest_add_edge (dom->forest, node2, bbs[i]);
+    }
+  free (bbs);
+}
+
+/* Find first basic block in the tree dominating both BB1 and BB2.  */
+basic_block
+nearest_common_dominator (dominance_info dom, basic_block bb1, basic_block bb2)
+{
+  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 TRUE in case BB1 is dominated by BB2.  */
+bool
+dominated_by_p (dominance_info dom, basic_block bb1, basic_block bb2)
+{
+  return nearest_common_dominator (dom, bb1, bb2) == bb2;
+}
+
+/* Verify invariants of dominator structure.  */
+void
+verify_dominators (dominance_info dom)
+{
+  int err = 0;
+  basic_block bb;
+
+  FOR_EACH_BB (bb)
+    {
+      basic_block dom_bb;
+
+      dom_bb = recount_dominator (dom, bb);
+      if (dom_bb != get_immediate_dominator (dom, bb))
        {
-         basic_block b = BASIC_BLOCK (i);
-         TBB d = di.dom[di.dfs_order[b->index]];
-
-         /* The old code didn't modify array elements of nodes having only
-            itself as dominator (d==0) or only ENTRY_BLOCK (resp. EXIT_BLOCK)
-            (d==1).  */
-         if (d > 1)
-           idom[i] = di.dfs_to_bb[d]->index;
+         error ("dominator of %d should be %d, not %d",
+          bb->index, dom_bb->index, get_immediate_dominator(dom, bb)->index);
+         err = 1;
        }
     }
-  if (doms)
-    idoms_to_doms (&di, doms);
+  if (err)
+    abort ();
+}
 
-  free_dom_info (&di);
+/* Recount dominator of BB.  */
+basic_block
+recount_dominator (dominance_info dom, basic_block bb)
+{
+   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);
+     }
+
+   return dom_bb;
+}
+
+/* Iteratively recount dominators of BBS. The change is supposed to be local
+   and not to grow further.  */
+void
+iterate_fix_dominators (dominance_info dom, basic_block *bbs, int n)
+{
+  int i, changed = 1;
+  basic_block old_dom, new_dom;
+
+  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]);
+         if (old_dom != new_dom)
+           {
+             changed = 1;
+             set_immediate_dominator (dom, bbs[i], new_dom);
+           }
+       }
+    }
+}
+
+void
+add_to_dominance_info (dominance_info dom, 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));
+}
+
+void
+delete_from_dominance_info (dominance_info dom, basic_block bb)
+{
+  et_forest_remove_node (dom->forest, BB_NODE (dom, bb));
+  SET_BB_NODE (dom, bb, NULL);
+}
+
+void
+debug_dominance_info (dominance_info dom)
+{
+  basic_block bb, bb2;
+  FOR_EACH_BB (bb)
+    if ((bb2 = get_immediate_dominator (dom, bb)))
+      fprintf (stderr, "%i %i\n", bb->index, bb2->index);
 }