summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2009-03-28 09:08:52 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2009-03-28 09:08:52 +0000
commita5bfef5b903f411fa79333e850b65d304835a159 (patch)
tree4ebe94b877890d5f85418fb99ec4730610bcb172
parent86ecf8ad3e82852c1c5992e005c60409833f7549 (diff)
downloadgcc-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/ChangeLog16
-rw-r--r--gcc/except.c49
-rw-r--r--gcc/except.h6
-rw-r--r--gcc/tree-eh.c38
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);
}