summaryrefslogtreecommitdiff
path: root/gcc/except.c
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2006-03-22 12:50:45 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2006-03-22 12:50:45 +0000
commit30b822ea3ac49643606cec17d2c5052f5b45780f (patch)
tree600f6369cacf022589c2e874590e5a90eb2f99e5 /gcc/except.c
parentf2df240119d5a44567727d18f595f72b8876428e (diff)
downloadgcc-30b822ea3ac49643606cec17d2c5052f5b45780f.tar.gz
PR middle-end/26084
* except.c (duplicate_eh_regions_0): New. (duplicate_eh_region_1): Duplicate the children of the node as well as the node itself. Link them up properly. (duplicate_eh_region_2): Merge into ... (duplicate_eh_regions): ... here. Take copy_region argument, and copy only a sub-tree if asked. Simplify copying and fixup. (eh_region_outer_p): New. * except.h (duplicate_eh_regions): Update decl. (eh_region_outer_p): Declare. * omp-low.c (lower_omp_single): Fix eh region placement wrt OMP_RETURN. (lower_omp_master): Likewise. (lower_omp_ordered): Likewise. * tree-cfg.c (struct move_stmt_d): Add new_label_map. (move_stmt_r): Use it to remap labels. Handle recursion vs remap_decls_p properly. (move_block_to_fn): Pass in new_label_map. Remap RESX_EXPR. (find_outermost_region_in_block): New. (new_label_mapper): New. (move_sese_region_to_fn): Copy eh information to the new function properly. * tree-inline.c (copy_cfg_body): Update for new duplicate_eh_regions argument. * tree-pretty-print.c (dump_generic_node): Dump RESX_EXPR region number. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@112283 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/except.c')
-rw-r--r--gcc/except.c283
1 files changed, 177 insertions, 106 deletions
diff --git a/gcc/except.c b/gcc/except.c
index 7c0088e123a..01f11087c3b 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -857,84 +857,145 @@ current_function_has_exception_handlers (void)
return false;
}
-static struct eh_region *
-duplicate_eh_region_1 (struct eh_region *o)
-{
- struct eh_region *n = ggc_alloc_cleared (sizeof (struct eh_region));
-
- *n = *o;
+/* A subroutine of duplicate_eh_regions. Search the region tree under O
+ for the miniumum and maximum region numbers. Update *MIN and *MAX. */
- n->region_number = o->region_number + cfun->eh->last_region_number;
- VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
- gcc_assert (!o->aka);
+static void
+duplicate_eh_regions_0 (eh_region o, int *min, int *max)
+{
+ if (o->region_number < *min)
+ *min = o->region_number;
+ if (o->region_number > *max)
+ *max = o->region_number;
- return n;
+ if (o->inner)
+ {
+ o = o->inner;
+ duplicate_eh_regions_0 (o, min, max);
+ while (o->next_peer)
+ {
+ o = o->next_peer;
+ duplicate_eh_regions_0 (o, min, max);
+ }
+ }
}
-static void
-duplicate_eh_region_2 (struct eh_region *o, struct eh_region **n_array,
- struct eh_region *prev_try)
+/* A subroutine of duplicate_eh_regions. Copy the region tree under OLD.
+ Root it at OUTER, and apply EH_OFFSET to the region number. Don't worry
+ about the other internal pointers just yet, just the tree-like pointers. */
+
+static eh_region
+duplicate_eh_regions_1 (eh_region old, eh_region outer, int eh_offset)
{
- struct eh_region *n = n_array[o->region_number];
+ eh_region ret, n;
- switch (n->type)
- {
- case ERT_TRY:
- if (o->u.try.catch)
- n->u.try.catch = n_array[o->u.try.catch->region_number];
- if (o->u.try.last_catch)
- n->u.try.last_catch = n_array[o->u.try.last_catch->region_number];
- break;
+ ret = n = ggc_alloc (sizeof (struct eh_region));
- case ERT_CATCH:
- if (o->u.catch.next_catch)
- n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number];
- if (o->u.catch.prev_catch)
- n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number];
- break;
+ *n = *old;
+ n->outer = outer;
+ gcc_assert (!old->aka);
- case ERT_CLEANUP:
- if (o->u.cleanup.prev_try)
- n->u.cleanup.prev_try = n_array[o->u.cleanup.prev_try->region_number];
- else
- n->u.cleanup.prev_try = prev_try;
- break;
+ n->region_number += eh_offset;
+ VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
- default:
- break;
+ if (old->inner)
+ {
+ old = old->inner;
+ n = n->inner = duplicate_eh_regions_1 (old, ret, eh_offset);
+ while (old->next_peer)
+ {
+ old = old->next_peer;
+ n = n->next_peer = duplicate_eh_regions_1 (old, ret, eh_offset);
+ }
}
- if (o->outer)
- n->outer = n_array[o->outer->region_number];
- if (o->inner)
- n->inner = n_array[o->inner->region_number];
- if (o->next_peer)
- n->next_peer = n_array[o->next_peer->region_number];
+ return ret;
}
-/* Duplicate the EH regions of IFUN into current function, root the tree in
- OUTER_REGION and remap labels using MAP callback. */
+/* Duplicate the EH regions of IFUN, rootted at COPY_REGION, into current
+ function and root the tree below OUTER_REGION. Remap labels using MAP
+ callback. The special case of COPY_REGION of 0 means all regions. */
+
int
duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
- void *data, int outer_region)
+ void *data, int copy_region, int outer_region)
{
- int ifun_last_region_number = ifun->eh->last_region_number;
- struct eh_region **n_array, *root, *cur, *prev_try;
- int i;
+ eh_region cur, prev_try, outer, *splice;
+ int i, min_region, max_region, eh_offset, cfun_last_region_number;
+ int num_regions;
- if (ifun_last_region_number == 0 || !ifun->eh->region_tree)
+ if (!ifun->eh->region_tree)
return 0;
- n_array = xcalloc (ifun_last_region_number + 1, sizeof (*n_array));
+ /* Find the range of region numbers to be copied. The interface we
+ provide here mandates a single offset to find new number from old,
+ which means we must look at the numbers present, instead of the
+ count or something else. */
+ if (copy_region > 0)
+ {
+ min_region = INT_MAX;
+ max_region = 0;
+
+ cur = VEC_index (eh_region, ifun->eh->region_array, copy_region);
+ duplicate_eh_regions_0 (cur, &min_region, &max_region);
+ }
+ else
+ min_region = 1, max_region = ifun->eh->last_region_number;
+ num_regions = max_region - min_region + 1;
+ cfun_last_region_number = cfun->eh->last_region_number;
+ eh_offset = cfun_last_region_number + 1 - min_region;
+
+ /* If we've not yet created a region array, do so now. */
VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
- cfun->eh->last_region_number + 1 + ifun_last_region_number);
+ cfun_last_region_number + 1 + num_regions);
+ cfun->eh->last_region_number = max_region + eh_offset;
- /* We might've created new cfun->eh->region_array so zero out nonexisting region 0. */
+ /* We may have just allocated the array for the first time.
+ Make sure that element zero is null. */
VEC_replace (eh_region, cfun->eh->region_array, 0, 0);
- for (i = cfun->eh->last_region_number + 1;
- i < cfun->eh->last_region_number + 1 + ifun_last_region_number; i++)
- VEC_replace (eh_region, cfun->eh->region_array, i, 0);
+ /* Zero all entries in the range allocated. */
+ memset (VEC_address (eh_region, cfun->eh->region_array)
+ + cfun_last_region_number + 1, 0, num_regions);
+
+ /* Locate the spot at which to insert the new tree. */
+ if (outer_region > 0)
+ {
+ outer = VEC_index (eh_region, cfun->eh->region_array, outer_region);
+ splice = &outer->inner;
+ }
+ else
+ {
+ outer = NULL;
+ splice = &cfun->eh->region_tree;
+ }
+ while (*splice)
+ splice = &(*splice)->next_peer;
+
+ /* Copy all the regions in the subtree. */
+ if (copy_region > 0)
+ {
+ cur = VEC_index (eh_region, ifun->eh->region_array, copy_region);
+ *splice = duplicate_eh_regions_1 (cur, outer, eh_offset);
+ }
+ else
+ {
+ eh_region n;
+
+ cur = ifun->eh->region_tree;
+ *splice = n = duplicate_eh_regions_1 (cur, outer, eh_offset);
+ while (cur->next_peer)
+ {
+ cur = cur->next_peer;
+ n = n->next_peer = duplicate_eh_regions_1 (cur, outer, eh_offset);
+ }
+ }
+
+ /* Remap all the labels in the new regions. */
+ for (i = cfun_last_region_number + 1;
+ VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i)
+ if (cur && cur->tree_label)
+ cur->tree_label = map (cur->tree_label, data);
/* Search for the containing ERT_TRY region to fix up
the prev_try short-cuts for ERT_CLEANUP regions. */
@@ -945,67 +1006,77 @@ duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
prev_try = prev_try->outer)
;
- for (i = 1; i <= ifun_last_region_number; ++i)
- {
- cur = VEC_index (eh_region, ifun->eh->region_array, i);
- if (!cur || cur->region_number != i)
- continue;
- n_array[i] = duplicate_eh_region_1 (cur);
- if (cur->tree_label)
- {
- tree newlabel = map (cur->tree_label, data);
- n_array[i]->tree_label = newlabel;
- }
- else
- n_array[i]->tree_label = NULL;
- }
- for (i = 1; i <= ifun_last_region_number; ++i)
+ /* Remap all of the internal catch and cleanup linkages. Since we
+ duplicate entire subtrees, all of the referenced regions will have
+ been copied too. And since we renumbered them as a block, a simple
+ bit of arithmetic finds us the index for the replacement region. */
+ for (i = cfun_last_region_number + 1;
+ VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i)
{
- cur = VEC_index (eh_region, ifun->eh->region_array, i);
- if (!cur || cur->region_number != i)
+ if (cur == NULL)
continue;
- duplicate_eh_region_2 (cur, n_array, prev_try);
- }
- root = n_array[ifun->eh->region_tree->region_number];
- gcc_assert (root->outer == NULL);
- if (outer_region > 0)
- {
- struct eh_region *cur
- = VEC_index (eh_region, cfun->eh->region_array, outer_region);
- struct eh_region *p = cur->inner;
+#define REMAP(REG) \
+ (REG) = VEC_index (eh_region, cfun->eh->region_array, \
+ (REG)->region_number + eh_offset)
- if (p)
+ switch (cur->type)
{
- while (p->next_peer)
- p = p->next_peer;
- p->next_peer = root;
- }
- else
- cur->inner = root;
- for (i = 1; i <= ifun_last_region_number; ++i)
- if (n_array[i] && n_array[i]->outer == NULL)
- n_array[i]->outer = cur;
- }
- else
- {
- struct eh_region *p = cfun->eh->region_tree;
- if (p)
- {
- while (p->next_peer)
- p = p->next_peer;
- p->next_peer = root;
+ case ERT_TRY:
+ if (cur->u.try.catch)
+ REMAP (cur->u.try.catch);
+ if (cur->u.try.last_catch)
+ REMAP (cur->u.try.last_catch);
+ break;
+
+ case ERT_CATCH:
+ if (cur->u.catch.next_catch)
+ REMAP (cur->u.catch.next_catch);
+ if (cur->u.catch.prev_catch)
+ REMAP (cur->u.catch.prev_catch);
+ break;
+
+ case ERT_CLEANUP:
+ if (cur->u.cleanup.prev_try)
+ REMAP (cur->u.cleanup.prev_try);
+ else
+ cur->u.cleanup.prev_try = prev_try;
+ break;
+
+ default:
+ break;
}
- else
- cfun->eh->region_tree = root;
+
+#undef REMAP
}
- free (n_array);
+ return eh_offset;
+}
- i = cfun->eh->last_region_number;
- cfun->eh->last_region_number = i + ifun_last_region_number;
+/* Return true if REGION_A is outer to REGION_B in IFUN. */
- return i;
+bool
+eh_region_outer_p (struct function *ifun, int region_a, int region_b)
+{
+ struct eh_region *rp_a, *rp_b;
+
+ gcc_assert (ifun->eh->last_region_number > 0);
+ gcc_assert (ifun->eh->region_tree);
+
+ rp_a = VEC_index (eh_region, ifun->eh->region_array, region_a);
+ rp_b = VEC_index (eh_region, ifun->eh->region_array, region_b);
+ gcc_assert (rp_a != NULL);
+ gcc_assert (rp_b != NULL);
+
+ do
+ {
+ if (rp_a == rp_b)
+ return true;
+ rp_b = rp_b->outer;
+ }
+ while (rp_b);
+
+ return false;
}
static int