OSDN Git Service

2008-05-06 Jerry DeLisle <jvdelisle@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / ipa-inline.c
index cd7d2af..68a4201 100644 (file)
@@ -1,12 +1,12 @@
 /* Inlining decision heuristics.
-   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 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) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +15,8 @@ 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/>.  */
 
 /*  Inlining decision heuristics
 
@@ -405,10 +404,10 @@ cgraph_default_inline_p (struct cgraph_node *n, const char **reason)
 
   if (n->inline_decl)
     decl = n->inline_decl;
-  if (!DECL_INLINE (decl))
+  if (!flag_inline_small_functions && !DECL_DECLARED_INLINE_P (decl))
     {
       if (reason)
-       *reason = N_("function not inlinable");
+       *reason = N_("function not inline candidate");
       return false;
     }
 
@@ -667,7 +666,8 @@ cgraph_decide_recursive_inlining (struct cgraph_node *node)
   int depth = 0;
   int n = 0;
 
-  if (optimize_size)
+  if (optimize_size
+      || (!flag_inline_functions && !DECL_DECLARED_INLINE_P (node->decl)))
     return false;
 
   if (DECL_DECLARED_INLINE_P (node->decl))
@@ -864,6 +864,7 @@ cgraph_decide_inlining_of_small_functions (void)
       struct cgraph_node *where;
       int growth =
        cgraph_estimate_size_after_inlining (1, edge->caller, edge->callee);
+      const char *not_good = NULL;
 
       growth -= edge->caller->global.insns;
 
@@ -917,13 +918,19 @@ cgraph_decide_inlining_of_small_functions (void)
            }
        }
 
-      if ((!cgraph_maybe_hot_edge_p (edge) || optimize_size) && growth > 0)
+      if (!cgraph_maybe_hot_edge_p (edge))
+       not_good = N_("call is unlikely and code size would grow");
+      if (!flag_inline_functions
+         && !DECL_DECLARED_INLINE_P (edge->callee->decl))
+       not_good = N_("function not declared inline and code size would grow");
+      if (optimize_size)
+       not_good = N_("optimizing for size and code size would grow");
+      if (not_good && growth > 0 && cgraph_estimate_growth (edge->callee) > 0)
        {
           if (!cgraph_recursive_inlining_p (edge->caller, edge->callee,
                                            &edge->inline_failed))
            {
-             edge->inline_failed = 
-               N_("call is unlikely");
+             edge->inline_failed = not_good;
              if (dump_file)
                fprintf (dump_file, " inline_failed:%s.\n", edge->inline_failed);
            }
@@ -1364,7 +1371,9 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node,
        /* When the function body would grow and inlining the function won't
           eliminate the need for offline copy of the function, don't inline.
         */
-       if (mode == INLINE_SIZE
+       if ((mode == INLINE_SIZE
+            || (!flag_inline_functions
+                && !DECL_DECLARED_INLINE_P (e->callee->decl)))
            && (cgraph_estimate_size_after_inlining (1, e->caller, e->callee)
                > e->caller->global.insns)
            && cgraph_estimate_growth (e->callee) > 0)
@@ -1417,24 +1426,6 @@ cgraph_gate_inlining (void)
   return flag_inline_trees;
 }
 
-struct tree_opt_pass pass_ipa_inline = 
-{
-  "inline",                            /* name */
-  cgraph_gate_inlining,                        /* gate */
-  cgraph_decide_inlining,              /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_INLINE_HEURISTICS,                        /* tv_id */
-  0,                                   /* properties_required */
-  PROP_cfg,                            /* properties_provided */
-  0,                                   /* properties_destroyed */
-  TODO_remove_functions,               /* todo_flags_finish */
-  TODO_dump_cgraph | TODO_dump_func
-  | TODO_remove_functions,             /* todo_flags_finish */
-  0                                    /* letter */
-};
-
 /* Because inlining might remove no-longer reachable nodes, we need to
    keep the array visible to garbage collector to avoid reading collected
    out nodes.  */
@@ -1470,8 +1461,10 @@ cgraph_gate_early_inlining (void)
   return flag_inline_trees && flag_early_inlining;
 }
 
-struct tree_opt_pass pass_early_inline = 
+struct gimple_opt_pass pass_early_inline = 
 {
+ {
+  GIMPLE_PASS,
   "einline",                           /* name */
   cgraph_gate_early_inlining,          /* gate */
   cgraph_early_inlining,               /* execute */
@@ -1483,8 +1476,8 @@ struct tree_opt_pass pass_early_inline =
   PROP_cfg,                            /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func,                      /* todo_flags_finish */
-  0                                    /* letter */
+  TODO_dump_func                       /* todo_flags_finish */
+ }
 };
 
 /* When inlining shall be performed.  */
@@ -1498,8 +1491,10 @@ cgraph_gate_ipa_early_inlining (void)
 
 /* IPA pass wrapper for early inlining pass.  We need to run early inlining
    before tree profiling so we have stand alone IPA pass for doing so.  */
-struct tree_opt_pass pass_ipa_early_inline = 
+struct simple_ipa_opt_pass pass_ipa_early_inline = 
 {
+ {
+  SIMPLE_IPA_PASS,
   "einline_ipa",                       /* name */
   cgraph_gate_ipa_early_inlining,      /* gate */
   NULL,                                        /* execute */
@@ -1511,8 +1506,8 @@ struct tree_opt_pass pass_ipa_early_inline =
   PROP_cfg,                            /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_cgraph,                    /* todo_flags_finish */
-  0                                    /* letter */
+  TODO_dump_cgraph                     /* todo_flags_finish */
+ }
 };
 
 /* Compute parameters of functions used by inliner.  */
@@ -1528,9 +1523,9 @@ compute_inline_parameters (void)
   node->local.inlinable = tree_inlinable_function_p (current_function_decl);
   node->local.self_insns = estimate_num_insns (current_function_decl,
                                               &eni_inlining_weights);
-  if (node->local.inlinable)
+  if (node->local.inlinable && !node->local.disregard_inline_limits)
     node->local.disregard_inline_limits
-      = lang_hooks.tree_inlining.disregard_inline_limits (current_function_decl);
+      = DECL_DISREGARD_INLINE_LIMITS (current_function_decl);
   if (flag_really_no_inline && !node->local.disregard_inline_limits)
     node->local.inlinable = 0;
   /* Inlining characteristics are maintained by the cgraph_mark_inline.  */
@@ -1545,8 +1540,10 @@ gate_inline_passes (void)
   return flag_inline_trees;
 }
 
-struct tree_opt_pass pass_inline_parameters = 
+struct gimple_opt_pass pass_inline_parameters = 
 {
+ {
+  GIMPLE_PASS,
   NULL,                                        /* name */
   gate_inline_passes,                  /* gate */
   compute_inline_parameters,           /* execute */
@@ -1558,22 +1555,24 @@ struct tree_opt_pass pass_inline_parameters =
   PROP_cfg,                            /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0,                                   /* todo_flags_finish */
-  0                                    /* letter */
+  0                                    /* todo_flags_finish */
+ }
 };
 
-/* Apply inline plan to the function.  */
+/* Note function body size.  */
+static void
+inline_generate_summary (struct cgraph_node *node ATTRIBUTE_UNUSED)
+{
+  compute_inline_parameters ();
+  return;
+}
+
+/* Apply inline plan to function.  */
 static unsigned int
-apply_inline (void)
+inline_transform (struct cgraph_node *node)
 {
   unsigned int todo = 0;
   struct cgraph_edge *e;
-  struct cgraph_node *node = cgraph_node (current_function_decl);
-
-  /* Even when not optimizing, ensure that always_inline functions get inlined.
-   */
-  if (!optimize)
-   cgraph_decide_inlining_incrementally (node, INLINE_SPEED, 0);
 
   /* We might need the body of this function so that we can expand
      it inline somewhere else.  */
@@ -1589,6 +1588,66 @@ apply_inline (void)
       todo = optimize_inline_calls (current_function_decl);
       timevar_pop (TV_INTEGRATION);
     }
+  return todo | execute_fixup_cfg ();
+}
+
+struct ipa_opt_pass pass_ipa_inline = 
+{
+ {
+  IPA_PASS,
+  "inline",                            /* name */
+  cgraph_gate_inlining,                        /* gate */
+  cgraph_decide_inlining,              /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  TV_INLINE_HEURISTICS,                        /* tv_id */
+  0,                                   /* properties_required */
+  PROP_cfg,                            /* properties_provided */
+  0,                                   /* properties_destroyed */
+  TODO_remove_functions,               /* todo_flags_finish */
+  TODO_dump_cgraph | TODO_dump_func
+  | TODO_remove_functions              /* todo_flags_finish */
+ },
+ inline_generate_summary,              /* function_generate_summary */
+ NULL,                                 /* variable_generate_summary */
+ NULL,                                 /* function_write_summary */
+ NULL,                                 /* variable_write_summary */
+ NULL,                                 /* function_read_summary */
+ NULL,                                 /* variable_read_summary */
+ 0,                                    /* TODOs */
+ inline_transform,                     /* function_transform */
+ NULL,                                 /* variable_transform */
+};
+
+
+/* When inlining shall be performed.  */
+static bool
+cgraph_gate_O0_always_inline (void)
+{
+  return !flag_unit_at_a_time || !flag_inline_trees;
+}
+
+static unsigned int
+cgraph_O0_always_inline (void)
+{
+  struct cgraph_node *node = cgraph_node (current_function_decl);
+  unsigned int todo = 0;
+  bool inlined;
+
+  if (sorrycount || errorcount)
+    return 0;
+  inlined = cgraph_decide_inlining_incrementally (node, INLINE_SPEED, 0);
+  /* We might need the body of this function so that we can expand
+     it inline somewhere else.  */
+  if (cgraph_preserve_function_body_p (current_function_decl))
+    save_inline_function_body (node);
+  if (inlined || warn_inline)
+    {
+      timevar_push (TV_INTEGRATION);
+      todo = optimize_inline_calls (current_function_decl);
+      timevar_pop (TV_INTEGRATION);
+    }
   /* In non-unit-at-a-time we must mark all referenced functions as needed.  */
   if (!flag_unit_at_a_time)
     {
@@ -1600,11 +1659,13 @@ apply_inline (void)
   return todo | execute_fixup_cfg ();
 }
 
-struct tree_opt_pass pass_apply_inline = 
+struct gimple_opt_pass pass_O0_always_inline = 
 {
-  "apply_inline",                      /* name */
-  NULL,                                        /* gate */
-  apply_inline,                                /* execute */
+ {
+  GIMPLE_PASS,
+  "always_inline",                     /* name */
+  cgraph_gate_O0_always_inline,                /* gate */
+  cgraph_O0_always_inline,             /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
@@ -1614,8 +1675,8 @@ struct tree_opt_pass pass_apply_inline =
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   TODO_dump_func | TODO_verify_flow
-  | TODO_verify_stmts,                 /* todo_flags_finish */
-  0                                    /* letter */
+  | TODO_verify_stmts                  /* todo_flags_finish */
+ }
 };
 
 #include "gt-ipa-inline.h"