diff options
-rw-r--r-- | gcc/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/except.c | 151 | ||||
-rw-r--r-- | gcc/except.h | 2 | ||||
-rw-r--r-- | gcc/function.h | 1 | ||||
-rw-r--r-- | gcc/tree-cfg.c | 2 | ||||
-rw-r--r-- | gcc/tree-eh.c | 5 | ||||
-rw-r--r-- | gcc/tree-optimize.c | 1 |
7 files changed, 177 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 56615851773..cb6bc1bc239 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2005-05-12 Steven Bosscher <stevenb@suse.de> + Stuart Hastings <stuart@apple.com> + Jan Hubicka <jh@suse.cz> + + * except.c (duplicate_eh_region_1, duplicate_eh_region_2, + duplicate_eh_regions): New functions, based on old + implementation removed with RTL inliner. + (reachable_next_level): Modify behaviour pre-inline. + * except.h (duplicate_eh_regions_map, duplicate_eh_regions): + Declare. + * function.h (struct function): Add after_inlining flag. + * tree-optimize.c (tree_rest_of_compilation): Set it. + * tree-eh.c (add_stmt_to_eh_region_fn): Initialize hashtable + when needed. + * tree-cfg.c (label_to_block_fn): Deal with cases where + label was never insterted into code. + 2005-05-12 Zack Weinberg <zack@codesourcery.com> * doc/cpp.texi: Document that #sccs is a synonym for #ident. diff --git a/gcc/except.c b/gcc/except.c index 35105f9d7ad..9f1bfe926af 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -853,6 +853,148 @@ 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; + + n->region_number = o->region_number + cfun->eh->last_region_number; + gcc_assert (!o->aka); + + return n; +} + +static void +duplicate_eh_region_2 (struct eh_region *o, struct eh_region **n_array, + struct eh_region *prev_try) +{ + struct eh_region *n = n_array[o->region_number]; + + 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; + + 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; + + 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; + + default: + break; + } + + 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]; +} + +/* Duplicate the EH regions of IFUN into current function, root the tree in + OUTER_REGION and remap labels using MAP callback. */ +int +duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map, + void *data, int outer_region) +{ + int ifun_last_region_number = ifun->eh->last_region_number; + struct eh_region **n_array, *root, *cur, *prev_try; + int i; + + if (ifun_last_region_number == 0 || !ifun->eh->region_tree) + return 0; + + n_array = xcalloc (ifun_last_region_number + 1, sizeof (*n_array)); + + /* Search for the containing ERT_TRY region to fix up + the prev_try short-cuts for ERT_CLEANUP regions. */ + prev_try = NULL; + if (outer_region > 0) + for (prev_try = cfun->eh->region_array[outer_region]; + prev_try && prev_try->type != ERT_TRY; + prev_try = prev_try->outer) + ; + + for (i = 1; i <= ifun_last_region_number; ++i) + { + cur = 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) + { + cur = ifun->eh->region_array[i]; + if (!cur || cur->region_number != i) + 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 = cfun->eh->region_array[outer_region]; + struct eh_region *p = cur->inner; + + if (p) + { + 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; + } + else + cfun->eh->region_tree = root; + } + + free (n_array); + + i = cfun->eh->last_region_number; + cfun->eh->last_region_number = i + ifun_last_region_number; + + collect_eh_region_array (); + + return i; +} + static int t2r_eq (const void *pentry, const void *pdata) { @@ -2273,8 +2415,13 @@ reachable_next_level (struct eh_region *region, tree type_thrown, /* Here we end our search, since no exceptions may propagate. If we've touched down at some landing pad previous, then the explicit function call we generated may be used. Otherwise - the call is made by the runtime. */ - if (info && info->saw_any_handlers) + the call is made by the runtime. + + Before inlining, do not perform this optimization. We may + inline a subroutine that contains handlers, and that will + change the value of saw_any_handlers. */ + + if ((info && info->saw_any_handlers) || !cfun->after_inlining) { add_reachable_handler (info, region, region); return RNL_CAUGHT; diff --git a/gcc/except.h b/gcc/except.h index 746b3d4aca8..9526b865909 100644 --- a/gcc/except.h +++ b/gcc/except.h @@ -81,6 +81,8 @@ extern void expand_eh_return (void); extern rtx expand_builtin_extend_pointer (tree); extern rtx get_exception_pointer (struct function *); extern rtx get_exception_filter (struct function *); +typedef tree (*duplicate_eh_regions_map) (tree, void *); +extern int duplicate_eh_regions (struct function *, duplicate_eh_regions_map, void *, int); extern void sjlj_emit_function_exit_after (rtx); diff --git a/gcc/function.h b/gcc/function.h index 4f6181aa08c..0720c12ca5d 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -168,6 +168,7 @@ struct function GTY(()) /* The control flow graph for this function. */ struct control_flow_graph *cfg; + bool after_inlining; /* For tree-optimize.c. */ diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index c54305c898b..9860a29da00 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -823,6 +823,8 @@ label_to_block_fn (struct function *ifun, tree dest) bsi_insert_before (&bsi, stmt, BSI_NEW_STMT); uid = LABEL_DECL_UID (dest); } + if (VARRAY_SIZE (ifun->cfg->x_label_to_block_map) <= (unsigned int)uid) + return NULL; return VARRAY_BB (ifun->cfg->x_label_to_block_map, uid); } diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index 72644aa0b04..3bf58300d27 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -112,6 +112,11 @@ add_stmt_to_eh_region_fn (struct function *ifun, tree t, int num) n->stmt = t; n->region_nr = num; + if (!get_eh_throw_stmt_table (ifun)) + set_eh_throw_stmt_table (ifun, htab_create_ggc (31, struct_ptr_hash, + struct_ptr_eq, + ggc_free)); + slot = htab_find_slot (get_eh_throw_stmt_table (ifun), n, INSERT); gcc_assert (!*slot); *slot = n; diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c index 6e07a2b504f..c3ceb31f59c 100644 --- a/gcc/tree-optimize.c +++ b/gcc/tree-optimize.c @@ -675,6 +675,7 @@ tree_rest_of_compilation (tree fndecl) We haven't necessarily assigned RTL to all variables yet, so it's not safe to try to expand expressions involving them. */ cfun->x_dont_save_pending_sizes_p = 1; + cfun->after_inlining = true; node = cgraph_node (fndecl); |