Commit d273b176 by Steven Bosscher

re PR c++/55135 (Segfault of gcc on a big file)

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.

From-SVN: r196464
parent 574f9d7e
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> 2013-03-05 Richard Biener <rguenther@suse.de>
PR middle-end/56525 PR middle-end/56525
......
...@@ -1505,12 +1505,12 @@ remove_eh_landing_pad (eh_landing_pad lp) ...@@ -1505,12 +1505,12 @@ remove_eh_landing_pad (eh_landing_pad lp)
(*cfun->eh->lp_array)[lp->index] = NULL; (*cfun->eh->lp_array)[lp->index] = NULL;
} }
/* Splice REGION from the region tree. */ /* Splice the EH region at PP from the region tree. */
void static void
remove_eh_handler (eh_region region) remove_eh_handler_splicer (eh_region *pp)
{ {
eh_region *pp, *pp_start, p, outer; eh_region region = *pp;
eh_landing_pad lp; eh_landing_pad lp;
for (lp = region->landing_pads; lp ; lp = lp->next_lp) for (lp = region->landing_pads; lp ; lp = lp->next_lp)
...@@ -1520,15 +1520,11 @@ remove_eh_handler (eh_region region) ...@@ -1520,15 +1520,11 @@ remove_eh_handler (eh_region region)
(*cfun->eh->lp_array)[lp->index] = NULL; (*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) if (region->inner)
{ {
eh_region p, outer;
outer = region->outer;
*pp = p = region->inner; *pp = p = region->inner;
do do
{ {
...@@ -1543,6 +1539,59 @@ remove_eh_handler (eh_region region) ...@@ -1543,6 +1539,59 @@ remove_eh_handler (eh_region region)
(*cfun->eh->region_array)[region->index] = NULL; (*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. /* Invokes CALLBACK for every exception handler landing pad label.
Only used by reload hackery; should not be used by new code. */ Only used by reload hackery; should not be used by new code. */
......
...@@ -229,6 +229,7 @@ extern void init_eh_for_function (void); ...@@ -229,6 +229,7 @@ extern void init_eh_for_function (void);
extern void remove_eh_landing_pad (eh_landing_pad); extern void remove_eh_landing_pad (eh_landing_pad);
extern void remove_eh_handler (eh_region); extern void remove_eh_handler (eh_region);
extern void remove_unreachable_eh_regions (sbitmap);
extern bool current_function_has_exception_handlers (void); extern bool current_function_has_exception_handlers (void);
extern void output_function_exception_table (const char *); extern void output_function_exception_table (const char *);
......
...@@ -3519,22 +3519,37 @@ struct gimple_opt_pass pass_lower_eh_dispatch = ...@@ -3519,22 +3519,37 @@ struct gimple_opt_pass pass_lower_eh_dispatch =
} }
}; };
/* Walk statements, see what regions are really referenced and remove /* Walk statements, see what regions and, optionally, landing pads
those that are unused. */ 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 static void
remove_unreachable_handlers (void) mark_reachable_handlers (sbitmap *r_reachablep, sbitmap *lp_reachablep)
{ {
sbitmap r_reachable, lp_reachable; sbitmap r_reachable, lp_reachable;
eh_region region;
eh_landing_pad lp;
basic_block bb; 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 ()); r_reachable = sbitmap_alloc (cfun->eh->region_array->length ());
lp_reachable = sbitmap_alloc (cfun->eh->lp_array->length ());
bitmap_clear (r_reachable); 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) FOR_EACH_BB (bb)
{ {
...@@ -3543,20 +3558,24 @@ remove_unreachable_handlers (void) ...@@ -3543,20 +3558,24 @@ remove_unreachable_handlers (void)
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{ {
gimple stmt = gsi_stmt (gsi); gimple stmt = gsi_stmt (gsi);
lp_nr = lookup_stmt_eh_lp (stmt);
/* Negative LP numbers are MUST_NOT_THROW regions which if (mark_landing_pads)
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)
{ {
gcc_assert (gsi_one_before_end_p (gsi)); int lp_nr = lookup_stmt_eh_lp (stmt);
region = get_eh_region_from_lp_number (lp_nr);
bitmap_set_bit (r_reachable, region->index); /* Negative LP numbers are MUST_NOT_THROW regions which
bitmap_set_bit (lp_reachable, lp_nr); 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. */ /* Avoid removing regions referenced from RESX/EH_DISPATCH. */
...@@ -3573,6 +3592,19 @@ remove_unreachable_handlers (void) ...@@ -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) if (dump_file)
{ {
...@@ -3584,21 +3616,24 @@ remove_unreachable_handlers (void) ...@@ -3584,21 +3616,24 @@ remove_unreachable_handlers (void)
dump_bitmap_file (dump_file, lp_reachable); dump_bitmap_file (dump_file, lp_reachable);
} }
for (r_nr = 1; if (dump_file)
vec_safe_iterate (cfun->eh->region_array, r_nr, &region); ++r_nr) {
if (region && !bitmap_bit_p (r_reachable, r_nr)) FOR_EACH_VEC_SAFE_ELT (cfun->eh->region_array, i, region)
{ if (region && !bitmap_bit_p (r_reachable, region->index))
if (dump_file) fprintf (dump_file,
fprintf (dump_file, "Removing unreachable region %d\n", r_nr); "Removing unreachable region %d\n",
remove_eh_handler (region); region->index);
} }
remove_unreachable_eh_regions (r_reachable);
for (lp_nr = 1; FOR_EACH_VEC_SAFE_ELT (cfun->eh->lp_array, i, lp)
vec_safe_iterate (cfun->eh->lp_array, lp_nr, &lp); ++lp_nr) if (lp && !bitmap_bit_p (lp_reachable, lp->index))
if (lp && !bitmap_bit_p (lp_reachable, lp_nr))
{ {
if (dump_file) 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); remove_eh_landing_pad (lp);
} }
...@@ -3624,12 +3659,12 @@ void ...@@ -3624,12 +3659,12 @@ void
maybe_remove_unreachable_handlers (void) maybe_remove_unreachable_handlers (void)
{ {
eh_landing_pad lp; eh_landing_pad lp;
int i; unsigned i;
if (cfun->eh == NULL) if (cfun->eh == NULL)
return; 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 (lp && lp->post_landing_pad)
{ {
if (label_to_block (lp->post_landing_pad) == NULL) if (label_to_block (lp->post_landing_pad) == NULL)
...@@ -3642,45 +3677,38 @@ maybe_remove_unreachable_handlers (void) ...@@ -3642,45 +3677,38 @@ maybe_remove_unreachable_handlers (void)
/* Remove regions that do not have landing pads. This assumes /* Remove regions that do not have landing pads. This assumes
that remove_unreachable_handlers has already been run, and 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 static void
remove_unreachable_handlers_no_lp (void) remove_unreachable_handlers_no_lp (void)
{ {
eh_region r; eh_region region;
int i;
sbitmap r_reachable; sbitmap r_reachable;
basic_block bb; unsigned i;
r_reachable = sbitmap_alloc (cfun->eh->region_array->length ()); mark_reachable_handlers (&r_reachable, /*lp_reachablep=*/NULL);
bitmap_clear (r_reachable);
FOR_EACH_BB (bb) FOR_EACH_VEC_SAFE_ELT (cfun->eh->region_array, i, region)
{ {
gimple stmt = last_stmt (bb); if (! region)
if (stmt) continue;
/* Avoid removing regions referenced from RESX/EH_DISPATCH. */
switch (gimple_code (stmt)) if (region->landing_pads != NULL
{ || region->type == ERT_MUST_NOT_THROW)
case GIMPLE_RESX: bitmap_set_bit (r_reachable, region->index);
bitmap_set_bit (r_reachable, gimple_resx_region (stmt));
break; if (dump_file
case GIMPLE_EH_DISPATCH: && !bitmap_bit_p (r_reachable, region->index))
bitmap_set_bit (r_reachable, gimple_eh_dispatch_region (stmt)); fprintf (dump_file,
break; "Removing unreachable region %d\n",
default: region->index);
break;
}
} }
for (i = 1; cfun->eh->region_array->iterate (i, &r); ++i) remove_unreachable_eh_regions (r_reachable);
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);
}
sbitmap_free (r_reachable); sbitmap_free (r_reachable);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment