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
This commit is contained in:
parent
3764d512d5
commit
a3710436b6
13 changed files with 594 additions and 18 deletions
|
@ -1,3 +1,36 @@
|
|||
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>
|
||||
|
||||
PR bootstrap/39645
|
||||
|
|
|
@ -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 \
|
||||
dwarf2asm.h dwarf2out.h $(TOPLEV_H) $(HASHTAB_H) intl.h $(GGC_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) \
|
||||
$(TREE_H) $(FLAGS_H) $(FUNCTION_H) $(REGS_H) $(EXPR_H) $(OPTABS_H) \
|
||||
libfuncs.h $(INSN_ATTR_H) insn-config.h $(RECOG_H) output.h \
|
||||
|
|
|
@ -147,8 +147,6 @@ struct GTY(()) edge_def {
|
|||
in profile.c */
|
||||
};
|
||||
|
||||
typedef struct edge_def *edge;
|
||||
typedef const struct edge_def *const_edge;
|
||||
DEF_VEC_P(edge);
|
||||
DEF_VEC_ALLOC_P(edge,gc);
|
||||
DEF_VEC_ALLOC_P(edge,heap);
|
||||
|
@ -277,9 +275,6 @@ struct GTY(()) gimple_bb_info {
|
|||
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_ALLOC_P(basic_block,gc);
|
||||
DEF_VEC_ALLOC_P(basic_block,heap);
|
||||
|
|
|
@ -97,6 +97,12 @@ enum tls_model {
|
|||
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
|
||||
|
||||
struct _dont_use_rtx_here_;
|
||||
|
|
477
gcc/except.c
477
gcc/except.c
|
@ -77,6 +77,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "diagnostic.h"
|
||||
#include "tree-pass.h"
|
||||
#include "timevar.h"
|
||||
#include "tree-flow.h"
|
||||
|
||||
/* Provide defaults for stuff that may not be defined when using
|
||||
sjlj exceptions. */
|
||||
|
@ -628,6 +629,238 @@ bring_to_root (struct eh_region *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.
|
||||
REACHABLE is bitmap of all regions that are used by the function
|
||||
CONTAINS_STMT is bitmap of all regions that contains stmt (or NULL). */
|
||||
|
@ -748,6 +981,7 @@ remove_unreachable_regions (sbitmap reachable, sbitmap contains_stmt)
|
|||
else
|
||||
bring_to_root (r);
|
||||
}
|
||||
merge_peers (cfun->eh->region_tree);
|
||||
#ifdef ENABLE_CHECKING
|
||||
verify_eh_tree (cfun);
|
||||
#endif
|
||||
|
@ -1140,6 +1374,238 @@ duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
|
|||
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
|
||||
REGION_B in IFUN. */
|
||||
|
||||
|
@ -1478,6 +1944,12 @@ build_post_landing_pads (void)
|
|||
switch (region->type)
|
||||
{
|
||||
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
|
||||
all the way up the chain until blocked by a cleanup. */
|
||||
/* ??? Outer try regions can share landing pads with inner
|
||||
|
@ -1537,6 +2009,8 @@ build_post_landing_pads (void)
|
|||
break;
|
||||
|
||||
case ERT_ALLOWED_EXCEPTIONS:
|
||||
if (!region->label)
|
||||
break;
|
||||
region->post_landing_pad = gen_label_rtx ();
|
||||
|
||||
start_sequence ();
|
||||
|
@ -1679,6 +2153,9 @@ dw2_build_landing_pads (void)
|
|||
&& region->type != ERT_ALLOWED_EXCEPTIONS)
|
||||
continue;
|
||||
|
||||
if (!region->post_landing_pad)
|
||||
continue;
|
||||
|
||||
start_sequence ();
|
||||
|
||||
region->landing_pad = gen_label_rtx ();
|
||||
|
|
|
@ -278,4 +278,5 @@ 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 struct eh_region *redirect_eh_edge_to_label (struct edge_def *, tree, bool, bool, int);
|
||||
extern int get_next_region_sharing_label (int);
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
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>
|
||||
|
||||
PR fortran/39688
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// { dg-options "-O2 -fdump-tree-ehcleanup1" }
|
||||
// { dg-options "-O2 -fdump-tree-ehcleanup1-details" }
|
||||
extern void can_throw ();
|
||||
class a
|
||||
{
|
||||
|
|
|
@ -4800,6 +4800,9 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
|
|||
if (e->dest == dest)
|
||||
return NULL;
|
||||
|
||||
if (e->flags & EDGE_EH)
|
||||
return redirect_eh_edge (e, dest);
|
||||
|
||||
gsi = gsi_last_bb (bb);
|
||||
stmt = gsi_end_p (gsi) ? NULL : gsi_stmt (gsi);
|
||||
|
||||
|
|
|
@ -1962,7 +1962,7 @@ make_eh_edge (struct eh_region *region, void *data)
|
|||
src = gimple_bb (stmt);
|
||||
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. */
|
||||
|
@ -2019,6 +2019,50 @@ make_eh_edges (gimple stmt)
|
|||
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;
|
||||
|
||||
/* Mark edge make_eh_edge would create for given region by setting it aux
|
||||
|
@ -2702,7 +2746,9 @@ tree_remove_unreachable_handlers (void)
|
|||
SET_BIT (reachable, region);
|
||||
}
|
||||
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)
|
||||
SET_BIT (contains_stmt, region);
|
||||
}
|
||||
|
@ -2937,7 +2983,7 @@ make_eh_edge_and_update_phi (struct eh_region *region, void *data)
|
|||
}
|
||||
dominance_info_invalidated = true;
|
||||
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;
|
||||
gcc_assert (e2);
|
||||
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)
|
|||
is really dead. */
|
||||
|
||||
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)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -32,13 +32,6 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "ipa-reference.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;
|
||||
|
||||
|
||||
|
@ -974,5 +967,6 @@ unsigned int execute_fixup_cfg (void);
|
|||
void swap_tree_operands (gimple, tree *, tree *);
|
||||
|
||||
int least_common_multiple (int, int);
|
||||
edge redirect_eh_edge (edge e, basic_block new_bb);
|
||||
|
||||
#endif /* _TREE_FLOW_H */
|
||||
|
|
12
gcc/tree.c
12
gcc/tree.c
|
@ -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"
|
||||
|
|
|
@ -5134,6 +5134,7 @@ struct GTY(()) tree_map_base {
|
|||
extern int tree_map_base_eq (const void *, const void *);
|
||||
extern unsigned int tree_map_base_hash (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. */
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue