OSDN Git Service

2008-05-11 Aaron W. LaFramboise <aaronavay62@aaronwl.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-optimize.c
index 0678889..2703536 100644 (file)
@@ -1,12 +1,12 @@
 /* Top-level control of tree optimizations.
 /* 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
    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,
 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
 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"
 
 #include "config.h"
 #include "system.h"
@@ -57,12 +56,15 @@ static bool
 gate_all_optimizations (void)
 {
   return (optimize >= 1
 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 =
+struct gimple_opt_pass pass_all_optimizations =
 {
 {
+ {
+  GIMPLE_PASS,
   NULL,                                        /* name */
   gate_all_optimizations,              /* gate */
   NULL,                                        /* execute */
   NULL,                                        /* name */
   gate_all_optimizations,              /* gate */
   NULL,                                        /* execute */
@@ -74,14 +76,25 @@ struct tree_opt_pass pass_all_optimizations =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0,                                   /* todo_flags_finish */
-  0                                    /* letter */
+  0                                    /* todo_flags_finish */
+ }
 };
 
 };
 
-struct tree_opt_pass pass_early_local_passes =
+/* Gate: execute, or not, all of the non-trivial optimizations.  */
+
+static bool
+gate_all_early_local_passes (void)
 {
 {
-  NULL,                                        /* name */
-  gate_all_optimizations,              /* gate */
+         /* Don't bother doing anything if the program has errors.  */
+  return (!errorcount && !sorrycount);
+}
+
+struct simple_ipa_opt_pass pass_early_local_passes =
+{
+ {
+  SIMPLE_IPA_PASS,
+  "early_local_cleanups",              /* name */
+  gate_all_early_local_passes,         /* gate */
   NULL,                                        /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
   NULL,                                        /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
@@ -91,8 +104,45 @@ struct tree_opt_pass pass_early_local_passes =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0,                                   /* todo_flags_finish */
-  0                                    /* letter */
+  TODO_remove_functions                        /* todo_flags_finish */
+ }
+};
+
+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 gimple_opt_pass pass_all_early_optimizations =
+{
+ {
+  GIMPLE_PASS,
+  "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 */
+ }
 };
 
 /* Pass: cleanup the CFG just before expanding trees to RTL.
 };
 
 /* Pass: cleanup the CFG just before expanding trees to RTL.
@@ -100,14 +150,17 @@ struct tree_opt_pass pass_early_local_passes =
    because after the tree optimizers have run such cleanups may
    be necessary.  */
 
    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 ();
 execute_cleanup_cfg_pre_ipa (void)
 {
   cleanup_tree_cfg ();
+  return 0;
 }
 
 }
 
-struct tree_opt_pass pass_cleanup_cfg =
+struct gimple_opt_pass pass_cleanup_cfg =
 {
 {
+ {
+  GIMPLE_PASS,
   "cleanup_cfg",                       /* name */
   NULL,                                        /* gate */
   execute_cleanup_cfg_pre_ipa,         /* execute */
   "cleanup_cfg",                       /* name */
   NULL,                                        /* gate */
   execute_cleanup_cfg_pre_ipa,         /* execute */
@@ -119,8 +172,8 @@ struct tree_opt_pass pass_cleanup_cfg =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func,                                      /* todo_flags_finish */
-  0                                    /* letter */
+  TODO_dump_func                       /* todo_flags_finish */
+ }
 };
 
 
 };
 
 
@@ -129,17 +182,20 @@ struct tree_opt_pass pass_cleanup_cfg =
    because after the tree optimizers have run such cleanups may
    be necessary.  */
 
    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 ();
 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 =
+struct gimple_opt_pass pass_cleanup_cfg_post_optimizing =
 {
 {
+ {
+  GIMPLE_PASS,
   "final_cleanup",                     /* name */
   NULL,                                        /* gate */
   execute_cleanup_cfg_post_optimizing, /* execute */
   "final_cleanup",                     /* name */
   NULL,                                        /* gate */
   execute_cleanup_cfg_post_optimizing, /* execute */
@@ -151,28 +207,29 @@ struct tree_opt_pass pass_cleanup_cfg_post_optimizing =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func,                                      /* todo_flags_finish */
-  0                                    /* letter */
+  TODO_dump_func                       /* todo_flags_finish */
+ }
 };
 
 /* Pass: do the actions required to finish with tree-ssa optimization
    passes.  */
 
 };
 
 /* Pass: do the actions required to finish with tree-ssa optimization
    passes.  */
 
-static void
+static unsigned int
 execute_free_datastructures (void)
 {
 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);
 
   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 =
+struct gimple_opt_pass pass_free_datastructures =
 {
 {
+ {
+  GIMPLE_PASS,
   NULL,                                        /* name */
   NULL,                                        /* gate */
   execute_free_datastructures,                 /* execute */
   NULL,                                        /* name */
   NULL,                                        /* gate */
   execute_free_datastructures,                 /* execute */
@@ -184,35 +241,24 @@ struct tree_opt_pass pass_free_datastructures =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0,                                   /* todo_flags_finish */
-  0                                    /* letter */
+  0                                    /* todo_flags_finish */
+ }
 };
 /* Pass: free cfg annotations.  */
 
 };
 /* Pass: free cfg annotations.  */
 
-static void
+static unsigned int
 execute_free_cfg_annotations (void)
 {
 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 ();
   /* And get rid of annotations we no longer need.  */
   delete_tree_cfg_annotations ();
+
+  return 0;
 }
 
 }
 
-struct tree_opt_pass pass_free_cfg_annotations =
+struct gimple_opt_pass pass_free_cfg_annotations =
 {
 {
+ {
+  GIMPLE_PASS,
   NULL,                                        /* name */
   NULL,                                        /* gate */
   execute_free_cfg_annotations,                /* execute */
   NULL,                                        /* name */
   NULL,                                        /* gate */
   execute_free_cfg_annotations,                /* execute */
@@ -224,18 +270,25 @@ struct tree_opt_pass pass_free_cfg_annotations =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0,                                   /* todo_flags_finish */
-  0                                    /* letter */
+  0                                    /* todo_flags_finish */
+ }
 };
 };
-/* 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;
 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)
 
   if (cfun->eh)
     FOR_EACH_BB (bb)
@@ -244,49 +297,60 @@ execute_fixup_cfg (void)
          {
            tree stmt = bsi_stmt (bsi);
            tree call = get_call_expr_in (stmt);
          {
            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 
+                                                 | ECF_LOOPING_CONST_OR_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);
          }
            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.  */
 
 
 /* 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 ();
 execute_init_datastructures (void)
 {
   /* Allocate hash tables, arrays and other structures.  */
   init_tree_ssa ();
+  return 0;
 }
 
 }
 
-struct tree_opt_pass pass_init_datastructures =
+/* Gate: initialize or not the SSA datastructures.  */
+
+static bool
+gate_init_datastructures (void)
 {
 {
+  return (optimize >= 1);
+}
+
+struct gimple_opt_pass pass_init_datastructures =
+{
+ {
+  GIMPLE_PASS,
   NULL,                                        /* name */
   NULL,                                        /* name */
-  NULL,                                        /* gate */
+  gate_init_datastructures,            /* gate */
   execute_init_datastructures,         /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
   execute_init_datastructures,         /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
@@ -296,8 +360,8 @@ struct tree_opt_pass pass_init_datastructures =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0,                                   /* todo_flags_finish */
-  0                                    /* letter */
+  0                                    /* todo_flags_finish */
+ }
 };
 
 void
 };
 
 void
@@ -310,30 +374,15 @@ tree_lowering_passes (tree fn)
   tree_register_cfg_hooks ();
   bitmap_obstack_initialize (NULL);
   execute_pass_list (all_lowering_passes);
   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.pass.sub);
   free_dominance_info (CDI_POST_DOMINATORS);
   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 ();
 }
   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.  */
 \f
 /* For functions-as-trees languages, this performs all optimization and
    compilation for FNDECL.  */
@@ -342,12 +391,17 @@ void
 tree_rest_of_compilation (tree fndecl)
 {
   location_t saved_loc;
 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);
 
 
   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;
   /* Initialize the RTL code for the function.  */
   current_function_decl = fndecl;
   saved_loc = input_location;
@@ -358,63 +412,11 @@ tree_rest_of_compilation (tree fndecl)
      call expand_expr to calculate the size of a variable-sized array.
      We haven't necessarily assigned RTL to all variables yet, so it's
      not safe to try to expand expressions involving them.  */
      call expand_expr to calculate the size of a variable-sized array.
      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*/
+  cfun->dont_save_pending_sizes_p = 1;
   
   tree_register_cfg_hooks ();
   
   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);
   
   /* Perform all tree transforms and optimizations.  */
   execute_pass_list (all_passes);
   
@@ -423,41 +425,8 @@ tree_rest_of_compilation (tree fndecl)
   /* Release the default bitmap obstack.  */
   bitmap_obstack_release (NULL);
   
   /* 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
 
   /* 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 +444,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)
            = 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_eq, "size of return value of %q+D is %u bytes",
                      fndecl, size_as_int);
          else
                      fndecl, size_as_int);
          else
-           warning (0, "size of return value of %q+D is larger than %wd bytes",
+           warning (OPT_Wlarger_than_eq, "size of return value of %q+D is larger than %wd bytes",
                      fndecl, larger_than_size);
        }
     }
                      fndecl, larger_than_size);
        }
     }