This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] PR42859
- From: Andrey Belevantsev <abel at ispras dot ru>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Cc: Richard Henderson <rth at redhat dot com>
- Date: Wed, 10 Mar 2010 11:40:19 +0300
- Subject: [PATCH] PR42859
Hello,
As explained in the PR, the patch just filters out duplicate case labels
in lower_eh_dispatch, removes unneeded edges, and finally removes
unreachable blocks if some edges were really removed. I have no idea
whether there is a better place to do this.
The nested try construct in the test is needed to show that it's not
enough to remove a single unreachable block. The hunk to Makefile.in
adding the pointer-set.h dependency to tree-eh.o is missing because the
dependency is already there :)
Bootstrapped and regtested fine on x86-64 linux, ok for trunk?
Andrey
2010-03-10 Andrey Belevantsev <abel@ispras.ru>
PR middle-end/42859
* tree-eh.c: Include pointer-set.h.
(lower_eh_dispatch): Filter out duplicate case labels and
remove the unneeded edge when the label is unused. Return
true when some edges are removed.
(execute_lower_eh_dispatch): When any lowering resulted in
removing an edge, also delete unreachable blocks.
2010-03-10 Andrey Belevantsev <abel@ispras.ru>
* g++.dg/eh/pr42859.C: New test.
diff --git a/gcc/testsuite/g++.dg/eh/pr42859.C b/gcc/testsuite/g++.dg/eh/pr42859.C
new file mode 100644
index 0000000..a9f1473
--- /dev/null
+++ b/gcc/testsuite/g++.dg/eh/pr42859.C
@@ -0,0 +1,23 @@
+// { dg-do compile }
+
+void start (void);
+void
+ptw32_terminate (void)
+{
+ try
+ {
+ try
+ {
+ start ();
+ }
+ catch (int)
+ {
+ }
+ catch (int)
+ {
+ }
+ }
+ catch (int)
+ {
+ }
+}
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 2cb334f..5ae47f0 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "flags.h"
#include "function.h"
#include "except.h"
+#include "pointer-set.h"
#include "tree-flow.h"
#include "tree-dump.h"
#include "tree-inline.h"
@@ -3038,9 +3039,10 @@ struct gimple_opt_pass pass_lower_resx =
};
-/* At the end of inlining, we can lower EH_DISPATCH. */
+/* At the end of inlining, we can lower EH_DISPATCH. Return true when
+ we have found some duplicate labels and removed some edges. */
-static void
+static bool
lower_eh_dispatch (basic_block src, gimple stmt)
{
gimple_stmt_iterator gsi;
@@ -3048,6 +3050,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
eh_region r;
tree filter, fn;
gimple x;
+ bool redirected = false;
region_nr = gimple_eh_dispatch_region (stmt);
r = get_eh_region_from_number (region_nr);
@@ -3063,6 +3066,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
eh_catch c;
edge_iterator ei;
edge e;
+ struct pointer_set_t *seen_values = pointer_set_create ();
/* Collect the labels for a switch. Zero the post_landing_pad
field becase we'll no longer have anything keeping these labels
@@ -3071,6 +3075,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
{
tree tp_node, flt_node, lab = c->label;
+ bool have_label = false;
c->label = NULL;
tp_node = c->type_list;
@@ -3083,14 +3088,29 @@ lower_eh_dispatch (basic_block src, gimple stmt)
}
do
{
- tree t = build3 (CASE_LABEL_EXPR, void_type_node,
- TREE_VALUE (flt_node), NULL, lab);
- VEC_safe_push (tree, heap, labels, t);
+ /* Filter out duplicate labels that arise when this handler
+ is shadowed by an earlier one. When no labels are
+ attached to the handler anymore, we remove
+ the corresponding edge and then we delete unreachable
+ blocks at the end of this pass. */
+ if (! pointer_set_contains (seen_values, TREE_VALUE (flt_node)))
+ {
+ tree t = build3 (CASE_LABEL_EXPR, void_type_node,
+ TREE_VALUE (flt_node), NULL, lab);
+ VEC_safe_push (tree, heap, labels, t);
+ pointer_set_insert (seen_values, TREE_VALUE (flt_node));
+ have_label = true;
+ }
tp_node = TREE_CHAIN (tp_node);
flt_node = TREE_CHAIN (flt_node);
}
while (tp_node);
+ if (! have_label)
+ {
+ remove_edge (find_edge (src, label_to_block (lab)));
+ redirected = true;
+ }
}
/* Clean up the edge flags. */
@@ -3132,6 +3152,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
VEC_free (tree, heap, labels);
}
+ pointer_set_destroy (seen_values);
}
break;
@@ -3165,6 +3186,7 @@ lower_eh_dispatch (basic_block src, gimple stmt)
/* Replace the EH_DISPATCH with the SWITCH or COND generated above. */
gsi_remove (&gsi, true);
+ return redirected;
}
static unsigned
@@ -3172,6 +3194,7 @@ execute_lower_eh_dispatch (void)
{
basic_block bb;
bool any_rewritten = false;
+ bool redirected = false;
assign_filter_values ();
@@ -3180,11 +3203,13 @@ execute_lower_eh_dispatch (void)
gimple last = last_stmt (bb);
if (last && gimple_code (last) == GIMPLE_EH_DISPATCH)
{
- lower_eh_dispatch (bb, last);
+ redirected |= lower_eh_dispatch (bb, last);
any_rewritten = true;
}
}
+ if (redirected)
+ delete_unreachable_blocks ();
return any_rewritten ? TODO_update_ssa_only_virtuals : 0;
}