aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/testsuite/g++.dg/opt/eh5.C43
-rw-r--r--gcc/tree-eh.c67
3 files changed, 94 insertions, 29 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e2a71f9..a1108fc 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,7 +1,16 @@
+2009-10-13 Richard Henderson <rth@redhat.com>
+
+ PR tree-optimization/41377
+ * tree-eh.c (unsplit_eh): Propagate degenerate PHIs.
+ (cleanup_empty_eh_merge_phis): New change_region parameter;
+ pass it on to redirect_eh_edge_1. Update callers.
+ (cleanup_empty_eh_unsplit): Don't require an existing EH label
+ at the destination block.
2009-10-13 Basile Starynkevitch <basile@starynkevitch.net>
- * passes.c (register_pass): Replaced gcc_unreachable by
- fatal_error on failure. Mentions plugins in comments & messages.
+
+ * passes.c (register_pass): Replaced gcc_unreachable by
+ fatal_error on failure. Mentions plugins in comments & messages.
2009-10-13 Jakub Jelinek <jakub@redhat.com>
diff --git a/gcc/testsuite/g++.dg/opt/eh5.C b/gcc/testsuite/g++.dg/opt/eh5.C
new file mode 100644
index 0000000..3557ab2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/eh5.C
@@ -0,0 +1,43 @@
+// PR 41377
+// { dg-do compile }
+// { dg-options "-O3" }
+
+struct A
+{
+ bool foo(int*) const;
+} a;
+
+struct B {};
+
+struct B1 : B
+{
+ bool (A::*pmf)(int*) const;
+ const A* pa;
+
+ B1() : pmf(&A::foo), pa(&a) {}
+ bool operator()() const { return (pa->*pmf)(new int); }
+};
+
+struct B2 : B
+{
+ B1 b1;
+
+ B2(const B1& _b1) : b1(_b1) {}
+ bool operator()() const { return b1(); }
+};
+
+template<int> struct C
+{
+ void bar(B2 b2) { while (b2()) ; }
+ C() { bar(B2(B1())); }
+};
+
+void baz(int i)
+{
+ switch(i)
+ {
+ case 0: new C<0>;
+ case 1: new C<1>;
+ case 2: new C<2>;
+ }
+}
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index e782738..c077d94 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -3381,12 +3381,31 @@ unsplit_eh (eh_landing_pad lp)
if (find_edge (e_in->src, e_out->dest))
return false;
- /* ??? I can't imagine there would be PHI nodes, since by nature
- of critical edge splitting this block should never have been
- a dominance frontier. If cfg cleanups somehow confuse this,
- due to single edges in and out we ought to have degenerate PHIs
- and can easily propagate the PHI arguments. */
- gcc_assert (gimple_seq_empty_p (phi_nodes (bb)));
+ /* ??? We can get degenerate phis due to cfg cleanups. I would have
+ thought this should have been cleaned up by a phicprop pass, but
+ that doesn't appear to handle virtuals. Propagate by hand. */
+ if (!gimple_seq_empty_p (phi_nodes (bb)))
+ {
+ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); )
+ {
+ gimple use_stmt, phi = gsi_stmt (gsi);
+ tree lhs = gimple_phi_result (phi);
+ tree rhs = gimple_phi_arg_def (phi, 0);
+ use_operand_p use_p;
+ imm_use_iterator iter;
+
+ FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
+ {
+ FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
+ SET_USE (use_p, rhs);
+ }
+
+ if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
+ SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs) = 1;
+
+ remove_phi_node (&gsi, true);
+ }
+ }
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Unsplit EH landing pad %d to block %i.\n",
@@ -3431,7 +3450,7 @@ unsplit_all_eh (void)
static bool
cleanup_empty_eh_merge_phis (basic_block new_bb, basic_block old_bb,
- edge old_bb_out)
+ edge old_bb_out, bool change_region)
{
gimple_stmt_iterator ngsi, ogsi;
edge_iterator ei;
@@ -3531,7 +3550,7 @@ cleanup_empty_eh_merge_phis (basic_block new_bb, basic_block old_bb,
for (ei = ei_start (old_bb->preds); (e = ei_safe_edge (ei)); )
if (e->flags & EDGE_EH)
{
- redirect_eh_edge_1 (e, new_bb, true);
+ redirect_eh_edge_1 (e, new_bb, change_region);
redirect_edge_succ (e, new_bb);
flush_pending_stmts (e);
}
@@ -3583,10 +3602,9 @@ cleanup_empty_eh_move_lp (basic_block bb, edge e_out,
multiple incoming edges and phis are involved. */
static bool
-cleanup_empty_eh_unsplit (basic_block bb, edge e_out, eh_landing_pad olp)
+cleanup_empty_eh_unsplit (basic_block bb, edge e_out, eh_landing_pad lp)
{
gimple_stmt_iterator gsi;
- eh_landing_pad nlp;
tree lab;
/* We really ought not have totally lost everything following
@@ -3594,35 +3612,30 @@ cleanup_empty_eh_unsplit (basic_block bb, edge e_out, eh_landing_pad olp)
be a successor. */
gcc_assert (e_out != NULL);
- /* Look for an EH label in the successor block. */
+ /* The destination block must not already have a landing pad
+ for a different region. */
lab = NULL;
for (gsi = gsi_start_bb (e_out->dest); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
+ int lp_nr;
+
if (gimple_code (stmt) != GIMPLE_LABEL)
break;
lab = gimple_label_label (stmt);
- if (EH_LANDING_PAD_NR (lab))
- goto found;
+ lp_nr = EH_LANDING_PAD_NR (lab);
+ if (lp_nr && get_eh_region_from_lp_number (lp_nr) != lp->region)
+ return false;
}
- return false;
- found:
-
- /* The other label had better be part of the same EH region. Given that
- we've not lowered RESX, there should be no way to have a totally empty
- landing pad that crosses to another EH region. */
- nlp = get_eh_landing_pad_from_number (EH_LANDING_PAD_NR (lab));
- gcc_assert (nlp->region == olp->region);
/* Attempt to move the PHIs into the successor block. */
- if (cleanup_empty_eh_merge_phis (e_out->dest, bb, e_out))
+ if (cleanup_empty_eh_merge_phis (e_out->dest, bb, e_out, false))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
- "Unsplit EH landing pad %d to block %d via lp %d.\n",
- olp->index, e_out->dest->index, nlp->index);
-
- remove_eh_landing_pad (olp);
+ "Unsplit EH landing pad %d to block %i "
+ "(via cleanup_empty_eh).\n",
+ lp->index, e_out->dest->index);
return true;
}
@@ -3725,7 +3738,7 @@ cleanup_empty_eh (eh_landing_pad lp)
landing pad block. If the merge succeeds, we'll already have redirected
all the EH edges. The handler itself will go unreachable if there were
no normal edges. */
- if (cleanup_empty_eh_merge_phis (e_out->dest, bb, e_out))
+ if (cleanup_empty_eh_merge_phis (e_out->dest, bb, e_out, true))
goto succeed;
/* Finally, if all input edges are EH edges, then we can (potentially)