aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAndrew MacLeod <amacleod@redhat.com>2004-11-02 00:23:04 +0000
committerAndrew Macleod <amacleod@gcc.gnu.org>2004-11-02 00:23:04 +0000
commitedfaf675109ca666d7ddbd901c82c18383385255 (patch)
treeb53d70edc3071cf94765fb9657ab1326ec36c283 /gcc
parent8bf639fa5e1887d9313c9a251cfe550033708bef (diff)
downloadgcc-edfaf675109ca666d7ddbd901c82c18383385255.zip
gcc-edfaf675109ca666d7ddbd901c82c18383385255.tar.gz
gcc-edfaf675109ca666d7ddbd901c82c18383385255.tar.bz2
re PR tree-optimization/16447 (out of ssa generates bloated code)
2004-11-01 Andrew MacLeod <amacleod@redhat.com> PR tree-optimization/16447 * tree-cfg.c (bsi_commit_one_edge_insert): Rename from bsi_commit_edge_inserts_1, and make funtion external. Return new block. (bsi_commit_edge_inserts): Use renamed bsi_commit_one_edge_insert. * tree-optimize.c (pass_cleanup_cfg_post_optimizing): Enable listing. * tree-flow.h (bsi_commit_one_edge_insert): Extern decl. * tree-outof-ssa.c (rewrite_trees): Don't commit edges here. (same_stmt_list_p): New. Return TRUE if edge is to be forwarded. (identical_copies_p): New. Return true is two copies are the same. (identical_stmt_lists_p): New. Return true if stmt lists are the same. (analyze_edges_for_bb): New. Determine how best to insert edge stmts for a basic block. (perform_edge_inserts): New. Determine what to do with all stmts that have been inserted on edges. (remove_ssa_form): Analyze and commit edges from here. From-SVN: r89970
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog18
-rw-r--r--gcc/tree-cfg.c16
-rw-r--r--gcc/tree-flow.h1
-rw-r--r--gcc/tree-optimize.c4
-rw-r--r--gcc/tree-outof-ssa.c329
5 files changed, 357 insertions, 11 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 07be43f..2610259 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,21 @@
+2004-11-01 Andrew MacLeod <amacleod@redhat.com>
+
+ PR tree-optimization/16447
+ * tree-cfg.c (bsi_commit_one_edge_insert): Rename from
+ bsi_commit_edge_inserts_1, and make funtion external. Return new block.
+ (bsi_commit_edge_inserts): Use renamed bsi_commit_one_edge_insert.
+ * tree-optimize.c (pass_cleanup_cfg_post_optimizing): Enable listing.
+ * tree-flow.h (bsi_commit_one_edge_insert): Extern decl.
+ * tree-outof-ssa.c (rewrite_trees): Don't commit edges here.
+ (same_stmt_list_p): New. Return TRUE if edge is to be forwarded.
+ (identical_copies_p): New. Return true is two copies are the same.
+ (identical_stmt_lists_p): New. Return true if stmt lists are the same.
+ (analyze_edges_for_bb): New. Determine how best to insert edge stmts
+ for a basic block.
+ (perform_edge_inserts): New. Determine what to do with all stmts that
+ have been inserted on edges.
+ (remove_ssa_form): Analyze and commit edges from here.
+
2004-11-01 Andrew Pinski <pinskia@physics.uc.edu>
PR bootstrap/18232
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 1861c4f..c886f6a 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -93,7 +93,6 @@ static int tree_verify_flow_info (void);
static void tree_make_forwarder_block (edge);
static bool thread_jumps (void);
static bool tree_forwarder_block_p (basic_block);
-static void bsi_commit_edge_inserts_1 (edge e);
static void tree_cfg2vcg (FILE *);
/* Flowgraph optimization and cleanup. */
@@ -2871,22 +2870,25 @@ bsi_commit_edge_inserts (int *new_blocks)
blocks = n_basic_blocks;
- bsi_commit_edge_inserts_1 (EDGE_SUCC (ENTRY_BLOCK_PTR, 0));
+ bsi_commit_one_edge_insert (EDGE_SUCC (ENTRY_BLOCK_PTR, 0), NULL);
FOR_EACH_BB (bb)
FOR_EACH_EDGE (e, ei, bb->succs)
- bsi_commit_edge_inserts_1 (e);
+ bsi_commit_one_edge_insert (e, NULL);
if (new_blocks)
*new_blocks = n_basic_blocks - blocks;
}
-/* Commit insertions pending at edge E. */
+/* Commit insertions pending at edge E. If a new block is created, set NEW_BB
+ to this block, otherwise set it to NULL. */
-static void
-bsi_commit_edge_inserts_1 (edge e)
+void
+bsi_commit_one_edge_insert (edge e, basic_block *new_bb)
{
+ if (new_bb)
+ *new_bb = NULL;
if (PENDING_STMT (e))
{
block_stmt_iterator bsi;
@@ -2894,7 +2896,7 @@ bsi_commit_edge_inserts_1 (edge e)
PENDING_STMT (e) = NULL_TREE;
- if (tree_find_edge_insert_loc (e, &bsi, NULL))
+ if (tree_find_edge_insert_loc (e, &bsi, new_bb))
bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
else
bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h
index 82ebd6d..9e77fe2 100644
--- a/gcc/tree-flow.h
+++ b/gcc/tree-flow.h
@@ -479,6 +479,7 @@ extern basic_block label_to_block (tree);
extern void tree_optimize_tail_calls (bool, enum tree_dump_index);
extern void bsi_insert_on_edge (edge, tree);
extern basic_block bsi_insert_on_edge_immediate (edge, tree);
+extern void bsi_commit_one_edge_insert (edge e, basic_block *);
extern void bsi_commit_edge_inserts (int *);
extern void notice_special_calls (tree);
extern void clear_special_calls (void);
diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c
index 7089c27..da7a2e7 100644
--- a/gcc/tree-optimize.c
+++ b/gcc/tree-optimize.c
@@ -118,7 +118,7 @@ execute_cleanup_cfg_post_optimizing (void)
static struct tree_opt_pass pass_cleanup_cfg_post_optimizing =
{
- NULL, /* name */
+ "final_cleanup", /* name */
NULL, /* gate */
execute_cleanup_cfg_post_optimizing, /* execute */
NULL, /* sub */
@@ -129,7 +129,7 @@ static struct tree_opt_pass pass_cleanup_cfg_post_optimizing =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
+ TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};
diff --git a/gcc/tree-outof-ssa.c b/gcc/tree-outof-ssa.c
index 827f91d..6d33c47 100644
--- a/gcc/tree-outof-ssa.c
+++ b/gcc/tree-outof-ssa.c
@@ -1933,9 +1933,331 @@ rewrite_trees (var_map map, tree *values)
}
delete_elim_graph (g);
+}
+
+
+/* These are the local work structures used to determine the best place to
+ insert the copies that were placed on edges by the SSA->normal pass.. */
+static varray_type edge_leader = NULL;
+static varray_type GTY(()) stmt_list = NULL;
+static bitmap leader_has_match = NULL;
+static edge leader_match = NULL;
+
+
+/* Pass this function to make_forwarder_block so that all the edges with
+ matching PENDING_STMT lists to 'curr_stmt_list' get redirected. */
+static bool
+same_stmt_list_p (edge e)
+{
+ return (e->aux == (PTR) leader_match) ? true : false;
+}
+
+
+/* Return TRUE if S1 and S2 are equivalent copies. */
+static inline bool
+identical_copies_p (tree s1, tree s2)
+{
+#ifdef ENABLE_CHECKING
+ gcc_assert (TREE_CODE (s1) == MODIFY_EXPR);
+ gcc_assert (TREE_CODE (s2) == MODIFY_EXPR);
+ gcc_assert (DECL_P (TREE_OPERAND (s1, 0)));
+ gcc_assert (DECL_P (TREE_OPERAND (s2, 0)));
+#endif
+
+ if (TREE_OPERAND (s1, 0) != TREE_OPERAND (s2, 0))
+ return false;
+
+ s1 = TREE_OPERAND (s1, 1);
+ s2 = TREE_OPERAND (s2, 1);
+
+ if (s1 != s2)
+ return false;
+
+ return true;
+}
+
+
+/* Compare the PENDING_STMT list for two edges, and return true if the lists
+ contain the same sequence of copies. */
+
+static inline bool
+identical_stmt_lists_p (edge e1, edge e2)
+{
+ tree t1 = PENDING_STMT (e1);
+ tree t2 = PENDING_STMT (e2);
+ tree_stmt_iterator tsi1, tsi2;
+
+ gcc_assert (TREE_CODE (t1) == STATEMENT_LIST);
+ gcc_assert (TREE_CODE (t2) == STATEMENT_LIST);
+
+ for (tsi1 = tsi_start (t1), tsi2 = tsi_start (t2);
+ !tsi_end_p (tsi1) && !tsi_end_p (tsi2);
+ tsi_next (&tsi1), tsi_next (&tsi2))
+ {
+ if (!identical_copies_p (tsi_stmt (tsi1), tsi_stmt (tsi2)))
+ break;
+ }
+
+ if (!tsi_end_p (tsi1) || ! tsi_end_p (tsi2))
+ return false;
+
+ return true;
+}
+
+
+/* Look at all the incoming edges to block BB, and decide where the best place
+ to insert the stmts on each edge are, and perform those insertions. Output
+ any debug information to DEBUG_FILE. Return true if anything other than a
+ standard edge insertion is done. */
+
+static bool
+analyze_edges_for_bb (basic_block bb, FILE *debug_file)
+{
+ edge e;
+ edge_iterator ei;
+ int count;
+ unsigned int x;
+ bool have_opportunity;
+ block_stmt_iterator bsi;
+ tree stmt;
+ edge single_edge = NULL;
+ bool is_label;
+
+ count = 0;
+ /* Find out how many edges there are with interesting pending stmts on them.
+ Commit the stmts on edges we are not interested in. */
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ if (PENDING_STMT (e))
+ {
+ gcc_assert (!(e->flags & EDGE_ABNORMAL));
+ if (e->flags & EDGE_FALLTHRU)
+ {
+ bsi = bsi_start (e->src);
+ if (!bsi_end_p (bsi))
+ {
+ stmt = bsi_stmt (bsi);
+ bsi_next (&bsi);
+ gcc_assert (stmt != NULL_TREE);
+ is_label = (TREE_CODE (stmt) == LABEL_EXPR);
+ /* Punt if it has non-label stmts, or isn't local. */
+ if (!is_label || DECL_NONLOCAL (TREE_OPERAND (stmt, 0))
+ || !bsi_end_p (bsi))
+ {
+ bsi_commit_one_edge_insert (e, NULL);
+ continue;
+ }
+ }
+ }
+ single_edge = e;
+ count++;
+ }
+ }
+
+ /* If there aren't at least 2 edges, no sharing will happen. */
+ if (count < 2)
+ {
+ if (single_edge)
+ bsi_commit_one_edge_insert (single_edge, NULL);
+ return false;
+ }
+
+ /* Ensure that we have empty worklists. */
+ if (edge_leader == NULL)
+ {
+ VARRAY_EDGE_INIT (edge_leader, 25, "edge_leader");
+ VARRAY_TREE_INIT (stmt_list, 25, "stmt_list");
+ leader_has_match = BITMAP_XMALLOC ();
+ }
+ else
+ {
+#ifdef ENABLE_CHECKING
+ gcc_assert (VARRAY_ACTIVE_SIZE (edge_leader) == 0);
+ gcc_assert (VARRAY_ACTIVE_SIZE (stmt_list) == 0);
+ gcc_assert (bitmap_first_set_bit (leader_has_match) == -1);
+#endif
+ }
+
+ /* Find the "leader" block for each set of unique stmt lists. Preference is
+ given to FALLTHRU blocks since they would need a GOTO to arrive at another
+ block. The leader edge destination is the block which all the other edges
+ with the same stmt list will be redirected to. */
+ have_opportunity = false;
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ if (PENDING_STMT (e))
+ {
+ bool found = false;
+
+ /* Look for the same stmt list in edge leaders list. */
+ for (x = 0; x < VARRAY_ACTIVE_SIZE (edge_leader); x++)
+ {
+ edge leader = VARRAY_EDGE (edge_leader, x);
+ if (identical_stmt_lists_p (leader, e))
+ {
+ /* Give this edge the same stmt list pointer. */
+ PENDING_STMT (e) = NULL;
+ e->aux = leader;
+ bitmap_set_bit (leader_has_match, x);
+ have_opportunity = found = true;
+ break;
+ }
+ }
+
+ /* If no similar stmt list, add this edge to the leader list. */
+ if (!found)
+ {
+ VARRAY_PUSH_EDGE (edge_leader, e);
+ VARRAY_PUSH_TREE (stmt_list, PENDING_STMT (e));
+ }
+ }
+ }
+
+ /* If there are no similar lists, just issue the stmts. */
+ if (!have_opportunity)
+ {
+ for (x = 0; x < VARRAY_ACTIVE_SIZE (edge_leader); x++)
+ bsi_commit_one_edge_insert (VARRAY_EDGE (edge_leader, x), NULL);
+ VARRAY_POP_ALL (edge_leader);
+ VARRAY_POP_ALL (stmt_list);
+ bitmap_clear (leader_has_match);
+ return false;
+ }
+
+
+ if (debug_file)
+ fprintf (debug_file, "\nOpportunities in BB %d for stmt/block reduction:\n",
+ bb->index);
+
+
+ /* For each common list, create a forwarding block and issue the stmt's
+ in that block. */
+ for (x = 0 ; x < VARRAY_ACTIVE_SIZE (edge_leader); x++)
+ if (bitmap_bit_p (leader_has_match, x))
+ {
+ edge new_edge, leader_edge;
+ block_stmt_iterator bsi;
+ tree curr_stmt_list;
+
+ leader_match = leader_edge = VARRAY_EDGE (edge_leader, x);
+
+ /* The tree_* cfg manipulation routines use the PENDING_EDGE field
+ for various PHI manipulations, so it gets cleared whhen calls are
+ made to make_forwarder_block(). So make sure the edge is clear,
+ and use the saved stmt list. */
+ PENDING_STMT (leader_edge) = NULL;
+ leader_edge->aux = leader_edge;
+ curr_stmt_list = VARRAY_TREE (stmt_list, x);
+
+ new_edge = make_forwarder_block (leader_edge->dest, same_stmt_list_p,
+ NULL);
+ bb = new_edge->dest;
+ if (debug_file)
+ {
+ fprintf (debug_file, "Splitting BB %d for Common stmt list. ",
+ leader_edge->dest->index);
+ fprintf (debug_file, "Original block is now BB%d.\n", bb->index);
+ print_generic_stmt (debug_file, curr_stmt_list, TDF_VOPS);
+ }
+
+ FOR_EACH_EDGE (e, ei, new_edge->src->preds)
+ {
+ e->aux = NULL;
+ if (debug_file)
+ fprintf (debug_file, " Edge (%d->%d) lands here.\n",
+ e->src->index, e->dest->index);
+ }
+
+ bsi = bsi_last (leader_edge->dest);
+ bsi_insert_after (&bsi, curr_stmt_list, BSI_NEW_STMT);
+
+ leader_match = NULL;
+ /* We should never get a new block now. */
+ }
+ else
+ {
+ e = VARRAY_EDGE (edge_leader, x);
+ PENDING_STMT (e) = VARRAY_TREE (stmt_list, x);
+ bsi_commit_one_edge_insert (e, NULL);
+ }
+
+
+ /* Clear the working data structures. */
+ VARRAY_POP_ALL (edge_leader);
+ VARRAY_POP_ALL (stmt_list);
+ bitmap_clear (leader_has_match);
+
+ return true;
+}
+
+
+/* This function will analyze the insertions which were performed on edges,
+ and decide whether they should be left on that edge, or whether it is more
+ efficient to emit some subset of them in a single block. All stmts are
+ inserted somewhere, and if non-NULL, debug information is printed via
+ DUMP_FILE. */
+
+static void
+perform_edge_inserts (FILE *dump_file)
+{
+ basic_block bb;
+ bool changed = false;
+
+ if (dump_file)
+ fprintf(dump_file, "Analyzing Edge Insertions.\n");
+
+ FOR_EACH_BB (bb)
+ changed |= analyze_edges_for_bb (bb, dump_file);
+
+ changed |= analyze_edges_for_bb (EXIT_BLOCK_PTR, dump_file);
+
+ /* Clear out any tables which were created. */
+ edge_leader = NULL;
+ if (leader_has_match != NULL)
+ {
+ free (leader_has_match);
+ leader_has_match = NULL;
+ }
- /* If any copies were inserted on edges, actually insert them now. */
- bsi_commit_edge_inserts (NULL);
+ if (changed)
+ {
+ free_dominance_info (CDI_DOMINATORS);
+ free_dominance_info (CDI_POST_DOMINATORS);
+ }
+
+#ifdef ENABLE_CHECKING
+ {
+ edge_iterator ei;
+ edge e;
+ FOR_EACH_BB (bb)
+ {
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ if (PENDING_STMT (e))
+ error (" Pending stmts not issued on PRED edge (%d, %d)\n",
+ e->src->index, e->dest->index);
+ }
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ if (PENDING_STMT (e))
+ error (" Pending stmts not issued on SUCC edge (%d, %d)\n",
+ e->src->index, e->dest->index);
+ }
+ }
+ FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
+ {
+ if (PENDING_STMT (e))
+ error (" Pending stmts not issued on ENTRY edge (%d, %d)\n",
+ e->src->index, e->dest->index);
+ }
+ FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
+ {
+ if (PENDING_STMT (e))
+ error (" Pending stmts not issued on EXIT edge (%d, %d)\n",
+ e->src->index, e->dest->index);
+ }
+ }
+#endif
}
@@ -2022,6 +2344,9 @@ remove_ssa_form (FILE *dump, var_map map, int flags)
}
}
+ /* If any copies were inserted on edges, analyze and insert them now. */
+ perform_edge_inserts (dump_file);
+
dump_file = save;
}