#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 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. */
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 *));
+void debug_dominance_info PARAMS ((dominance_info));
/* Helper macro for allocating and initializing an array,
for aesthetic reasons. */
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;
{
- /* We need memory for num_basic_blocks nodes and the ENTRY_BLOCK or
+ /* We need memory for n_basic_blocks nodes and the ENTRY_BLOCK or
EXIT_BLOCK. */
- unsigned int num = num_basic_blocks + 2;
+ unsigned int num = n_basic_blocks + 1 + 1;
init_ar (di->dfs_parent, TBB, num, 0);
init_ar (di->path_min, TBB, num, i);
init_ar (di->key, TBB, num, i);
/* Ending block. */
basic_block ex_block;
- stack = (edge *) xmalloc ((num_basic_blocks + 3) * sizeof (edge));
+ stack = (edge *) xmalloc ((n_basic_blocks + 3) * sizeof (edge));
sp = 0;
/* Initialize our border blocks, and the first edge. */
/* If the next node BN is either already visited or a border
block the current edge is useless, and simply overwritten
with the next edge out of the current node. */
- if (bn == ex_block || di->dfs_order[bn->sindex])
+ if (bn == ex_block || di->dfs_order[bn->index])
{
e = e->pred_next;
continue;
else
{
bn = e->dest;
- if (bn == ex_block || di->dfs_order[bn->sindex])
+ if (bn == ex_block || di->dfs_order[bn->index])
{
e = e->succ_next;
continue;
/* Fill the DFS tree info calculatable _before_ recursing. */
if (bb != en_block)
- my_i = di->dfs_order[bb->sindex];
+ my_i = di->dfs_order[bb->index];
else
my_i = di->dfs_order[last_basic_block];
- child_i = di->dfs_order[bn->sindex] = di->dfsnum++;
+ child_i = di->dfs_order[bn->index] = di->dfsnum++;
di->dfs_to_bb[child_i] = bn;
di->dfs_parent[child_i] = my_i;
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. */
basic_block b;
- FOR_ALL_BB_REVERSE (b)
+ FOR_EACH_BB_REVERSE (b)
{
- if (di->dfs_order[b->sindex])
+ if (di->dfs_order[b->index])
continue;
- di->dfs_order[b->sindex] = di->dfsnum;
+ di->dfs_order[b->index] = di->dfsnum;
di->dfs_to_bb[di->dfsnum] = b;
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) num_basic_blocks + 1)
+ if (di->nodes != (unsigned int) n_basic_blocks + 1)
abort ();
}
if (b == en_block)
k1 = di->dfs_order[last_basic_block];
else
- k1 = di->dfs_order[b->sindex];
+ k1 = di->dfs_order[b->index];
/* Call eval() only if really needed. If k1 is above V in DFS tree,
then we know, that eval(k1) == k1 and key[k1] == k1. */
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, last_basic_block);
- /* 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[last_basic_block];
-
- for (i = 1; i <= di->nodes; i++)
- {
- if (i == e_index)
- continue;
- bb = di->dfs_to_bb[i]->sindex;
-
- if (di->dom[i] && (di->dom[i] != e_index))
- {
- bb_idom = di->dfs_to_bb[di->dom[i]]->sindex;
- 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 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
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;
+dominance_info
+calculate_dominance_info (reverse)
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)
{
- basic_block b;
+ TBB d = di.dom[di.dfs_order[b->index]];
- FOR_ALL_BB (b)
+ 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 (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 (dom, bb)
+ 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 (dom, bb, dominated_by)
+ dominance_info dom;
+ basic_block bb, 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 (dom, bb, bbs)
+ 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 (dom, bb, to)
+ 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 (dom, bb1, bb2)
+ 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 (dom, bb1, bb2)
+ 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 (dom)
+ 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))
{
- TBB d = di.dom[di.dfs_order[b->sindex]];
+ error ("dominator of %d should be %d, not %d",
+ bb->index, dom_bb->index, get_immediate_dominator(dom, bb)->index);
+ err = 1;
+ }
+ }
+ if (err)
+ abort ();
+}
+
+/* Recount dominator of BB. */
+basic_block
+recount_dominator (dom, bb)
+ 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);
+ }
- /* 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[b->sindex] = di.dfs_to_bb[d]->sindex;
+ 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;
+{
+ 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);
+ }
}
}
- if (doms)
- idoms_to_doms (&di, doms);
+}
- free_dom_info (&di);
+void
+add_to_dominance_info (dom, bb)
+ 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 (dom, bb)
+ 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 (dom)
+ 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);
}