OSDN Git Service

* tree-eh.c (inlinable_call_p): New function.
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 28 Mar 2009 09:08:52 +0000 (09:08 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 28 Mar 2009 09:08:52 +0000 (09:08 +0000)
(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

gcc/ChangeLog
gcc/except.c
gcc/except.h
gcc/tree-eh.c

index 0bb96a6..f327b67 100644 (file)
@@ -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,
index 2913fc8..91af716 100644 (file)
@@ -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.  */
index 9f83a99..b32312e 100644 (file)
@@ -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 *);
 
index e4fbaf7..c789acb 100644 (file)
@@ -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);
 }