diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-03-28 09:08:52 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-03-28 09:08:52 +0000 |
commit | a5bfef5b903f411fa79333e850b65d304835a159 (patch) | |
tree | 4ebe94b877890d5f85418fb99ec4730610bcb172 | |
parent | 86ecf8ad3e82852c1c5992e005c60409833f7549 (diff) | |
download | gcc-a5bfef5b903f411fa79333e850b65d304835a159.tar.gz |
* tree-eh.c (inlinable_call_p): New function.
(make_eh_edges): Use it.
(verify_eh_edges): Use it.
(stmt_can_throw_external, stmt_can_throw_internal): Use it.
* except.c (reachable_next_level): Add inlinable_function argument
(sjlj_find_directly_reachable_regions): Update.
(add_reachable_handler): Do not set saw_any_handlers.
(reachable_next_level): Handle MUST_NOT_THROW more curefully.
(foreach_reachable_handler, can_throw_internal_1, can_throw_external_1):
Add new inlinable call parameter.
(can_throw_internal, can_throw_external): Update.
* except.h (can_throw_internal_1, can_throw_external_1,
foreach_reachable_handler): Update declaration.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@145166 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/except.c | 49 | ||||
-rw-r--r-- | gcc/except.h | 6 | ||||
-rw-r--r-- | gcc/tree-eh.c | 38 |
4 files changed, 79 insertions, 30 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0bb96a65228..f327b671e89 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2009-03-28 Jan Hubicka <jh@suse.cz> + + * tree-eh.c (inlinable_call_p): New function. + (make_eh_edges): Use it. + (verify_eh_edges): Use it. + (stmt_can_throw_external, stmt_can_throw_internal): Use it. + * except.c (reachable_next_level): Add inlinable_function argument + (sjlj_find_directly_reachable_regions): Update. + (add_reachable_handler): Do not set saw_any_handlers. + (reachable_next_level): Handle MUST_NOT_THROW more curefully. + (foreach_reachable_handler, can_throw_internal_1, can_throw_external_1): + Add new inlinable call parameter. + (can_throw_internal, can_throw_external): Update. + * except.h (can_throw_internal_1, can_throw_external_1, + foreach_reachable_handler): Update declaration. + 2009-03-28 Joseph Myers <joseph@codesourcery.com> * config/arm/t-arm-coff, config/h8300/coff.h, diff --git a/gcc/except.c b/gcc/except.c index 2913fc8f31f..91af716f631 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -271,7 +271,7 @@ enum reachable_code struct reachable_info; static enum reachable_code reachable_next_level (struct eh_region *, tree, - struct reachable_info *); + struct reachable_info *, bool); static int action_record_eq (const void *, const void *); static hashval_t action_record_hash (const void *); @@ -1660,7 +1660,7 @@ sjlj_find_directly_reachable_regions (struct sjlj_lp_info *lp_info) rc = RNL_NOT_CAUGHT; for (; region; region = region->outer) { - rc = reachable_next_level (region, type_thrown, NULL); + rc = reachable_next_level (region, type_thrown, NULL, false); if (rc != RNL_NOT_CAUGHT) break; } @@ -2359,8 +2359,6 @@ add_reachable_handler (struct reachable_info *info, if (! info) return; - info->saw_any_handlers = true; - if (crtl->eh.built_landing_pads) info->callback (lp_region, info->callback_data); else @@ -2374,7 +2372,8 @@ add_reachable_handler (struct reachable_info *info, static enum reachable_code reachable_next_level (struct eh_region *region, tree type_thrown, - struct reachable_info *info) + struct reachable_info *info, + bool maybe_resx) { switch (region->type) { @@ -2510,15 +2509,16 @@ reachable_next_level (struct eh_region *region, tree type_thrown, case ERT_MUST_NOT_THROW: /* 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. + + Local landing pads of ERT_MUST_NOT_THROW instructions are reachable + only via locally handled RESX instructions. - 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. */ + When we inline a function call, we can bring in new handlers. In order + to avoid ERT_MUST_NOT_THROW landing pads from being deleted as unreachable + assume that such handlers exists prior for any inlinable call prior + inlining decisions are fixed. */ - if ((info && info->saw_any_handlers) || !cfun->after_inlining) + if (maybe_resx) { add_reachable_handler (info, region, region); return RNL_CAUGHT; @@ -2539,7 +2539,7 @@ reachable_next_level (struct eh_region *region, tree type_thrown, /* Invoke CALLBACK on each region reachable from REGION_NUMBER. */ void -foreach_reachable_handler (int region_number, bool is_resx, +foreach_reachable_handler (int region_number, bool is_resx, bool inlinable_call, void (*callback) (struct eh_region *, void *), void *callback_data) { @@ -2570,7 +2570,8 @@ foreach_reachable_handler (int region_number, bool is_resx, while (region) { - if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT) + if (reachable_next_level (region, type_thrown, &info, + inlinable_call || is_resx) >= RNL_CAUGHT) break; /* If we have processed one cleanup, there is no point in processing any more of them. Each cleanup will have an edge @@ -2622,7 +2623,7 @@ reachable_handlers (rtx insn) region_number = INTVAL (XEXP (note, 0)); } - foreach_reachable_handler (region_number, is_resx, + foreach_reachable_handler (region_number, is_resx, false, (crtl->eh.built_landing_pads ? arh_to_landing_pad : arh_to_label), @@ -2635,7 +2636,7 @@ reachable_handlers (rtx insn) within the function. */ bool -can_throw_internal_1 (int region_number, bool is_resx) +can_throw_internal_1 (int region_number, bool is_resx, bool inlinable_call) { struct eh_region *region; tree type_thrown; @@ -2656,7 +2657,8 @@ can_throw_internal_1 (int region_number, bool is_resx) regions, which also do not require processing internally. */ for (; region; region = region->outer) { - enum reachable_code how = reachable_next_level (region, type_thrown, 0); + enum reachable_code how = reachable_next_level (region, type_thrown, 0, + inlinable_call || is_resx); if (how == RNL_BLOCKED) return false; if (how != RNL_NOT_CAUGHT) @@ -2677,7 +2679,7 @@ can_throw_internal (const_rtx insn) if (JUMP_P (insn) && GET_CODE (PATTERN (insn)) == RESX && XINT (PATTERN (insn), 0) > 0) - return can_throw_internal_1 (XINT (PATTERN (insn), 0), true); + return can_throw_internal_1 (XINT (PATTERN (insn), 0), true, false); if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) @@ -2688,14 +2690,14 @@ can_throw_internal (const_rtx insn) if (!note || INTVAL (XEXP (note, 0)) <= 0) return false; - return can_throw_internal_1 (INTVAL (XEXP (note, 0)), false); + return can_throw_internal_1 (INTVAL (XEXP (note, 0)), false, false); } /* Determine if the given INSN can throw an exception that is visible outside the function. */ bool -can_throw_external_1 (int region_number, bool is_resx) +can_throw_external_1 (int region_number, bool is_resx, bool inlinable_call) { struct eh_region *region; tree type_thrown; @@ -2714,7 +2716,8 @@ can_throw_external_1 (int region_number, bool is_resx) /* If the exception is caught or blocked by any containing region, then it is not seen by any calling function. */ for (; region ; region = region->outer) - if (reachable_next_level (region, type_thrown, NULL) >= RNL_CAUGHT) + if (reachable_next_level (region, type_thrown, NULL, + inlinable_call || is_resx) >= RNL_CAUGHT) return false; return true; @@ -2731,7 +2734,7 @@ can_throw_external (const_rtx insn) if (JUMP_P (insn) && GET_CODE (PATTERN (insn)) == RESX && XINT (PATTERN (insn), 0) > 0) - return can_throw_external_1 (XINT (PATTERN (insn), 0), true); + return can_throw_external_1 (XINT (PATTERN (insn), 0), true, false); if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) @@ -2752,7 +2755,7 @@ can_throw_external (const_rtx insn) if (INTVAL (XEXP (note, 0)) <= 0) return false; - return can_throw_external_1 (INTVAL (XEXP (note, 0)), false); + return can_throw_external_1 (INTVAL (XEXP (note, 0)), false, false); } /* Set TREE_NOTHROW and crtl->all_throwers_are_sibcalls. */ diff --git a/gcc/except.h b/gcc/except.h index 9f83a9948f8..b32312ea373 100644 --- a/gcc/except.h +++ b/gcc/except.h @@ -44,9 +44,9 @@ extern void for_each_eh_label (void (*) (rtx)); extern void for_each_eh_region (void (*) (struct eh_region *)); /* Determine if the given INSN can throw an exception. */ -extern bool can_throw_internal_1 (int, bool); +extern bool can_throw_internal_1 (int, bool, bool); extern bool can_throw_internal (const_rtx); -extern bool can_throw_external_1 (int, bool); +extern bool can_throw_external_1 (int, bool, bool); extern bool can_throw_external (const_rtx); /* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls. */ @@ -97,7 +97,7 @@ extern bool get_eh_region_may_contain_throw (struct eh_region *); extern tree get_eh_region_tree_label (struct eh_region *); extern void set_eh_region_tree_label (struct eh_region *, tree); -extern void foreach_reachable_handler (int, bool, +extern void foreach_reachable_handler (int, bool, bool, void (*) (struct eh_region *, void *), void *); diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index e4fbaf7327c..c789acbd118 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -1946,11 +1946,34 @@ make_eh_edge (struct eh_region *region, void *data) make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH); } +/* See if STMT is call that might be inlined. */ + +static bool +inlinable_call_p (gimple stmt) +{ + tree decl; + if (gimple_code (stmt) != GIMPLE_CALL) + return false; + if (cfun->after_inlining) + return false; + /* Indirect calls can be propagated to direct call + and inlined. */ + decl = gimple_call_fndecl (stmt); + if (!decl) + return true; + if (cgraph_function_flags_ready + && cgraph_function_body_availability (cgraph_node (decl)) + < AVAIL_OVERWRITABLE) + return false; + return !DECL_UNINLINABLE (decl); +} + void make_eh_edges (gimple stmt) { int region_nr; bool is_resx; + bool inlinable = false; if (gimple_code (stmt) == GIMPLE_RESX) { @@ -1963,9 +1986,10 @@ make_eh_edges (gimple stmt) if (region_nr < 0) return; is_resx = false; + inlinable = inlinable_call_p (stmt); } - foreach_reachable_handler (region_nr, is_resx, make_eh_edge, stmt); + foreach_reachable_handler (region_nr, is_resx, inlinable, make_eh_edge, stmt); } static bool mark_eh_edge_found_error; @@ -2019,6 +2043,7 @@ verify_eh_edges (gimple stmt) basic_block bb = gimple_bb (stmt); edge_iterator ei; edge e; + bool inlinable = false; FOR_EACH_EDGE (e, ei, bb->succs) gcc_assert (!e->aux); @@ -2046,10 +2071,11 @@ verify_eh_edges (gimple stmt) error ("BB %i last statement has incorrectly set region", bb->index); return true; } + inlinable = inlinable_call_p (stmt); is_resx = false; } - foreach_reachable_handler (region_nr, is_resx, mark_eh_edge, stmt); + foreach_reachable_handler (region_nr, is_resx, inlinable, mark_eh_edge, stmt); FOR_EACH_EDGE (e, ei, bb->succs) { if ((e->flags & EDGE_EH) && !e->aux) @@ -2393,6 +2419,7 @@ stmt_can_throw_internal (gimple stmt) { int region_nr; bool is_resx = false; + bool inlinable_call = false; if (gimple_code (stmt) == GIMPLE_RESX) { @@ -2400,12 +2427,15 @@ stmt_can_throw_internal (gimple stmt) is_resx = true; } else - region_nr = lookup_stmt_eh_region (stmt); + { + region_nr = lookup_stmt_eh_region (stmt); + inlinable_call = inlinable_call_p (stmt); + } if (region_nr < 0) return false; - return can_throw_internal_1 (region_nr, is_resx); + return can_throw_internal_1 (region_nr, is_resx, inlinable_call); } |