From c9aa4821823dd926052b557599da982e26fbce1d Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Sat, 25 Dec 2010 03:32:58 -0800
Subject: [PATCH 4/4] Account for devirtualization in inlining heuristics.

---
 gcc/ipa-inline.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 7ac50dd..7bf4365 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -193,6 +193,75 @@ cgraph_estimate_size_after_inlining (struct cgraph_node *to,
   return size;
 }
 
+/* Estimate benefit from devirtualization opportunities should NODE be inlined.
+   INFO represents NODE's parameters' information if NODE were inlined.  */
+static int
+ipa_inline_devirt_benefit (struct cgraph_node *node,
+			   struct ipa_node_params *info)
+{
+  struct cgraph_edge *ie;
+  int devirt_benefit = 0;
+
+  for (ie = node->indirect_calls; ie; ie = ie->next_callee)
+    {
+      tree target;
+
+      if (ipcp_try_devirtualize_edge (ie, info, &target, NULL))
+	{
+	  int growth;
+	  struct cgraph_node *callee = cgraph_get_node (target);
+
+	  if (callee == NULL)
+	    continue;
+
+	  growth = cgraph_estimate_size_after_inlining (node, callee);
+	  growth -= ie->caller->global.size;
+
+	  /* Count benefit only from functions that definitely will be inlined
+	     if additional information from inlining NODE were available.  */
+	  if (growth < 0)
+	    devirt_benefit += -growth;
+	}
+    }
+
+  return devirt_benefit;
+}
+
+/* Estimate self size of the function after inlining EDGE.  */
+
+static int
+cgraph_estimate_size_after_inlining_edge (struct cgraph_edge *edge)
+{
+  int size;
+  int i, count;
+  struct ipa_node_params callee_info_, *callee_info = &callee_info_;
+
+  size = cgraph_estimate_size_after_inlining (edge->caller, edge->callee);
+
+  if (ipa_node_params_vector == NULL)
+    /* IPCP data structures are not set up yet.  */
+    return size;
+
+  /* Create a local copy of parameters' information.  */
+  ipa_copy_node_params (callee_info, IPA_NODE_REF (edge->callee));
+  /* Set type information to TOP.  */
+  count = ipa_get_param_count (callee_info);
+  for (i = 0; i < count; i++)
+    ipcp_set_type_lattice_to (ipcp_get_type_lattice (callee_info, i), IPA_TOP);
+  /* Propagate type information across EDGE.  */
+  if (ipcp_propagate_across_edge (edge, callee_info, false, true))
+    {
+      int devirt_benefit;
+      /* Calculate benefir from devirtualization opportunities.  */
+      devirt_benefit = ipa_inline_devirt_benefit (edge->callee, callee_info);
+      size -= devirt_benefit;
+    }
+  /* Clean up.  */
+  ipa_free_node_params_substructures (callee_info);
+
+  return size > 0 ? size : 0;
+}
+
 /* Scale frequency of NODE edges by FREQ_SCALE and increase loop nest
    by NEST.  */
 
@@ -351,7 +420,7 @@ cgraph_estimate_growth (struct cgraph_node *node)
       if (e->caller == node)
         self_recursive = true;
       if (e->inline_failed)
-	growth += (cgraph_estimate_size_after_inlining (e->caller, node)
+	growth += (cgraph_estimate_size_after_inlining_edge (e)
 		   - e->caller->global.size);
     }
 
@@ -513,9 +582,8 @@ static int
 cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
 {
   gcov_type badness;
-  int growth =
-    (cgraph_estimate_size_after_inlining (edge->caller, edge->callee)
-     - edge->caller->global.size);
+  int growth = (cgraph_estimate_size_after_inlining_edge (edge)
+		- edge->caller->global.size);
 
   if (edge->callee->local.disregard_inline_limits)
     return INT_MIN;
@@ -1077,7 +1145,7 @@ cgraph_decide_inlining_of_small_functions (void)
       
       callee = edge->callee;
 
-      growth = (cgraph_estimate_size_after_inlining (edge->caller, edge->callee)
+      growth = (cgraph_estimate_size_after_inlining_edge (edge)
 		- edge->caller->global.size);
 
       if (dump_file)
-- 
1.6.2.4

