except.c (remove_eh_handler_and_replace): Break out from ...
* except.c (remove_eh_handler_and_replace): Break out from ... (remove_eh_handler): ... here. (bring_to_root): New function. (remove_unreachable_regions): Collect MUST_NOT_THROW, unify runtime handled ones, bring others to root of tree. From-SVN: r145545
This commit is contained in:
parent
4cb735f794
commit
14925fcd47
|
@ -1,3 +1,11 @@
|
|||
2009-04-04 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* except.c (remove_eh_handler_and_replace): Break out from ...
|
||||
(remove_eh_handler): ... here.
|
||||
(bring_to_root): New function.
|
||||
(remove_unreachable_regions): Collect MUST_NOT_THROW, unify runtime
|
||||
handled ones, bring others to root of tree.
|
||||
|
||||
2009-04-04 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* tree-eh.c (tree_empty_eh_handler_p): Pattern match more curefully.
|
||||
|
|
116
gcc/except.c
116
gcc/except.c
|
@ -208,6 +208,7 @@ struct call_site_record GTY(())
|
|||
|
||||
DEF_VEC_P(eh_region);
|
||||
DEF_VEC_ALLOC_P(eh_region, gc);
|
||||
DEF_VEC_ALLOC_P(eh_region, heap);
|
||||
|
||||
/* Used to save exception status for each function. */
|
||||
struct eh_status GTY(())
|
||||
|
@ -252,6 +253,8 @@ static int ehl_eq (const void *, const void *);
|
|||
static void add_ehl_entry (rtx, struct eh_region *);
|
||||
static void remove_exception_handler_label (rtx);
|
||||
static void remove_eh_handler (struct eh_region *);
|
||||
static void remove_eh_handler_and_replace (struct eh_region *,
|
||||
struct eh_region *);
|
||||
static int for_each_eh_label_1 (void **, void *);
|
||||
|
||||
/* The return value of reachable_next_level. */
|
||||
|
@ -718,21 +721,42 @@ can_be_reached_by_runtime (sbitmap contains_stmt, struct eh_region *r)
|
|||
}
|
||||
}
|
||||
|
||||
/* Bring region R to the root of tree. */
|
||||
|
||||
static void
|
||||
bring_to_root (struct eh_region *r)
|
||||
{
|
||||
struct eh_region **pp;
|
||||
struct eh_region *outer = r->outer;
|
||||
if (!r->outer)
|
||||
return;
|
||||
for (pp = &outer->inner; *pp != r; pp = &(*pp)->next_peer)
|
||||
continue;
|
||||
*pp = r->next_peer;
|
||||
r->outer = NULL;
|
||||
r->next_peer = cfun->eh->region_tree;
|
||||
cfun->eh->region_tree = r;
|
||||
}
|
||||
|
||||
/* Remove all regions whose labels are not reachable.
|
||||
REACHABLE is bitmap of all regions that are used by the function
|
||||
CONTAINS_STMT is bitmap of all regions that contains stmt (or NULL). */
|
||||
|
||||
void
|
||||
remove_unreachable_regions (sbitmap reachable, sbitmap contains_stmt)
|
||||
{
|
||||
int i;
|
||||
struct eh_region *r;
|
||||
VEC(eh_region,heap) *must_not_throws = VEC_alloc (eh_region, heap, 16);
|
||||
struct eh_region *local_must_not_throw = NULL;
|
||||
struct eh_region *first_must_not_throw = NULL;
|
||||
|
||||
for (i = cfun->eh->last_region_number; i > 0; --i)
|
||||
{
|
||||
r = VEC_index (eh_region, cfun->eh->region_array, i);
|
||||
if (!r)
|
||||
if (!r || r->region_number != i)
|
||||
continue;
|
||||
if (r->region_number == i && !TEST_BIT (reachable, i) && !r->resume)
|
||||
if (!TEST_BIT (reachable, i) && !r->resume)
|
||||
{
|
||||
bool kill_it = true;
|
||||
|
||||
|
@ -783,11 +807,60 @@ remove_unreachable_regions (sbitmap reachable, sbitmap contains_stmt)
|
|||
r->region_number);
|
||||
remove_eh_handler (r);
|
||||
}
|
||||
else if (r->type == ERT_MUST_NOT_THROW)
|
||||
{
|
||||
if (!first_must_not_throw)
|
||||
first_must_not_throw = r;
|
||||
VEC_safe_push (eh_region, heap, must_not_throws, r);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (r->type == ERT_MUST_NOT_THROW)
|
||||
{
|
||||
if (!local_must_not_throw)
|
||||
local_must_not_throw = r;
|
||||
if (r->outer)
|
||||
VEC_safe_push (eh_region, heap, must_not_throws, r);
|
||||
}
|
||||
}
|
||||
|
||||
/* MUST_NOT_THROW regions without local handler are all the same; they
|
||||
trigger terminate call in runtime.
|
||||
MUST_NOT_THROW handled locally can differ in debug info associated
|
||||
to std::terminate () call or if one is coming from Java and other
|
||||
from C++ whether they call terminate or abort.
|
||||
|
||||
We merge all MUST_NOT_THROW regions handled by the run-time into one.
|
||||
We alsobring all local MUST_NOT_THROW regions to the roots of EH tree
|
||||
(since unwinding never continues to the outer region anyway).
|
||||
If MUST_NOT_THROW with local handler is present in the tree, we use
|
||||
that region to merge into, since it will remain in tree anyway;
|
||||
otherwise we use first MUST_NOT_THROW.
|
||||
|
||||
Merging of locally handled regions needs changes to the CFG. Crossjumping
|
||||
should take care of this, by looking at the actual code and
|
||||
ensuring that the cleanup actions are really the same. */
|
||||
|
||||
if (local_must_not_throw)
|
||||
first_must_not_throw = local_must_not_throw;
|
||||
|
||||
for (i = 0; VEC_iterate (eh_region, must_not_throws, i, r); i++)
|
||||
{
|
||||
if (!r->label && !r->tree_label && r != first_must_not_throw)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Replacing MUST_NOT_THROW region %i by %i\n",
|
||||
r->region_number,
|
||||
first_must_not_throw->region_number);
|
||||
remove_eh_handler_and_replace (r, first_must_not_throw);
|
||||
}
|
||||
else
|
||||
bring_to_root (r);
|
||||
}
|
||||
#ifdef ENABLE_CHECKING
|
||||
verify_eh_tree (cfun);
|
||||
#endif
|
||||
VEC_free (eh_region, heap, must_not_throws);
|
||||
}
|
||||
|
||||
/* Return array mapping LABEL_DECL_UID to region such that region's tree_label
|
||||
|
@ -2352,22 +2425,24 @@ remove_exception_handler_label (rtx label)
|
|||
htab_clear_slot (crtl->eh.exception_handler_label_map, (void **) slot);
|
||||
}
|
||||
|
||||
/* Splice REGION from the region tree etc. */
|
||||
/* Splice REGION from the region tree and replace it by REPLACE etc. */
|
||||
|
||||
static void
|
||||
remove_eh_handler (struct eh_region *region)
|
||||
remove_eh_handler_and_replace (struct eh_region *region,
|
||||
struct eh_region *replace)
|
||||
{
|
||||
struct eh_region **pp, **pp_start, *p, *outer, *inner;
|
||||
rtx lab;
|
||||
|
||||
outer = region->outer;
|
||||
/* For the benefit of efficiently handling REG_EH_REGION notes,
|
||||
replace this region in the region array with its containing
|
||||
region. Note that previous region deletions may result in
|
||||
multiple copies of this region in the array, so we have a
|
||||
list of alternate numbers by which we are known. */
|
||||
|
||||
outer = region->outer;
|
||||
VEC_replace (eh_region, cfun->eh->region_array, region->region_number, outer);
|
||||
VEC_replace (eh_region, cfun->eh->region_array, region->region_number,
|
||||
replace);
|
||||
if (region->aka)
|
||||
{
|
||||
unsigned i;
|
||||
|
@ -2375,17 +2450,17 @@ remove_eh_handler (struct eh_region *region)
|
|||
|
||||
EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i, bi)
|
||||
{
|
||||
VEC_replace (eh_region, cfun->eh->region_array, i, outer);
|
||||
VEC_replace (eh_region, cfun->eh->region_array, i, replace);
|
||||
}
|
||||
}
|
||||
|
||||
if (outer)
|
||||
if (replace)
|
||||
{
|
||||
if (!outer->aka)
|
||||
outer->aka = BITMAP_GGC_ALLOC ();
|
||||
if (!replace->aka)
|
||||
replace->aka = BITMAP_GGC_ALLOC ();
|
||||
if (region->aka)
|
||||
bitmap_ior_into (outer->aka, region->aka);
|
||||
bitmap_set_bit (outer->aka, region->region_number);
|
||||
bitmap_ior_into (replace->aka, region->aka);
|
||||
bitmap_set_bit (replace->aka, region->region_number);
|
||||
}
|
||||
|
||||
if (crtl->eh.built_landing_pads)
|
||||
|
@ -2403,12 +2478,16 @@ remove_eh_handler (struct eh_region *region)
|
|||
continue;
|
||||
*pp = region->next_peer;
|
||||
|
||||
if (replace)
|
||||
pp_start = &replace->inner;
|
||||
else
|
||||
pp_start = &cfun->eh->region_tree;
|
||||
inner = region->inner;
|
||||
if (inner)
|
||||
{
|
||||
for (p = inner; p->next_peer ; p = p->next_peer)
|
||||
p->outer = outer;
|
||||
p->outer = outer;
|
||||
p->outer = replace;
|
||||
p->outer = replace;
|
||||
|
||||
p->next_peer = *pp_start;
|
||||
*pp_start = inner;
|
||||
|
@ -2442,6 +2521,15 @@ remove_eh_handler (struct eh_region *region)
|
|||
}
|
||||
}
|
||||
|
||||
/* Splice REGION from the region tree and replace it by the outer region
|
||||
etc. */
|
||||
|
||||
static void
|
||||
remove_eh_handler (struct eh_region *region)
|
||||
{
|
||||
remove_eh_handler_and_replace (region, region->outer);
|
||||
}
|
||||
|
||||
/* LABEL heads a basic block that is about to be deleted. If this
|
||||
label corresponds to an exception region, we may be able to
|
||||
delete the region. */
|
||||
|
|
Loading…
Reference in New Issue