From 14925fcd4738293fae74f5f86328d6bee131dcf8 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sat, 4 Apr 2009 19:15:31 +0200 Subject: [PATCH] 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 --- gcc/ChangeLog | 8 ++++ gcc/except.c | 116 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 110 insertions(+), 14 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7239ecf32e1..730df1d450a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2009-04-04 Jan Hubicka + + * 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 * tree-eh.c (tree_empty_eh_handler_p): Pattern match more curefully. diff --git a/gcc/except.c b/gcc/except.c index 64be6afd2c4..2651e99f2d4 100644 --- a/gcc/except.c +++ b/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. */ -- 2.30.2