OSDN Git Service

2010-04-12 Richard Guenther <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 12 Apr 2010 13:37:32 +0000 (13:37 +0000)
committerMasaki Muranaka <monaka@monami-software.com>
Sun, 23 May 2010 00:56:24 +0000 (09:56 +0900)
* ipa.c (cgraph_postorder): Adjust postorder to guarantee
single-iteration always-inline inlining.
* ipa-inline.c (cgraph_mark_inline): Do not return anything.
(cgraph_decide_inlining): Do not handle always-inline
specially.
(try_inline): Remove always-inline cycle detection special case.
Do not recurse on always-inlines.
(cgraph_early_inlining): Do not iterate if not optimizing.
(cgraph_gate_early_inlining): remove.
(pass_early_inline): Run unconditionally.
(gate_cgraph_decide_inlining): New function.
(pass_ipa_inline): Use it.  Do not run the IPA inliner if
not inlining or optimizing.
(cgraph_decide_inlining_of_small_functions): Also consider
always-inline functions.
(cgraph_default_inline_p): Return true for nodes which should
disregard inline limits.
(estimate_function_body_sizes): Assume zero size and time for
nodes which are marked as disregarding inline limits.
(cgraph_decide_recursive_inlining): Do not perform recursive
inlining on always-inline nodes.

* gcc.dg/torture/inline-2.c: New testcase.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@158225 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/ipa-inline.c
gcc/ipa.c
gcc/testsuite/ChangeLog

index 88c9903..91a18dc 100644 (file)
@@ -1,3 +1,27 @@
+2010-04-12  Richard Guenther  <rguenther@suse.de>
+
+       * ipa.c (cgraph_postorder): Adjust postorder to guarantee
+       single-iteration always-inline inlining.
+       * ipa-inline.c (cgraph_mark_inline): Do not return anything.
+       (cgraph_decide_inlining): Do not handle always-inline
+       specially.
+       (try_inline): Remove always-inline cycle detection special case.
+       Do not recurse on always-inlines.
+       (cgraph_early_inlining): Do not iterate if not optimizing.
+       (cgraph_gate_early_inlining): remove.
+       (pass_early_inline): Run unconditionally.
+       (gate_cgraph_decide_inlining): New function.
+       (pass_ipa_inline): Use it.  Do not run the IPA inliner if
+       not inlining or optimizing.
+       (cgraph_decide_inlining_of_small_functions): Also consider
+       always-inline functions.
+       (cgraph_default_inline_p): Return true for nodes which should
+       disregard inline limits.
+       (estimate_function_body_sizes): Assume zero size and time for
+       nodes which are marked as disregarding inline limits.
+       (cgraph_decide_recursive_inlining): Do not perform recursive
+       inlining on always-inline nodes.
+
 2010-04-12  Jakub Jelinek  <jakub@redhat.com>
 
        PR bootstrap/43699
index 38a9c56..e9ba04b 100644 (file)
@@ -128,7 +128,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "cgraph.h"
 #include "diagnostic.h"
-#include "gimple-pretty-print.h"
 #include "timevar.h"
 #include "params.h"
 #include "fibheap.h"
@@ -269,8 +268,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
       else
        {
          struct cgraph_node *n;
-         n = cgraph_clone_node (e->callee, e->callee->decl,
-                                e->count, e->frequency, e->loop_nest,
+         n = cgraph_clone_node (e->callee, e->count, e->frequency, e->loop_nest,
                                 update_original, NULL);
          cgraph_redirect_edge_callee (e, n);
        }
@@ -287,7 +285,6 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
       + inline_summary (e->callee)->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;
-  cgraph_propagate_frequency (e->callee);
 
   /* Recursively clone all bodies.  */
   for (e = e->callee->callees; e; e = e->next_callee)
@@ -309,11 +306,20 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original,
   struct cgraph_node *to = NULL, *what;
   struct cgraph_edge *curr = e;
   int freq;
+  bool duplicate = false;
+  int orig_size = e->callee->global.size;
 
   gcc_assert (e->inline_failed);
   e->inline_failed = CIF_OK;
-  DECL_POSSIBLY_INLINED (e->callee->decl) = true;
 
+  if (!e->callee->global.inlined)
+    DECL_POSSIBLY_INLINED (e->callee->decl) = true;
+  e->callee->global.inlined = true;
+
+  if (e->callee->callers->next_caller
+      || !cgraph_can_remove_if_no_direct_calls_p (e->callee)
+      || e->callee->same_comdat_group)
+    duplicate = true;
   cgraph_clone_inlined_nodes (e, true, update_original);
 
   what = e->callee;
@@ -331,6 +337,8 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original,
   gcc_assert (what->global.inlined_to == to);
   if (new_size > old_size)
     overall_size += new_size - old_size;
+  if (!duplicate)
+    overall_size -= orig_size;
   ncalls_inlined++;
 
   if (flag_indirect_inlining)
@@ -536,57 +544,23 @@ cgraph_recursive_inlining_p (struct cgraph_node *to,
    of the function or function body size.  */
 
 static int
-cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
+cgraph_edge_badness (struct cgraph_edge *edge)
 {
   gcov_type badness;
   int growth =
-    (cgraph_estimate_size_after_inlining (1, edge->caller, edge->callee)
-     - edge->caller->global.size);
+    cgraph_estimate_size_after_inlining (1, edge->caller, edge->callee);
 
-  if (edge->callee->local.disregard_inline_limits)
-    return INT_MIN;
-
-  if (dump)
-    {
-      fprintf (dump_file, "    Badness calculcation for %s -> %s\n",
-              cgraph_node_name (edge->caller),
-              cgraph_node_name (edge->callee));
-      fprintf (dump_file, "      growth %i, time %i-%i, size %i-%i\n",
-              growth,
-              edge->callee->global.time,
-              inline_summary (edge->callee)->time_inlining_benefit,
-              edge->callee->global.size,
-              inline_summary (edge->callee)->size_inlining_benefit);
-    }
+  growth -= edge->caller->global.size;
 
   /* Always prefer inlining saving code size.  */
   if (growth <= 0)
-    {
-      badness = INT_MIN - growth;
-      if (dump)
-       fprintf (dump_file, "      %i: Growth %i < 0\n", (int) badness,
-                growth);
-    }
+    badness = INT_MIN - growth;
 
   /* When profiling is available, base priorities -(#calls / growth).
      So we optimize for overall number of "executed" inlined calls.  */
   else if (max_count)
-    {
-      badness =
-       ((int)
-        ((double) edge->count * INT_MIN / max_count / (max_benefit + 1)) *
-        (inline_summary (edge->callee)->time_inlining_benefit + 1)) / growth;
-      if (dump)
-       {
-         fprintf (dump_file,
-                  "      %i (relative %f): profile info. Relative count %f"
-                  " * Relative benefit %f\n",
-                  (int) badness, (double) badness / INT_MIN,
-                  (double) edge->count / max_count,
-                  (double) (inline_summary (edge->callee)->
-                            time_inlining_benefit + 1) / (max_benefit + 1));
-       }
-    }
+    badness = ((int)((double)edge->count * INT_MIN / max_count / (max_benefit + 1))
+             * (inline_summary (edge->callee)->time_inlining_benefit + 1)) / growth;
 
   /* When function local profile is available, base priorities on
      growth / frequency, so we optimize for overall frequency of inlined
@@ -600,13 +574,9 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
   else if (flag_guess_branch_prob)
     {
       int div = edge->frequency * 100 / CGRAPH_FREQ_BASE + 1;
-      int benefitperc;
-      int growth_for_all;
       badness = growth * 10000;
-      benefitperc =
-       MIN (100 * inline_summary (edge->callee)->time_inlining_benefit /
-            (edge->callee->global.time + 1) +1, 100);
-      div *= benefitperc;
+      div *= MIN (100 * inline_summary (edge->callee)->time_inlining_benefit
+                 / (edge->callee->global.time + 1) + 1, 100);
 
 
       /* Decrease badness if call is nested.  */
@@ -617,17 +587,9 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
        div = 1;
       if (badness > 0)
        badness /= div;
-      growth_for_all = cgraph_estimate_growth (edge->callee);
-      badness += growth_for_all;
+      badness += cgraph_estimate_growth (edge->callee);
       if (badness > INT_MAX)
-       badness = INT_MAX;
-      if (dump)
-       {
-         fprintf (dump_file,
-                  "      %i: guessed profile. frequency %i, overall growth %i,"
-                  " benefit %i%%, divisor %i\n",
-                  (int) badness, edge->frequency, growth_for_all, benefitperc, div);
-       }
+        badness = INT_MAX;
     }
   /* When function local profile is not available or it does not give
      useful information (ie frequency is zero), base the cost on
@@ -642,17 +604,10 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
       if (badness > 0)
        badness >>= nest;
       else
-       {
+        {
          badness <<= nest;
-       }
-      if (dump)
-       fprintf (dump_file, "      %i: no profile. nest %i\n", (int) badness,
-                nest);
+        }
     }
-
-  /* Ensure that we did not overflow in all the fixed point math above.  */
-  gcc_assert (badness >= INT_MIN);
-  gcc_assert (badness <= INT_MAX - 1);
   /* Make recursive inlining happen always after other inlining is done.  */
   if (cgraph_recursive_inlining_p (edge->caller, edge->callee, NULL))
     return badness + 1;
@@ -669,7 +624,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
   struct cgraph_edge *edge;
   cgraph_inline_failed_t failed_reason;
 
-  if (!node->local.inlinable
+  if (!node->local.inlinable || node->local.disregard_inline_limits
       || node->global.inlined_to)
     return;
   if (bitmap_bit_p (updated_nodes, node->uid))
@@ -696,7 +651,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
   for (edge = node->callers; edge; edge = edge->next_caller)
     if (edge->inline_failed)
       {
-       int badness = cgraph_edge_badness (edge, false);
+       int badness = cgraph_edge_badness (edge);
        if (edge->aux)
          {
            fibnode_t n = (fibnode_t) edge->aux;
@@ -705,12 +660,8 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
              continue;
 
            /* fibheap_replace_key only increase the keys.  */
-           if (badness < n->key)
-             {
-               fibheap_replace_key (heap, n, badness);
-               gcc_assert (n->key == badness);
-               continue;
-             }
+           if (fibheap_replace_key (heap, n, badness))
+             continue;
            fibheap_delete_node (heap, (fibnode_t) edge->aux);
          }
        edge->aux = fibheap_insert (heap, badness, edge);
@@ -810,8 +761,7 @@ cgraph_decide_recursive_inlining (struct cgraph_node *node,
             cgraph_node_name (node));
 
   /* We need original clone to copy around.  */
-  master_clone = cgraph_clone_node (node, node->decl,
-                                   node->count, CGRAPH_FREQ_BASE, 1,
+  master_clone = cgraph_clone_node (node, node->count, CGRAPH_FREQ_BASE, 1,
                                    false, NULL);
   master_clone->needed = true;
   for (e = master_clone->callees; e; e = e->next_callee)
@@ -939,7 +889,7 @@ add_new_edges_to_heap (fibheap_t heap, VEC (cgraph_edge_p, heap) *new_edges)
       struct cgraph_edge *edge = VEC_pop (cgraph_edge_p, new_edges);
 
       gcc_assert (!edge->aux);
-      edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge, false), edge);
+      edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge), edge);
     }
 }
 
@@ -988,7 +938,7 @@ cgraph_decide_inlining_of_small_functions (void)
        if (edge->inline_failed)
          {
            gcc_assert (!edge->aux);
-           edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge, false), edge);
+           edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge), edge);
          }
     }
 
@@ -996,26 +946,15 @@ cgraph_decide_inlining_of_small_functions (void)
   min_size = overall_size;
 
   while (overall_size <= max_size
-        && !fibheap_empty (heap))
+        && (edge = (struct cgraph_edge *) fibheap_extract_min (heap)))
     {
       int old_size = overall_size;
-      struct cgraph_node *where, *callee;
-      int badness = fibheap_min_key (heap);
-      int growth;
+      struct cgraph_node *where;
+      int growth =
+       cgraph_estimate_size_after_inlining (1, edge->caller, edge->callee);
       cgraph_inline_failed_t not_good = CIF_OK;
 
-      edge = (struct cgraph_edge *) fibheap_extract_min (heap);
-      gcc_assert (edge->aux);
-      edge->aux = NULL;
-      if (!edge->inline_failed)
-       continue;
-#ifdef ENABLE_CHECKING
-      gcc_assert (cgraph_edge_badness (edge, false) == badness);
-#endif
-      callee = edge->callee;
-
-      growth = (cgraph_estimate_size_after_inlining (1, edge->caller, edge->callee)
-               - edge->caller->global.size);
+      growth -= edge->caller->global.size;
 
       if (dump_file)
        {
@@ -1028,17 +967,18 @@ cgraph_decide_inlining_of_small_functions (void)
                   " Estimated growth after inlined into all callees is %+i insns.\n"
                   " Estimated badness is %i, frequency %.2f.\n",
                   cgraph_node_name (edge->caller),
-                  flag_wpa ? "unknown"
-                  : gimple_filename ((const_gimple) edge->call_stmt),
-                  flag_wpa ? -1 : gimple_lineno ((const_gimple) edge->call_stmt),
+                  gimple_filename ((const_gimple) edge->call_stmt),
+                  gimple_lineno ((const_gimple) edge->call_stmt),
                   cgraph_estimate_growth (edge->callee),
-                  badness,
+                  cgraph_edge_badness (edge),
                   edge->frequency / (double)CGRAPH_FREQ_BASE);
          if (edge->count)
            fprintf (dump_file," Called "HOST_WIDEST_INT_PRINT_DEC"x\n", edge->count);
-         if (dump_flags & TDF_DETAILS)
-           cgraph_edge_badness (edge, true);
        }
+      gcc_assert (edge->aux);
+      edge->aux = NULL;
+      if (!edge->inline_failed)
+       continue;
 
       /* When not having profile info ready we don't weight by any way the
          position of call in procedure itself.  This means if call of
@@ -1074,14 +1014,12 @@ cgraph_decide_inlining_of_small_functions (void)
            }
        }
 
-      if (edge->callee->local.disregard_inline_limits)
-       ;
-      else if (!cgraph_maybe_hot_edge_p (edge))
+      if (!cgraph_maybe_hot_edge_p (edge))
        not_good = CIF_UNLIKELY_CALL;
-      else if (!flag_inline_functions
+      if (!flag_inline_functions
          && !DECL_DECLARED_INLINE_P (edge->callee->decl))
        not_good = CIF_NOT_DECLARED_INLINED;
-      else if (optimize_function_for_size_p (DECL_STRUCT_FUNCTION(edge->caller->decl)))
+      if (optimize_function_for_size_p (DECL_STRUCT_FUNCTION(edge->caller->decl)))
        not_good = CIF_OPTIMIZING_FOR_SIZE;
       if (not_good && growth > 0 && cgraph_estimate_growth (edge->callee) > 0)
        {
@@ -1158,11 +1096,6 @@ cgraph_decide_inlining_of_small_functions (void)
         called by function we inlined (since number of it inlinable callers
         might change).  */
       update_caller_keys (heap, where, updated_nodes);
-
-      /* We removed one call of the function we just inlined.  If offline
-        copy is still needed, be sure to update the keys.  */
-      if (callee != where && !callee->global.inlined_to)
-        update_caller_keys (heap, callee, updated_nodes);
       bitmap_clear (updated_nodes);
 
       if (dump_file)
@@ -1184,40 +1117,10 @@ cgraph_decide_inlining_of_small_functions (void)
            fprintf (dump_file, "New minimal size reached: %i\n", min_size);
        }
     }
-  while (!fibheap_empty (heap))
+  while ((edge = (struct cgraph_edge *) fibheap_extract_min (heap)) != NULL)
     {
-      int badness = fibheap_min_key (heap);
-
-      edge = (struct cgraph_edge *) fibheap_extract_min (heap);
       gcc_assert (edge->aux);
       edge->aux = NULL;
-      if (!edge->inline_failed)
-       continue;
-#ifdef ENABLE_CHECKING
-      gcc_assert (cgraph_edge_badness (edge, false) == badness);
-#endif
-      if (dump_file)
-       {
-         fprintf (dump_file,
-                  "\nSkipping %s with %i size\n",
-                  cgraph_node_name (edge->callee),
-                  edge->callee->global.size);
-         fprintf (dump_file,
-                  " called by %s in %s:%i\n"
-                  " Estimated growth after inlined into all callees is %+i insns.\n"
-                  " Estimated badness is %i, frequency %.2f.\n",
-                  cgraph_node_name (edge->caller),
-                  flag_wpa ? "unknown"
-                  : gimple_filename ((const_gimple) edge->call_stmt),
-                  flag_wpa ? -1 : gimple_lineno ((const_gimple) edge->call_stmt),
-                  cgraph_estimate_growth (edge->callee),
-                  badness,
-                  edge->frequency / (double)CGRAPH_FREQ_BASE);
-         if (edge->count)
-           fprintf (dump_file," Called "HOST_WIDEST_INT_PRINT_DEC"x\n", edge->count);
-         if (dump_flags & TDF_DETAILS)
-           cgraph_edge_badness (edge, true);
-       }
       if (!edge->callee->local.disregard_inline_limits && edge->inline_failed
           && !cgraph_recursive_inlining_p (edge->caller, edge->callee,
                                           &edge->inline_failed))
@@ -1327,8 +1230,6 @@ cgraph_decide_inlining (void)
   cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
   if (in_lto_p && flag_indirect_inlining)
     ipa_update_after_lto_read ();
-  if (flag_indirect_inlining)
-    ipa_create_all_structures_for_iinln ();
 
   max_count = 0;
   max_benefit = 0;
@@ -1426,14 +1327,13 @@ cgraph_decide_inlining (void)
              if (cgraph_check_inline_limits (node->callers->caller, node,
                                              &reason, false))
                {
-                 struct cgraph_node *caller = node->callers->caller;
                  cgraph_mark_inline (node->callers);
                  if (dump_file)
                    fprintf (dump_file,
                             " Inlined into %s which now has %i size"
                             " for a net change of %+i size.\n",
-                            cgraph_node_name (caller),
-                            caller->global.size,
+                            cgraph_node_name (node->callers->caller),
+                            node->callers->caller->global.size,
                             overall_size - old_size);
                }
              else
@@ -1449,7 +1349,7 @@ cgraph_decide_inlining (void)
 
   /* Free ipa-prop structures if they are no longer needed.  */
   if (flag_indirect_inlining)
-    ipa_free_all_structures_after_iinln ();
+    free_all_ipa_structures_after_iinln ();
 
   if (dump_file)
     fprintf (dump_file,
@@ -1678,17 +1578,6 @@ cgraph_early_inlining (void)
     }
   else
     {
-      if (lookup_attribute ("flatten",
-                           DECL_ATTRIBUTES (node->decl)) != NULL)
-       {
-         if (dump_file)
-           fprintf (dump_file,
-                    "Flattening %s\n", cgraph_node_name (node));
-         cgraph_flatten (node);
-         timevar_push (TV_INTEGRATION);
-         todo |= optimize_inline_calls (current_function_decl);
-         timevar_pop (TV_INTEGRATION);
-       }
       /* We iterate incremental inlining to get trivial cases of indirect
         inlining.  */
       while (iterations < PARAM_VALUE (PARAM_EARLY_INLINER_MAX_ITERATIONS)
@@ -1841,6 +1730,14 @@ estimate_function_body_sizes (struct cgraph_node *node)
   int freq;
   tree funtype = TREE_TYPE (node->decl);
 
+  if (node->local.disregard_inline_limits)
+    {
+      inline_summary (node)->self_time = 0;
+      inline_summary (node)->self_size = 0;
+      inline_summary (node)->time_inlining_benefit = 0;
+      inline_summary (node)->size_inlining_benefit = 0;
+    }
+
   if (dump_file)
     fprintf (dump_file, "Analyzing function body size: %s\n",
             cgraph_node_name (node));
@@ -1972,10 +1869,21 @@ struct gimple_opt_pass pass_inline_parameters =
 static void
 inline_indirect_intraprocedural_analysis (struct cgraph_node *node)
 {
-  ipa_initialize_node_params (node);
-  ipa_detect_param_modifications (node);
+  struct cgraph_edge *cs;
+
+  if (!flag_ipa_cp)
+    {
+      ipa_initialize_node_params (node);
+      ipa_detect_param_modifications (node);
+    }
   ipa_analyze_params_uses (node);
-  ipa_compute_jump_functions (node);
+
+  if (!flag_ipa_cp)
+    for (cs = node->callees; cs; cs = cs->next_callee)
+      {
+       ipa_count_arguments (cs);
+       ipa_compute_jump_functions (cs);
+      }
 
   if (dump_file)
     {
@@ -2083,8 +1991,7 @@ inline_read_summary (void)
    active, we don't need to write them twice.  */
 
 static void
-inline_write_summary (cgraph_node_set set,
-                     varpool_node_set vset ATTRIBUTE_UNUSED)
+inline_write_summary (cgraph_node_set set)
 {
   if (flag_indirect_inlining && !flag_ipa_cp)
     ipa_prop_write_jump_functions (set);
@@ -2120,14 +2027,13 @@ struct ipa_opt_pass_d pass_ipa_inline =
   0,                                   /* properties_destroyed */
   TODO_remove_functions,               /* todo_flags_finish */
   TODO_dump_cgraph | TODO_dump_func
-  | TODO_remove_functions | TODO_ggc_collect   /* todo_flags_finish */
+  | TODO_remove_functions              /* todo_flags_finish */
  },
  inline_generate_summary,              /* generate_summary */
  inline_write_summary,                 /* write_summary */
  inline_read_summary,                  /* read_summary */
- NULL,                                 /* write_optimization_summary */
- NULL,                                 /* read_optimization_summary */
- NULL,                                 /* stmt_fixup */
+ NULL,                                 /* function_read_summary */
+ lto_ipa_fixup_call_notes,             /* stmt_fixup */
  0,                                    /* TODOs */
  inline_transform,                     /* function_transform */
  NULL,                                 /* variable_transform */
index 1cc7221..d559ab2 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -70,6 +70,12 @@ cgraph_postorder (struct cgraph_node **order)
                    node2->aux = edge->next_caller;
                  else
                    node2->aux = &last;
+                 /* Break possible cycles involving always-inline
+                    functions by ignoring edges from always-inline
+                    functions to non-always-inline functions.  */
+                 if (edge->caller->local.disregard_inline_limits
+                     && !edge->callee->local.disregard_inline_limits)
+                   continue;
                  if (!edge->caller->aux)
                    {
                      if (!edge->caller->callers)
index 642f085..21cf512 100644 (file)
@@ -1,3 +1,7 @@
+2010-04-12  Richard Guenther  <rguenther@suse.de>
+
+       * gcc.dg/torture/inline-2.c: New testcase.
+
 2010-04-12  Jakub Jelinek  <jakub@redhat.com>
 
        PR bootstrap/43699