re PR middle-end/28071 (A file that can not be compiled in reasonable time/space)
PR rtl-optimization/28071 * basic-block.h (bb_dom_dfs_in, bb_dom_dfs_out): Declare. * dominance.c (bb_dom_dfs_in, bb_dom_dfs_out): New functions. * tree-into-ssa.c (struct dom_dfsnum): New. (cmp_dfsnum, find_dfsnum_interval, prune_unused_phi_nodes): New functions. (insert_phi_nodes_for): Use prune_unused_phi_nodes instead of compute_global_livein. (prepare_block_for_update, prepare_use_sites_for): Mark the uses in phi nodes in the correct blocks. From-SVN: r116190
This commit is contained in:
parent
b43a2366d6
commit
f074ff6cc0
@ -1,3 +1,16 @@
|
||||
2006-08-16 Zdenek Dvorak <dvorakz@suse.cz>
|
||||
|
||||
PR rtl-optimization/28071
|
||||
* basic-block.h (bb_dom_dfs_in, bb_dom_dfs_out): Declare.
|
||||
* dominance.c (bb_dom_dfs_in, bb_dom_dfs_out): New functions.
|
||||
* tree-into-ssa.c (struct dom_dfsnum): New.
|
||||
(cmp_dfsnum, find_dfsnum_interval, prune_unused_phi_nodes): New
|
||||
functions.
|
||||
(insert_phi_nodes_for): Use prune_unused_phi_nodes instead of
|
||||
compute_global_livein.
|
||||
(prepare_block_for_update, prepare_use_sites_for): Mark the uses
|
||||
in phi nodes in the correct blocks.
|
||||
|
||||
2006-08-16 Zdenek Dvorak <dvorakz@suse.cz>
|
||||
|
||||
PR tree-optimization/28364
|
||||
|
@ -988,6 +988,9 @@ extern void iterate_fix_dominators (enum cdi_direction, basic_block *, int);
|
||||
extern void verify_dominators (enum cdi_direction);
|
||||
extern basic_block first_dom_son (enum cdi_direction, basic_block);
|
||||
extern basic_block next_dom_son (enum cdi_direction, basic_block);
|
||||
unsigned bb_dom_dfs_in (enum cdi_direction, basic_block);
|
||||
unsigned bb_dom_dfs_out (enum cdi_direction, basic_block);
|
||||
|
||||
extern edge try_redirect_by_replacing_jump (edge, basic_block, bool);
|
||||
extern void break_superblocks (void);
|
||||
extern void check_bb_profile (basic_block, FILE *);
|
||||
|
@ -909,6 +909,28 @@ dominated_by_p (enum cdi_direction dir, basic_block bb1, basic_block bb2)
|
||||
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)
|
||||
{
|
||||
struct et_node *n = bb->dom[dir];
|
||||
|
||||
gcc_assert (dom_computed[dir] == 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)
|
||||
{
|
||||
struct et_node *n = bb->dom[dir];
|
||||
|
||||
gcc_assert (dom_computed[dir] == DOM_OK);
|
||||
return n->dfs_num_out;
|
||||
}
|
||||
|
||||
/* Verify invariants of dominator structure. */
|
||||
void
|
||||
verify_dominators (enum cdi_direction dir)
|
||||
|
@ -779,6 +779,214 @@ mark_def_sites (struct dom_walk_data *walk_data,
|
||||
SET_BIT (gd->interesting_blocks, bb->index);
|
||||
}
|
||||
|
||||
/* Structure used by prune_unused_phi_nodes to record bounds of the intervals
|
||||
in the dfs numbering of the dominance tree. */
|
||||
|
||||
struct dom_dfsnum
|
||||
{
|
||||
/* Basic block whose index this entry corresponds to. */
|
||||
unsigned bb_index;
|
||||
|
||||
/* The dfs number of this node. */
|
||||
unsigned dfs_num;
|
||||
};
|
||||
|
||||
/* Compares two entries of type struct dom_dfsnum by dfs_num field. Callback
|
||||
for qsort. */
|
||||
|
||||
static int
|
||||
cmp_dfsnum (const void *a, const void *b)
|
||||
{
|
||||
const struct dom_dfsnum *da = a;
|
||||
const struct dom_dfsnum *db = b;
|
||||
|
||||
return (int) da->dfs_num - (int) db->dfs_num;
|
||||
}
|
||||
|
||||
/* Among the intervals starting at the N points specified in DEFS, find
|
||||
the one that contains S, and return its bb_index. */
|
||||
|
||||
static unsigned
|
||||
find_dfsnum_interval (struct dom_dfsnum *defs, unsigned n, unsigned s)
|
||||
{
|
||||
unsigned f = 0, t = n, m;
|
||||
|
||||
while (t > f + 1)
|
||||
{
|
||||
m = (f + t) / 2;
|
||||
if (defs[m].dfs_num <= s)
|
||||
f = m;
|
||||
else
|
||||
t = m;
|
||||
}
|
||||
|
||||
return defs[f].bb_index;
|
||||
}
|
||||
|
||||
/* Clean bits from PHIS for phi nodes whose value cannot be used in USES.
|
||||
KILLS is a bitmap of blocks where the value is defined before any use. */
|
||||
|
||||
static void
|
||||
prune_unused_phi_nodes (bitmap phis, bitmap kills, bitmap uses)
|
||||
{
|
||||
VEC(int, heap) *worklist;
|
||||
bitmap_iterator bi;
|
||||
unsigned i, b, p, u, top;
|
||||
bitmap live_phis;
|
||||
basic_block def_bb, use_bb;
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
bitmap to_remove;
|
||||
struct dom_dfsnum *defs;
|
||||
unsigned n_defs, adef;
|
||||
|
||||
if (bitmap_empty_p (uses))
|
||||
{
|
||||
bitmap_clear (phis);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The phi must dominate a use, or an argument of a live phi. Also, we
|
||||
do not create any phi nodes in def blocks, unless they are also livein. */
|
||||
to_remove = BITMAP_ALLOC (NULL);
|
||||
bitmap_and_compl (to_remove, kills, uses);
|
||||
bitmap_and_compl_into (phis, to_remove);
|
||||
if (bitmap_empty_p (phis))
|
||||
{
|
||||
BITMAP_FREE (to_remove);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We want to remove the unnecessary phi nodes, but we do not want to compute
|
||||
liveness information, as that may be linear in the size of CFG, and if
|
||||
there are lot of different variables to rewrite, this may lead to quadratic
|
||||
behavior.
|
||||
|
||||
Instead, we basically emulate standard dce. We put all uses to worklist,
|
||||
then for each of them find the nearest def that dominates them. If this
|
||||
def is a phi node, we mark it live, and if it was not live before, we
|
||||
add the predecessors of its basic block to the worklist.
|
||||
|
||||
To quickly locate the nearest def that dominates use, we use dfs numbering
|
||||
of the dominance tree (that is already available in order to speed up
|
||||
queries). For each def, we have the interval given by the dfs number on
|
||||
entry to and on exit from the corresponding subtree in the dominance tree.
|
||||
The nearest dominator for a given use is the smallest of these intervals
|
||||
that contains entry and exit dfs numbers for the basic block with the use.
|
||||
If we store the bounds for all the uses to an array and sort it, we can
|
||||
locate the nearest dominating def in logarithmic time by binary search.*/
|
||||
bitmap_ior (to_remove, kills, phis);
|
||||
n_defs = bitmap_count_bits (to_remove);
|
||||
defs = XNEWVEC (struct dom_dfsnum, 2 * n_defs + 1);
|
||||
defs[0].bb_index = 1;
|
||||
defs[0].dfs_num = 0;
|
||||
adef = 1;
|
||||
EXECUTE_IF_SET_IN_BITMAP (to_remove, 0, i, bi)
|
||||
{
|
||||
def_bb = BASIC_BLOCK (i);
|
||||
defs[adef].bb_index = i;
|
||||
defs[adef].dfs_num = bb_dom_dfs_in (CDI_DOMINATORS, def_bb);
|
||||
defs[adef + 1].bb_index = i;
|
||||
defs[adef + 1].dfs_num = bb_dom_dfs_out (CDI_DOMINATORS, def_bb);
|
||||
adef += 2;
|
||||
}
|
||||
BITMAP_FREE (to_remove);
|
||||
gcc_assert (adef == 2 * n_defs + 1);
|
||||
qsort (defs, adef, sizeof (struct dom_dfsnum), cmp_dfsnum);
|
||||
gcc_assert (defs[0].bb_index == 1);
|
||||
|
||||
/* Now each DEFS entry contains the number of the basic block to that the
|
||||
dfs number corresponds. Change them to the number of basic block that
|
||||
corresponds to the interval following the dfs number. Also, for the
|
||||
dfs_out numbers, increase the dfs number by one (so that it corresponds
|
||||
to the start of the following interval, not to the end of the current
|
||||
one). We use WORKLIST as a stack. */
|
||||
worklist = VEC_alloc (int, heap, n_defs + 1);
|
||||
VEC_quick_push (int, worklist, 1);
|
||||
top = 1;
|
||||
n_defs = 1;
|
||||
for (i = 1; i < adef; i++)
|
||||
{
|
||||
b = defs[i].bb_index;
|
||||
if (b == top)
|
||||
{
|
||||
/* This is a closing element. Interval corresponding to the top
|
||||
of the stack after removing it follows. */
|
||||
VEC_pop (int, worklist);
|
||||
top = VEC_index (int, worklist, VEC_length (int, worklist) - 1);
|
||||
defs[n_defs].bb_index = top;
|
||||
defs[n_defs].dfs_num = defs[i].dfs_num + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Opening element. Nothing to do, just push it to the stack and move
|
||||
it to the correct position. */
|
||||
defs[n_defs].bb_index = defs[i].bb_index;
|
||||
defs[n_defs].dfs_num = defs[i].dfs_num;
|
||||
VEC_quick_push (int, worklist, b);
|
||||
top = b;
|
||||
}
|
||||
|
||||
/* If this interval starts at the same point as the previous one, cancel
|
||||
the previous one. */
|
||||
if (defs[n_defs].dfs_num == defs[n_defs - 1].dfs_num)
|
||||
defs[n_defs - 1].bb_index = defs[n_defs].bb_index;
|
||||
else
|
||||
n_defs++;
|
||||
}
|
||||
VEC_pop (int, worklist);
|
||||
gcc_assert (VEC_empty (int, worklist));
|
||||
|
||||
/* Now process the uses. */
|
||||
live_phis = BITMAP_ALLOC (NULL);
|
||||
EXECUTE_IF_SET_IN_BITMAP (uses, 0, i, bi)
|
||||
{
|
||||
VEC_safe_push (int, heap, worklist, i);
|
||||
}
|
||||
|
||||
while (!VEC_empty (int, worklist))
|
||||
{
|
||||
b = VEC_pop (int, worklist);
|
||||
if (b == ENTRY_BLOCK)
|
||||
continue;
|
||||
|
||||
/* If there is a phi node in USE_BB, it is made live. Otherwise,
|
||||
find the def that dominates the immediate dominator of USE_BB
|
||||
(the kill in USE_BB does not dominate the use). */
|
||||
if (bitmap_bit_p (phis, b))
|
||||
p = b;
|
||||
else
|
||||
{
|
||||
use_bb = get_immediate_dominator (CDI_DOMINATORS, BASIC_BLOCK (b));
|
||||
p = find_dfsnum_interval (defs, n_defs,
|
||||
bb_dom_dfs_in (CDI_DOMINATORS, use_bb));
|
||||
if (!bitmap_bit_p (phis, p))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the phi node is already live, there is nothing to do. */
|
||||
if (bitmap_bit_p (live_phis, p))
|
||||
continue;
|
||||
|
||||
/* Mark the phi as live, and add the new uses to the worklist. */
|
||||
bitmap_set_bit (live_phis, p);
|
||||
def_bb = BASIC_BLOCK (p);
|
||||
FOR_EACH_EDGE (e, ei, def_bb->preds)
|
||||
{
|
||||
u = e->src->index;
|
||||
if (bitmap_bit_p (uses, u))
|
||||
continue;
|
||||
|
||||
bitmap_set_bit (uses, u);
|
||||
VEC_safe_push (int, heap, worklist, u);
|
||||
}
|
||||
}
|
||||
|
||||
VEC_free (int, heap, worklist);
|
||||
bitmap_copy (phis, live_phis);
|
||||
BITMAP_FREE (live_phis);
|
||||
free (defs);
|
||||
}
|
||||
|
||||
/* Given a set of blocks with variable definitions (DEF_BLOCKS),
|
||||
return a bitmap with all the blocks in the iterated dominance
|
||||
@ -926,13 +1134,12 @@ insert_phi_nodes_for (tree var, bitmap phi_insertion_points, bool update_p)
|
||||
/* Remove the blocks where we already have PHI nodes for VAR. */
|
||||
bitmap_and_compl_into (phi_insertion_points, def_map->phi_blocks);
|
||||
|
||||
/* Now compute global livein for this variable. Note this modifies
|
||||
def_map->livein_blocks. */
|
||||
compute_global_livein (def_map->livein_blocks, def_map->def_blocks);
|
||||
/* Remove obviously useless phi nodes. */
|
||||
prune_unused_phi_nodes (phi_insertion_points, def_map->def_blocks,
|
||||
def_map->livein_blocks);
|
||||
|
||||
/* And insert the PHI nodes. */
|
||||
EXECUTE_IF_AND_IN_BITMAP (phi_insertion_points, def_map->livein_blocks,
|
||||
0, bb_index, bi)
|
||||
EXECUTE_IF_SET_IN_BITMAP (phi_insertion_points, 0, bb_index, bi)
|
||||
{
|
||||
bb = BASIC_BLOCK (bb_index);
|
||||
if (update_p)
|
||||
@ -2009,6 +2216,8 @@ prepare_block_for_update (basic_block bb, bool insert_phi_p)
|
||||
basic_block son;
|
||||
block_stmt_iterator si;
|
||||
tree phi;
|
||||
edge e;
|
||||
edge_iterator ei;
|
||||
|
||||
mark_block_for_update (bb);
|
||||
|
||||
@ -2020,10 +2229,20 @@ prepare_block_for_update (basic_block bb, bool insert_phi_p)
|
||||
|
||||
lhs_sym = DECL_P (lhs) ? lhs : SSA_NAME_VAR (lhs);
|
||||
|
||||
if (symbol_marked_for_renaming (lhs_sym))
|
||||
if (!symbol_marked_for_renaming (lhs_sym))
|
||||
continue;
|
||||
mark_def_interesting (lhs_sym, phi, bb, insert_phi_p);
|
||||
|
||||
/* Mark the uses in phi nodes as interesting. It would be more correct
|
||||
to process the arguments of the phi nodes of the successor edges of
|
||||
BB at the end of prepare_block_for_update, however, that turns out
|
||||
to be significantly more expensive. Doing it here is conservatively
|
||||
correct -- it may only cause us to believe a value to be live in a
|
||||
block that also contains its definition, and thus insert a few more
|
||||
phi nodes for it. */
|
||||
FOR_EACH_EDGE (e, ei, bb->preds)
|
||||
{
|
||||
mark_use_interesting (lhs_sym, phi, bb, insert_phi_p);
|
||||
mark_def_interesting (lhs_sym, phi, bb, insert_phi_p);
|
||||
mark_use_interesting (lhs_sym, phi, e->src, insert_phi_p);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2101,38 +2320,9 @@ prepare_use_sites_for (tree name, bool insert_phi_p)
|
||||
|
||||
if (TREE_CODE (stmt) == PHI_NODE)
|
||||
{
|
||||
/* Mark this use of NAME interesting for the renamer.
|
||||
Notice that we explicitly call mark_use_interesting with
|
||||
INSERT_PHI_P == false.
|
||||
|
||||
This is to avoid marking NAME as live-in in this block
|
||||
BB. If we were to mark NAME live-in to BB, then NAME
|
||||
would be considered live-in through ALL incoming edges to
|
||||
BB which is not what we want. Since we are updating the
|
||||
SSA form for NAME, we don't really know what other names
|
||||
of NAME are coming in through other edges into BB.
|
||||
|
||||
If we considered NAME live-in at BB, then the PHI
|
||||
placement algorithm may try to insert PHI nodes in blocks
|
||||
that are not only unnecessary but also the renamer would
|
||||
not know how to fill in. */
|
||||
mark_use_interesting (name, stmt, bb, false);
|
||||
|
||||
/* As discussed above, we only want to mark NAME live-in
|
||||
through the edge corresponding to its slot inside the PHI
|
||||
argument list. So, we look for the block BB1 where NAME
|
||||
is flowing through. If BB1 does not contain a definition
|
||||
of NAME, then consider NAME live-in at BB1. */
|
||||
if (insert_phi_p)
|
||||
{
|
||||
int ix = PHI_ARG_INDEX_FROM_USE (use_p);
|
||||
edge e = PHI_ARG_EDGE (stmt, ix);
|
||||
basic_block bb1 = e->src;
|
||||
struct def_blocks_d *db = get_def_blocks_for (name);
|
||||
|
||||
if (!bitmap_bit_p (db->def_blocks, bb1->index))
|
||||
set_livein_block (name, bb1);
|
||||
}
|
||||
int ix = PHI_ARG_INDEX_FROM_USE (use_p);
|
||||
edge e = PHI_ARG_EDGE (stmt, ix);
|
||||
mark_use_interesting (name, stmt, e->src, insert_phi_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user