OSDN Git Service

2005-12-16 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / gimple-low.c
index f5ee15b..4417134 100644 (file)
@@ -1,6 +1,6 @@
 /* Tree lowering pass.  Lowers GIMPLE into unstructured form.
 
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -25,7 +25,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm.h"
 #include "tree.h"
 #include "rtl.h"
-#include "errors.h"
 #include "varray.h"
 #include "tree-gimple.h"
 #include "tree-inline.h"
@@ -69,8 +68,7 @@ lower_function_body (void)
   tree_stmt_iterator i;
   tree t, x;
 
-  if (TREE_CODE (bind) != BIND_EXPR)
-    abort ();
+  gcc_assert (TREE_CODE (bind) == BIND_EXPR);
 
   data.block = DECL_INITIAL (current_function_decl);
   BLOCK_SUBBLOCKS (data.block) = NULL_TREE;
@@ -93,7 +91,7 @@ lower_function_body (void)
       && (data.return_statements == NULL
           || TREE_OPERAND (TREE_VALUE (data.return_statements), 0) != NULL))
     {
-      x = build (RETURN_EXPR, void_type_node, NULL);
+      x = build1 (RETURN_EXPR, void_type_node, NULL);
       SET_EXPR_LOCATION (x, cfun->function_end_locus);
       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
     }
@@ -102,7 +100,7 @@ lower_function_body (void)
      at the end of the function.  */
   for (t = data.return_statements ; t ; t = TREE_CHAIN (t))
     {
-      x = build (LABEL_EXPR, void_type_node, TREE_PURPOSE (t));
+      x = build1 (LABEL_EXPR, void_type_node, TREE_PURPOSE (t));
       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
 
       /* Remove the line number from the representative return statement.
@@ -117,16 +115,11 @@ lower_function_body (void)
       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
     }
 
-  if (data.block != DECL_INITIAL (current_function_decl))
-    abort ();
+  gcc_assert (data.block == DECL_INITIAL (current_function_decl));
   BLOCK_SUBBLOCKS (data.block)
     = blocks_nreverse (BLOCK_SUBBLOCKS (data.block));
 
   clear_block_marks (data.block);
-
-  /* Avoid producing notes for blocks.  */
-  cfun->dont_emit_block_notes = 1;
-  reset_block_changes ();
 }
 
 struct tree_opt_pass pass_lower_cf = 
@@ -142,7 +135,8 @@ struct tree_opt_pass pass_lower_cf =
   PROP_gimple_lcf,                     /* properties_provided */
   PROP_gimple_any,                     /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func                       /* todo_flags_finish */
+  TODO_dump_func,                      /* todo_flags_finish */
+  0                                    /* letter */
 };
 
 
@@ -150,7 +144,7 @@ struct tree_opt_pass pass_lower_cf =
    when they are changed -- if this has to be done, the lowering routine must
    do it explicitly.  DATA is passed through the recursion.  */
 
-void
+static void
 lower_stmt_body (tree expr, struct lower_data *data)
 {
   tree_stmt_iterator tsi;
@@ -199,14 +193,16 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
     case CALL_EXPR:
     case GOTO_EXPR:
     case LABEL_EXPR:
-    case VA_ARG_EXPR:
     case SWITCH_EXPR:
       break;
 
     default:
+#ifdef ENABLE_CHECKING
       print_node_brief (stderr, "", stmt, 0);
+      internal_error ("unexpected node");
+#endif
     case COMPOUND_EXPR:
-      abort ();
+      gcc_unreachable ();
     }
 
   tsi_next (tsi);
@@ -228,15 +224,13 @@ lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data)
          /* The outermost block of the original function may not be the
             outermost statement chain of the gimplified function.  So we
             may see the outermost block just inside the function.  */
-         if (new_block != DECL_INITIAL (current_function_decl))
-           abort ();
+         gcc_assert (new_block == DECL_INITIAL (current_function_decl));
          new_block = NULL;
        }
       else
        {
          /* We do not expect to handle duplicate blocks.  */
-         if (TREE_ASM_WRITTEN (new_block))
-           abort ();
+         gcc_assert (!TREE_ASM_WRITTEN (new_block));
          TREE_ASM_WRITTEN (new_block) = 1;
 
          /* Block tree may get clobbered by inlining.  Normally this would
@@ -256,8 +250,7 @@ lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data)
 
   if (new_block)
     {
-      if (data->block != new_block)
-       abort ();
+      gcc_assert (data->block == new_block);
 
       BLOCK_SUBBLOCKS (new_block)
        = blocks_nreverse (BLOCK_SUBBLOCKS (new_block));
@@ -269,6 +262,54 @@ lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data)
   tsi_delink (tsi);
 }
 
+/* Try to determine whether a TRY_CATCH expression can fall through.
+   This is a subroutine of block_may_fallthru.  */
+
+static bool
+try_catch_may_fallthru (tree stmt)
+{
+  tree_stmt_iterator i;
+
+  /* If the TRY block can fall through, the whole TRY_CATCH can
+     fall through.  */
+  if (block_may_fallthru (TREE_OPERAND (stmt, 0)))
+    return true;
+
+  i = tsi_start (TREE_OPERAND (stmt, 1));
+  switch (TREE_CODE (tsi_stmt (i)))
+    {
+    case CATCH_EXPR:
+      /* We expect to see a sequence of CATCH_EXPR trees, each with a
+        catch expression and a body.  The whole TRY_CATCH may fall
+        through iff any of the catch bodies falls through.  */
+      for (; !tsi_end_p (i); tsi_next (&i))
+       {
+         if (block_may_fallthru (CATCH_BODY (tsi_stmt (i))))
+           return true;
+       }
+      return false;
+
+    case EH_FILTER_EXPR:
+      /* The exception filter expression only matters if there is an
+        exception.  If the exception does not match EH_FILTER_TYPES,
+        we will execute EH_FILTER_FAILURE, and we will fall through
+        if that falls through.  If the exception does match
+        EH_FILTER_TYPES, the stack unwinder will continue up the
+        stack, so we will not fall through.  We don't know whether we
+        will throw an exception which matches EH_FILTER_TYPES or not,
+        so we just ignore EH_FILTER_TYPES and assume that we might
+        throw an exception which doesn't match.  */
+      return block_may_fallthru (EH_FILTER_FAILURE (tsi_stmt (i)));
+
+    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.  */
+      return false;
+    }
+}
+
 /* Try to determine if we can fall out of the bottom of BLOCK.  This guess
    need not be 100% accurate; simply be conservative and return true if we
    don't know.  This is used only to avoid stupidly generating extra code.
@@ -284,11 +325,17 @@ block_may_fallthru (tree block)
     case GOTO_EXPR:
     case RETURN_EXPR:
     case RESX_EXPR:
-    case SWITCH_EXPR:
       /* Easy cases.  If the last statement of the block implies 
         control transfer, then we can't fall through.  */
       return false;
 
+    case SWITCH_EXPR:
+      /* If SWITCH_LABELS is set, this is lowered, and represents a
+        branch to a selected label and hence can not fall through.
+        Otherwise SWITCH_BODY is set, and the switch can fall
+        through.  */
+      return SWITCH_LABELS (stmt) == NULL_TREE;
+
     case COND_EXPR:
       if (block_may_fallthru (COND_EXPR_THEN (stmt)))
        return true;
@@ -297,8 +344,19 @@ block_may_fallthru (tree block)
     case BIND_EXPR:
       return block_may_fallthru (BIND_EXPR_BODY (stmt));
 
+    case TRY_CATCH_EXPR:
+      return try_catch_may_fallthru (stmt);
+
     case TRY_FINALLY_EXPR:
-      return block_may_fallthru (TREE_OPERAND (stmt, 1));
+      /* The finally clause is always executed after the try clause,
+        so if it does not fall through, then the try-finally will not
+        fall through.  Otherwise, if the try clause does not fall
+        through, then when the finally clause falls through it will
+        resume execution wherever the try clause was going.  So the
+        whole try-finally will only fall through if both the try
+        clause and the finally clause fall through.  */
+      return (block_may_fallthru (TREE_OPERAND (stmt, 0))
+             && block_may_fallthru (TREE_OPERAND (stmt, 1)));
 
     case MODIFY_EXPR:
       if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)
@@ -310,6 +368,9 @@ block_may_fallthru (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));
 
     default:
       return true;
@@ -442,7 +503,7 @@ lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data)
 
   /* Generate a goto statement and remove the return statement.  */
  found:
-  t = build (GOTO_EXPR, void_type_node, label);
+  t = build1 (GOTO_EXPR, void_type_node, label);
   SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
   tsi_link_before (tsi, t, TSI_SAME_STMT);
   tsi_delink (tsi);
@@ -458,11 +519,13 @@ record_vars (tree vars)
     {
       tree var = vars;
 
+      /* BIND_EXPRs contains also function/type/constant declarations
+         we don't need to care about.  */
+      if (TREE_CODE (var) != VAR_DECL)
+       continue;
       /* Nothing to do in this case.  */
       if (DECL_EXTERNAL (var))
        continue;
-      if (TREE_CODE (var) == FUNCTION_DECL)
-       continue;
 
       /* Record the variable.  */
       cfun->unexpanded_var_list = tree_cons (NULL_TREE, var,
@@ -480,16 +543,13 @@ expand_var_p (tree var)
   if (TREE_CODE (var) != VAR_DECL)
     return true;
 
-  /* Remove all unused, unaliased temporaries.  Also remove unused, unaliased
-     local variables during highly optimizing compilations.  */
+  /* Leave statics and externals alone.  */
+  if (TREE_STATIC (var) || DECL_EXTERNAL (var))
+    return true;
+
+  /* Remove all unused local variables.  */
   ann = var_ann (var);
-  if (ann
-      && ! ann->may_aliases
-      && ! ann->used
-      && ! ann->has_hidden_use
-      && ! TREE_ADDRESSABLE (var)
-      && ! TREE_THIS_VOLATILE (var)
-      && (DECL_ARTIFICIAL (var) || optimize >= 2))
+  if (!ann || !ann->used)
     return false;
 
   return true;
@@ -501,6 +561,13 @@ static void
 remove_useless_vars (void)
 {
   tree var, *cell;
+  FILE *df = NULL;
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      df = dump_file;
+      fputs ("Discarding as unused:\n", df);
+    }
 
   for (cell = &cfun->unexpanded_var_list; *cell; )
     {
@@ -508,34 +575,83 @@ remove_useless_vars (void)
 
       if (!expand_var_p (var))
        {
+         if (df)
+           {
+             fputs ("  ", df);
+             print_generic_expr (df, var, dump_flags);
+             fputc ('\n', df);
+           }
+
          *cell = TREE_CHAIN (*cell);
          continue;
        }
 
       cell = &TREE_CHAIN (*cell);
     }
-}
 
-/* Expand variables in the unexpanded_var_list.  */
+  if (df)
+    fputc ('\n', df);
+}
 
-void
-expand_used_vars (void)
+struct tree_opt_pass pass_remove_useless_vars = 
 {
-  tree cell;
+  "vars",                              /* name */
+  NULL,                                        /* gate */
+  remove_useless_vars,                 /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  0,                                   /* tv_id */
+  0,                                   /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_dump_func,                      /* todo_flags_finish */
+  0                                    /* letter */
+};
 
-  cfun->unexpanded_var_list = nreverse (cfun->unexpanded_var_list);
+/* Mark BLOCK used if it has a used variable in it, then recurse over its
+   subblocks.  */
 
-  for (cell = cfun->unexpanded_var_list; cell; cell = TREE_CHAIN (cell))
-    expand_var (TREE_VALUE (cell));
+static void
+mark_blocks_with_used_vars (tree block)
+{
+  tree var;
+  tree subblock;
 
-  cfun->unexpanded_var_list = NULL_TREE;
+  if (!TREE_USED (block))
+    {
+      for (var = BLOCK_VARS (block);
+          var;
+          var = TREE_CHAIN (var))
+       {
+         if (TREE_USED (var))
+           {
+             TREE_USED (block) = true;
+             break;
+           }
+       }
+    }
+  for (subblock = BLOCK_SUBBLOCKS (block);
+       subblock;
+       subblock = BLOCK_CHAIN (subblock))
+    mark_blocks_with_used_vars (subblock);
 }
 
-struct tree_opt_pass pass_remove_useless_vars = 
+/* Mark the used attribute on blocks correctly.  */
+  
+static void
+mark_used_blocks (void)
+{  
+  mark_blocks_with_used_vars (DECL_INITIAL (current_function_decl));
+}
+
+
+struct tree_opt_pass pass_mark_used_blocks = 
 {
-  "vars",                              /* name */
+  "blocks",                            /* name */
   NULL,                                        /* gate */
-  remove_useless_vars,                 /* execute */
+  mark_used_blocks,                    /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
@@ -544,5 +660,6 @@ struct tree_opt_pass pass_remove_useless_vars =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func                       /* todo_flags_finish */
+  TODO_dump_func,                      /* todo_flags_finish */
+  0                                    /* letter */
 };