Commit a3710436 by Jan Hubicka Committed by Jan Hubicka

tree.c (list_equal_p): New function.

	* tree.c (list_equal_p): New function.
	* tree.h (list_equal_p): Declare.
	* coretypes.h (edge_def, edge, const_edge, basic_block_def
	basic_block_def, basic_block, const_basic_block): New.
	* tree-eh.c (make_eh_edge): EH edges are not abnormal.
	(redirect_eh_edge): New function.
	(make_eh_edge_update_phi): EH edges are not abnormal.
	* except.c: Include tree-flow.h.
	(list_match): New function.
	(eh_region_replaceable_by_p): New function.
	(replace_region): New function.
	(hash_type_list): New function.
	(hash_eh_region): New function.
	(eh_regions_equal_p): New function.
	(merge_peers): New function.
	(remove_unreachable_regions): Verify EH tree when checking;
	merge peers.
	(copy_eh_region_1): New function.
	(copy_eh_region): New function.
	(push_reachable_handler): New function.
	(build_post_landing_pads, dw2_build_landing_pads): Be ready for
	regions without label but with live RESX.
	* except.h (redirect_eh_edge_to_label): New.
	* tree-flow.h (redirect_eh_edge): New.
	* coretypes.h (edge_def, edge, const_edge, basic_block_def
	basic_block_def, basic_block, const_basic_block): Remove.
	* Makefile.in (except.o): Add dependency on tree-flow.h
	* tree-cfg.c (gimple_redirect_edge_and_branch): Handle EH edges.
	* basic-block.h (edge, const_edge, basic_block, const_basic_block):
	Remove.

From-SVN: r146776
parent 3764d512
2009-04-25 Jan Hubicka <jh@suse.cz>
* tree.c (list_equal_p): New function.
* tree.h (list_equal_p): Declare.
* coretypes.h (edge_def, edge, const_edge, basic_block_def
basic_block_def, basic_block, const_basic_block): New.
* tree-eh.c (make_eh_edge): EH edges are not abnormal.
(redirect_eh_edge): New function.
(make_eh_edge_update_phi): EH edges are not abnormal.
* except.c: Include tree-flow.h.
(list_match): New function.
(eh_region_replaceable_by_p): New function.
(replace_region): New function.
(hash_type_list): New function.
(hash_eh_region): New function.
(eh_regions_equal_p): New function.
(merge_peers): New function.
(remove_unreachable_regions): Verify EH tree when checking;
merge peers.
(copy_eh_region_1): New function.
(copy_eh_region): New function.
(push_reachable_handler): New function.
(build_post_landing_pads, dw2_build_landing_pads): Be ready for
regions without label but with live RESX.
* except.h (redirect_eh_edge_to_label): New.
* tree-flow.h (redirect_eh_edge): New.
* coretypes.h (edge_def, edge, const_edge, basic_block_def
basic_block_def, basic_block, const_basic_block): Remove.
* Makefile.in (except.o): Add dependency on tree-flow.h
* tree-cfg.c (gimple_redirect_edge_and_branch): Handle EH edges.
* basic-block.h (edge, const_edge, basic_block, const_basic_block):
Remove.
2009-04-25 Eric Botcazou <ebotcazou@adacore.com> 2009-04-25 Eric Botcazou <ebotcazou@adacore.com>
PR bootstrap/39645 PR bootstrap/39645
......
...@@ -2525,7 +2525,7 @@ except.o : except.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ ...@@ -2525,7 +2525,7 @@ except.o : except.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
langhooks.h insn-config.h hard-reg-set.h $(BASIC_BLOCK_H) output.h \ langhooks.h insn-config.h hard-reg-set.h $(BASIC_BLOCK_H) output.h \
dwarf2asm.h dwarf2out.h $(TOPLEV_H) $(HASHTAB_H) intl.h $(GGC_H) \ dwarf2asm.h dwarf2out.h $(TOPLEV_H) $(HASHTAB_H) intl.h $(GGC_H) \
gt-$(EXCEPT_H) $(CGRAPH_H) $(INTEGRATE_H) $(DIAGNOSTIC_H) dwarf2.h \ gt-$(EXCEPT_H) $(CGRAPH_H) $(INTEGRATE_H) $(DIAGNOSTIC_H) dwarf2.h \
$(TARGET_H) $(TM_P_H) $(TREE_PASS_H) $(TIMEVAR_H) $(TARGET_H) $(TM_P_H) $(TREE_PASS_H) $(TIMEVAR_H) $(TREE_FLOW_H)
expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(TREE_H) $(FLAGS_H) $(FUNCTION_H) $(REGS_H) $(EXPR_H) $(OPTABS_H) \ $(TREE_H) $(FLAGS_H) $(FUNCTION_H) $(REGS_H) $(EXPR_H) $(OPTABS_H) \
libfuncs.h $(INSN_ATTR_H) insn-config.h $(RECOG_H) output.h \ libfuncs.h $(INSN_ATTR_H) insn-config.h $(RECOG_H) output.h \
......
...@@ -147,8 +147,6 @@ struct GTY(()) edge_def { ...@@ -147,8 +147,6 @@ struct GTY(()) edge_def {
in profile.c */ in profile.c */
}; };
typedef struct edge_def *edge;
typedef const struct edge_def *const_edge;
DEF_VEC_P(edge); DEF_VEC_P(edge);
DEF_VEC_ALLOC_P(edge,gc); DEF_VEC_ALLOC_P(edge,gc);
DEF_VEC_ALLOC_P(edge,heap); DEF_VEC_ALLOC_P(edge,heap);
...@@ -277,9 +275,6 @@ struct GTY(()) gimple_bb_info { ...@@ -277,9 +275,6 @@ struct GTY(()) gimple_bb_info {
gimple_seq phi_nodes; gimple_seq phi_nodes;
}; };
typedef struct basic_block_def *basic_block;
typedef const struct basic_block_def *const_basic_block;
DEF_VEC_P(basic_block); DEF_VEC_P(basic_block);
DEF_VEC_ALLOC_P(basic_block,gc); DEF_VEC_ALLOC_P(basic_block,gc);
DEF_VEC_ALLOC_P(basic_block,heap); DEF_VEC_ALLOC_P(basic_block,heap);
......
...@@ -97,6 +97,12 @@ enum tls_model { ...@@ -97,6 +97,12 @@ enum tls_model {
TLS_MODEL_LOCAL_EXEC TLS_MODEL_LOCAL_EXEC
}; };
struct edge_def;
typedef struct edge_def *edge;
typedef const struct edge_def *const_edge;
struct basic_block_def;
typedef struct basic_block_def *basic_block;
typedef const struct basic_block_def *const_basic_block;
#else #else
struct _dont_use_rtx_here_; struct _dont_use_rtx_here_;
......
...@@ -77,6 +77,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -77,6 +77,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h" #include "diagnostic.h"
#include "tree-pass.h" #include "tree-pass.h"
#include "timevar.h" #include "timevar.h"
#include "tree-flow.h"
/* Provide defaults for stuff that may not be defined when using /* Provide defaults for stuff that may not be defined when using
sjlj exceptions. */ sjlj exceptions. */
...@@ -628,6 +629,238 @@ bring_to_root (struct eh_region *r) ...@@ -628,6 +629,238 @@ bring_to_root (struct eh_region *r)
cfun->eh->region_tree = r; cfun->eh->region_tree = r;
} }
/* Return true if region R2 can be replaced by R1. */
static bool
eh_region_replaceable_by_p (const struct eh_region *r1,
const struct eh_region *r2)
{
/* Regions are semantically same if they are of same type,
have same label and type. */
if (r1->type != r2->type)
return false;
if (r1->tree_label != r2->tree_label)
return false;
/* Verify that also region type dependent data are the same. */
switch (r1->type)
{
case ERT_MUST_NOT_THROW:
case ERT_CLEANUP:
break;
case ERT_TRY:
{
struct eh_region *c1, *c2;
for (c1 = r1->u.eh_try.eh_catch,
c2 = r2->u.eh_try.eh_catch;
c1 && c2;
c1 = c1->u.eh_catch.next_catch,
c2 = c2->u.eh_catch.next_catch)
if (!eh_region_replaceable_by_p (c1, c2))
return false;
if (c1 || c2)
return false;
}
break;
case ERT_CATCH:
if (!list_equal_p (r1->u.eh_catch.type_list, r2->u.eh_catch.type_list))
return false;
if (!list_equal_p (r1->u.eh_catch.filter_list,
r2->u.eh_catch.filter_list))
return false;
break;
case ERT_ALLOWED_EXCEPTIONS:
if (!list_equal_p (r1->u.allowed.type_list, r2->u.allowed.type_list))
return false;
if (r1->u.allowed.filter != r2->u.allowed.filter)
return false;
break;
case ERT_THROW:
if (r1->u.eh_throw.type != r2->u.eh_throw.type)
return false;
break;
default:
gcc_unreachable ();
}
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Regions %i and %i match\n", r1->region_number,
r2->region_number);
return true;
}
/* Replace region R2 by R1. */
static void
replace_region (struct eh_region *r1, struct eh_region *r2)
{
struct eh_region *next1 = r1->u.eh_try.eh_catch;
struct eh_region *next2 = r2->u.eh_try.eh_catch;
bool is_try = r1->type == ERT_TRY;
gcc_assert (r1->type != ERT_CATCH);
remove_eh_handler_and_replace (r2, r1, false);
if (is_try)
{
while (next1)
{
r1 = next1;
r2 = next2;
gcc_assert (next1->type == ERT_CATCH);
gcc_assert (next2->type == ERT_CATCH);
next1 = next1->u.eh_catch.next_catch;
next2 = next2->u.eh_catch.next_catch;
remove_eh_handler_and_replace (r2, r1, false);
}
}
}
/* Return hash value of type list T. */
static hashval_t
hash_type_list (tree t)
{
hashval_t val = 0;
for (; t; t = TREE_CHAIN (t))
val = iterative_hash_hashval_t (TREE_HASH (TREE_VALUE (t)), val);
return val;
}
/* Hash EH regions so semantically same regions get same hash value. */
static hashval_t
hash_eh_region (const void *r)
{
const struct eh_region *region = (const struct eh_region *)r;
hashval_t val = region->type;
if (region->tree_label)
val = iterative_hash_hashval_t (LABEL_DECL_UID (region->tree_label), val);
switch (region->type)
{
case ERT_MUST_NOT_THROW:
case ERT_CLEANUP:
break;
case ERT_TRY:
{
struct eh_region *c;
for (c = region->u.eh_try.eh_catch;
c; c = c->u.eh_catch.next_catch)
val = iterative_hash_hashval_t (hash_eh_region (c), val);
}
break;
case ERT_CATCH:
val = iterative_hash_hashval_t (hash_type_list
(region->u.eh_catch.type_list), val);
break;
case ERT_ALLOWED_EXCEPTIONS:
val = iterative_hash_hashval_t
(hash_type_list (region->u.allowed.type_list), val);
val = iterative_hash_hashval_t (region->u.allowed.filter, val);
break;
case ERT_THROW:
val |= iterative_hash_hashval_t (TYPE_UID (region->u.eh_throw.type), val);
break;
default:
gcc_unreachable ();
}
return val;
}
/* Return true if regions R1 and R2 are equal. */
static int
eh_regions_equal_p (const void *r1, const void *r2)
{
return eh_region_replaceable_by_p ((const struct eh_region *)r1,
(const struct eh_region *)r2);
}
/* Walk all peers of REGION and try to merge those regions
that are semantically equivalent. Look into subregions
recursively too. */
static bool
merge_peers (struct eh_region *region)
{
struct eh_region *r1, *r2, *outer = NULL, *next;
bool merged = false;
int num_regions = 0;
if (region)
outer = region->outer;
else
return false;
/* First see if there is inner region equivalent to region
in question. EH control flow is acyclic so we know we
can merge them. */
if (outer)
for (r1 = region; r1; r1 = next)
{
next = r1->next_peer;
if (r1->type == ERT_CATCH)
continue;
if (eh_region_replaceable_by_p (r1->outer, r1))
{
replace_region (r1->outer, r1);
merged = true;
}
else
num_regions ++;
}
/* Get new first region and try to match the peers
for equivalence. */
if (outer)
region = outer->inner;
else
region = cfun->eh->region_tree;
/* There are few regions to inspect:
N^2 loop matching each region with each region
will do the job well. */
if (num_regions < 10)
{
for (r1 = region; r1; r1 = r1->next_peer)
{
if (r1->type == ERT_CATCH)
continue;
for (r2 = r1->next_peer; r2; r2 = next)
{
next = r2->next_peer;
if (eh_region_replaceable_by_p (r1, r2))
{
replace_region (r1, r2);
merged = true;
}
}
}
}
/* Or use hashtable to avoid N^2 behaviour. */
else
{
htab_t hash;
hash = htab_create (num_regions, hash_eh_region,
eh_regions_equal_p, NULL);
for (r1 = region; r1; r1 = next)
{
void **slot;
next = r1->next_peer;
if (r1->type == ERT_CATCH)
continue;
slot = htab_find_slot (hash, r1, INSERT);
if (!*slot)
*slot = r1;
else
replace_region ((struct eh_region *)*slot, r1);
}
htab_delete (hash);
}
for (r1 = region; r1; r1 = r1->next_peer)
merged |= merge_peers (r1->inner);
return merged;
}
/* Remove all regions whose labels are not reachable. /* Remove all regions whose labels are not reachable.
REACHABLE is bitmap of all regions that are used by the function REACHABLE is bitmap of all regions that are used by the function
CONTAINS_STMT is bitmap of all regions that contains stmt (or NULL). */ CONTAINS_STMT is bitmap of all regions that contains stmt (or NULL). */
...@@ -748,6 +981,7 @@ remove_unreachable_regions (sbitmap reachable, sbitmap contains_stmt) ...@@ -748,6 +981,7 @@ remove_unreachable_regions (sbitmap reachable, sbitmap contains_stmt)
else else
bring_to_root (r); bring_to_root (r);
} }
merge_peers (cfun->eh->region_tree);
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
verify_eh_tree (cfun); verify_eh_tree (cfun);
#endif #endif
...@@ -1140,6 +1374,238 @@ duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map, ...@@ -1140,6 +1374,238 @@ duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
return eh_offset; return eh_offset;
} }
/* Return new copy of eh region OLD inside region NEW_OUTER.
Do not care about updating the tree otherwise. */
static struct eh_region *
copy_eh_region_1 (struct eh_region *old, struct eh_region *new_outer)
{
struct eh_region *new_eh = gen_eh_region (old->type, new_outer);
new_eh->u = old->u;
new_eh->tree_label = old->tree_label;
new_eh->may_contain_throw = old->may_contain_throw;
VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
cfun->eh->last_region_number + 1);
VEC_replace (eh_region, cfun->eh->region_array, new_eh->region_number, new_eh);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Copying region %i to %i\n", old->region_number, new_eh->region_number);
return new_eh;
}
/* Return new copy of eh region OLD inside region NEW_OUTER.
Copy whole catch-try chain if neccesary and update cleanup region prev_try
pointers.
PREV_TRY_MAP points to outer TRY region if it was copied in trace already. */
static struct eh_region *
copy_eh_region (struct eh_region *old, struct eh_region *new_outer,
struct eh_region *prev_try_map)
{
struct eh_region *r, *n, *old_try, *new_try, *ret = NULL;
VEC(eh_region,heap) *catch_list = NULL;
if (old->type != ERT_CATCH)
{
gcc_assert (old->type != ERT_TRY);
r = copy_eh_region_1 (old, new_outer);
if (r->type == ERT_CLEANUP && prev_try_map)
{
gcc_assert (r->u.cleanup.prev_try);
r->u.cleanup.prev_try = prev_try_map;
}
return r;
}
/* Locate and copy corresponding TRY. */
for (old_try = old->next_peer; old_try->type == ERT_CATCH; old_try = old_try->next_peer)
continue;
gcc_assert (old_try->type == ERT_TRY);
new_try = gen_eh_region_try (new_outer);
new_try->tree_label = old_try->tree_label;
new_try->may_contain_throw = old_try->may_contain_throw;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Copying try-catch regions. Try: %i to %i\n",
old_try->region_number, new_try->region_number);
VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
cfun->eh->last_region_number + 1);
VEC_replace (eh_region, cfun->eh->region_array, new_try->region_number, new_try);
/* In order to keep CATCH list in order, we need to copy in reverse order. */
for (r = old_try->u.eh_try.last_catch; r->type == ERT_CATCH; r = r->next_peer)
VEC_safe_push (eh_region, heap, catch_list, r);
while (VEC_length (eh_region, catch_list))
{
r = VEC_pop (eh_region, catch_list);
/* Duplicate CATCH. */
n = gen_eh_region_catch (new_try, r->u.eh_catch.type_list);
n->tree_label = r->tree_label;
n->may_contain_throw = r->may_contain_throw;
VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
cfun->eh->last_region_number + 1);
VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
n->tree_label = r->tree_label;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Copying try-catch regions. Catch: %i to %i\n",
r->region_number, n->region_number);
if (r == old)
ret = n;
}
VEC_free (eh_region, heap, catch_list);
gcc_assert (ret);
return ret;
}
/* Callback for forach_reachable_handler that push REGION into single VECtor DATA. */
static void
push_reachable_handler (struct eh_region *region, void *data)
{
VEC(eh_region,heap) **trace = (VEC(eh_region,heap) **) data;
VEC_safe_push (eh_region, heap, *trace, region);
}
/* Redirect EH edge E that to NEW_DEST_LABEL.
IS_RESX, INLINABLE_CALL and REGION_NMUBER match the parameter of
foreach_reachable_handler. */
struct eh_region *
redirect_eh_edge_to_label (edge e, tree new_dest_label, bool is_resx,
bool inlinable_call, int region_number)
{
struct eh_region *outer, *prev_try_map = NULL;
struct eh_region *region;
VEC (eh_region, heap) * trace = NULL;
int i;
int start_here = -1;
basic_block old_bb = e->dest;
struct eh_region *old, *r = NULL;
bool update_inplace = true;
edge_iterator ei;
edge e2;
/* If there is only one EH edge, we don't need to duplicate;
just update labels in the tree. */
FOR_EACH_EDGE (e2, ei, old_bb->preds)
if ((e2->flags & EDGE_EH) && e2 != e)
{
update_inplace = false;
break;
}
region = VEC_index (eh_region, cfun->eh->region_array, region_number);
gcc_assert (region);
foreach_reachable_handler (region_number, is_resx, inlinable_call,
push_reachable_handler, &trace);
if (dump_file && (dump_flags & TDF_DETAILS))
{
dump_eh_tree (dump_file, cfun);
fprintf (dump_file, "Trace: ");
for (i = 0; i < (int) VEC_length (eh_region, trace); i++)
fprintf (dump_file, " %i", VEC_index (eh_region, trace, i)->region_number);
fprintf (dump_file, " inplace: %i\n", update_inplace);
}
if (update_inplace)
{
/* In easy route just walk trace and update all occurences of the label. */
for (i = 0; i < (int) VEC_length (eh_region, trace); i++)
{
r = VEC_index (eh_region, trace, i);
if (r->tree_label && label_to_block (r->tree_label) == old_bb)
{
r->tree_label = new_dest_label;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Updating label for region %i\n",
r->region_number);
}
}
r = region;
}
else
{
/* Now look for outermost handler that reffers to the basic block in question.
We start our duplication there. */
for (i = 0; i < (int) VEC_length (eh_region, trace); i++)
{
r = VEC_index (eh_region, trace, i);
if (r->tree_label && label_to_block (r->tree_label) == old_bb)
start_here = i;
}
outer = VEC_index (eh_region, trace, start_here)->outer;
gcc_assert (start_here >= 0);
/* And now do the dirty job! */
for (i = start_here; i >= 0; i--)
{
old = VEC_index (eh_region, trace, i);
gcc_assert (!outer || old->outer != outer->outer);
/* Copy region and update label. */
r = copy_eh_region (old, outer, prev_try_map);
VEC_replace (eh_region, trace, i, r);
if (r->tree_label && label_to_block (r->tree_label) == old_bb)
{
r->tree_label = new_dest_label;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Updating label for region %i\n",
r->region_number);
}
/* We got into copying CATCH. copy_eh_region already did job
of copying all catch blocks corresponding to the try. Now
we need to update labels in all of them and see trace.
We continue nesting into TRY region corresponding to CATCH:
When duplicating EH tree contaiing subregions of CATCH,
the CATCH region itself is never inserted to trace so we
never get here anyway. */
if (r->type == ERT_CATCH)
{
/* Walk other catch regions we copied and update labels as needed. */
for (r = r->next_peer; r->type == ERT_CATCH; r = r->next_peer)
if (r->tree_label && label_to_block (r->tree_label) == old_bb)
{
r->tree_label = new_dest_label;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Updating label for region %i\n",
r->region_number);
}
gcc_assert (r->type == ERT_TRY);
/* Skip sibling catch regions from the trace.
They are already updated. */
while (i > 0 && VEC_index (eh_region, trace, i - 1)->outer == old->outer)
{
gcc_assert (VEC_index (eh_region, trace, i - 1)->type == ERT_CATCH);
i--;
}
}
/* Cleanup regions points to outer TRY blocks. */
if (r->type == ERT_TRY)
prev_try_map = r;
outer = r;
}
if (is_resx || region->type == ERT_THROW)
r = copy_eh_region (region, outer, prev_try_map);
}
VEC_free (eh_region, heap, trace);
if (dump_file && (dump_flags & TDF_DETAILS))
{
dump_eh_tree (dump_file, cfun);
fprintf (dump_file, "New region: %i\n", r->region_number);
}
return r;
}
/* Return region number of region that is outer to both if REGION_A and /* Return region number of region that is outer to both if REGION_A and
REGION_B in IFUN. */ REGION_B in IFUN. */
...@@ -1478,6 +1944,12 @@ build_post_landing_pads (void) ...@@ -1478,6 +1944,12 @@ build_post_landing_pads (void)
switch (region->type) switch (region->type)
{ {
case ERT_TRY: case ERT_TRY:
/* It is possible that TRY region is kept alive only because some of
contained catch region still have RESX instruction but they are
reached via their copies. In this case we need to do nothing. */
if (!region->u.eh_try.eh_catch->label)
break;
/* ??? Collect the set of all non-overlapping catch handlers /* ??? Collect the set of all non-overlapping catch handlers
all the way up the chain until blocked by a cleanup. */ all the way up the chain until blocked by a cleanup. */
/* ??? Outer try regions can share landing pads with inner /* ??? Outer try regions can share landing pads with inner
...@@ -1537,6 +2009,8 @@ build_post_landing_pads (void) ...@@ -1537,6 +2009,8 @@ build_post_landing_pads (void)
break; break;
case ERT_ALLOWED_EXCEPTIONS: case ERT_ALLOWED_EXCEPTIONS:
if (!region->label)
break;
region->post_landing_pad = gen_label_rtx (); region->post_landing_pad = gen_label_rtx ();
start_sequence (); start_sequence ();
...@@ -1679,6 +2153,9 @@ dw2_build_landing_pads (void) ...@@ -1679,6 +2153,9 @@ dw2_build_landing_pads (void)
&& region->type != ERT_ALLOWED_EXCEPTIONS) && region->type != ERT_ALLOWED_EXCEPTIONS)
continue; continue;
if (!region->post_landing_pad)
continue;
start_sequence (); start_sequence ();
region->landing_pad = gen_label_rtx (); region->landing_pad = gen_label_rtx ();
......
...@@ -278,4 +278,5 @@ extern void set_eh_throw_stmt_table (struct function *, struct htab *); ...@@ -278,4 +278,5 @@ extern void set_eh_throw_stmt_table (struct function *, struct htab *);
extern void remove_unreachable_regions (sbitmap, sbitmap); extern void remove_unreachable_regions (sbitmap, sbitmap);
extern VEC(int,heap) * label_to_region_map (void); extern VEC(int,heap) * label_to_region_map (void);
extern int num_eh_regions (void); extern int num_eh_regions (void);
extern struct eh_region *redirect_eh_edge_to_label (struct edge_def *, tree, bool, bool, int);
extern int get_next_region_sharing_label (int); extern int get_next_region_sharing_label (int);
2009-04-25 Jan Hubicka <jh@suse.cz>
* g++.dg/tree-ssa/ehcleanup-1.C: Update.
2009-04-25 Janus Weil <janus@gcc.gnu.org> 2009-04-25 Janus Weil <janus@gcc.gnu.org>
PR fortran/39688 PR fortran/39688
......
// { dg-options "-O2 -fdump-tree-ehcleanup1" } // { dg-options "-O2 -fdump-tree-ehcleanup1-details" }
extern void can_throw (); extern void can_throw ();
class a class a
{ {
......
...@@ -4800,6 +4800,9 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest) ...@@ -4800,6 +4800,9 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
if (e->dest == dest) if (e->dest == dest)
return NULL; return NULL;
if (e->flags & EDGE_EH)
return redirect_eh_edge (e, dest);
gsi = gsi_last_bb (bb); gsi = gsi_last_bb (bb);
stmt = gsi_end_p (gsi) ? NULL : gsi_stmt (gsi); stmt = gsi_end_p (gsi) ? NULL : gsi_stmt (gsi);
......
...@@ -1962,7 +1962,7 @@ make_eh_edge (struct eh_region *region, void *data) ...@@ -1962,7 +1962,7 @@ make_eh_edge (struct eh_region *region, void *data)
src = gimple_bb (stmt); src = gimple_bb (stmt);
dst = label_to_block (lab); dst = label_to_block (lab);
make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH); make_edge (src, dst, EDGE_EH);
} }
/* See if STMT is call that might be inlined. */ /* See if STMT is call that might be inlined. */
...@@ -2019,6 +2019,50 @@ make_eh_edges (gimple stmt) ...@@ -2019,6 +2019,50 @@ make_eh_edges (gimple stmt)
EDGE_SUCC (bb, 0)->probability = REG_BR_PROB_BASE; EDGE_SUCC (bb, 0)->probability = REG_BR_PROB_BASE;
} }
/* Redirect EH edge E to NEW_BB. */
edge
redirect_eh_edge (edge e, basic_block new_bb)
{
gimple stmt = gsi_stmt (gsi_last_bb (e->src));
int region_nr, new_region_nr;
bool is_resx;
bool inlinable = false;
tree label = gimple_block_label (new_bb);
struct eh_region *r;
if (gimple_code (stmt) == GIMPLE_RESX)
{
region_nr = gimple_resx_region (stmt);
is_resx = true;
}
else
{
region_nr = lookup_stmt_eh_region (stmt);
gcc_assert (region_nr >= 0);
is_resx = false;
inlinable = inlinable_call_p (stmt);
}
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Redirecting EH edge %i->%i to %i, region %i, resx %i\n",
e->src->index, e->dest->index, new_bb->index, region_nr, is_resx);
r = redirect_eh_edge_to_label (e, label, is_resx, inlinable, region_nr);
new_region_nr = get_eh_region_number (r);
if (new_region_nr != region_nr)
{
if (is_resx)
gimple_resx_set_region (stmt, new_region_nr);
else
{
remove_stmt_from_eh_region (stmt);
add_stmt_to_eh_region (stmt, new_region_nr);
}
}
e = ssa_redirect_edge (e, new_bb);
return e;
}
static bool mark_eh_edge_found_error; static bool mark_eh_edge_found_error;
/* Mark edge make_eh_edge would create for given region by setting it aux /* Mark edge make_eh_edge would create for given region by setting it aux
...@@ -2702,7 +2746,9 @@ tree_remove_unreachable_handlers (void) ...@@ -2702,7 +2746,9 @@ tree_remove_unreachable_handlers (void)
SET_BIT (reachable, region); SET_BIT (reachable, region);
} }
if (gimple_code (stmt) == GIMPLE_RESX) if (gimple_code (stmt) == GIMPLE_RESX)
SET_BIT (reachable, gimple_resx_region (stmt)); SET_BIT (reachable,
VEC_index (eh_region, cfun->eh->region_array,
gimple_resx_region (stmt))->region_number);
if ((region = lookup_stmt_eh_region (stmt)) >= 0) if ((region = lookup_stmt_eh_region (stmt)) >= 0)
SET_BIT (contains_stmt, region); SET_BIT (contains_stmt, region);
} }
...@@ -2937,7 +2983,7 @@ make_eh_edge_and_update_phi (struct eh_region *region, void *data) ...@@ -2937,7 +2983,7 @@ make_eh_edge_and_update_phi (struct eh_region *region, void *data)
} }
dominance_info_invalidated = true; dominance_info_invalidated = true;
e2 = find_edge (info->bb_to_remove, dst); e2 = find_edge (info->bb_to_remove, dst);
e = make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH); e = make_edge (src, dst, EDGE_EH);
e->aux = e; e->aux = e;
gcc_assert (e2); gcc_assert (e2);
for (si = gsi_start_phis (dst); !gsi_end_p (si); gsi_next (&si)) for (si = gsi_start_phis (dst); !gsi_end_p (si); gsi_next (&si))
...@@ -3091,7 +3137,11 @@ cleanup_empty_eh (basic_block bb, VEC(int,heap) * label_to_region) ...@@ -3091,7 +3137,11 @@ cleanup_empty_eh (basic_block bb, VEC(int,heap) * label_to_region)
is really dead. */ is really dead. */
if (found && !has_non_eh_preds) if (found && !has_non_eh_preds)
remove_eh_region (region); {
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Empty EH handler %i removed.\n", region);
remove_eh_region (region);
}
else if (!removed_some) else if (!removed_some)
return false; return false;
......
...@@ -32,13 +32,6 @@ along with GCC; see the file COPYING3. If not see ...@@ -32,13 +32,6 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-reference.h" #include "ipa-reference.h"
#include "tree-ssa-alias.h" #include "tree-ssa-alias.h"
/* Forward declare structures for the garbage collector GTY markers. */
#ifndef GCC_BASIC_BLOCK_H
struct edge_def;
typedef struct edge_def *edge;
struct basic_block_def;
typedef struct basic_block_def *basic_block;
#endif
struct static_var_ann_d; struct static_var_ann_d;
...@@ -974,5 +967,6 @@ unsigned int execute_fixup_cfg (void); ...@@ -974,5 +967,6 @@ unsigned int execute_fixup_cfg (void);
void swap_tree_operands (gimple, tree *, tree *); void swap_tree_operands (gimple, tree *, tree *);
int least_common_multiple (int, int); int least_common_multiple (int, int);
edge redirect_eh_edge (edge e, basic_block new_bb);
#endif /* _TREE_FLOW_H */ #endif /* _TREE_FLOW_H */
...@@ -9320,4 +9320,16 @@ block_ultimate_origin (const_tree block) ...@@ -9320,4 +9320,16 @@ block_ultimate_origin (const_tree block)
} }
} }
/* Return true if T1 and T2 are equivalent lists. */
bool
list_equal_p (const_tree t1, const_tree t2)
{
for (; t1 && t2; t1 = TREE_CHAIN (t1) , t2 = TREE_CHAIN (t2))
if (TREE_VALUE (t1) != TREE_VALUE (t2))
return false;
return !t1 && !t2;
}
#include "gt-tree.h" #include "gt-tree.h"
...@@ -5134,6 +5134,7 @@ struct GTY(()) tree_map_base { ...@@ -5134,6 +5134,7 @@ struct GTY(()) tree_map_base {
extern int tree_map_base_eq (const void *, const void *); extern int tree_map_base_eq (const void *, const void *);
extern unsigned int tree_map_base_hash (const void *); extern unsigned int tree_map_base_hash (const void *);
extern int tree_map_base_marked_p (const void *); extern int tree_map_base_marked_p (const void *);
extern bool list_equal_p (const_tree, const_tree);
/* Map from a tree to another tree. */ /* Map from a tree to another tree. */
......
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