OSDN Git Service

* gcc.dg/dfp/func-array.c: Support -DDBG to report individual failures.
[pf3gnuchains/gcc-fork.git] / gcc / dominance.c
index 1018d1a..a9af9d5 100644 (file)
@@ -16,8 +16,8 @@
 
    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, 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, 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
 #include "basic-block.h"
 #include "toplev.h"
 #include "et-forest.h"
+#include "timevar.h"
 
 /* Whether the dominators and the postdominators are available.  */
-enum dom_state dom_computed[2];
+static 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
    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
-   'last_basic_block' for that.  Its dfs number is of course 1.  */
+   support multiple entry points.  Its dfs number is of course 1.  */
 
 /* Type of Basic Block aka. TBB */
 typedef unsigned int TBB;
@@ -114,13 +114,12 @@ 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*/
@@ -133,10 +132,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);                               \
        }                                                       \
@@ -149,9 +148,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 and the ENTRY_BLOCK or
-     EXIT_BLOCK.  */
-  unsigned int num = n_basic_blocks + 1 + 1;
+  unsigned int num = n_basic_blocks;
   init_ar (di->dfs_parent, TBB, num, 0);
   init_ar (di->path_min, TBB, num, i);
   init_ar (di->key, TBB, num, i);
@@ -170,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
@@ -201,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;
@@ -216,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 + 3) * sizeof (edge_iterator));
+  stack = XNEWVEC (edge_iterator, n_basic_blocks + 1);
   sp = 0;
 
   /* Initialize our border blocks, and the first edge.  */
@@ -313,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;
@@ -372,8 +391,8 @@ calc_dfs_tree (struct dom_info *di, enum cdi_direction reverse)
 
   di->nodes = di->dfsnum - 1;
 
-  /* Make sure there is a path from ENTRY to EXIT at all.  */
-  gcc_assert (di->nodes == (unsigned int) n_basic_blocks + 1);
+  /* This aborts e.g. when there is _no_ path from ENTRY to EXIT at all.  */
+  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
@@ -473,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;
@@ -592,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
@@ -615,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 + 2;
+      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.  */
@@ -653,28 +678,31 @@ 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;
@@ -688,9 +716,10 @@ inline void
 set_immediate_dominator (enum cdi_direction dir, basic_block bb,
                         basic_block dominated_by)
 {
-  struct et_node *node = bb->dom[dir];
-
-  gcc_assert (dom_computed[dir]);
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
+  struct et_node *node = bb->dom[dir_index];
+  gcc_assert (dom_computed[dir_index]);
 
   if (node->father)
     {
@@ -700,10 +729,10 @@ 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
@@ -711,10 +740,11 @@ set_immediate_dominator (enum cdi_direction dir, basic_block bb,
 int
 get_dominated_by (enum cdi_direction dir, basic_block bb, basic_block **bbs)
 {
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
   int n;
-  struct et_node *node = bb->dom[dir], *son = node->son, *ason;
-
-  gcc_assert (dom_computed[dir]);
+  struct et_node *node = bb->dom[dir_index], *son = node->son, *ason;
+  gcc_assert (dom_computed[dir_index]);
 
   if (!son)
     {
@@ -725,7 +755,7 @@ get_dominated_by (enum cdi_direction dir, basic_block bb, basic_block **bbs)
   for (ason = son->right, n = 1; ason != son; ason = ason->right)
     n++;
 
-  *bbs = xmalloc (n * sizeof (basic_block));
+  *bbs = XNEWVEC (basic_block, n);
   (*bbs)[0] = son->data;
   for (ason = son->right, n = 1; ason != son; ason = ason->right)
     (*bbs)[n++] = ason->data;
@@ -764,9 +794,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;
@@ -779,22 +813,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 et_nca (bb1->dom[dir_index], bb2->dom[dir_index])->data;
 }
 
 
@@ -817,22 +853,121 @@ 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];
+  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_index]);
 
-  gcc_assert (dom_computed[dir]);
-
-  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
 verify_dominators (enum cdi_direction dir)
@@ -883,11 +1018,12 @@ verify_dominators (enum cdi_direction dir)
 basic_block
 recount_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)
     {
@@ -919,10 +1055,11 @@ recount_dominator (enum cdi_direction dir, basic_block bb)
 void
 iterate_fix_dominators (enum cdi_direction dir, basic_block *bbs, int n)
 {
+  unsigned int dir_index = dom_convert_dir_to_idx (dir);
   int i, changed = 1;
   basic_block old_dom, new_dom;
 
-  gcc_assert (dom_computed[dir]);
+  gcc_assert (dom_computed[dir_index]);
 
   for (i = 0; i < n; i++)
     set_immediate_dominator (dir, bbs[i], NULL);
@@ -949,28 +1086,32 @@ iterate_fix_dominators (enum cdi_direction dir, basic_block *bbs, int n)
 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]++;
+  n_bbs_in_dom_tree[dir_index]++;
   
-  bb->dom[dir] = et_new_tree (bb);
+  bb->dom[dir_index] = et_new_tree (bb);
 
-  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;
 }
 
 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
@@ -979,7 +1120,8 @@ 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;
 }
@@ -990,17 +1132,40 @@ 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 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.  */
 
 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