Commit 01273677 by Steven Bosscher

re PR middle-end/54146 (Very slow compile with attribute((flatten)))

	PR middle-end/54146
	* tree-flow.h (compute_global_livein): Remove prototype.
	* tree-into-ssa.c (compute_global_livein): Remove function.
	* tree-ssa-loop-manip.c: Include gimple-pretty-print.h.
	(find_sibling_superloop): New function.
	(compute_live_loop_exits): New function.
	(add_exit_phis_edge): Rename to add_exit_phi.  Do not allow
	inserting a PHI in a block that is not a loop exit for VAR.
	Add dumping if TDF_DETAILS.
	(add_exit_phis_var): Rewrite.
	(add_exit_phis): Update.
	(get_loops_exits): Rewrite to return an array of per-loop exits
	rather than one bitmap with all loop exits.
	(find_uses_to_rename_bb): Ignore virtual PHI nodes.
	(rewrite_into_loop_closed_ssa): Update.

From-SVN: r190442
parent ca9b1cd8
2012-08-16 Steven Bosscher <steven@gcc.gnu.org>
PR middle-end/54146
* tree-flow.h (compute_global_livein): Remove prototype.
* tree-into-ssa.c (compute_global_livein): Remove function.
* tree-ssa-loop-manip.c: Include gimple-pretty-print.h.
(find_sibling_superloop): New function.
(compute_live_loop_exits): New function.
(add_exit_phis_edge): Rename to add_exit_phi. Do not allow
inserting a PHI in a block that is not a loop exit for VAR.
Add dumping if TDF_DETAILS.
(add_exit_phis_var): Rewrite.
(add_exit_phis): Update.
(get_loops_exits): Rewrite to return an array of per-loop exits
rather than one bitmap with all loop exits.
(find_uses_to_rename_bb): Ignore virtual PHI nodes.
(rewrite_into_loop_closed_ssa): Update.
2012-08-16 Nick Clifton <nickc@redhat.com> 2012-08-16 Nick Clifton <nickc@redhat.com>
* config/i386/i386elf.h (ASM_OUTPUT_ASCII): Cast _ascii_bytes * config/i386/i386elf.h (ASM_OUTPUT_ASCII): Cast _ascii_bytes
......
...@@ -521,7 +521,6 @@ tree create_new_def_for (tree, gimple, def_operand_p); ...@@ -521,7 +521,6 @@ tree create_new_def_for (tree, gimple, def_operand_p);
bool need_ssa_update_p (struct function *); bool need_ssa_update_p (struct function *);
bool name_registered_for_update_p (tree); bool name_registered_for_update_p (tree);
void release_ssa_name_after_update_ssa (tree); void release_ssa_name_after_update_ssa (tree);
void compute_global_livein (bitmap, bitmap);
void mark_virtual_operands_for_renaming (struct function *); void mark_virtual_operands_for_renaming (struct function *);
tree get_current_def (tree); tree get_current_def (tree);
void set_current_def (tree, tree); void set_current_def (tree, tree);
......
...@@ -404,63 +404,6 @@ set_current_def (tree var, tree def) ...@@ -404,63 +404,6 @@ set_current_def (tree var, tree def)
get_common_info (var)->current_def = def; get_common_info (var)->current_def = def;
} }
/* Compute global livein information given the set of blocks where
an object is locally live at the start of the block (LIVEIN)
and the set of blocks where the object is defined (DEF_BLOCKS).
Note: This routine augments the existing local livein information
to include global livein (i.e., it modifies the underlying bitmap
for LIVEIN). */
void
compute_global_livein (bitmap livein, bitmap def_blocks)
{
unsigned i;
bitmap_iterator bi;
VEC (basic_block, heap) *worklist;
/* Normally the work list size is bounded by the number of basic
blocks in the largest loop. We don't know this number, but we
can be fairly sure that it will be relatively small. */
worklist = VEC_alloc (basic_block, heap, MAX (8, n_basic_blocks / 128));
EXECUTE_IF_SET_IN_BITMAP (livein, 0, i, bi)
VEC_safe_push (basic_block, heap, worklist, BASIC_BLOCK (i));
/* Iterate until the worklist is empty. */
while (! VEC_empty (basic_block, worklist))
{
edge e;
edge_iterator ei;
/* Pull a block off the worklist. */
basic_block bb = VEC_pop (basic_block, worklist);
/* Make sure we have at least enough room in the work list
for all predecessors of this block. */
VEC_reserve (basic_block, heap, worklist, EDGE_COUNT (bb->preds));
/* For each predecessor block. */
FOR_EACH_EDGE (e, ei, bb->preds)
{
basic_block pred = e->src;
int pred_index = pred->index;
/* None of this is necessary for the entry block. */
if (pred != ENTRY_BLOCK_PTR
&& ! bitmap_bit_p (def_blocks, pred_index)
&& bitmap_set_bit (livein, pred_index))
{
VEC_quick_push (basic_block, worklist, pred);
}
}
}
VEC_free (basic_block, heap, worklist);
}
/* Cleans up the REWRITE_THIS_STMT and REGISTER_DEFS_IN_THIS_STMT flags for /* Cleans up the REWRITE_THIS_STMT and REGISTER_DEFS_IN_THIS_STMT flags for
all statements in basic block BB. */ all statements in basic block BB. */
......
...@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "basic-block.h" #include "basic-block.h"
#include "tree-flow.h" #include "tree-flow.h"
#include "dumpfile.h" #include "dumpfile.h"
#include "gimple-pretty-print.h"
#include "cfgloop.h" #include "cfgloop.h"
#include "tree-pass.h" /* ??? for TODO_update_ssa but this isn't a pass. */ #include "tree-pass.h" /* ??? for TODO_update_ssa but this isn't a pass. */
#include "tree-scalar-evolution.h" #include "tree-scalar-evolution.h"
...@@ -129,62 +130,190 @@ create_iv (tree base, tree step, tree var, struct loop *loop, ...@@ -129,62 +130,190 @@ create_iv (tree base, tree step, tree var, struct loop *loop,
add_phi_arg (stmt, va, loop_latch_edge (loop), UNKNOWN_LOCATION); add_phi_arg (stmt, va, loop_latch_edge (loop), UNKNOWN_LOCATION);
} }
/* Add exit phis for the USE on EXIT. */ /* Return the outermost superloop LOOP of USE_LOOP that is a superloop of
both DEF_LOOP and USE_LOOP. */
static inline struct loop *
find_sibling_superloop (struct loop *use_loop, struct loop *def_loop)
{
unsigned ud = loop_depth (use_loop);
unsigned dd = loop_depth (def_loop);
gcc_assert (ud > 0 && dd > 0);
if (ud > dd)
use_loop = superloop_at_depth (use_loop, dd);
if (ud < dd)
def_loop = superloop_at_depth (def_loop, ud);
while (loop_outer (use_loop) != loop_outer (def_loop))
{
use_loop = loop_outer (use_loop);
def_loop = loop_outer (def_loop);
gcc_assert (use_loop && def_loop);
}
return use_loop;
}
/* DEF_BB is a basic block containing a DEF that needs rewriting into
loop-closed SSA form. USE_BLOCKS is the set of basic blocks containing
uses of DEF that "escape" from the loop containing DEF_BB (i.e. blocks in
USE_BLOCKS are dominated by DEF_BB but not in the loop father of DEF_B).
ALL_EXITS[I] is the set of all basic blocks that exit loop I.
Compute the subset of LOOP_EXITS that exit the loop containing DEF_BB
or one of its loop fathers, in which DEF is live. This set is returned
in the bitmap LIVE_EXITS.
Instead of computing the complete livein set of the def, we use the loop
nesting tree as a form of poor man's structure analysis. This greatly
speeds up the analysis, which is important because this function may be
called on all SSA names that need rewriting, one at a time. */
static void static void
add_exit_phis_edge (basic_block exit, tree use) compute_live_loop_exits (bitmap live_exits, bitmap use_blocks,
bitmap *loop_exits, basic_block def_bb)
{ {
gimple phi, def_stmt = SSA_NAME_DEF_STMT (use); unsigned i;
basic_block def_bb = gimple_bb (def_stmt); bitmap_iterator bi;
struct loop *def_loop; VEC (basic_block, heap) *worklist;
struct loop *def_loop = def_bb->loop_father;
unsigned def_loop_depth = loop_depth (def_loop);
bitmap def_loop_exits;
/* Normally the work list size is bounded by the number of basic
blocks in the largest loop. We don't know this number, but we
can be fairly sure that it will be relatively small. */
worklist = VEC_alloc (basic_block, heap, MAX (8, n_basic_blocks / 128));
EXECUTE_IF_SET_IN_BITMAP (use_blocks, 0, i, bi)
{
basic_block use_bb = BASIC_BLOCK (i);
struct loop *use_loop = use_bb->loop_father;
gcc_checking_assert (def_loop != use_loop
&& ! flow_loop_nested_p (def_loop, use_loop));
if (! flow_loop_nested_p (use_loop, def_loop))
use_bb = find_sibling_superloop (use_loop, def_loop)->header;
if (bitmap_set_bit (live_exits, use_bb->index))
VEC_safe_push (basic_block, heap, worklist, use_bb);
}
/* Iterate until the worklist is empty. */
while (! VEC_empty (basic_block, worklist))
{
edge e;
edge_iterator ei;
/* Pull a block off the worklist. */
basic_block bb = VEC_pop (basic_block, worklist);
/* Make sure we have at least enough room in the work list
for all predecessors of this block. */
VEC_reserve (basic_block, heap, worklist, EDGE_COUNT (bb->preds));
/* For each predecessor block. */
FOR_EACH_EDGE (e, ei, bb->preds)
{
basic_block pred = e->src;
struct loop *pred_loop = pred->loop_father;
unsigned pred_loop_depth = loop_depth (pred_loop);
bool pred_visited;
/* We should have met DEF_BB along the way. */
gcc_assert (pred != ENTRY_BLOCK_PTR);
if (pred_loop_depth >= def_loop_depth)
{
if (pred_loop_depth > def_loop_depth)
pred_loop = superloop_at_depth (pred_loop, def_loop_depth);
/* If we've reached DEF_LOOP, our train ends here. */
if (pred_loop == def_loop)
continue;
}
else if (! flow_loop_nested_p (pred_loop, def_loop))
pred = find_sibling_superloop (pred_loop, def_loop)->header;
/* Add PRED to the LIVEIN set. PRED_VISITED is true if
we had already added PRED to LIVEIN before. */
pred_visited = !bitmap_set_bit (live_exits, pred->index);
/* If we have visited PRED before, don't add it to the worklist.
If BB dominates PRED, then we're probably looking at a loop.
We're only interested in looking up in the dominance tree
because DEF_BB dominates all the uses. */
if (pred_visited || dominated_by_p (CDI_DOMINATORS, pred, bb))
continue;
VEC_quick_push (basic_block, worklist, pred);
}
}
VEC_free (basic_block, heap, worklist);
def_loop_exits = BITMAP_ALLOC (&loop_renamer_obstack);
for (struct loop *loop = def_loop;
loop != current_loops->tree_root;
loop = loop_outer (loop))
bitmap_ior_into (def_loop_exits, loop_exits[loop->num]);
bitmap_and_into (live_exits, def_loop_exits);
BITMAP_FREE (def_loop_exits);
}
/* Add a loop-closing PHI for VAR in basic block EXIT. */
static void
add_exit_phi (basic_block exit, tree var)
{
gimple phi;
edge e; edge e;
edge_iterator ei; edge_iterator ei;
/* Check that some of the edges entering the EXIT block exits a loop in #ifdef ENABLE_CHECKING
that USE is defined. */ /* Check that at least one of the edges entering the EXIT block exits
the loop, or a superloop of that loop, that VAR is defined in. */
gimple def_stmt = SSA_NAME_DEF_STMT (var);
basic_block def_bb = gimple_bb (def_stmt);
FOR_EACH_EDGE (e, ei, exit->preds) FOR_EACH_EDGE (e, ei, exit->preds)
{ {
def_loop = find_common_loop (def_bb->loop_father, e->src->loop_father); struct loop *aloop = find_common_loop (def_bb->loop_father,
if (!flow_bb_inside_loop_p (def_loop, e->dest)) e->src->loop_father);
if (!flow_bb_inside_loop_p (aloop, e->dest))
break; break;
} }
if (!e) gcc_checking_assert (e);
return; #endif
phi = create_phi_node (NULL_TREE, exit); phi = create_phi_node (NULL_TREE, exit);
create_new_def_for (use, phi, gimple_phi_result_ptr (phi)); create_new_def_for (var, phi, gimple_phi_result_ptr (phi));
FOR_EACH_EDGE (e, ei, exit->preds) FOR_EACH_EDGE (e, ei, exit->preds)
add_phi_arg (phi, use, e, UNKNOWN_LOCATION); add_phi_arg (phi, var, e, UNKNOWN_LOCATION);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, ";; Created LCSSA PHI: ");
print_gimple_stmt (dump_file, phi, 0, dump_flags);
}
} }
/* Add exit phis for VAR that is used in LIVEIN. /* Add exit phis for VAR that is used in LIVEIN.
Exits of the loops are stored in EXITS. */ Exits of the loops are stored in LOOP_EXITS. */
static void static void
add_exit_phis_var (tree var, bitmap livein, bitmap exits) add_exit_phis_var (tree var, bitmap use_blocks, bitmap *loop_exits)
{ {
bitmap def;
unsigned index; unsigned index;
basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (var));
bitmap_iterator bi; bitmap_iterator bi;
basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (var));
bitmap live_exits = BITMAP_ALLOC (&loop_renamer_obstack);
gcc_checking_assert (! virtual_operand_p (var)); gcc_checking_assert (! virtual_operand_p (var));
bitmap_clear_bit (livein, def_bb->index); gcc_assert (! bitmap_bit_p (use_blocks, def_bb->index));
def = BITMAP_ALLOC (&loop_renamer_obstack); compute_live_loop_exits (live_exits, use_blocks, loop_exits, def_bb);
bitmap_set_bit (def, def_bb->index);
compute_global_livein (livein, def);
BITMAP_FREE (def);
EXECUTE_IF_AND_IN_BITMAP (exits, livein, 0, index, bi) EXECUTE_IF_SET_IN_BITMAP (live_exits, 0, index, bi)
{ {
add_exit_phis_edge (BASIC_BLOCK (index), var); add_exit_phi (BASIC_BLOCK (index), var);
} }
/* Free the livein bitmap. We'll not be needing it anymore, and BITMAP_FREE (live_exits);
it may have grown quite large. No reason to hold on to it. */
bitmap_clear (livein);
} }
/* Add exit phis for the names marked in NAMES_TO_RENAME. /* Add exit phis for the names marked in NAMES_TO_RENAME.
...@@ -192,7 +321,7 @@ add_exit_phis_var (tree var, bitmap livein, bitmap exits) ...@@ -192,7 +321,7 @@ add_exit_phis_var (tree var, bitmap livein, bitmap exits)
names are used are stored in USE_BLOCKS. */ names are used are stored in USE_BLOCKS. */
static void static void
add_exit_phis (bitmap names_to_rename, bitmap *use_blocks, bitmap loop_exits) add_exit_phis (bitmap names_to_rename, bitmap *use_blocks, bitmap *loop_exits)
{ {
unsigned i; unsigned i;
bitmap_iterator bi; bitmap_iterator bi;
...@@ -203,28 +332,24 @@ add_exit_phis (bitmap names_to_rename, bitmap *use_blocks, bitmap loop_exits) ...@@ -203,28 +332,24 @@ add_exit_phis (bitmap names_to_rename, bitmap *use_blocks, bitmap loop_exits)
} }
} }
/* Returns a bitmap of all loop exit edge targets. */ /* Fill the array of bitmaps LOOP_EXITS with all loop exit edge targets. */
static bitmap static void
get_loops_exits (void) get_loops_exits (bitmap *loop_exits)
{ {
bitmap exits = BITMAP_ALLOC (&loop_renamer_obstack); loop_iterator li;
basic_block bb; struct loop *loop;
unsigned j;
edge e; edge e;
edge_iterator ei;
FOR_EACH_BB (bb) FOR_EACH_LOOP (li, loop, 0)
{ {
FOR_EACH_EDGE (e, ei, bb->preds) VEC(edge, heap) *exit_edges = get_loop_exit_edges (loop);
if (e->src != ENTRY_BLOCK_PTR loop_exits[loop->num] = BITMAP_ALLOC (&loop_renamer_obstack);
&& !flow_bb_inside_loop_p (e->src->loop_father, bb)) FOR_EACH_VEC_ELT (edge, exit_edges, j, e)
{ bitmap_set_bit (loop_exits[loop->num], e->dest->index);
bitmap_set_bit (exits, bb->index); VEC_free (edge, heap, exit_edges);
break;
}
} }
return exits;
} }
/* For USE in BB, if it is used outside of the loop it is defined in, /* For USE in BB, if it is used outside of the loop it is defined in,
...@@ -301,8 +426,12 @@ find_uses_to_rename_bb (basic_block bb, bitmap *use_blocks, bitmap need_phis) ...@@ -301,8 +426,12 @@ find_uses_to_rename_bb (basic_block bb, bitmap *use_blocks, bitmap need_phis)
FOR_EACH_EDGE (e, ei, bb->succs) FOR_EACH_EDGE (e, ei, bb->succs)
for (bsi = gsi_start_phis (e->dest); !gsi_end_p (bsi); gsi_next (&bsi)) for (bsi = gsi_start_phis (e->dest); !gsi_end_p (bsi); gsi_next (&bsi))
find_uses_to_rename_use (bb, PHI_ARG_DEF_FROM_EDGE (gsi_stmt (bsi), e), {
use_blocks, need_phis); gimple phi = gsi_stmt (bsi);
if (! virtual_operand_p (gimple_phi_result (phi)))
find_uses_to_rename_use (bb, PHI_ARG_DEF_FROM_EDGE (phi, e),
use_blocks, need_phis);
}
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
find_uses_to_rename_stmt (gsi_stmt (bsi), use_blocks, need_phis); find_uses_to_rename_stmt (gsi_stmt (bsi), use_blocks, need_phis);
...@@ -372,7 +501,7 @@ find_uses_to_rename (bitmap changed_bbs, bitmap *use_blocks, bitmap need_phis) ...@@ -372,7 +501,7 @@ find_uses_to_rename (bitmap changed_bbs, bitmap *use_blocks, bitmap need_phis)
void void
rewrite_into_loop_closed_ssa (bitmap changed_bbs, unsigned update_flag) rewrite_into_loop_closed_ssa (bitmap changed_bbs, unsigned update_flag)
{ {
bitmap loop_exits; bitmap *loop_exits;
bitmap *use_blocks; bitmap *use_blocks;
bitmap names_to_rename; bitmap names_to_rename;
...@@ -380,14 +509,18 @@ rewrite_into_loop_closed_ssa (bitmap changed_bbs, unsigned update_flag) ...@@ -380,14 +509,18 @@ rewrite_into_loop_closed_ssa (bitmap changed_bbs, unsigned update_flag)
if (number_of_loops () <= 1) if (number_of_loops () <= 1)
return; return;
/* If the pass has caused the SSA form to be out-of-date, update it
now. */
update_ssa (update_flag);
bitmap_obstack_initialize (&loop_renamer_obstack); bitmap_obstack_initialize (&loop_renamer_obstack);
loop_exits = get_loops_exits ();
names_to_rename = BITMAP_ALLOC (&loop_renamer_obstack); names_to_rename = BITMAP_ALLOC (&loop_renamer_obstack);
/* If the pass has caused the SSA form to be out-of-date, update it /* An array of bitmaps where LOOP_EXITS[I] is the set of basic blocks
now. */ that are the destination of an edge exiting loop number I. */
update_ssa (update_flag); loop_exits = XNEWVEC (bitmap, number_of_loops ());
get_loops_exits (loop_exits);
/* Uses of names to rename. We don't have to initialize this array, /* Uses of names to rename. We don't have to initialize this array,
because we know that we will only have entries for the SSA names because we know that we will only have entries for the SSA names
...@@ -403,6 +536,7 @@ rewrite_into_loop_closed_ssa (bitmap changed_bbs, unsigned update_flag) ...@@ -403,6 +536,7 @@ rewrite_into_loop_closed_ssa (bitmap changed_bbs, unsigned update_flag)
bitmap_obstack_release (&loop_renamer_obstack); bitmap_obstack_release (&loop_renamer_obstack);
free (use_blocks); free (use_blocks);
free (loop_exits);
/* Fix up all the names found to be used outside their original /* Fix up all the names found to be used outside their original
loops. */ loops. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment