OSDN Git Service

2007-01-08 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / ipa-inline.c
index cc83d36..bf9790f 100644 (file)
@@ -115,6 +115,7 @@ cgraph_estimate_size_after_inlining (int times, struct cgraph_node *to,
 void
 cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, bool update_original)
 {
+  HOST_WIDE_INT peak;
   if (duplicate)
     {
       /* We may eliminate the need for out-of-line copy to be output.
@@ -141,6 +142,11 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, bool update_o
     e->callee->global.inlined_to = e->caller->global.inlined_to;
   else
     e->callee->global.inlined_to = e->caller;
+  e->callee->global.stack_frame_offset
+    = e->caller->global.stack_frame_offset + e->caller->local.estimated_self_stack_size;
+  peak = e->callee->global.stack_frame_offset + e->callee->local.estimated_self_stack_size;
+  if (e->callee->global.inlined_to->global.estimated_stack_size < peak)
+    e->callee->global.inlined_to->global.estimated_stack_size = peak;
 
   /* Recursively clone all bodies.  */
   for (e = e->callee->callees; e; e = e->next_callee)
@@ -243,20 +249,28 @@ cgraph_estimate_growth (struct cgraph_node *node)
 }
 
 /* Return false when inlining WHAT into TO is not good idea
-   as it would cause too large growth of function bodies.  */
+   as it would cause too large growth of function bodies.  
+   When ONE_ONLY is true, assume that only one call site is going
+   to be inlined, otherwise figure out how many call sites in
+   TO calls WHAT and verify that all can be inlined.
+   */
 
 static bool
 cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
-                           const char **reason)
+                           const char **reason, bool one_only)
 {
   int times = 0;
   struct cgraph_edge *e;
   int newsize;
   int limit;
+  HOST_WIDE_INT stack_size_limit, inlined_stack;
 
-  for (e = to->callees; e; e = e->next_callee)
-    if (e->callee == what)
-      times++;
+  if (one_only)
+    times = 1;
+  else
+    for (e = to->callees; e; e = e->next_callee)
+      if (e->callee == what)
+       times++;
 
   if (to->global.inlined_to)
     to = to->global.inlined_to;
@@ -281,6 +295,21 @@ cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
         *reason = N_("--param large-function-growth limit reached");
       return false;
     }
+
+  stack_size_limit = to->local.estimated_self_stack_size;
+
+  stack_size_limit += stack_size_limit * PARAM_VALUE (PARAM_STACK_FRAME_GROWTH) / 100;
+
+  inlined_stack = (to->global.stack_frame_offset
+                  + to->local.estimated_self_stack_size
+                  + what->global.estimated_stack_size);
+  if (inlined_stack  > stack_size_limit
+      && inlined_stack > PARAM_VALUE (PARAM_LARGE_STACK_FRAME))
+    {
+      if (reason)
+        *reason = N_("--param large-stack-frame-growth limit reached");
+      return false;
+    }
   return true;
 }
 
@@ -529,7 +558,7 @@ cgraph_find_cycles (struct cgraph_node *node, htab_t cycles)
   node->aux = 0;
 }
 
-/* Leafify the cgraph node.  We have to be careful in recursing
+/* Flatten the cgraph node.  We have to be careful in recursing
    as to not run endlessly in circles of the callgraph.
    We do so by using a hashtab of cycle entering nodes as generated
    by cgraph_find_cycles.  */
@@ -836,7 +865,7 @@ cgraph_decide_inlining_of_small_functions (void)
        {
          struct cgraph_node *callee;
          if (!cgraph_check_inline_limits (edge->caller, edge->callee,
-                                          &edge->inline_failed))
+                                          &edge->inline_failed, true))
            {
              if (dump_file)
                fprintf (dump_file, " Not inlining into %s:%s.\n",
@@ -896,7 +925,6 @@ cgraph_decide_inlining (void)
   int old_insns = 0;
   int i;
 
-  timevar_push (TV_INLINE_HEURISTICS);
   max_count = 0;
   for (node = cgraph_nodes; node; node = node->next)
     if (node->analyzed && (node->needed || node->reachable))
@@ -954,7 +982,7 @@ cgraph_decide_inlining (void)
          htab_t cycles;
          if (dump_file)
            fprintf (dump_file,
-                    "Leafifying %s\n", cgraph_node_name (node));
+                    "Flattening %s\n", cgraph_node_name (node));
          cycles = htab_create (7, htab_hash_pointer, htab_eq_pointer, NULL);
          cgraph_find_cycles (node, cycles);
          cgraph_flatten_node (node, cycles);
@@ -1012,48 +1040,36 @@ cgraph_decide_inlining (void)
              && node->local.inlinable && node->callers->inline_failed
              && !DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl))
            {
-             bool ok = true;
-             struct cgraph_node *node1;
-
-             /* Verify that we won't duplicate the caller.  */
-             for (node1 = node->callers->caller;
-                  node1->callers && !node1->callers->inline_failed
-                  && ok; node1 = node1->callers->caller)
-               if (node1->callers->next_caller || node1->needed)
-                 ok = false;
-             if (ok)
+             if (dump_file)
+               {
+                 fprintf (dump_file,
+                          "\nConsidering %s %i insns.\n",
+                          cgraph_node_name (node), node->global.insns);
+                 fprintf (dump_file,
+                          " Called once from %s %i insns.\n",
+                          cgraph_node_name (node->callers->caller),
+                          node->callers->caller->global.insns);
+               }
+
+             old_insns = overall_insns;
+
+             if (cgraph_check_inline_limits (node->callers->caller, node,
+                                             NULL, false))
+               {
+                 cgraph_mark_inline (node->callers);
+                 if (dump_file)
+                   fprintf (dump_file,
+                            " Inlined into %s which now has %i insns"
+                            " for a net change of %+i insns.\n",
+                            cgraph_node_name (node->callers->caller),
+                            node->callers->caller->global.insns,
+                            overall_insns - old_insns);
+               }
+             else
                {
                  if (dump_file)
-                   {
-                     fprintf (dump_file,
-                              "\nConsidering %s %i insns.\n",
-                              cgraph_node_name (node), node->global.insns);
-                     fprintf (dump_file,
-                              " Called once from %s %i insns.\n",
-                              cgraph_node_name (node->callers->caller),
-                              node->callers->caller->global.insns);
-                   }
-
-                 old_insns = overall_insns;
-
-                 if (cgraph_check_inline_limits (node->callers->caller, node,
-                                                 NULL))
-                   {
-                     cgraph_mark_inline (node->callers);
-                     if (dump_file)
-                       fprintf (dump_file,
-                                " Inlined into %s which now has %i insns"
-                                " for a net change of %+i insns.\n",
-                                cgraph_node_name (node->callers->caller),
-                                node->callers->caller->global.insns,
-                                overall_insns - old_insns);
-                   }
-                 else
-                   {
-                     if (dump_file)
-                       fprintf (dump_file,
-                                " Inline limit reached, not inlined.\n");
-                   }
+                   fprintf (dump_file,
+                            " Inline limit reached, not inlined.\n");
                }
            }
        }
@@ -1066,7 +1082,6 @@ cgraph_decide_inlining (void)
             ncalls_inlined, nfunctions_inlined, initial_insns,
             overall_insns);
   free (order);
-  timevar_pop (TV_INLINE_HEURISTICS);
   return 0;
 }
 
@@ -1109,7 +1124,8 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node, bool early)
          && (!early
              || (cgraph_estimate_size_after_inlining (1, e->caller, e->callee)
                  <= e->caller->global.insns))
-         && cgraph_check_inline_limits (node, e->callee, &e->inline_failed)
+         && cgraph_check_inline_limits (node, e->callee, &e->inline_failed,
+                                        false)
          && (DECL_SAVED_TREE (e->callee->decl) || e->callee->inline_decl))
        {
          if (cgraph_default_inline_p (e->callee, &failed_reason))
@@ -1128,6 +1144,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node, bool early)
        }
   if (early && inlined)
     {
+      timevar_push (TV_INTEGRATION);
       push_cfun (DECL_STRUCT_FUNCTION (node->decl));
       tree_register_cfg_hooks ();
       current_function_decl = node->decl;
@@ -1135,6 +1152,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node, bool early)
       node->local.self_insns = node->global.insns;
       current_function_decl = NULL;
       pop_cfun ();
+      timevar_pop (TV_INTEGRATION);
     }
   return inlined;
 }
@@ -1154,12 +1172,13 @@ struct tree_opt_pass pass_ipa_inline =
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
-  TV_INTEGRATION,                      /* tv_id */
+  TV_INLINE_HEURISTICS,                        /* tv_id */
   0,                                   /* properties_required */
   PROP_cfg,                            /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_cgraph | TODO_dump_func,   /* todo_flags_finish */
+  TODO_dump_cgraph | TODO_dump_func
+  | TODO_remove_functions,             /* todo_flags_finish */
   0                                    /* letter */
 };
 
@@ -1205,7 +1224,6 @@ cgraph_early_inlining (void)
            ggc_collect ();
        }
     }
-  cgraph_remove_unreachable_nodes (true, dump_file);
 #ifdef ENABLE_CHECKING
   for (node = cgraph_nodes; node; node = node->next)
     gcc_assert (!node->global.inlined_to);
@@ -1231,12 +1249,13 @@ struct tree_opt_pass pass_early_ipa_inline =
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
-  TV_INTEGRATION,                      /* tv_id */
+  TV_INLINE_HEURISTICS,                        /* tv_id */
   0,                                   /* properties_required */
   PROP_cfg,                            /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_cgraph | TODO_dump_func,   /* todo_flags_finish */
+  TODO_dump_cgraph | TODO_dump_func
+  | TODO_remove_functions,             /* todo_flags_finish */
   0                                    /* letter */
 };