OSDN Git Service

PR middle-end/19984
[pf3gnuchains/gcc-fork.git] / gcc / tree-optimize.c
index 0678889..cb30ba4 100644 (file)
@@ -1,12 +1,12 @@
 /* Top-level control of tree optimizations.
-   Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -15,9 +15,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License 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, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -57,8 +56,9 @@ static bool
 gate_all_optimizations (void)
 {
   return (optimize >= 1
-         /* Don't bother doing anything if the program has errors.  */
-         && !(errorcount || sorrycount));
+         /* Don't bother doing anything if the program has errors. 
+            We have to pass down the queue if we already went into SSA */
+         && (!(errorcount || sorrycount) || gimple_in_ssa_p (cfun)));
 }
 
 struct tree_opt_pass pass_all_optimizations =
@@ -78,10 +78,19 @@ struct tree_opt_pass pass_all_optimizations =
   0                                    /* letter */
 };
 
+/* Gate: execute, or not, all of the non-trivial optimizations.  */
+
+static bool
+gate_all_early_local_passes (void)
+{
+         /* Don't bother doing anything if the program has errors.  */
+  return (!errorcount && !sorrycount);
+}
+
 struct tree_opt_pass pass_early_local_passes =
 {
-  NULL,                                        /* name */
-  gate_all_optimizations,              /* gate */
+  "early_local_cleanups",              /* name */
+  gate_all_early_local_passes,         /* gate */
   NULL,                                        /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
@@ -91,6 +100,41 @@ struct tree_opt_pass pass_early_local_passes =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
+  TODO_remove_functions,               /* todo_flags_finish */
+  0                                    /* letter */
+};
+
+static unsigned int
+execute_early_local_optimizations (void)
+{
+  if (flag_unit_at_a_time)
+    cgraph_state = CGRAPH_STATE_IPA_SSA;
+  return 0;
+}
+
+/* Gate: execute, or not, all of the non-trivial optimizations.  */
+
+static bool
+gate_all_early_optimizations (void)
+{
+  return (optimize >= 1
+         /* Don't bother doing anything if the program has errors.  */
+         && !(errorcount || sorrycount));
+}
+
+struct tree_opt_pass pass_all_early_optimizations =
+{
+  "early_optimizations",               /* name */
+  gate_all_early_optimizations,                /* gate */
+  execute_early_local_optimizations,   /* 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 */
   0,                                   /* todo_flags_finish */
   0                                    /* letter */
 };
@@ -100,10 +144,11 @@ struct tree_opt_pass pass_early_local_passes =
    because after the tree optimizers have run such cleanups may
    be necessary.  */
 
-static void 
+static unsigned int
 execute_cleanup_cfg_pre_ipa (void)
 {
   cleanup_tree_cfg ();
+  return 0;
 }
 
 struct tree_opt_pass pass_cleanup_cfg =
@@ -129,13 +174,14 @@ struct tree_opt_pass pass_cleanup_cfg =
    because after the tree optimizers have run such cleanups may
    be necessary.  */
 
-static void 
+static unsigned int
 execute_cleanup_cfg_post_optimizing (void)
 {
   fold_cond_expr_cond ();
   cleanup_tree_cfg ();
   cleanup_dead_labels ();
   group_case_labels ();
+  return 0;
 }
 
 struct tree_opt_pass pass_cleanup_cfg_post_optimizing =
@@ -158,17 +204,16 @@ struct tree_opt_pass pass_cleanup_cfg_post_optimizing =
 /* Pass: do the actions required to finish with tree-ssa optimization
    passes.  */
 
-static void
+static unsigned int
 execute_free_datastructures (void)
 {
-  /* ??? This isn't the right place for this.  Worse, it got computed
-     more or less at random in various passes.  */
   free_dominance_info (CDI_DOMINATORS);
   free_dominance_info (CDI_POST_DOMINATORS);
 
-  /* Remove the ssa structures.  Do it here since this includes statement
-     annotations that need to be intact during disband_implicit_edges.  */
-  delete_tree_ssa ();
+  /* Remove the ssa structures.  */
+  if (cfun->gimple_df)
+    delete_tree_ssa ();
+  return 0;
 }
 
 struct tree_opt_pass pass_free_datastructures =
@@ -189,26 +234,13 @@ struct tree_opt_pass pass_free_datastructures =
 };
 /* Pass: free cfg annotations.  */
 
-static void
+static unsigned int
 execute_free_cfg_annotations (void)
 {
-  basic_block bb;
-  block_stmt_iterator bsi;
-
-  /* Emit gotos for implicit jumps.  */
-  disband_implicit_edges ();
-
-  /* Remove annotations from every tree in the function.  */
-  FOR_EACH_BB (bb)
-    for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-      {
-       tree stmt = bsi_stmt (bsi);
-       ggc_free (stmt->common.ann);
-       stmt->common.ann = NULL;
-      }
-
   /* And get rid of annotations we no longer need.  */
   delete_tree_cfg_annotations ();
+
+  return 0;
 }
 
 struct tree_opt_pass pass_free_cfg_annotations =
@@ -227,15 +259,22 @@ struct tree_opt_pass pass_free_cfg_annotations =
   0,                                   /* todo_flags_finish */
   0                                    /* letter */
 };
-/* Pass: fixup_cfg - IPA passes or compilation of earlier functions might've
-   changed some properties - such as marked functions nothrow.  Remove now
-   redundant edges and basic blocks.  */
 
-static void
+/* Pass: fixup_cfg.  IPA passes, compilation of earlier functions or inlining
+   might have changed some properties, such as marked functions nothrow.
+   Remove redundant edges and basic blocks, and create new ones if necessary.
+
+   This pass can't be executed as stand alone pass from pass manager, because
+   in between inlining and this fixup the verify_flow_info would fail.  */
+
+unsigned int
 execute_fixup_cfg (void)
 {
   basic_block bb;
   block_stmt_iterator bsi;
+  int todo = gimple_in_ssa_p (cfun) ? TODO_verify_ssa : 0;
+
+  cfun->after_inlining = true;
 
   if (cfun->eh)
     FOR_EACH_BB (bb)
@@ -244,49 +283,57 @@ execute_fixup_cfg (void)
          {
            tree stmt = bsi_stmt (bsi);
            tree call = get_call_expr_in (stmt);
-
-           if (call && call_expr_flags (call) & (ECF_CONST | ECF_PURE))
-             TREE_SIDE_EFFECTS (call) = 0;
+           tree decl = call ? get_callee_fndecl (call) : NULL;
+
+           if (decl && call_expr_flags (call) & (ECF_CONST | ECF_PURE)
+               && TREE_SIDE_EFFECTS (call))
+             {
+               if (gimple_in_ssa_p (cfun))
+                 {
+                   todo |= TODO_update_ssa | TODO_cleanup_cfg;
+                   update_stmt (stmt);
+                 }
+               TREE_SIDE_EFFECTS (call) = 0;
+             }
+           if (decl && TREE_NOTHROW (decl))
+             TREE_NOTHROW (call) = 1;
            if (!tree_could_throw_p (stmt) && lookup_stmt_eh_region (stmt))
              remove_stmt_from_eh_region (stmt);
          }
-       tree_purge_dead_eh_edges (bb);
+       if (tree_purge_dead_eh_edges (bb))
+          todo |= TODO_cleanup_cfg;
       }
-    
-  cleanup_tree_cfg ();
-}
 
-struct tree_opt_pass pass_fixup_cfg =
-{
-  "fixupcfg",                          /* name */
-  NULL,                                        /* gate */
-  execute_fixup_cfg,                   /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  0,                                   /* tv_id */
-  PROP_cfg,                            /* properties_required */
-  0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  TODO_dump_func,                      /* todo_flags_finish */
-  0                                    /* letter */
-};
+  /* Dump a textual representation of the flowgraph.  */
+  if (dump_file)
+    dump_tree_cfg (dump_file, dump_flags);
+
+  return todo;
+}
 
 /* Do the actions required to initialize internal data structures used
    in tree-ssa optimization passes.  */
 
-static void
+static unsigned int
 execute_init_datastructures (void)
 {
   /* Allocate hash tables, arrays and other structures.  */
   init_tree_ssa ();
+  return 0;
+}
+
+/* Gate: initialize or not the SSA datastructures.  */
+
+static bool
+gate_init_datastructures (void)
+{
+  return (optimize >= 1);
 }
 
 struct tree_opt_pass pass_init_datastructures =
 {
   NULL,                                        /* name */
-  NULL,                                        /* gate */
+  gate_init_datastructures,            /* gate */
   execute_init_datastructures,         /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
@@ -310,30 +357,15 @@ tree_lowering_passes (tree fn)
   tree_register_cfg_hooks ();
   bitmap_obstack_initialize (NULL);
   execute_pass_list (all_lowering_passes);
+  if (optimize && cgraph_global_info_ready)
+    execute_pass_list (pass_early_local_passes.sub);
   free_dominance_info (CDI_POST_DOMINATORS);
+  free_dominance_info (CDI_DOMINATORS);
   compact_blocks ();
   current_function_decl = saved_current_function_decl;
   bitmap_obstack_release (NULL);
   pop_cfun ();
 }
-
-/* Update recursively all inlined_to pointers of functions
-   inlined into NODE to INLINED_TO.  */
-static void
-update_inlined_to_pointers (struct cgraph_node *node,
-                           struct cgraph_node *inlined_to)
-{
-  struct cgraph_edge *e;
-  for (e = node->callees; e; e = e->next_callee)
-    {
-      if (e->callee->global.inlined_to)
-       {
-         e->callee->global.inlined_to = inlined_to;
-         update_inlined_to_pointers (e->callee, inlined_to);
-       }
-    }
-}
-
 \f
 /* For functions-as-trees languages, this performs all optimization and
    compilation for FNDECL.  */
@@ -342,12 +374,17 @@ void
 tree_rest_of_compilation (tree fndecl)
 {
   location_t saved_loc;
-  struct cgraph_node *saved_node = NULL, *node;
+  struct cgraph_node *node;
 
   timevar_push (TV_EXPAND);
 
   gcc_assert (!flag_unit_at_a_time || cgraph_global_info_ready);
 
+  node = cgraph_node (fndecl);
+
+  /* Initialize the default bitmap obstack.  */
+  bitmap_obstack_initialize (NULL);
+
   /* Initialize the RTL code for the function.  */
   current_function_decl = fndecl;
   saved_loc = input_location;
@@ -359,62 +396,10 @@ tree_rest_of_compilation (tree fndecl)
      We haven't necessarily assigned RTL to all variables yet, so it's
      not safe to try to expand expressions involving them.  */
   cfun->x_dont_save_pending_sizes_p = 1;
-  cfun->after_inlining = true;
-
-  node = cgraph_node (fndecl);
-
-  /* We might need the body of this function so that we can expand
-     it inline somewhere else.  This means not lowering some constructs
-     such as exception handling.  */
-  if (cgraph_preserve_function_body_p (fndecl))
-    {
-      if (!flag_unit_at_a_time)
-       {
-         struct cgraph_edge *e;
-
-         saved_node = cgraph_clone_node (node, node->count, 1, false);
-         for (e = saved_node->callees; e; e = e->next_callee)
-           if (!e->inline_failed)
-             cgraph_clone_inlined_nodes (e, true, false);
-       }
-      cfun->saved_static_chain_decl = cfun->static_chain_decl;
-      save_body (fndecl, &cfun->saved_args, &cfun->saved_static_chain_decl);
-    }
-
-  if (flag_inline_trees)
-    {
-      struct cgraph_edge *e;
-      for (e = node->callees; e; e = e->next_callee)
-       if (!e->inline_failed || warn_inline)
-         break;
-      if (e)
-       {
-         timevar_push (TV_INTEGRATION);
-         optimize_inline_calls (fndecl);
-         timevar_pop (TV_INTEGRATION);
-       }
-    }
-  /* We are not going to maintain the cgraph edges up to date.
-     Kill it so it won't confuse us.  */
-  while (node->callees)
-    {
-      /* In non-unit-at-a-time we must mark all referenced functions as needed.
-         */
-      if (node->callees->callee->analyzed && !flag_unit_at_a_time)
-        cgraph_mark_needed_node (node->callees->callee);
-      cgraph_remove_edge (node->callees);
-    }
-
-  /* We are not going to maintain the cgraph edges up to date.
-     Kill it so it won't confuse us.  */
-  cgraph_node_remove_callees (node);
-
-
-  /* Initialize the default bitmap obstack.  */
-  bitmap_obstack_initialize (NULL);
-  bitmap_obstack_initialize (&reg_obstack); /* FIXME, only at RTL generation*/
   
   tree_register_cfg_hooks ();
+
+  bitmap_obstack_initialize (&reg_obstack); /* FIXME, only at RTL generation*/
   /* Perform all tree transforms and optimizations.  */
   execute_pass_list (all_passes);
   
@@ -423,41 +408,8 @@ tree_rest_of_compilation (tree fndecl)
   /* Release the default bitmap obstack.  */
   bitmap_obstack_release (NULL);
   
-  /* Restore original body if still needed.  */
-  if (cfun->saved_cfg)
-    {
-      DECL_ARGUMENTS (fndecl) = cfun->saved_args;
-      cfun->cfg = cfun->saved_cfg;
-      cfun->eh = cfun->saved_eh;
-      DECL_INITIAL (fndecl) = cfun->saved_blocks;
-      cfun->unexpanded_var_list = cfun->saved_unexpanded_var_list;
-      cfun->saved_cfg = NULL;
-      cfun->saved_eh = NULL;
-      cfun->saved_args = NULL_TREE;
-      cfun->saved_blocks = NULL_TREE;
-      cfun->saved_unexpanded_var_list = NULL_TREE;
-      cfun->static_chain_decl = cfun->saved_static_chain_decl;
-      cfun->saved_static_chain_decl = NULL;
-      /* When not in unit-at-a-time mode, we must preserve out of line copy
-        representing node before inlining.  Restore original outgoing edges
-        using clone we created earlier.  */
-      if (!flag_unit_at_a_time)
-       {
-         struct cgraph_edge *e;
-
-         node = cgraph_node (current_function_decl);
-         cgraph_node_remove_callees (node);
-         node->callees = saved_node->callees;
-         saved_node->callees = NULL;
-         update_inlined_to_pointers (node, node);
-         for (e = node->callees; e; e = e->next_callee)
-           e->caller = node;
-         cgraph_remove_node (saved_node);
-       }
-    }
-  else
-    DECL_SAVED_TREE (fndecl) = NULL;
-  cfun = 0;
+  DECL_SAVED_TREE (fndecl) = NULL;
+  set_cfun (NULL);
 
   /* If requested, warn about function definitions where the function will
      return a value (usually of some struct or union type) which itself will
@@ -475,10 +427,10 @@ tree_rest_of_compilation (tree fndecl)
            = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type));
 
          if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0)
-           warning (0, "size of return value of %q+D is %u bytes",
+           warning (OPT_Wlarger_than_, "size of return value of %q+D is %u bytes",
                      fndecl, size_as_int);
          else
-           warning (0, "size of return value of %q+D is larger than %wd bytes",
+           warning (OPT_Wlarger_than_, "size of return value of %q+D is larger than %wd bytes",
                      fndecl, larger_than_size);
        }
     }