summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/cfgexpand.c50
-rw-r--r--gcc/tree-eh.c86
3 files changed, 116 insertions, 30 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 306f9c31762..876245b6976 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2011-12-13 Jakub Jelinek <jakub@redhat.com>
+ Michael Matz <matz@suse.de>
+
+ PR tree-optimization/51117
+ * tree-eh.c (sink_clobbers): New function.
+ (execute_lower_eh_dispatch): Call it for BBs ending with
+ internally throwing RESX.
+ * cfgexpand.c (add_scope_conflicts_1): Add all conflicts only
+ at the first real instruction.
+
2011-12-13 Tristan Gingold <gingold@adacore.com>
* final.c (final_scan_insn): Guard the call to begin_epilogue
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 86847217322..d41497d31c0 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -456,34 +456,14 @@ add_scope_conflicts_1 (basic_block bb, bitmap work, bool for_conflict)
FOR_EACH_EDGE (e, ei, bb->preds)
bitmap_ior_into (work, (bitmap)e->src->aux);
- if (for_conflict)
- {
- /* We need to add conflicts for everything life at the start of
- this block. Unlike classical lifeness for named objects we can't
- rely on seeing a def/use of the names we're interested in.
- There might merely be indirect loads/stores. We'd not add any
- conflicts for such partitions. */
- bitmap_iterator bi;
- unsigned i;
- EXECUTE_IF_SET_IN_BITMAP (work, 0, i, bi)
- {
- unsigned j;
- bitmap_iterator bj;
- EXECUTE_IF_SET_IN_BITMAP (work, i, j, bj)
- add_stack_var_conflict (i, j);
- }
- visit = visit_conflict;
- }
- else
- visit = visit_op;
+ visit = visit_op;
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
- if (!is_gimple_debug (stmt))
- walk_stmt_load_store_addr_ops (stmt, work, visit, visit, visit);
+ walk_stmt_load_store_addr_ops (stmt, work, NULL, NULL, visit);
}
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
@@ -501,7 +481,29 @@ add_scope_conflicts_1 (basic_block bb, bitmap work, bool for_conflict)
bitmap_clear_bit (work, *v);
}
else if (!is_gimple_debug (stmt))
- walk_stmt_load_store_addr_ops (stmt, work, visit, visit, visit);
+ {
+ if (for_conflict
+ && visit == visit_op)
+ {
+ /* If this is the first real instruction in this BB we need
+ to add conflicts for everything life at this point now.
+ Unlike classical lifeness for named objects we can't
+ rely on seeing a def/use of the names we're interested in.
+ There might merely be indirect loads/stores. We'd not add any
+ conflicts for such partitions. */
+ bitmap_iterator bi;
+ unsigned i;
+ EXECUTE_IF_SET_IN_BITMAP (work, 0, i, bi)
+ {
+ unsigned j;
+ bitmap_iterator bj;
+ EXECUTE_IF_SET_IN_BITMAP (work, i + 1, j, bj)
+ add_stack_var_conflict (i, j);
+ }
+ visit = visit_conflict;
+ }
+ walk_stmt_load_store_addr_ops (stmt, work, visit, visit, visit);
+ }
}
}
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 7ab8a90a37f..0631ee1cf8d 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -3194,6 +3194,76 @@ optimize_clobbers (basic_block bb)
}
}
+/* Try to sink var = {v} {CLOBBER} stmts followed just by
+ internal throw to successor BB. */
+
+static int
+sink_clobbers (basic_block bb)
+{
+ edge e;
+ edge_iterator ei;
+ gimple_stmt_iterator gsi, dgsi;
+ basic_block succbb;
+ bool any_clobbers = false;
+
+ /* Only optimize if BB has a single EH successor and
+ all predecessor edges are EH too. */
+ if (!single_succ_p (bb)
+ || (single_succ_edge (bb)->flags & EDGE_EH) == 0)
+ return 0;
+
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ if ((e->flags & EDGE_EH) == 0)
+ return 0;
+ }
+
+ /* And BB contains only CLOBBER stmts before the final
+ RESX. */
+ gsi = gsi_last_bb (bb);
+ for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
+ {
+ gimple stmt = gsi_stmt (gsi);
+ if (is_gimple_debug (stmt))
+ continue;
+ if (gimple_code (stmt) == GIMPLE_LABEL)
+ break;
+ if (!gimple_clobber_p (stmt)
+ || TREE_CODE (gimple_assign_lhs (stmt)) == SSA_NAME)
+ return 0;
+ any_clobbers = true;
+ }
+ if (!any_clobbers)
+ return 0;
+
+ succbb = single_succ (bb);
+ dgsi = gsi_after_labels (succbb);
+ gsi = gsi_last_bb (bb);
+ for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
+ {
+ gimple stmt = gsi_stmt (gsi);
+ tree vdef;
+ if (is_gimple_debug (stmt))
+ continue;
+ if (gimple_code (stmt) == GIMPLE_LABEL)
+ break;
+ unlink_stmt_vdef (stmt);
+ gsi_remove (&gsi, false);
+ vdef = gimple_vdef (stmt);
+ if (vdef && TREE_CODE (vdef) == SSA_NAME)
+ {
+ vdef = SSA_NAME_VAR (vdef);
+ mark_sym_for_renaming (vdef);
+ gimple_set_vdef (stmt, vdef);
+ gimple_set_vuse (stmt, vdef);
+ }
+ release_defs (stmt);
+ gsi_insert_before (&dgsi, stmt, GSI_SAME_STMT);
+ }
+
+ return TODO_update_ssa_only_virtuals;
+}
+
/* At the end of inlining, we can lower EH_DISPATCH. Return true when
we have found some duplicate labels and removed some edges. */
@@ -3349,7 +3419,7 @@ static unsigned
execute_lower_eh_dispatch (void)
{
basic_block bb;
- bool any_rewritten = false;
+ int flags = 0;
bool redirected = false;
assign_filter_values ();
@@ -3362,16 +3432,20 @@ execute_lower_eh_dispatch (void)
if (gimple_code (last) == GIMPLE_EH_DISPATCH)
{
redirected |= lower_eh_dispatch (bb, last);
- any_rewritten = true;
+ flags |= TODO_update_ssa_only_virtuals;
+ }
+ else if (gimple_code (last) == GIMPLE_RESX)
+ {
+ if (stmt_can_throw_external (last))
+ optimize_clobbers (bb);
+ else
+ flags |= sink_clobbers (bb);
}
- else if (gimple_code (last) == GIMPLE_RESX
- && stmt_can_throw_external (last))
- optimize_clobbers (bb);
}
if (redirected)
delete_unreachable_blocks ();
- return any_rewritten ? TODO_update_ssa_only_virtuals : 0;
+ return flags;
}
static bool