summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsteven <steven@138bc75d-0d04-0410-961f-82ee72b054a4>2013-03-05 14:45:23 +0000
committersteven <steven@138bc75d-0d04-0410-961f-82ee72b054a4>2013-03-05 14:45:23 +0000
commit390f4a4b5eb4ff6f4f06d7346d641729703bbad6 (patch)
tree4ff07f0d40ea5cef8af4fe46b0f91b0ca63c916a
parentf5f9d87c0243ce7d99422290997432990a4d8de9 (diff)
downloadgcc-390f4a4b5eb4ff6f4f06d7346d641729703bbad6.tar.gz
gcc/
PR c++/55135 * except.h (remove_unreachable_eh_regions): New prototype. * except.c (remove_eh_handler_splicer): New function, split out of remove_eh_handler. (remove_eh_handler): Use remove_eh_handler_splicer. Add comment warning about running it on many EH regions one at a time. (remove_unreachable_eh_regions_worker): New function, walk the EH tree in depth-first order and remove non-marked regions. (remove_unreachable_eh_regions): New function. * tree-eh.c (mark_reachable_handlers): New function, split out from remove_unreachable_handlers. (remove_unreachable_handlers): Use mark_reachable_handlers and remove_unreachable_eh_regions. (remove_unreachable_handlers_no_lp): Use mark_reachable_handlers and remove_unreachable_eh_regions. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@196464 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog18
-rw-r--r--gcc/except.c71
-rw-r--r--gcc/except.h1
-rw-r--r--gcc/tree-eh.c156
4 files changed, 171 insertions, 75 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 06a0ca2b6fe..dbef6b39da2 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,21 @@
+2013-03-05 Steven Bosscher <steven@gcc.gnu.org>
+
+ PR c++/55135
+ * except.h (remove_unreachable_eh_regions): New prototype.
+ * except.c (remove_eh_handler_splicer): New function, split out
+ of remove_eh_handler.
+ (remove_eh_handler): Use remove_eh_handler_splicer. Add comment
+ warning about running it on many EH regions one at a time.
+ (remove_unreachable_eh_regions_worker): New function, walk the
+ EH tree in depth-first order and remove non-marked regions.
+ (remove_unreachable_eh_regions): New function.
+ * tree-eh.c (mark_reachable_handlers): New function, split out
+ from remove_unreachable_handlers.
+ (remove_unreachable_handlers): Use mark_reachable_handlers and
+ remove_unreachable_eh_regions.
+ (remove_unreachable_handlers_no_lp): Use mark_reachable_handlers
+ and remove_unreachable_eh_regions.
+
2013-03-05 Richard Biener <rguenther@suse.de>
PR middle-end/56525
diff --git a/gcc/except.c b/gcc/except.c
index 3e424eb9d7f..4e85f731837 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -1505,12 +1505,12 @@ remove_eh_landing_pad (eh_landing_pad lp)
(*cfun->eh->lp_array)[lp->index] = NULL;
}
-/* Splice REGION from the region tree. */
+/* Splice the EH region at PP from the region tree. */
-void
-remove_eh_handler (eh_region region)
+static void
+remove_eh_handler_splicer (eh_region *pp)
{
- eh_region *pp, *pp_start, p, outer;
+ eh_region region = *pp;
eh_landing_pad lp;
for (lp = region->landing_pads; lp ; lp = lp->next_lp)
@@ -1520,15 +1520,11 @@ remove_eh_handler (eh_region region)
(*cfun->eh->lp_array)[lp->index] = NULL;
}
- outer = region->outer;
- if (outer)
- pp_start = &outer->inner;
- else
- pp_start = &cfun->eh->region_tree;
- for (pp = pp_start, p = *pp; p != region; pp = &p->next_peer, p = *pp)
- continue;
if (region->inner)
{
+ eh_region p, outer;
+ outer = region->outer;
+
*pp = p = region->inner;
do
{
@@ -1543,6 +1539,59 @@ remove_eh_handler (eh_region region)
(*cfun->eh->region_array)[region->index] = NULL;
}
+/* Splice a single EH region REGION from the region tree.
+
+ To unlink REGION, we need to find the pointer to it with a relatively
+ expensive search in REGION's outer region. If you are going to
+ remove a number of handlers, using remove_unreachable_eh_regions may
+ be a better option. */
+
+void
+remove_eh_handler (eh_region region)
+{
+ eh_region *pp, *pp_start, p, outer;
+
+ outer = region->outer;
+ if (outer)
+ pp_start = &outer->inner;
+ else
+ pp_start = &cfun->eh->region_tree;
+ for (pp = pp_start, p = *pp; p != region; pp = &p->next_peer, p = *pp)
+ continue;
+
+ remove_eh_handler_splicer (pp);
+}
+
+/* Worker for remove_unreachable_eh_regions.
+ PP is a pointer to the region to start a region tree depth-first
+ search from. R_REACHABLE is the set of regions that have to be
+ preserved. */
+
+static void
+remove_unreachable_eh_regions_worker (eh_region *pp, sbitmap r_reachable)
+{
+ while (*pp)
+ {
+ eh_region region = *pp;
+ remove_unreachable_eh_regions_worker (&region->inner, r_reachable);
+ if (!bitmap_bit_p (r_reachable, region->index))
+ remove_eh_handler_splicer (pp);
+ else
+ pp = &region->next_peer;
+ }
+}
+
+/* Splice all EH regions *not* marked in R_REACHABLE from the region tree.
+ Do this by traversing the EH tree top-down and splice out regions that
+ are not marked. By removing regions from the leaves, we avoid costly
+ searches in the region tree. */
+
+void
+remove_unreachable_eh_regions (sbitmap r_reachable)
+{
+ remove_unreachable_eh_regions_worker (&cfun->eh->region_tree, r_reachable);
+}
+
/* Invokes CALLBACK for every exception handler landing pad label.
Only used by reload hackery; should not be used by new code. */
diff --git a/gcc/except.h b/gcc/except.h
index 6c202415f83..bc9654a7ae4 100644
--- a/gcc/except.h
+++ b/gcc/except.h
@@ -229,6 +229,7 @@ extern void init_eh_for_function (void);
extern void remove_eh_landing_pad (eh_landing_pad);
extern void remove_eh_handler (eh_region);
+extern void remove_unreachable_eh_regions (sbitmap);
extern bool current_function_has_exception_handlers (void);
extern void output_function_exception_table (const char *);
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 29b4f9a7c71..6b9dac9258e 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -3519,22 +3519,37 @@ struct gimple_opt_pass pass_lower_eh_dispatch =
}
};
-/* Walk statements, see what regions are really referenced and remove
- those that are unused. */
+/* Walk statements, see what regions and, optionally, landing pads
+ are really referenced.
+
+ Returns in R_REACHABLEP an sbitmap with bits set for reachable regions,
+ and in LP_REACHABLE an sbitmap with bits set for reachable landing pads.
+
+ Passing NULL for LP_REACHABLE is valid, in this case only reachable
+ regions are marked.
+
+ The caller is responsible for freeing the returned sbitmaps. */
static void
-remove_unreachable_handlers (void)
+mark_reachable_handlers (sbitmap *r_reachablep, sbitmap *lp_reachablep)
{
sbitmap r_reachable, lp_reachable;
- eh_region region;
- eh_landing_pad lp;
basic_block bb;
- int lp_nr, r_nr;
+ bool mark_landing_pads = (lp_reachablep != NULL);
+ gcc_checking_assert (r_reachablep != NULL);
r_reachable = sbitmap_alloc (cfun->eh->region_array->length ());
- lp_reachable = sbitmap_alloc (cfun->eh->lp_array->length ());
bitmap_clear (r_reachable);
- bitmap_clear (lp_reachable);
+ *r_reachablep = r_reachable;
+
+ if (mark_landing_pads)
+ {
+ lp_reachable = sbitmap_alloc (cfun->eh->lp_array->length ());
+ bitmap_clear (lp_reachable);
+ *lp_reachablep = lp_reachable;
+ }
+ else
+ lp_reachable = NULL;
FOR_EACH_BB (bb)
{
@@ -3543,20 +3558,24 @@ remove_unreachable_handlers (void)
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
- lp_nr = lookup_stmt_eh_lp (stmt);
- /* Negative LP numbers are MUST_NOT_THROW regions which
- are not considered BB enders. */
- if (lp_nr < 0)
- bitmap_set_bit (r_reachable, -lp_nr);
-
- /* Positive LP numbers are real landing pads, are are BB enders. */
- else if (lp_nr > 0)
+ if (mark_landing_pads)
{
- gcc_assert (gsi_one_before_end_p (gsi));
- region = get_eh_region_from_lp_number (lp_nr);
- bitmap_set_bit (r_reachable, region->index);
- bitmap_set_bit (lp_reachable, lp_nr);
+ int lp_nr = lookup_stmt_eh_lp (stmt);
+
+ /* Negative LP numbers are MUST_NOT_THROW regions which
+ are not considered BB enders. */
+ if (lp_nr < 0)
+ bitmap_set_bit (r_reachable, -lp_nr);
+
+ /* Positive LP numbers are real landing pads, and BB enders. */
+ else if (lp_nr > 0)
+ {
+ gcc_assert (gsi_one_before_end_p (gsi));
+ eh_region region = get_eh_region_from_lp_number (lp_nr);
+ bitmap_set_bit (r_reachable, region->index);
+ bitmap_set_bit (lp_reachable, lp_nr);
+ }
}
/* Avoid removing regions referenced from RESX/EH_DISPATCH. */
@@ -3573,6 +3592,19 @@ remove_unreachable_handlers (void)
}
}
}
+}
+
+/* Remove unreachable handlers and unreachable landing pads. */
+
+static void
+remove_unreachable_handlers (void)
+{
+ sbitmap r_reachable, lp_reachable;
+ eh_region region;
+ eh_landing_pad lp;
+ unsigned i;
+
+ mark_reachable_handlers (&r_reachable, &lp_reachable);
if (dump_file)
{
@@ -3584,21 +3616,24 @@ remove_unreachable_handlers (void)
dump_bitmap_file (dump_file, lp_reachable);
}
- for (r_nr = 1;
- vec_safe_iterate (cfun->eh->region_array, r_nr, &region); ++r_nr)
- if (region && !bitmap_bit_p (r_reachable, r_nr))
- {
- if (dump_file)
- fprintf (dump_file, "Removing unreachable region %d\n", r_nr);
- remove_eh_handler (region);
- }
+ if (dump_file)
+ {
+ FOR_EACH_VEC_SAFE_ELT (cfun->eh->region_array, i, region)
+ if (region && !bitmap_bit_p (r_reachable, region->index))
+ fprintf (dump_file,
+ "Removing unreachable region %d\n",
+ region->index);
+ }
+
+ remove_unreachable_eh_regions (r_reachable);
- for (lp_nr = 1;
- vec_safe_iterate (cfun->eh->lp_array, lp_nr, &lp); ++lp_nr)
- if (lp && !bitmap_bit_p (lp_reachable, lp_nr))
+ FOR_EACH_VEC_SAFE_ELT (cfun->eh->lp_array, i, lp)
+ if (lp && !bitmap_bit_p (lp_reachable, lp->index))
{
if (dump_file)
- fprintf (dump_file, "Removing unreachable landing pad %d\n", lp_nr);
+ fprintf (dump_file,
+ "Removing unreachable landing pad %d\n",
+ lp->index);
remove_eh_landing_pad (lp);
}
@@ -3624,12 +3659,12 @@ void
maybe_remove_unreachable_handlers (void)
{
eh_landing_pad lp;
- int i;
+ unsigned i;
if (cfun->eh == NULL)
return;
-
- for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
+
+ FOR_EACH_VEC_SAFE_ELT (cfun->eh->lp_array, i, lp)
if (lp && lp->post_landing_pad)
{
if (label_to_block (lp->post_landing_pad) == NULL)
@@ -3642,45 +3677,38 @@ maybe_remove_unreachable_handlers (void)
/* Remove regions that do not have landing pads. This assumes
that remove_unreachable_handlers has already been run, and
- that we've just manipulated the landing pads since then. */
+ that we've just manipulated the landing pads since then.
+
+ Preserve regions with landing pads and regions that prevent
+ exceptions from propagating further, even if these regions
+ are not reachable. */
static void
remove_unreachable_handlers_no_lp (void)
{
- eh_region r;
- int i;
+ eh_region region;
sbitmap r_reachable;
- basic_block bb;
+ unsigned i;
- r_reachable = sbitmap_alloc (cfun->eh->region_array->length ());
- bitmap_clear (r_reachable);
+ mark_reachable_handlers (&r_reachable, /*lp_reachablep=*/NULL);
- FOR_EACH_BB (bb)
+ FOR_EACH_VEC_SAFE_ELT (cfun->eh->region_array, i, region)
{
- gimple stmt = last_stmt (bb);
- if (stmt)
- /* Avoid removing regions referenced from RESX/EH_DISPATCH. */
- switch (gimple_code (stmt))
- {
- case GIMPLE_RESX:
- bitmap_set_bit (r_reachable, gimple_resx_region (stmt));
- break;
- case GIMPLE_EH_DISPATCH:
- bitmap_set_bit (r_reachable, gimple_eh_dispatch_region (stmt));
- break;
- default:
- break;
- }
+ if (! region)
+ continue;
+
+ if (region->landing_pads != NULL
+ || region->type == ERT_MUST_NOT_THROW)
+ bitmap_set_bit (r_reachable, region->index);
+
+ if (dump_file
+ && !bitmap_bit_p (r_reachable, region->index))
+ fprintf (dump_file,
+ "Removing unreachable region %d\n",
+ region->index);
}
- for (i = 1; cfun->eh->region_array->iterate (i, &r); ++i)
- if (r && r->landing_pads == NULL && r->type != ERT_MUST_NOT_THROW
- && !bitmap_bit_p (r_reachable, i))
- {
- if (dump_file)
- fprintf (dump_file, "Removing unreachable region %d\n", i);
- remove_eh_handler (r);
- }
+ remove_unreachable_eh_regions (r_reachable);
sbitmap_free (r_reachable);
}