OSDN Git Service

2010-04-13 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / gimple-low.c
index 8d7ead6..ae5a9fd 100644 (file)
@@ -25,7 +25,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "tree.h"
 #include "rtl.h"
-#include "varray.h"
 #include "gimple.h"
 #include "tree-iterator.h"
 #include "tree-inline.h"
@@ -76,6 +75,9 @@ struct lower_data
      of the function.  */
   VEC(return_statements_t,heap) *return_statements;
 
+  /* True if the current statement cannot fall through.  */
+  bool cannot_fallthru;
+
   /* True if the function calls __builtin_setjmp.  */
   bool calls_builtin_setjmp;
 };
@@ -199,7 +201,7 @@ lower_function_body (void)
   return 0;
 }
 
-struct gimple_opt_pass pass_lower_cf = 
+struct gimple_opt_pass pass_lower_cf =
 {
  {
   GIMPLE_PASS,
@@ -221,17 +223,14 @@ struct gimple_opt_pass pass_lower_cf =
 
 /* Verify if the type of the argument matches that of the function
    declaration.  If we cannot verify this or there is a mismatch,
-   mark the call expression so it doesn't get inlined later.  */
+   return false.  */
 
-static void
-check_call_args (gimple stmt)
+bool
+gimple_check_call_args (gimple stmt)
 {
   tree fndecl, parms, p;
   unsigned int i, nargs;
 
-  if (gimple_call_cannot_inline_p (stmt))
-    return;
-
   nargs = gimple_call_num_args (stmt);
 
   /* Get argument types for verification.  */
@@ -244,7 +243,7 @@ check_call_args (gimple stmt)
 
   /* Verify if the type of the argument matches that of the function
      declaration.  If we cannot verify this or there is a mismatch,
-     mark the call expression so it doesn't get inlined later.  */
+     return false.  */
   if (fndecl && DECL_ARGUMENTS (fndecl))
     {
       for (i = 0, p = DECL_ARGUMENTS (fndecl);
@@ -260,10 +259,7 @@ check_call_args (gimple stmt)
              || gimple_call_arg (stmt, i) == error_mark_node
              || !fold_convertible_p (DECL_ARG_TYPE (p),
                                      gimple_call_arg (stmt, i)))
-           {
-             gimple_call_set_cannot_inline (stmt, true);
-             break;
-           }
+            return false;
        }
     }
   else if (parms)
@@ -279,17 +275,15 @@ check_call_args (gimple stmt)
              || TREE_CODE (TREE_VALUE (p)) == VOID_TYPE
              || !fold_convertible_p (TREE_VALUE (p),
                                      gimple_call_arg (stmt, i)))
-           {
-             gimple_call_set_cannot_inline (stmt, true);
-             break;
-           }
+            return false;
        }
     }
   else
     {
       if (nargs != 0)
-       gimple_call_set_cannot_inline (stmt, true);
+        return false;
     }
+  return true;
 }
 
 
@@ -314,7 +308,7 @@ static void
 lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data)
 {
   gimple stmt;
-  
+
   stmt = gsi_stmt (*gsi);
 
   lower_sequence (gimple_omp_body (stmt), data);
@@ -325,7 +319,12 @@ lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data)
 }
 
 
-/* Lower statement GSI.  DATA is passed through the recursion.  */
+/* Lower statement GSI.  DATA is passed through the recursion.  We try to
+   track the fallthruness of statements and get rid of unreachable return
+   statements in order to prevent the EH lowering pass from adding useless
+   edges that can cause bogus warnings to be issued later; this guess need
+   not be 100% accurate, simply be conservative and reset cannot_fallthru
+   to false if we don't know.  */
 
 static void
 lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
@@ -338,36 +337,62 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
     {
     case GIMPLE_BIND:
       lower_gimple_bind (gsi, data);
+      /* Propagate fallthruness.  */
       return;
 
     case GIMPLE_COND:
-      /* The gimplifier has already lowered this into gotos.  */
-      break;
+    case GIMPLE_GOTO:
+    case GIMPLE_SWITCH:
+      data->cannot_fallthru = true;
+      gsi_next (gsi);
+      return;
 
     case GIMPLE_RETURN:
-      lower_gimple_return (gsi, data);
+      if (data->cannot_fallthru)
+       {
+         gsi_remove (gsi, false);
+         /* Propagate fallthruness.  */
+       }
+      else
+       {
+         lower_gimple_return (gsi, data);
+         data->cannot_fallthru = true;
+       }
       return;
 
     case GIMPLE_TRY:
-      lower_sequence (gimple_try_eval (stmt), data);
-      lower_sequence (gimple_try_cleanup (stmt), data);
+      {
+       bool try_cannot_fallthru;
+       lower_sequence (gimple_try_eval (stmt), data);
+       try_cannot_fallthru = data->cannot_fallthru;
+       data->cannot_fallthru = false;
+       lower_sequence (gimple_try_cleanup (stmt), data);
+       /* See gimple_stmt_may_fallthru for the rationale.  */
+       if (gimple_try_kind (stmt) == GIMPLE_TRY_FINALLY)
+         {
+           data->cannot_fallthru |= try_cannot_fallthru;
+           gsi_next (gsi);
+           return;
+         }
+      }
       break;
 
     case GIMPLE_CATCH:
+      data->cannot_fallthru = false;
       lower_sequence (gimple_catch_handler (stmt), data);
       break;
 
     case GIMPLE_EH_FILTER:
+      data->cannot_fallthru = false;
       lower_sequence (gimple_eh_filter_failure (stmt), data);
       break;
 
     case GIMPLE_NOP:
     case GIMPLE_ASM:
     case GIMPLE_ASSIGN:
-    case GIMPLE_GOTO:
     case GIMPLE_PREDICT:
     case GIMPLE_LABEL:
-    case GIMPLE_SWITCH:
+    case GIMPLE_EH_MUST_NOT_THROW:
     case GIMPLE_OMP_FOR:
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SECTIONS_SWITCH:
@@ -390,23 +415,33 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
            && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
            && DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP)
          {
-           data->calls_builtin_setjmp = true;
            lower_builtin_setjmp (gsi);
+           data->cannot_fallthru = false;
+           data->calls_builtin_setjmp = true;
+           return;
+         }
+
+       if (decl && (flags_from_decl_or_type (decl) & ECF_NORETURN))
+         {
+           data->cannot_fallthru = true;
+           gsi_next (gsi);
            return;
          }
-       check_call_args (stmt);
       }
       break;
 
     case GIMPLE_OMP_PARALLEL:
     case GIMPLE_OMP_TASK:
+      data->cannot_fallthru = false;
       lower_omp_directive (gsi, data);
+      data->cannot_fallthru = false;
       return;
 
     default:
       gcc_unreachable ();
     }
 
+  data->cannot_fallthru = false;
   gsi_next (gsi);
 }
 
@@ -506,8 +541,8 @@ try_catch_may_fallthru (const_tree stmt)
     default:
       /* This case represents statements to be executed when an
         exception occurs.  Those statements are implicitly followed
-        by a RESX_EXPR to resume execution after the exception.  So
-        in this case the TRY_CATCH never falls through.  */
+        by a RESX statement to resume execution after the exception.
+        So in this case the TRY_CATCH never falls through.  */
       return false;
     }
 }
@@ -580,8 +615,7 @@ block_may_fallthru (const_tree block)
     {
     case GOTO_EXPR:
     case RETURN_EXPR:
-    case RESX_EXPR:
-      /* Easy cases.  If the last statement of the block implies 
+      /* Easy cases.  If the last statement of the block implies
         control transfer, then we can't fall through.  */
       return false;
 
@@ -624,7 +658,7 @@ block_may_fallthru (const_tree block)
     case CALL_EXPR:
       /* Functions that do not return do not fall through.  */
       return (call_expr_flags (stmt) & ECF_NORETURN) == 0;
-    
+
     case CLEANUP_POINT_EXPR:
       return block_may_fallthru (TREE_OPERAND (stmt, 0));
 
@@ -651,14 +685,14 @@ gimple_stmt_may_fallthru (gimple stmt)
     case GIMPLE_GOTO:
     case GIMPLE_RETURN:
     case GIMPLE_RESX:
-      /* Easy cases.  If the last statement of the seq implies 
+      /* Easy cases.  If the last statement of the seq implies
         control transfer, then we can't fall through.  */
       return false;
 
     case GIMPLE_SWITCH:
-      /* Switch has already been lowered and represents a
-        branch to a selected label and hence can not fall through.  */
-      return true;
+      /* Switch has already been lowered and represents a branch
+        to a selected label and hence can't fall through.  */
+      return false;
 
     case GIMPLE_COND:
       /* GIMPLE_COND's are already lowered into a two-way branch.  They
@@ -684,13 +718,10 @@ gimple_stmt_may_fallthru (gimple stmt)
       return (gimple_seq_may_fallthru (gimple_try_eval (stmt))
              && gimple_seq_may_fallthru (gimple_try_cleanup (stmt)));
 
-    case GIMPLE_ASSIGN:
-      return true;
-
     case GIMPLE_CALL:
       /* Functions that do not return do not fall through.  */
       return (gimple_call_flags (stmt) & ECF_NORETURN) == 0;
-    
+
     default:
       return true;
     }
@@ -740,7 +771,7 @@ lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data)
   gsi_remove (gsi, false);
 }
 
-/* Lower a __builtin_setjmp TSI.
+/* Lower a __builtin_setjmp GSI.
 
    __builtin_setjmp is passed a pointer to an array of five words (not
    all will be used on all machines).  It operates similarly to the C