re PR ipa/65478 (crafty performance regression)
authorMartin Jambor <mjambor@suse.cz>
Sun, 29 Mar 2015 15:38:52 +0000 (17:38 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sun, 29 Mar 2015 15:38:52 +0000 (15:38 +0000)
PR ipa/65478
* params.def (PARAM_IPA_CP_RECURSION_PENALTY) : New.
(PARAM_IPA_CP_SINGLE_CALL_PENALTY): Likewise.
* ipa-prop.h (ipa_node_params): New flags node_within_scc and
node_calling_single_call.
* ipa-cp.c (count_callers): New function.
(set_single_call_flag): Likewise.
(initialize_node_lattices): Count callers and set single_flag_call if
necessary.
(incorporate_penalties): New function.
(good_cloning_opportunity_p): Use it, dump new flags.
(propagate_constants_topo): Set node_within_scc flag if appropriate.
* doc/invoke.texi (ipa-cp-recursion-penalty,
ipa-cp-single-call-pentalty): Document.

From-SVN: r221763

gcc/ChangeLog
gcc/doc/invoke.texi
gcc/ipa-cp.c
gcc/ipa-prop.h
gcc/params.def

index 554d8c6833512089b52eb2771a5996365a8ca072..9baf88b1471f949481915b5eda8e63afefd282b8 100644 (file)
@@ -1,3 +1,20 @@
+2015-03-27  Martin Jambor  <mjambor@suse.cz>
+
+       PR ipa/65478
+       * params.def (PARAM_IPA_CP_RECURSION_PENALTY) : New.
+       (PARAM_IPA_CP_SINGLE_CALL_PENALTY): Likewise.
+       * ipa-prop.h (ipa_node_params): New flags node_within_scc and
+       node_calling_single_call.
+       * ipa-cp.c (count_callers): New function.
+       (set_single_call_flag): Likewise.
+       (initialize_node_lattices): Count callers and set single_flag_call if
+       necessary.
+       (incorporate_penalties): New function.
+       (good_cloning_opportunity_p): Use it, dump new flags.
+       (propagate_constants_topo): Set node_within_scc flag if appropriate.
+       * doc/invoke.texi (ipa-cp-recursion-penalty,
+       ipa-cp-single-call-pentalty): Document.
+
 2015-03-27  Jan Hubicka  <hubicka@ucw.cz>
 
        PR ipa/65588
index 9749727c13f23658c2bcbc6211cc502c50a65ac1..bf8afadfb942ff7c6f1baf504dded054366e90ee 100644 (file)
@@ -10834,6 +10834,15 @@ IPA-CP calculates its own score of cloning profitability heuristics
 and performs those cloning opportunities with scores that exceed
 @option{ipa-cp-eval-threshold}.
 
+@item ipa-cp-recursion-penalty
+Percentage penalty the recursive functions will receive when they
+are evaluated for cloning.
+
+@item ipa-cp-single-call-penalty
+Percentage penalty functions containg a single call to another
+function will receive when they are evaluated for cloning.
+
+
 @item ipa-max-agg-items
 IPA-CP is also capable to propagate a number of scalar values passed
 in an aggregate. @option{ipa-max-agg-items} controls the maximum
index bfe4d972e735e06542c2d83341ad8d575f996960..d9aa92ed5b5a74950a6e3dbdfe880e272dbff7a4 100644 (file)
@@ -811,6 +811,41 @@ set_all_contains_variable (struct ipcp_param_lattices *plats)
   return ret;
 }
 
+/* Worker of call_for_symbol_thunks_and_aliases, increment the integer DATA
+   points to by the number of callers to NODE.  */
+
+static bool
+count_callers (cgraph_node *node, void *data)
+{
+  int *caller_count = (int *) data;
+
+  for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller)
+    /* Local thunks can be handled transparently, but if the thunk can not
+       be optimized out, count it as a real use.  */
+    if (!cs->caller->thunk.thunk_p || !cs->caller->local.local)
+      ++*caller_count;
+  return false;
+}
+
+/* Worker of call_for_symbol_thunks_and_aliases, it is supposed to be called on
+   the one caller of some other node.  Set the caller's corresponding flag.  */
+
+static bool
+set_single_call_flag (cgraph_node *node, void *)
+{
+  cgraph_edge *cs = node->callers;
+  /* Local thunks can be handled transparently, skip them.  */
+  while (cs && cs->caller->thunk.thunk_p && cs->caller->local.local)
+    cs = cs->next_caller;
+  if (cs)
+    {
+      gcc_assert (!cs->next_caller);
+      IPA_NODE_REF (cs->caller)->node_calling_single_call = true;
+      return true;
+    }
+  return false;
+}
+
 /* Initialize ipcp_lattices.  */
 
 static void
@@ -822,7 +857,17 @@ initialize_node_lattices (struct cgraph_node *node)
   int i;
 
   gcc_checking_assert (node->has_gimple_body_p ());
-  if (!cgraph_local_p (node))
+  if (cgraph_local_p (node))
+    {
+      int caller_count = 0;
+      node->call_for_symbol_thunks_and_aliases (count_callers, &caller_count,
+                                               true);
+      gcc_checking_assert (caller_count > 0);
+      if (caller_count == 1)
+       node->call_for_symbol_thunks_and_aliases (set_single_call_flag,
+                                                 NULL, true);
+    }
+  else
     {
       /* When cloning is allowed, we can assume that externally visible
         functions are not called.  We will compensate this by cloning
@@ -2105,6 +2150,24 @@ hint_time_bonus (inline_hints hints)
   return result;
 }
 
+/* If there is a reason to penalize the function described by INFO in the
+   cloning goodness evaluation, do so.  */
+
+static inline int64_t
+incorporate_penalties (ipa_node_params *info, int64_t evaluation)
+{
+  if (info->node_within_scc)
+    evaluation = (evaluation
+                 * (100 - PARAM_VALUE (PARAM_IPA_CP_RECURSION_PENALTY))) / 100;
+
+  if (info->node_calling_single_call)
+    evaluation = (evaluation
+                 * (100 - PARAM_VALUE (PARAM_IPA_CP_SINGLE_CALL_PENALTY)))
+      / 100;
+
+  return evaluation;
+}
+
 /* Return true if cloning NODE is a good idea, given the estimated TIME_BENEFIT
    and SIZE_COST and with the sum of frequencies of incoming edges to the
    potential new clone in FREQUENCIES.  */
@@ -2120,18 +2183,22 @@ good_cloning_opportunity_p (struct cgraph_node *node, int time_benefit,
 
   gcc_assert (size_cost > 0);
 
+  struct ipa_node_params *info = IPA_NODE_REF (node);
   if (max_count)
     {
       int factor = (count_sum * 1000) / max_count;
       int64_t evaluation = (((int64_t) time_benefit * factor)
                                    / size_cost);
+      evaluation = incorporate_penalties (info, evaluation);
 
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "     good_cloning_opportunity_p (time: %i, "
                 "size: %i, count_sum: " HOST_WIDE_INT_PRINT_DEC
-                ") -> evaluation: " "%"PRId64
+                "%s%s) -> evaluation: " "%"PRId64
                 ", threshold: %i\n",
                 time_benefit, size_cost, (HOST_WIDE_INT) count_sum,
+                info->node_within_scc ? ", scc" : "",
+                info->node_calling_single_call ? ", single_call" : "",
                 evaluation, PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
 
       return evaluation >= PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD);
@@ -2140,13 +2207,16 @@ good_cloning_opportunity_p (struct cgraph_node *node, int time_benefit,
     {
       int64_t evaluation = (((int64_t) time_benefit * freq_sum)
                                    / size_cost);
+      evaluation = incorporate_penalties (info, evaluation);
 
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "     good_cloning_opportunity_p (time: %i, "
-                "size: %i, freq_sum: %i) -> evaluation: "
+                "size: %i, freq_sum: %i%s%s) -> evaluation: "
                 "%"PRId64 ", threshold: %i\n",
-                time_benefit, size_cost, freq_sum, evaluation,
-                PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
+                time_benefit, size_cost, freq_sum,
+                info->node_within_scc ? ", scc" : "",
+                info->node_calling_single_call ? ", single_call" : "",
+                evaluation, PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
 
       return evaluation >= PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD);
     }
@@ -2637,9 +2707,12 @@ propagate_constants_topo (struct ipa_topo_info *topo)
          struct cgraph_edge *cs;
 
          for (cs = v->callees; cs; cs = cs->next_callee)
-           if (ipa_edge_within_scc (cs)
-               && propagate_constants_accross_call (cs))
-             push_node_to_stack (topo, cs->callee->function_symbol ());
+           if (ipa_edge_within_scc (cs))
+             {
+               IPA_NODE_REF (v)->node_within_scc = true;
+               if (propagate_constants_accross_call (cs))
+                 push_node_to_stack (topo, cs->callee->function_symbol ());
+             }
          v = pop_node_from_stack (topo);
        }
 
index 1b78ccc3a2bf40a327a8125241f6d6432cb04848..0488254492acb6b5763c21c818b211a8ee16601d 100644 (file)
@@ -330,6 +330,10 @@ struct ipa_node_params
   /* Node has been completely replaced by clones and will be removed after
      ipa-cp is finished.  */
   unsigned node_dead : 1;
+  /* Node is involved in a recursion, potentionally indirect.  */
+  unsigned node_within_scc : 1;
+  /* Node is calling a private function called only once.  */
+  unsigned node_calling_single_call : 1;
 };
 
 /* ipa_node_params access functions.  Please use these to access fields that
index f890cb0e176ef397612e23d2d74ea09cc69900ba..5e2c7695865672649570e71fbbbfa991210f4258 100644 (file)
@@ -999,6 +999,18 @@ DEFPARAM (PARAM_IPA_CP_EVAL_THRESHOLD,
          "beneficial to clone.",
          500, 0, 0)
 
+DEFPARAM (PARAM_IPA_CP_RECURSION_PENALTY,
+         "ipa-cp-recursion-penalty",
+         "Percentage penalty the recursive functions will receive when they "
+         "are evaluated for cloning.",
+         40, 0, 100)
+
+DEFPARAM (PARAM_IPA_CP_SINGLE_CALL_PENALTY,
+         "ipa-cp-single-call-penalty",
+         "Percentage penalty functions containg a single call to another "
+         "function will receive when they are evaluated for cloning.",
+         15, 0, 100)
+
 DEFPARAM (PARAM_IPA_MAX_AGG_ITEMS,
          "ipa-max-agg-items",
          "Maximum number of aggregate content items for a parameter in "