* pretty-ipa merge 14: EH region label sharing code
@ 2009-04-24 15:37 Jan Hubicka
2009-04-24 17:52 ` Richard Guenther
2009-04-25 15:45 ` H.J. Lu
0 siblings, 2 replies; 4+ messages in thread
From: Jan Hubicka @ 2009-04-24 15:37 UTC (permalink / raw)
To: gcc-patches, rguenther
Hi,
this is last EH redirection preparation bit. It makes code happy about case
where two regions share same label. This happens by EH redirection but also by
cfgcleanup and such.
While this is generally easy to maintain linked list of regions sharing
label, tricky part is eh cleanup where we now can have empty cleanup reached by
multiple EH handlers and none of them must be same as the one resuming it.
This is hanled by removing all the reaching EH handlers and replacing them by
outer handler of the resuming one.
It is also possible that other control flow reaches the empty handler and in
this case BB is no longer removed and resuming EH is kept in place. This
happens sometimes when EH region proves to be empty over some paths only
after edge splitting.
I also bundled in remove_eh_handler_and_replace change that allows removing
try region without associated catch and also to update prev_try pointers. This
is really needed for EH merging, but it is bit difficult to split it out of
the patch.
Bootstrapped/regtested x86_64-linux, OK?
* tree-eh.c (tree_remove_unreachable_handlers): Handle shared labels.
(tree_empty_eh_handler_p): Allow non-EH predecestors; allow region
to be reached by different label than left.
(update_eh_edges): Update comment; remove edge_to_remove if possible
and return true if suceeded.
(cleanup_empty_eh): Accept sharing map; handle shared regions.
(cleanup_eh): Compute sharing map.
* except.c (remove_eh_handler_and_replace): Add argument if we should
update regions.
(remove_unreachable_regions): Update for label sharing.
(label_to_region_map): Likewise.
(get_next_region_sharing_label): New function.
(remove_eh_handler_and_replace): Add update_catch_try parameter; update
prev_try pointers.
(remove_eh_handler): Update.
(remove_eh_region_and_replace_by_outer_of): New function.
* except.h (struct eh_region): Add next_region_sharing_label.
(remove_eh_region_and_replace_by_outer_of,
get_next_region_sharing_label): Declare.
* tree-cfgcleanup.c (tree_forwarder_block_p): Simplify.
*** /aux/hubicka/trunk-write/gcc/tree-eh.c Wed Apr 8 17:08:50 2009
--- tree-eh.c Fri Apr 24 13:56:55 2009
*************** tree_remove_unreachable_handlers (void)
*** 2695,2702 ****
if (gimple_code (stmt) == GIMPLE_LABEL && has_eh_preds)
{
int uid = LABEL_DECL_UID (gimple_label_label (stmt));
! int region = VEC_index (int, label_to_region, uid);
! SET_BIT (reachable, region);
}
if (gimple_code (stmt) == GIMPLE_RESX)
SET_BIT (reachable, gimple_resx_region (stmt));
--- 2738,2748 ----
if (gimple_code (stmt) == GIMPLE_LABEL && has_eh_preds)
{
int uid = LABEL_DECL_UID (gimple_label_label (stmt));
! int region;
!
! for (region = VEC_index (int, label_to_region, uid);
! region; region = get_next_region_sharing_label (region))
! SET_BIT (reachable, region);
}
if (gimple_code (stmt) == GIMPLE_RESX)
SET_BIT (reachable, gimple_resx_region (stmt));
*************** tree_empty_eh_handler_p (basic_block bb)
*** 2743,2750 ****
--- 2789,2799 ----
{
gimple_stmt_iterator gsi;
int region;
+ edge_iterator ei;
+ edge e;
use_operand_p imm_use;
gimple use_stmt;
+ bool found = false;
gsi = gsi_last_bb (bb);
*************** tree_empty_eh_handler_p (basic_block bb)
*** 2815,2829 ****
if (gsi_end_p (gsi))
return 0;
}
! while (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
! {
! if (gimple_label_label (gsi_stmt (gsi))
! == get_eh_region_no_tree_label (region))
! return region;
! gsi_prev (&gsi);
! if (gsi_end_p (gsi))
! return 0;
! }
return 0;
}
--- 2864,2880 ----
if (gsi_end_p (gsi))
return 0;
}
! if (gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
! return 0;
!
! /* Be sure that there is at least on EH region reaching the block directly.
! After EH edge redirection, it is possible that block is reached by one handler
! but resumed by different. */
! FOR_EACH_EDGE (e, ei, bb->preds)
! if ((e->flags & EDGE_EH))
! found = true;
! if (found)
! return region;
return 0;
}
*************** make_eh_edge_and_update_phi (struct eh_r
*** 2955,2963 ****
/* Make EH edges corresponding to STMT while updating PHI nodes after removal
empty cleanup BB_TO_REMOVE joined to BB containing STMT
! by EDGE_TO_REMOVE. */
! static void
update_eh_edges (gimple stmt, basic_block bb_to_remove, edge edge_to_remove)
{
int region_nr;
--- 3006,3017 ----
/* Make EH edges corresponding to STMT while updating PHI nodes after removal
empty cleanup BB_TO_REMOVE joined to BB containing STMT
! by EDGE_TO_REMOVE.
! Return if EDGE_TO_REMOVE was really removed. It might stay reachable when
! not all EH regions are cleaned up. */
!
! static bool
update_eh_edges (gimple stmt, basic_block bb_to_remove, edge edge_to_remove)
{
int region_nr;
*************** update_eh_edges (gimple stmt, basic_bloc
*** 2967,2972 ****
--- 3021,3027 ----
edge_iterator ei;
edge e;
int probability_sum = 0;
+ bool removed = false;
info.bb_to_remove = bb_to_remove;
info.bb = gimple_bb (stmt);
*************** update_eh_edges (gimple stmt, basic_bloc
*** 2980,2987 ****
else
{
region_nr = lookup_stmt_eh_region (stmt);
- if (region_nr < 0)
- return;
is_resx = false;
inlinable = inlinable_call_p (stmt);
}
--- 3035,3040 ----
*************** update_eh_edges (gimple stmt, basic_bloc
*** 2993,3001 ****
/* And remove edges we didn't marked. */
for (ei = ei_start (info.bb->succs); (e = ei_safe_edge (ei)); )
{
! if ((e->flags & EDGE_EH) && !e->aux && e != edge_to_remove)
{
dominance_info_invalidated = true;
remove_edge (e);
}
else
--- 3046,3056 ----
/* And remove edges we didn't marked. */
for (ei = ei_start (info.bb->succs); (e = ei_safe_edge (ei)); )
{
! if ((e->flags & EDGE_EH) && !e->aux)
{
dominance_info_invalidated = true;
+ if (e == edge_to_remove)
+ removed = true;
remove_edge (e);
}
else
*************** update_eh_edges (gimple stmt, basic_bloc
*** 3011,3026 ****
we get fewer consistency errors in the dumps. */
if (is_resx && EDGE_COUNT (info.bb->succs) && !probability_sum)
EDGE_SUCC (info.bb, 0)->probability = REG_BR_PROB_BASE;
}
/* Look for basic blocks containing empty exception handler and remove them.
This is similar to jump forwarding, just across EH edges. */
static bool
! cleanup_empty_eh (basic_block bb)
{
int region;
gimple_stmt_iterator si;
/* When handler of EH region winds up to be empty, we can safely
remove it. This leads to inner EH regions to be redirected
--- 3066,3083 ----
we get fewer consistency errors in the dumps. */
if (is_resx && EDGE_COUNT (info.bb->succs) && !probability_sum)
EDGE_SUCC (info.bb, 0)->probability = REG_BR_PROB_BASE;
+ return removed;
}
/* Look for basic blocks containing empty exception handler and remove them.
This is similar to jump forwarding, just across EH edges. */
static bool
! cleanup_empty_eh (basic_block bb, VEC(int,heap) * label_to_region)
{
int region;
gimple_stmt_iterator si;
+ edge_iterator ei;
/* When handler of EH region winds up to be empty, we can safely
remove it. This leads to inner EH regions to be redirected
*************** cleanup_empty_eh (basic_block bb)
*** 3030,3048 ****
&& all_phis_safe_to_merge (bb))
{
edge e;
! remove_eh_region (region);
! while ((e = ei_safe_edge (ei_start (bb->preds))))
{
basic_block src = e->src;
! gcc_assert (e->flags & EDGE_EH);
if (stmt_can_throw_internal (last_stmt (src)))
! update_eh_edges (last_stmt (src), bb, e);
! remove_edge (e);
}
- if (dump_file)
- fprintf (dump_file, "Empty EH handler %i removed\n", region);
/* Verify that we eliminated all uses of PHI we are going to remove.
If we didn't, rebuild SSA on affected variable (this is allowed only
--- 3087,3153 ----
&& all_phis_safe_to_merge (bb))
{
edge e;
+ bool found = false, removed_some = false, has_non_eh_preds = false;
+ gimple_stmt_iterator gsi;
! for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
! if (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
! {
! int uid = LABEL_DECL_UID (gimple_label_label (gsi_stmt (gsi)));
! int r = VEC_index (int, label_to_region, uid);
! int next;
! while (r)
! {
! next = get_next_region_sharing_label (r);
! if (r == region)
! found = true;
! else
! {
! removed_some = true;
! remove_eh_region_and_replace_by_outer_of (r, region);
! if (dump_file)
! fprintf (dump_file, "Empty EH handler %i removed and "
! "replaced by %i\n", r, region);
! }
! r = next;
! }
! }
! else
! break;
! gcc_assert (found || removed_some);
! FOR_EACH_EDGE (e, ei, bb->preds)
! if (!(e->flags & EDGE_EH))
! has_non_eh_preds = true;
!
! /* When block is empty EH cleanup, but it is reachable via non-EH code too,
! we can not remove the region it is resumed via, because doing so will
! lead to redirection of its RESX edges.
!
! This case will be handled later after edge forwarding if the EH cleanup
! is really dead. */
!
! if (found && !has_non_eh_preds)
! remove_eh_region (region);
! else if (!removed_some)
! return false;
!
! for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
{
basic_block src = e->src;
! if (!(e->flags & EDGE_EH))
! {
! ei_next (&ei);
! continue;
! }
if (stmt_can_throw_internal (last_stmt (src)))
! {
! if (!update_eh_edges (last_stmt (src), bb, e))
! ei_next (&ei);
! }
! else
! remove_edge (e);
}
/* Verify that we eliminated all uses of PHI we are going to remove.
If we didn't, rebuild SSA on affected variable (this is allowed only
*************** cleanup_empty_eh (basic_block bb)
*** 3091,3097 ****
}
}
}
! delete_basic_block (bb);
return true;
}
return false;
--- 3196,3203 ----
}
}
}
! if (!ei_safe_edge (ei_start (bb->preds)))
! delete_basic_block (bb);
return true;
}
return false;
*************** cleanup_eh (void)
*** 3111,3116 ****
--- 3217,3223 ----
{
bool changed = false;
basic_block bb;
+ VEC(int,heap) * label_to_region;
int i;
if (!cfun->eh)
*************** cleanup_eh (void)
*** 3123,3136 ****
if (optimize)
{
dominance_info_invalidated = false;
/* We cannot use FOR_EACH_BB, since the basic blocks may get removed. */
for (i = NUM_FIXED_BLOCKS; i < last_basic_block; i++)
{
bb = BASIC_BLOCK (i);
if (bb)
! changed |= cleanup_empty_eh (bb);
}
if (dominance_info_invalidated)
{
free_dominance_info (CDI_DOMINATORS);
--- 3230,3245 ----
if (optimize)
{
+ label_to_region = label_to_region_map ();
dominance_info_invalidated = false;
/* We cannot use FOR_EACH_BB, since the basic blocks may get removed. */
for (i = NUM_FIXED_BLOCKS; i < last_basic_block; i++)
{
bb = BASIC_BLOCK (i);
if (bb)
! changed |= cleanup_empty_eh (bb, label_to_region);
}
+ VEC_free (int, heap, label_to_region);
if (dominance_info_invalidated)
{
free_dominance_info (CDI_DOMINATORS);
*** /aux/hubicka/trunk-write/gcc/except.c Wed Apr 22 15:38:18 2009
--- except.c Wed Apr 22 20:07:02 2009
*************** static void sjlj_build_landing_pads (voi
*** 146,152 ****
static void remove_eh_handler (struct eh_region *);
static void remove_eh_handler_and_replace (struct eh_region *,
! struct eh_region *);
/* The return value of reachable_next_level. */
enum reachable_code
--- 147,153 ----
static void remove_eh_handler (struct eh_region *);
static void remove_eh_handler_and_replace (struct eh_region *,
! struct eh_region *, bool);
/* The return value of reachable_next_level. */
enum reachable_code
*************** remove_unreachable_regions (sbitmap reac
*** 743,754 ****
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);
first_must_not_throw->may_contain_throw |= r->may_contain_throw;
}
else
bring_to_root (r);
}
#ifdef ENABLE_CHECKING
verify_eh_tree (cfun);
#endif
--- 979,990 ----
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, false);
first_must_not_throw->may_contain_throw |= r->may_contain_throw;
}
else
bring_to_root (r);
}
#ifdef ENABLE_CHECKING
verify_eh_tree (cfun);
#endif
*************** remove_unreachable_regions (sbitmap reac
*** 758,768 ****
/* Return array mapping LABEL_DECL_UID to region such that region's tree_label
is identical to label. */
! VEC(int,heap) *
label_to_region_map (void)
{
! VEC(int,heap) * label_to_region = NULL;
int i;
VEC_safe_grow_cleared (int, heap, label_to_region,
cfun->cfg->last_label_uid + 1);
--- 995,1006 ----
/* Return array mapping LABEL_DECL_UID to region such that region's tree_label
is identical to label. */
! VEC (int, heap) *
label_to_region_map (void)
{
! VEC (int, heap) * label_to_region = NULL;
int i;
+ int idx;
VEC_safe_grow_cleared (int, heap, label_to_region,
cfun->cfg->last_label_uid + 1);
*************** label_to_region_map (void)
*** 770,777 ****
{
struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i);
if (r && r->region_number == i
! && r->tree_label && LABEL_DECL_UID (r->tree_label) >= 0)
{
VEC_replace (int, label_to_region, LABEL_DECL_UID (r->tree_label),
i);
}
--- 1008,1021 ----
{
struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i);
if (r && r->region_number == i
! && r->tree_label && LABEL_DECL_UID (r->tree_label) >= 0)
{
+ if ((idx = VEC_index (int, label_to_region,
+ LABEL_DECL_UID (r->tree_label))) != 0)
+ r->next_region_sharing_label =
+ VEC_index (eh_region, cfun->eh->region_array, idx);
+ else
+ r->next_region_sharing_label = NULL;
VEC_replace (int, label_to_region, LABEL_DECL_UID (r->tree_label),
i);
}
*************** num_eh_regions (void)
*** 786,791 ****
--- 1030,1049 ----
return cfun->eh->last_region_number + 1;
}
+ /* Return next region sharing same label as REGION. */
+
+ int
+ get_next_region_sharing_label (int region)
+ {
+ struct eh_region *r;
+ if (!region)
+ return 0;
+ r = VEC_index (eh_region, cfun->eh->region_array, region);
+ if (!r || !r->next_region_sharing_label)
+ return 0;
+ return r->next_region_sharing_label->region_number;
+ }
+
/* Set up EH labels for RTL. */
void
*************** finish_eh_generation (void)
*** 2163,2178 ****
\f
/* This section handles removing dead code for flow. */
! /* Splice REGION from the region tree and replace it by REPLACE etc. */
static void
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
--- 2718,2763 ----
\f
/* This section handles removing dead code for flow. */
! /* Splice REGION from the region tree and replace it by REPLACE etc.
! When UPDATE_CATCH_TRY is true mind updating links from catch to try
! region.*/
static void
remove_eh_handler_and_replace (struct eh_region *region,
! struct eh_region *replace,
! bool update_catch_try)
{
struct eh_region **pp, **pp_start, *p, *outer, *inner;
rtx lab;
outer = region->outer;
+
+ /* When we are moving the region in EH tree, update prev_try pointers. */
+ if (outer != replace && region->inner)
+ {
+ struct eh_region *prev_try = find_prev_try (replace);
+ p = region->inner;
+ while (p != region)
+ {
+ if (p->type == ERT_CLEANUP)
+ p->u.cleanup.prev_try = prev_try;
+ if (p->type != ERT_TRY
+ && p->type != ERT_MUST_NOT_THROW
+ && (p->type != ERT_ALLOWED_EXCEPTIONS
+ || p->u.allowed.type_list)
+ && p->inner)
+ p = p->inner;
+ else if (p->next_peer)
+ p = p->next_peer;
+ else
+ {
+ while (p != region && !p->next_peer)
+ p = p->outer;
+ if (p != region)
+ p = p->next_peer;
+ }
+ }
+ }
/* 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
*************** remove_eh_handler_and_replace (struct eh
*** 2228,2234 ****
*pp_start = inner;
}
! if (region->type == ERT_CATCH)
{
struct eh_region *eh_try, *next, *prev;
--- 2813,2820 ----
*pp_start = inner;
}
! if (region->type == ERT_CATCH
! && update_catch_try)
{
struct eh_region *eh_try, *next, *prev;
*************** remove_eh_handler_and_replace (struct eh
*** 2262,2268 ****
static void
remove_eh_handler (struct eh_region *region)
{
! remove_eh_handler_and_replace (region, region->outer);
}
/* Remove Eh region R that has turned out to have no code in its handler. */
--- 2848,2854 ----
static void
remove_eh_handler (struct eh_region *region)
{
! remove_eh_handler_and_replace (region, region->outer, true);
}
/* Remove Eh region R that has turned out to have no code in its handler. */
*************** remove_eh_region (int r)
*** 2276,2281 ****
--- 2862,2880 ----
remove_eh_handler (region);
}
+ /* Remove Eh region R that has turned out to have no code in its handler
+ and replace in by R2. */
+
+ void
+ remove_eh_region_and_replace_by_outer_of (int r, int r2)
+ {
+ struct eh_region *region, *region2;
+
+ region = VEC_index (eh_region, cfun->eh->region_array, r);
+ region2 = VEC_index (eh_region, cfun->eh->region_array, r2);
+ remove_eh_handler_and_replace (region, region2->outer, true);
+ }
+
/* Invokes CALLBACK for every exception handler label. Only used by old
loop hackery; should not be used by new code. */
*** /aux/hubicka/trunk-write/gcc/except.h Wed Apr 22 15:38:18 2009
--- except.h Sun Apr 19 19:53:37 2009
*************** struct eh_region GTY(())
*** 34,39 ****
--- 34,42 ----
struct eh_region *inner;
struct eh_region *next_peer;
+ /* List of regions sharing label. */
+ struct eh_region *next_region_sharing_label;
+
/* An identifier for this region. */
int region_number;
*************** extern bool can_throw_external (const_rt
*** 151,161 ****
--- 154,164 ----
/* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls. */
extern unsigned int set_nothrow_function_flags (void);
extern void init_eh (void);
extern void init_eh_for_function (void);
extern rtx reachable_handlers (rtx);
void remove_eh_region (int);
+ void remove_eh_region_and_replace_by_outer_of (int, int);
extern void convert_from_eh_region_ranges (void);
extern unsigned int convert_to_eh_region_ranges (void);
*************** struct throw_stmt_node GTY(())
*** 269,277 ****
--- 277,286 ----
gimple stmt;
int region_nr;
};
extern struct htab *get_eh_throw_stmt_table (struct function *);
extern void set_eh_throw_stmt_table (struct function *, struct htab *);
extern void remove_unreachable_regions (sbitmap, sbitmap);
extern VEC(int,heap) * label_to_region_map (void);
extern int num_eh_regions (void);
+ extern int get_next_region_sharing_label (int);
*** /aux/hubicka/trunk-write/gcc/tree-cfgcleanup.c Mon Feb 23 13:04:19 2009
--- tree-cfgcleanup.c Thu Apr 9 01:25:26 2009
*************** static bool
*** 221,229 ****
tree_forwarder_block_p (basic_block bb, bool phi_wanted)
{
gimple_stmt_iterator gsi;
- edge_iterator ei;
- edge e, succ;
- basic_block dest;
/* BB must have a single outgoing edge. */
if (single_succ_p (bb) != 1
--- 221,226 ----
*************** tree_forwarder_block_p (basic_block bb,
*** 274,296 ****
if (dest->loop_father->header == dest)
return false;
}
-
- /* If we have an EH edge leaving this block, make sure that the
- destination of this block has only one predecessor. This ensures
- that we don't get into the situation where we try to remove two
- forwarders that go to the same basic block but are handlers for
- different EH regions. */
- succ = single_succ_edge (bb);
- dest = succ->dest;
- FOR_EACH_EDGE (e, ei, bb->preds)
- {
- if (e->flags & EDGE_EH)
- {
- if (!single_pred_p (dest))
- return false;
- }
- }
-
return true;
}
--- 271,276 ----
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: pretty-ipa merge 14: EH region label sharing code
2009-04-24 15:37 pretty-ipa merge 14: EH region label sharing code Jan Hubicka
@ 2009-04-24 17:52 ` Richard Guenther
2009-04-24 19:40 ` Jan Hubicka
2009-04-25 15:45 ` H.J. Lu
1 sibling, 1 reply; 4+ messages in thread
From: Richard Guenther @ 2009-04-24 17:52 UTC (permalink / raw)
To: Jan Hubicka; +Cc: gcc-patches
On Fri, 24 Apr 2009, Jan Hubicka wrote:
> Hi,
> this is last EH redirection preparation bit. It makes code happy about case
> where two regions share same label. This happens by EH redirection but also by
> cfgcleanup and such.
>
> While this is generally easy to maintain linked list of regions sharing
> label, tricky part is eh cleanup where we now can have empty cleanup reached by
> multiple EH handlers and none of them must be same as the one resuming it.
> This is hanled by removing all the reaching EH handlers and replacing them by
> outer handler of the resuming one.
>
> It is also possible that other control flow reaches the empty handler and in
> this case BB is no longer removed and resuming EH is kept in place. This
> happens sometimes when EH region proves to be empty over some paths only
> after edge splitting.
>
> I also bundled in remove_eh_handler_and_replace change that allows removing
> try region without associated catch and also to update prev_try pointers. This
> is really needed for EH merging, but it is bit difficult to split it out of
> the patch.
>
> Bootstrapped/regtested x86_64-linux, OK?
> * tree-eh.c (tree_remove_unreachable_handlers): Handle shared labels.
> (tree_empty_eh_handler_p): Allow non-EH predecestors; allow region
> to be reached by different label than left.
> (update_eh_edges): Update comment; remove edge_to_remove if possible
> and return true if suceeded.
> (cleanup_empty_eh): Accept sharing map; handle shared regions.
> (cleanup_eh): Compute sharing map.
> * except.c (remove_eh_handler_and_replace): Add argument if we should
> update regions.
> (remove_unreachable_regions): Update for label sharing.
> (label_to_region_map): Likewise.
> (get_next_region_sharing_label): New function.
> (remove_eh_handler_and_replace): Add update_catch_try parameter; update
> prev_try pointers.
> (remove_eh_handler): Update.
> (remove_eh_region_and_replace_by_outer_of): New function.
> * except.h (struct eh_region): Add next_region_sharing_label.
> (remove_eh_region_and_replace_by_outer_of,
> get_next_region_sharing_label): Declare.
> * tree-cfgcleanup.c (tree_forwarder_block_p): Simplify.
> *** /aux/hubicka/trunk-write/gcc/tree-eh.c Wed Apr 8 17:08:50 2009
> --- tree-eh.c Fri Apr 24 13:56:55 2009
> *************** tree_remove_unreachable_handlers (void)
> *** 2695,2702 ****
> if (gimple_code (stmt) == GIMPLE_LABEL && has_eh_preds)
> {
> int uid = LABEL_DECL_UID (gimple_label_label (stmt));
> ! int region = VEC_index (int, label_to_region, uid);
> ! SET_BIT (reachable, region);
> }
> if (gimple_code (stmt) == GIMPLE_RESX)
> SET_BIT (reachable, gimple_resx_region (stmt));
> --- 2738,2748 ----
> if (gimple_code (stmt) == GIMPLE_LABEL && has_eh_preds)
> {
> int uid = LABEL_DECL_UID (gimple_label_label (stmt));
> ! int region;
> !
> ! for (region = VEC_index (int, label_to_region, uid);
> ! region; region = get_next_region_sharing_label (region))
> ! SET_BIT (reachable, region);
> }
> if (gimple_code (stmt) == GIMPLE_RESX)
> SET_BIT (reachable, gimple_resx_region (stmt));
> *************** tree_empty_eh_handler_p (basic_block bb)
> *** 2743,2750 ****
> --- 2789,2799 ----
> {
> gimple_stmt_iterator gsi;
> int region;
> + edge_iterator ei;
> + edge e;
> use_operand_p imm_use;
> gimple use_stmt;
> + bool found = false;
>
> gsi = gsi_last_bb (bb);
>
> *************** tree_empty_eh_handler_p (basic_block bb)
> *** 2815,2829 ****
> if (gsi_end_p (gsi))
> return 0;
> }
> ! while (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
> ! {
> ! if (gimple_label_label (gsi_stmt (gsi))
> ! == get_eh_region_no_tree_label (region))
> ! return region;
> ! gsi_prev (&gsi);
> ! if (gsi_end_p (gsi))
> ! return 0;
> ! }
> return 0;
> }
>
> --- 2864,2880 ----
> if (gsi_end_p (gsi))
> return 0;
> }
> ! if (gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
> ! return 0;
> !
> ! /* Be sure that there is at least on EH region reaching the block directly.
> ! After EH edge redirection, it is possible that block is reached by one handler
> ! but resumed by different. */
> ! FOR_EACH_EDGE (e, ei, bb->preds)
> ! if ((e->flags & EDGE_EH))
> ! found = true;
> ! if (found)
> ! return region;
> return 0;
> }
>
> *************** make_eh_edge_and_update_phi (struct eh_r
> *** 2955,2963 ****
>
> /* Make EH edges corresponding to STMT while updating PHI nodes after removal
> empty cleanup BB_TO_REMOVE joined to BB containing STMT
> ! by EDGE_TO_REMOVE. */
>
> ! static void
> update_eh_edges (gimple stmt, basic_block bb_to_remove, edge edge_to_remove)
> {
> int region_nr;
> --- 3006,3017 ----
>
> /* Make EH edges corresponding to STMT while updating PHI nodes after removal
> empty cleanup BB_TO_REMOVE joined to BB containing STMT
> ! by EDGE_TO_REMOVE.
>
> ! Return if EDGE_TO_REMOVE was really removed. It might stay reachable when
> ! not all EH regions are cleaned up. */
> !
> ! static bool
> update_eh_edges (gimple stmt, basic_block bb_to_remove, edge edge_to_remove)
> {
> int region_nr;
> *************** update_eh_edges (gimple stmt, basic_bloc
> *** 2967,2972 ****
> --- 3021,3027 ----
> edge_iterator ei;
> edge e;
> int probability_sum = 0;
> + bool removed = false;
>
> info.bb_to_remove = bb_to_remove;
> info.bb = gimple_bb (stmt);
> *************** update_eh_edges (gimple stmt, basic_bloc
> *** 2980,2987 ****
> else
> {
> region_nr = lookup_stmt_eh_region (stmt);
> - if (region_nr < 0)
> - return;
This doesn't look correct. foreach_reachable_handler will then index
with negative region_nr into the region array.
> is_resx = false;
> inlinable = inlinable_call_p (stmt);
> }
> --- 3035,3040 ----
> *************** update_eh_edges (gimple stmt, basic_bloc
> *** 2993,3001 ****
> /* And remove edges we didn't marked. */
> for (ei = ei_start (info.bb->succs); (e = ei_safe_edge (ei)); )
> {
> ! if ((e->flags & EDGE_EH) && !e->aux && e != edge_to_remove)
> {
> dominance_info_invalidated = true;
> remove_edge (e);
> }
> else
> --- 3046,3056 ----
> /* And remove edges we didn't marked. */
> for (ei = ei_start (info.bb->succs); (e = ei_safe_edge (ei)); )
> {
> ! if ((e->flags & EDGE_EH) && !e->aux)
> {
> dominance_info_invalidated = true;
> + if (e == edge_to_remove)
> + removed = true;
> remove_edge (e);
> }
> else
> *************** update_eh_edges (gimple stmt, basic_bloc
> *** 3011,3026 ****
> we get fewer consistency errors in the dumps. */
> if (is_resx && EDGE_COUNT (info.bb->succs) && !probability_sum)
> EDGE_SUCC (info.bb, 0)->probability = REG_BR_PROB_BASE;
> }
>
> /* Look for basic blocks containing empty exception handler and remove them.
> This is similar to jump forwarding, just across EH edges. */
>
> static bool
> ! cleanup_empty_eh (basic_block bb)
> {
> int region;
> gimple_stmt_iterator si;
>
> /* When handler of EH region winds up to be empty, we can safely
> remove it. This leads to inner EH regions to be redirected
> --- 3066,3083 ----
> we get fewer consistency errors in the dumps. */
> if (is_resx && EDGE_COUNT (info.bb->succs) && !probability_sum)
> EDGE_SUCC (info.bb, 0)->probability = REG_BR_PROB_BASE;
> + return removed;
> }
>
> /* Look for basic blocks containing empty exception handler and remove them.
> This is similar to jump forwarding, just across EH edges. */
>
> static bool
> ! cleanup_empty_eh (basic_block bb, VEC(int,heap) * label_to_region)
> {
> int region;
> gimple_stmt_iterator si;
> + edge_iterator ei;
>
> /* When handler of EH region winds up to be empty, we can safely
> remove it. This leads to inner EH regions to be redirected
> *************** cleanup_empty_eh (basic_block bb)
> *** 3030,3048 ****
> && all_phis_safe_to_merge (bb))
> {
> edge e;
>
> ! remove_eh_region (region);
>
> ! while ((e = ei_safe_edge (ei_start (bb->preds))))
> {
> basic_block src = e->src;
> ! gcc_assert (e->flags & EDGE_EH);
> if (stmt_can_throw_internal (last_stmt (src)))
> ! update_eh_edges (last_stmt (src), bb, e);
> ! remove_edge (e);
> }
> - if (dump_file)
> - fprintf (dump_file, "Empty EH handler %i removed\n", region);
>
> /* Verify that we eliminated all uses of PHI we are going to remove.
> If we didn't, rebuild SSA on affected variable (this is allowed only
> --- 3087,3153 ----
> && all_phis_safe_to_merge (bb))
> {
> edge e;
> + bool found = false, removed_some = false, has_non_eh_preds = false;
> + gimple_stmt_iterator gsi;
>
Please add a comment what the following loop(s) want to do. EH code
is hard to follow anyway.
> ! for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> ! if (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
> ! {
> ! int uid = LABEL_DECL_UID (gimple_label_label (gsi_stmt (gsi)));
> ! int r = VEC_index (int, label_to_region, uid);
> ! int next;
>
> ! while (r)
> ! {
> ! next = get_next_region_sharing_label (r);
> ! if (r == region)
> ! found = true;
> ! else
> ! {
> ! removed_some = true;
> ! remove_eh_region_and_replace_by_outer_of (r, region);
> ! if (dump_file)
&& (dump_flags & TDF_details)
> ! fprintf (dump_file, "Empty EH handler %i removed and "
> ! "replaced by %i\n", r, region);
> ! }
> ! r = next;
> ! }
> ! }
> ! else
> ! break;
Add vertical space here.
> ! gcc_assert (found || removed_some);
> ! FOR_EACH_EDGE (e, ei, bb->preds)
> ! if (!(e->flags & EDGE_EH))
> ! has_non_eh_preds = true;
> !
> ! /* When block is empty EH cleanup, but it is reachable via non-EH code too,
> ! we can not remove the region it is resumed via, because doing so will
> ! lead to redirection of its RESX edges.
> !
> ! This case will be handled later after edge forwarding if the EH cleanup
> ! is really dead. */
> !
> ! if (found && !has_non_eh_preds)
> ! remove_eh_region (region);
> ! else if (!removed_some)
> ! return false;
> !
> ! for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
> {
> basic_block src = e->src;
> ! if (!(e->flags & EDGE_EH))
> ! {
> ! ei_next (&ei);
> ! continue;
> ! }
> if (stmt_can_throw_internal (last_stmt (src)))
> ! {
> ! if (!update_eh_edges (last_stmt (src), bb, e))
> ! ei_next (&ei);
> ! }
> ! else
> ! remove_edge (e);
> }
>
> /* Verify that we eliminated all uses of PHI we are going to remove.
> If we didn't, rebuild SSA on affected variable (this is allowed only
> *************** cleanup_empty_eh (basic_block bb)
> *** 3091,3097 ****
> }
> }
> }
> ! delete_basic_block (bb);
> return true;
> }
> return false;
> --- 3196,3203 ----
> }
> }
> }
> ! if (!ei_safe_edge (ei_start (bb->preds)))
> ! delete_basic_block (bb);
> return true;
> }
> return false;
> *************** cleanup_eh (void)
> *** 3111,3116 ****
> --- 3217,3223 ----
> {
> bool changed = false;
> basic_block bb;
> + VEC(int,heap) * label_to_region;
> int i;
>
> if (!cfun->eh)
> *************** cleanup_eh (void)
> *** 3123,3136 ****
>
> if (optimize)
> {
> dominance_info_invalidated = false;
> /* We cannot use FOR_EACH_BB, since the basic blocks may get removed. */
> for (i = NUM_FIXED_BLOCKS; i < last_basic_block; i++)
> {
> bb = BASIC_BLOCK (i);
> if (bb)
> ! changed |= cleanup_empty_eh (bb);
> }
> if (dominance_info_invalidated)
> {
> free_dominance_info (CDI_DOMINATORS);
> --- 3230,3245 ----
>
> if (optimize)
> {
> + label_to_region = label_to_region_map ();
> dominance_info_invalidated = false;
> /* We cannot use FOR_EACH_BB, since the basic blocks may get removed. */
> for (i = NUM_FIXED_BLOCKS; i < last_basic_block; i++)
> {
> bb = BASIC_BLOCK (i);
> if (bb)
> ! changed |= cleanup_empty_eh (bb, label_to_region);
> }
> + VEC_free (int, heap, label_to_region);
> if (dominance_info_invalidated)
> {
> free_dominance_info (CDI_DOMINATORS);
> *** /aux/hubicka/trunk-write/gcc/except.c Wed Apr 22 15:38:18 2009
> --- except.c Wed Apr 22 20:07:02 2009
> *************** static void sjlj_build_landing_pads (voi
> *** 146,152 ****
>
> static void remove_eh_handler (struct eh_region *);
> static void remove_eh_handler_and_replace (struct eh_region *,
> ! struct eh_region *);
>
> /* The return value of reachable_next_level. */
> enum reachable_code
> --- 147,153 ----
>
> static void remove_eh_handler (struct eh_region *);
> static void remove_eh_handler_and_replace (struct eh_region *,
> ! struct eh_region *, bool);
>
> /* The return value of reachable_next_level. */
> enum reachable_code
> *************** remove_unreachable_regions (sbitmap reac
> *** 743,754 ****
> 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);
> first_must_not_throw->may_contain_throw |= r->may_contain_throw;
> }
> else
> bring_to_root (r);
> }
> #ifdef ENABLE_CHECKING
> verify_eh_tree (cfun);
> #endif
> --- 979,990 ----
> 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, false);
> first_must_not_throw->may_contain_throw |= r->may_contain_throw;
> }
> else
> bring_to_root (r);
> }
> #ifdef ENABLE_CHECKING
> verify_eh_tree (cfun);
> #endif
> *************** remove_unreachable_regions (sbitmap reac
> *** 758,768 ****
> /* Return array mapping LABEL_DECL_UID to region such that region's tree_label
> is identical to label. */
>
> ! VEC(int,heap) *
> label_to_region_map (void)
> {
> ! VEC(int,heap) * label_to_region = NULL;
> int i;
>
> VEC_safe_grow_cleared (int, heap, label_to_region,
> cfun->cfg->last_label_uid + 1);
> --- 995,1006 ----
> /* Return array mapping LABEL_DECL_UID to region such that region's tree_label
> is identical to label. */
>
> ! VEC (int, heap) *
> label_to_region_map (void)
> {
> ! VEC (int, heap) * label_to_region = NULL;
> int i;
> + int idx;
>
> VEC_safe_grow_cleared (int, heap, label_to_region,
> cfun->cfg->last_label_uid + 1);
> *************** label_to_region_map (void)
> *** 770,777 ****
> {
> struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i);
> if (r && r->region_number == i
> ! && r->tree_label && LABEL_DECL_UID (r->tree_label) >= 0)
> {
> VEC_replace (int, label_to_region, LABEL_DECL_UID (r->tree_label),
> i);
> }
> --- 1008,1021 ----
> {
> struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i);
> if (r && r->region_number == i
> ! && r->tree_label && LABEL_DECL_UID (r->tree_label) >= 0)
> {
> + if ((idx = VEC_index (int, label_to_region,
> + LABEL_DECL_UID (r->tree_label))) != 0)
> + r->next_region_sharing_label =
> + VEC_index (eh_region, cfun->eh->region_array, idx);
> + else
> + r->next_region_sharing_label = NULL;
> VEC_replace (int, label_to_region, LABEL_DECL_UID (r->tree_label),
> i);
> }
> *************** num_eh_regions (void)
> *** 786,791 ****
> --- 1030,1049 ----
> return cfun->eh->last_region_number + 1;
> }
>
> + /* Return next region sharing same label as REGION. */
> +
> + int
> + get_next_region_sharing_label (int region)
> + {
> + struct eh_region *r;
> + if (!region)
> + return 0;
> + r = VEC_index (eh_region, cfun->eh->region_array, region);
> + if (!r || !r->next_region_sharing_label)
> + return 0;
> + return r->next_region_sharing_label->region_number;
> + }
> +
> /* Set up EH labels for RTL. */
>
> void
> *************** finish_eh_generation (void)
> *** 2163,2178 ****
> \f
> /* This section handles removing dead code for flow. */
>
> ! /* Splice REGION from the region tree and replace it by REPLACE etc. */
>
> static void
> 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
> --- 2718,2763 ----
> \f
> /* This section handles removing dead code for flow. */
>
> ! /* Splice REGION from the region tree and replace it by REPLACE etc.
> ! When UPDATE_CATCH_TRY is true mind updating links from catch to try
> ! region.*/
>
> static void
> remove_eh_handler_and_replace (struct eh_region *region,
> ! struct eh_region *replace,
> ! bool update_catch_try)
> {
> struct eh_region **pp, **pp_start, *p, *outer, *inner;
> rtx lab;
>
> outer = region->outer;
> +
> + /* When we are moving the region in EH tree, update prev_try pointers. */
> + if (outer != replace && region->inner)
> + {
> + struct eh_region *prev_try = find_prev_try (replace);
> + p = region->inner;
> + while (p != region)
> + {
> + if (p->type == ERT_CLEANUP)
> + p->u.cleanup.prev_try = prev_try;
> + if (p->type != ERT_TRY
> + && p->type != ERT_MUST_NOT_THROW
> + && (p->type != ERT_ALLOWED_EXCEPTIONS
> + || p->u.allowed.type_list)
> + && p->inner)
> + p = p->inner;
> + else if (p->next_peer)
> + p = p->next_peer;
> + else
> + {
> + while (p != region && !p->next_peer)
> + p = p->outer;
> + if (p != region)
> + p = p->next_peer;
> + }
> + }
> + }
Either the patch has or your mailer garbles whitespace here. Please
make sure to have consistent TAB / space usage.
> /* 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
> *************** remove_eh_handler_and_replace (struct eh
> *** 2228,2234 ****
> *pp_start = inner;
> }
>
> ! if (region->type == ERT_CATCH)
> {
> struct eh_region *eh_try, *next, *prev;
>
> --- 2813,2820 ----
> *pp_start = inner;
> }
>
> ! if (region->type == ERT_CATCH
> ! && update_catch_try)
> {
> struct eh_region *eh_try, *next, *prev;
>
> *************** remove_eh_handler_and_replace (struct eh
> *** 2262,2268 ****
> static void
> remove_eh_handler (struct eh_region *region)
> {
> ! remove_eh_handler_and_replace (region, region->outer);
> }
>
> /* Remove Eh region R that has turned out to have no code in its handler. */
> --- 2848,2854 ----
> static void
> remove_eh_handler (struct eh_region *region)
> {
> ! remove_eh_handler_and_replace (region, region->outer, true);
> }
>
> /* Remove Eh region R that has turned out to have no code in its handler. */
> *************** remove_eh_region (int r)
> *** 2276,2281 ****
> --- 2862,2880 ----
> remove_eh_handler (region);
> }
>
> + /* Remove Eh region R that has turned out to have no code in its handler
> + and replace in by R2. */
> +
> + void
> + remove_eh_region_and_replace_by_outer_of (int r, int r2)
> + {
> + struct eh_region *region, *region2;
> +
> + region = VEC_index (eh_region, cfun->eh->region_array, r);
> + region2 = VEC_index (eh_region, cfun->eh->region_array, r2);
> + remove_eh_handler_and_replace (region, region2->outer, true);
> + }
> +
> /* Invokes CALLBACK for every exception handler label. Only used by old
> loop hackery; should not be used by new code. */
>
> *** /aux/hubicka/trunk-write/gcc/except.h Wed Apr 22 15:38:18 2009
> --- except.h Sun Apr 19 19:53:37 2009
> *************** struct eh_region GTY(())
> *** 34,39 ****
> --- 34,42 ----
> struct eh_region *inner;
> struct eh_region *next_peer;
>
> + /* List of regions sharing label. */
> + struct eh_region *next_region_sharing_label;
> +
> /* An identifier for this region. */
> int region_number;
>
> *************** extern bool can_throw_external (const_rt
> *** 151,161 ****
> --- 154,164 ----
> /* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls. */
> extern unsigned int set_nothrow_function_flags (void);
>
> extern void init_eh (void);
> extern void init_eh_for_function (void);
>
> extern rtx reachable_handlers (rtx);
> void remove_eh_region (int);
> + void remove_eh_region_and_replace_by_outer_of (int, int);
>
> extern void convert_from_eh_region_ranges (void);
> extern unsigned int convert_to_eh_region_ranges (void);
> *************** struct throw_stmt_node GTY(())
> *** 269,277 ****
> --- 277,286 ----
> gimple stmt;
> int region_nr;
> };
>
> extern struct htab *get_eh_throw_stmt_table (struct function *);
> extern void set_eh_throw_stmt_table (struct function *, struct htab *);
> extern void remove_unreachable_regions (sbitmap, sbitmap);
> extern VEC(int,heap) * label_to_region_map (void);
> extern int num_eh_regions (void);
> + extern int get_next_region_sharing_label (int);
> *** /aux/hubicka/trunk-write/gcc/tree-cfgcleanup.c Mon Feb 23 13:04:19 2009
> --- tree-cfgcleanup.c Thu Apr 9 01:25:26 2009
> *************** static bool
> *** 221,229 ****
> tree_forwarder_block_p (basic_block bb, bool phi_wanted)
> {
> gimple_stmt_iterator gsi;
> - edge_iterator ei;
> - edge e, succ;
> - basic_block dest;
>
> /* BB must have a single outgoing edge. */
> if (single_succ_p (bb) != 1
> --- 221,226 ----
> *************** tree_forwarder_block_p (basic_block bb,
> *** 274,296 ****
> if (dest->loop_father->header == dest)
> return false;
> }
> -
> - /* If we have an EH edge leaving this block, make sure that the
> - destination of this block has only one predecessor. This ensures
> - that we don't get into the situation where we try to remove two
> - forwarders that go to the same basic block but are handlers for
> - different EH regions. */
> - succ = single_succ_edge (bb);
> - dest = succ->dest;
> - FOR_EACH_EDGE (e, ei, bb->preds)
> - {
> - if (e->flags & EDGE_EH)
> - {
> - if (!single_pred_p (dest))
> - return false;
> - }
> - }
> -
> return true;
> }
>
> --- 271,276 ----
>
>
The rest of the patch looks ok. I am somewhat concerned that with all
the EH cleanup and optimizations you implemented we didn't get a single
testcase that verifies the code is working.
_Please_ consider adding some.
Thanks,
Richard.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: pretty-ipa merge 14: EH region label sharing code
2009-04-24 17:52 ` Richard Guenther
@ 2009-04-24 19:40 ` Jan Hubicka
0 siblings, 0 replies; 4+ messages in thread
From: Jan Hubicka @ 2009-04-24 19:40 UTC (permalink / raw)
To: Richard Guenther; +Cc: Jan Hubicka, gcc-patches
>
> > else
> > {
> > region_nr = lookup_stmt_eh_region (stmt);
> > - if (region_nr < 0)
> > - return;
>
> This doesn't look correct. foreach_reachable_handler will then index
> with negative region_nr into the region array.
The test is just redundant, we won't call the function when stmt can
not throw since there would be no EH at first place. It was just
cut&pasted along from EH-edges CFG building.
> The rest of the patch looks ok. I am somewhat concerned that with all
> the EH cleanup and optimizations you implemented we didn't get a single
> testcase that verifies the code is working.
>
> _Please_ consider adding some.
I already added g++.dg/tree-ssa/ehcleanup-1.C last week that tests the
basic functionality. (i.e. removing empty EH cleanup). I have one for
EH-cleanup followed by MUST_NOT_THROW. For testcase handled in this
patch I think I need EH redirection or the patch removing unnecesary
FILTER_EXPR set. Current mainline will never actually merge multiple
regions into single label yet. So I will add it next week.
I am also concerned that EH code is easy to get broken for longer
time without anyone noticing it. (the MUST_NOT_THROW issue was in the
tree at least since 4.1). Fortunately libstdc++ testsuite contains a lot
of EH throwing cases in the STL testsuite (simulating out of memory
scenarios on various datastructures).
Thanks!
Honza
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: pretty-ipa merge 14: EH region label sharing code
2009-04-24 15:37 pretty-ipa merge 14: EH region label sharing code Jan Hubicka
2009-04-24 17:52 ` Richard Guenther
@ 2009-04-25 15:45 ` H.J. Lu
1 sibling, 0 replies; 4+ messages in thread
From: H.J. Lu @ 2009-04-25 15:45 UTC (permalink / raw)
To: Jan Hubicka; +Cc: gcc-patches, rguenther
On Fri, Apr 24, 2009 at 8:34 AM, Jan Hubicka <hubicka@ucw.cz> wrote:
> Hi,
> this is last EH redirection preparation bit. It makes code happy about case
> where two regions share same label. This happens by EH redirection but also by
> cfgcleanup and such.
>
> While this is generally easy to maintain linked list of regions sharing
> label, tricky part is eh cleanup where we now can have empty cleanup reached by
> multiple EH handlers and none of them must be same as the one resuming it.
> This is hanled by removing all the reaching EH handlers and replacing them by
> outer handler of the resuming one.
>
> It is also possible that other control flow reaches the empty handler and in
> this case BB is no longer removed and resuming EH is kept in place. This
> happens sometimes when EH region proves to be empty over some paths only
> after edge splitting.
>
> I also bundled in remove_eh_handler_and_replace change that allows removing
> try region without associated catch and also to update prev_try pointers. This
> is really needed for EH merging, but it is bit difficult to split it out of
> the patch.
>
> Bootstrapped/regtested x86_64-linux, OK?
> * tree-eh.c (tree_remove_unreachable_handlers): Handle shared labels.
> (tree_empty_eh_handler_p): Allow non-EH predecestors; allow region
> to be reached by different label than left.
> (update_eh_edges): Update comment; remove edge_to_remove if possible
> and return true if suceeded.
> (cleanup_empty_eh): Accept sharing map; handle shared regions.
> (cleanup_eh): Compute sharing map.
> * except.c (remove_eh_handler_and_replace): Add argument if we should
> update regions.
> (remove_unreachable_regions): Update for label sharing.
> (label_to_region_map): Likewise.
> (get_next_region_sharing_label): New function.
> (remove_eh_handler_and_replace): Add update_catch_try parameter; update
> prev_try pointers.
> (remove_eh_handler): Update.
> (remove_eh_region_and_replace_by_outer_of): New function.
> * except.h (struct eh_region): Add next_region_sharing_label.
> (remove_eh_region_and_replace_by_outer_of,
> get_next_region_sharing_label): Declare.
> * tree-cfgcleanup.c (tree_forwarder_block_p): Simplify.
This caused:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39898
--
H.J.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2009-04-25 15:10 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-04-24 15:37 pretty-ipa merge 14: EH region label sharing code Jan Hubicka
2009-04-24 17:52 ` Richard Guenther
2009-04-24 19:40 ` Jan Hubicka
2009-04-25 15:45 ` H.J. Lu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).