From 2a6770dc4988d74d56a211b4a289544d1d06dda9 Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@codesourcery.com>
Date: Sat, 25 Dec 2010 03:19:15 -0800
Subject: [PATCH 2/4] Refactor ipa-cp.c to operate on type lattices.

---
 gcc/ipa-cp.c   |  489 +++++++++++++++++++++++++++++++++++---------------------
 gcc/ipa-prop.c |   37 +++--
 gcc/ipa-prop.h |   55 ++++---
 3 files changed, 364 insertions(+), 217 deletions(-)

diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index ce6fd59..937de01 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -125,9 +125,8 @@ along with GCC; see the file COPYING3.  If not see
    just like propagating scalar constants and then examining whether virtual
    calls which take a parameter as their object fold to the same target for all
    these types.  If we cannot enumerate all types or there is a type which does
-   not have any BINFO associated with it, cannot_devirtualize of the associated
-   parameter descriptor is set which is an equivalent of BOTTOM lattice value
-   in standard IPA constant propagation.
+   not have any BINFO associated with it, ipcp_type_lattice.type of
+   the associated parameter descriptor is set to IPA_BOTTOM lattice value.
 */
 
 #include "config.h"
@@ -282,16 +281,60 @@ ipa_lattice_meet (struct ipcp_lattice *res, struct ipcp_lattice *lat1,
 static inline struct ipcp_lattice *
 ipcp_get_lattice (struct ipa_node_params *info, int i)
 {
+  gcc_assert (i < info->param_count);
   return &(info->params[i].ipcp_lattice);
 }
 
+/* Return the type lattice corresponding to the Ith formal parameter of
+   the function described by INFO.  */
+struct ipcp_type_lattice *
+ipcp_get_type_lattice (struct ipa_node_params *info, int i)
+{
+  gcc_assert (i < info->param_count);
+  return &(info->params[i].ipcp_type_lattice);
+}
+
+/* Set type lattice LAT to either top or bottom value and
+   free underlying structures.  */
+void
+ipcp_set_type_lattice_to (struct ipcp_type_lattice *lat,
+			  enum ipa_lattice_type type)
+{
+  gcc_assert (type == IPA_TOP || type == IPA_BOTTOM);
+  lat->type = type;
+  VEC_free (tree, heap, lat->types);
+}
+
+/* Copy type lattice.  */
+void
+ipcp_copy_type_lattice (struct ipcp_type_lattice *dest,
+			struct ipcp_type_lattice *src)
+{
+  gcc_assert (src != dest
+	      && (src->types != dest->types || src->types == NULL));
+
+  if (src->type == IPA_CONST_VALUE)
+    {
+      dest->type = src->type;
+      VEC_truncate (tree, dest->types, 0);
+      VEC_safe_splice (tree, heap, dest->types, src->types);
+    }
+  else
+    ipcp_set_type_lattice_to (dest, src->type);
+}
+
 /* Given the jump function JFUNC, compute the lattice LAT that describes the
-   value coming down the callsite. INFO describes the caller node so that
+   value coming down the callsite.  CALLER is the caller node so that
    pass-through jump functions can be evaluated.  */
 static void
-ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
+ipcp_lattice_from_jfunc (struct cgraph_node *caller, struct ipcp_lattice *lat,
 			 struct ipa_jump_func *jfunc)
 {
+  struct ipa_node_params *info;
+
+  gcc_assert (caller->global.inlined_to == NULL);
+  info = IPA_NODE_REF (caller);
+
   if (jfunc->type == IPA_JF_CONST)
     {
       lat->type = IPA_CONST_VALUE;
@@ -384,6 +427,7 @@ ipcp_print_all_lattices (FILE * f)
       for (i = 0; i < count; i++)
 	{
 	  struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
+	  struct ipcp_type_lattice *type_lat = ipcp_get_type_lattice (info, i);
 
 	  fprintf (f, "    param [%d]: ", i);
 	  if (lat->type == IPA_CONST_VALUE)
@@ -403,9 +447,9 @@ ipcp_print_all_lattices (FILE * f)
 	    fprintf (f, "type is TOP");
 	  else
 	    fprintf (f, "type is BOTTOM");
-	  if (ipa_param_cannot_devirtualize_p (info, i))
+	  if (type_lat->type == IPA_BOTTOM)
 	    fprintf (f, " - cannot_devirtualize set\n");
-	  else if (ipa_param_types_vec_empty (info, i))
+	  else if (type_lat->type == IPA_TOP)
 	    fprintf (f, " - type list empty\n");
 	  else
 	    fprintf (f, "\n");
@@ -545,19 +589,6 @@ ipcp_cloning_candidate_p (struct cgraph_node *node)
   return true;
 }
 
-/* Mark parameter with index I of function described by INFO as unsuitable for
-   devirtualization.  Return true if it has already been marked so.  */
-
-static bool
-ipa_set_param_cannot_devirtualize (struct ipa_node_params *info, int i)
-{
-  bool ret = info->params[i].cannot_devirtualize;
-  info->params[i].cannot_devirtualize = true;
-  if (info->params[i].types)
-    VEC_free (tree, heap, info->params[i].types);
-  return ret;
-}
-
 /* Initialize ipcp_lattices array.  The lattices corresponding to supported
    types (integers, real types and Fortran constants defined as const_decls)
    are initialized to IPA_TOP, the rest of them to IPA_BOTTOM.  */
@@ -581,9 +612,12 @@ ipcp_initialize_node_lattices (struct cgraph_node *node)
 
   for (i = 0; i < ipa_get_param_count (info) ; i++)
     {
+      struct ipcp_type_lattice *type_lat;
+
       ipcp_get_lattice (info, i)->type = type;
-      if (type == IPA_BOTTOM)
-	ipa_set_param_cannot_devirtualize (info, i);
+      type_lat = ipcp_get_type_lattice (info, i);
+      type_lat->type = type;
+      gcc_assert (type_lat->types == NULL);
     }
 }
 
@@ -655,7 +689,10 @@ ipcp_change_tops_to_bottom (void)
       count = ipa_get_param_count (info);
       for (i = 0; i < count; i++)
 	{
-	  struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
+	  struct ipcp_lattice *lat;
+	  struct ipcp_type_lattice *type_lat;
+
+	  lat = ipcp_get_lattice (info, i);
 	  if (lat->type == IPA_TOP)
 	    {
 	      prop_again = true;
@@ -668,11 +705,12 @@ ipcp_change_tops_to_bottom (void)
 		}
 	      lat->type = IPA_BOTTOM;
 	    }
-	  if (!ipa_param_cannot_devirtualize_p (info, i)
-	      && ipa_param_types_vec_empty (info, i))
+
+	  type_lat = ipcp_get_type_lattice (info, i);
+	  if (type_lat->type == IPA_TOP)
 	    {
 	      prop_again = true;
-	      ipa_set_param_cannot_devirtualize (info, i);
+	      ipcp_set_type_lattice_to (type_lat, IPA_BOTTOM);
 	      if (dump_file)
 		{
 		  fprintf (dump_file, "Marking param ");
@@ -687,117 +725,221 @@ ipcp_change_tops_to_bottom (void)
   return prop_again;
 }
 
-/* Insert BINFO to the list of known types of parameter number I of the
-   function described by CALLEE_INFO.  Return true iff the type information
-   associated with the callee parameter changed in any way.  */
-
-static bool
-ipcp_add_param_type (struct ipa_node_params *callee_info, int i, tree binfo)
+/* Given the jump function JFUNC, compute the lattice LAT that describes the
+   types coming down the callsite.  CALLER is the caller node so that
+   pass-through jump functions can be evaluated.  */
+static void
+ipcp_set_type_lattice_from_jfunc (struct cgraph_node *caller,
+				  struct ipcp_type_lattice *lat,
+				  struct ipa_jump_func *jfunc)
 {
-  int j, count;
-
-  if (ipa_param_cannot_devirtualize_p (callee_info, i))
-    return false;
+  /* Start with bottom value.  */
+  ipcp_set_type_lattice_to (lat, IPA_BOTTOM);
 
-  if (callee_info->params[i].types)
+  switch (jfunc->type)
     {
-      count = VEC_length (tree, callee_info->params[i].types);
-      for (j = 0; j < count; j++)
-	if (VEC_index (tree, callee_info->params[i].types, j) == binfo)
-	  return false;
-    }
+    case IPA_JF_UNKNOWN:
+    case IPA_JF_CONST_MEMBER_PTR:
+    case IPA_JF_CONST:
+      return;
 
-  if (VEC_length (tree, callee_info->params[i].types)
-      == (unsigned) PARAM_VALUE (PARAM_DEVIRT_TYPE_LIST_SIZE))
-    return !ipa_set_param_cannot_devirtualize (callee_info, i);
+    case IPA_JF_KNOWN_TYPE:
+      lat->type = IPA_CONST_VALUE;
+      VEC_safe_push (tree, heap, lat->types, jfunc->value.base_binfo);
+      return;
 
-  VEC_safe_push (tree, heap, callee_info->params[i].types, binfo);
-  return true;
-}
+    case IPA_JF_PASS_THROUGH:
+    case IPA_JF_ANCESTOR:
+      {
+	int caller_idx;
+	struct ipa_node_params *info;
+	struct ipcp_type_lattice *caller_lat;
 
-/* Copy known types information for parameter number CALLEE_IDX of CALLEE_INFO
-   from a parameter of CALLER_INFO as described by JF.  Return true iff the
-   type information changed in any way.  JF must be a pass-through or an
-   ancestor jump function.  */
+	if (jfunc->type == IPA_JF_PASS_THROUGH)
+	  {
+	    if (jfunc->value.pass_through.operation != NOP_EXPR)
+	      return;
+	    caller_idx = jfunc->value.pass_through.formal_id;
+	  }
+	else
+	  caller_idx = jfunc->value.ancestor.formal_id;
 
-static bool
-ipcp_copy_types (struct ipa_node_params *caller_info,
-		 struct ipa_node_params *callee_info,
-		 int callee_idx, struct ipa_jump_func *jf)
-{
-  int caller_idx, j, count;
-  bool res;
+	/* If CALLER was inlined then JFUNC is already updated to refer to
+	   the CALLER->global.inlined_to.  */
+	if (caller->global.inlined_to)
+	  caller = caller->global.inlined_to;
 
-  if (ipa_param_cannot_devirtualize_p (callee_info, callee_idx))
-    return false;
+	gcc_assert (caller->global.inlined_to == NULL);
+	info = IPA_NODE_REF (caller);
 
-  if (jf->type == IPA_JF_PASS_THROUGH)
-    {
-      if (jf->value.pass_through.operation != NOP_EXPR)
-	{
-	  ipa_set_param_cannot_devirtualize (callee_info, callee_idx);
-	  return true;
-	}
-      caller_idx = jf->value.pass_through.formal_id;
+	caller_lat = ipcp_get_type_lattice (info, caller_idx);
+	if (caller_lat->type == IPA_BOTTOM)
+	  return;
+
+	gcc_assert (caller_lat->type == IPA_TOP
+		    || !VEC_empty (tree, caller_lat->types));
+
+	if (jfunc->type == IPA_JF_PASS_THROUGH)
+	  ipcp_copy_type_lattice (lat, caller_lat);
+	else /* jfunc->type == IPA_JF_ANCESTOR */
+	  {
+	    unsigned i;
+	    tree binfo;
+
+	    FOR_EACH_VEC_ELT (tree, caller_lat->types, i, binfo)
+	      {
+		binfo = get_binfo_at_offset (binfo,
+					     jfunc->value.ancestor.offset,
+					     jfunc->value.ancestor.type);
+		if (!binfo)
+		  break;
+		VEC_safe_push (tree, heap, lat->types, binfo);
+	      }
+
+	    if (i == VEC_length (tree, caller_lat->types))
+	      lat->type = caller_lat->type;
+	    else
+	      ipcp_set_type_lattice_to (lat, IPA_BOTTOM);
+	  }
+      }
+      return;
     }
-  else
-    caller_idx = jf->value.ancestor.formal_id;
+}
 
-  if (ipa_param_cannot_devirtualize_p (caller_info, caller_idx))
+/* Compute Meet of LAT1 and LAT2 in RES.
+   Return true if RES differs from LAT1.
+   Meet (IPA_BOTTOM, x) = IPA_BOTTOM
+   Meet (IPA_TOP,x) = x
+   Meet (types_a,types_b) = join (types_a,types_b).  */
+static bool
+ipcp_type_lattice_meet (struct ipcp_type_lattice *res,
+			struct ipcp_type_lattice *lat1,
+			struct ipcp_type_lattice *lat2)
+{
+  if (lat1->type == IPA_BOTTOM || lat2->type == IPA_BOTTOM)
     {
-      ipa_set_param_cannot_devirtualize (callee_info, callee_idx);
-      return true;
+      ipcp_set_type_lattice_to (res, IPA_BOTTOM);
+      return lat1->type != IPA_BOTTOM;
+    }
+  else if (lat1->type == IPA_TOP)
+    {
+      gcc_assert (VEC_empty (tree, lat1->types));
+      ipcp_copy_type_lattice (res, lat2);
+      return lat1->type != res->type;
     }
+  else if (lat2->type == IPA_TOP)
+    {
+      gcc_assert (VEC_empty (tree, lat2->types));
+      ipcp_copy_type_lattice (res, lat1);
+      return false;
+    }
+  else
+    {
+      int j;
+      tree binfo2;
+      bool changed_p = false;
 
-  if (!caller_info->params[caller_idx].types)
-    return false;
+      gcc_assert (lat1->type == IPA_CONST_VALUE
+		  && !VEC_empty (tree, lat1->types)
+		  && lat2->type == IPA_CONST_VALUE
+		  && !VEC_empty (tree, lat2->types));
 
-  res = false;
-  count = VEC_length (tree, caller_info->params[caller_idx].types);
-  for (j = 0; j < count; j++)
-    {
-      tree binfo = VEC_index (tree, caller_info->params[caller_idx].types, j);
-      if (jf->type == IPA_JF_ANCESTOR)
+      /* Copy LAT1 to RES.  */
+      ipcp_copy_type_lattice (res, lat1);
+
+      /* Add elements of LAT2 to RES that are not present in LAT1.  */
+      FOR_EACH_VEC_ELT (tree, lat2->types, j, binfo2)
 	{
-	  binfo = get_binfo_at_offset (binfo, jf->value.ancestor.offset,
-				       jf->value.ancestor.type);
-	  if (!binfo)
+	  int i;
+	  tree binfo1;
+
+	  FOR_EACH_VEC_ELT (tree, lat1->types, i, binfo1)
 	    {
-	      ipa_set_param_cannot_devirtualize (callee_info, callee_idx);
-	      return true;
+	      if (binfo1 == binfo2)
+		break;
+	    }
+
+	  if (binfo1 == NULL_TREE)
+	    {
+	      if (VEC_length (tree, res->types)
+		  == (unsigned) PARAM_VALUE (PARAM_DEVIRT_TYPE_LIST_SIZE))
+		{
+		  ipcp_set_type_lattice_to (res, IPA_BOTTOM);
+		  return true;
+		}
+
+	      VEC_safe_push (tree, heap, res->types, binfo2);
+	      changed_p = true;
 	    }
 	}
-      res |= ipcp_add_param_type (callee_info, callee_idx, binfo);
+
+      return changed_p;
     }
-  return res;
 }
 
-/* Propagate type information for parameter of CALLEE_INFO number I as
-   described by JF.  CALLER_INFO describes the caller.  Return true iff the
-   type information changed in any way.  */
-
-static bool
-ipcp_propagate_types (struct ipa_node_params *caller_info,
-		      struct ipa_node_params *callee_info,
-		      struct ipa_jump_func *jf, int i)
+/* Propagate information across edge CS.  Store the result in CALLEE_INFO.
+   Propagate value information if PROPAGATE_VALUES, propagate type information
+   if PROPAGATE_TYPES.
+   Return true if information in CALLEE_INFO has changed.  */
+bool
+ipcp_propagate_across_edge (struct cgraph_edge *cs,
+			    struct ipa_node_params *callee_info,
+			    bool propagate_values, bool propagate_types)
 {
-  switch (jf->type)
+  int i, count;
+  struct ipa_edge_args *args = IPA_EDGE_REF (cs);
+  bool changed = false;
+
+  if (ipa_is_called_with_var_arguments (callee_info)
+      || !cs->callee->analyzed
+      || ipa_is_called_with_var_arguments (callee_info))
+    return false;
+
+  count = ipa_get_cs_argument_count (args);
+  for (i = 0; i < count; i++)
     {
-    case IPA_JF_UNKNOWN:
-    case IPA_JF_CONST_MEMBER_PTR:
-    case IPA_JF_CONST:
-      break;
+      struct ipa_jump_func *jump_func = ipa_get_ith_jump_func (args, i);
 
-    case IPA_JF_KNOWN_TYPE:
-      return ipcp_add_param_type (callee_info, i, jf->value.base_binfo);
+      if (propagate_values)
+	{
+	  struct ipcp_lattice *dest_lat;
+	  struct ipcp_lattice inc_lat = { IPA_BOTTOM, NULL };
+	  struct ipcp_lattice new_lat = { IPA_BOTTOM, NULL };
+
+	  /* Process value lattice.  */
+	  ipcp_lattice_from_jfunc (cs->caller, &inc_lat, jump_func);
+	  dest_lat = ipcp_get_lattice (callee_info, i);
+	  ipa_lattice_meet (&new_lat, &inc_lat, dest_lat);
+	  if (ipcp_lattice_changed (&new_lat, dest_lat))
+	    {
+	      *dest_lat = new_lat;
+	      changed |= true;
+	    }
+	}
 
-    case IPA_JF_PASS_THROUGH:
-    case IPA_JF_ANCESTOR:
-      return ipcp_copy_types (caller_info, callee_info, i, jf);
+      if (propagate_types)
+	{
+	  struct ipcp_type_lattice *dest_type_lat;
+	  struct ipcp_type_lattice inc_type_lat = { IPA_TOP, NULL };
+	  struct ipcp_type_lattice new_type_lat = { IPA_TOP, NULL };
+
+	  /* Process type lattice.  */
+	  ipcp_set_type_lattice_from_jfunc (cs->caller, &inc_type_lat,
+					    jump_func);
+	  dest_type_lat = ipcp_get_type_lattice (callee_info, i);
+	  if (ipcp_type_lattice_meet (&new_type_lat,
+				      dest_type_lat, &inc_type_lat))
+	    {
+	      ipcp_copy_type_lattice (dest_type_lat, &new_type_lat);
+	      changed |= true;
+	    }
+
+	  ipcp_set_type_lattice_to (&inc_type_lat, IPA_TOP);
+	  ipcp_set_type_lattice_to (&new_type_lat, IPA_TOP);
+	}
     }
 
-  /* If we reach this we cannot use this parameter for devirtualization.  */
-  return !ipa_set_param_cannot_devirtualize (callee_info, i);
+  return changed;
 }
 
 /* Interprocedural analysis. The algorithm propagates constants from the
@@ -805,14 +947,8 @@ ipcp_propagate_types (struct ipa_node_params *caller_info,
 static void
 ipcp_propagate_stage (void)
 {
-  int i;
-  struct ipcp_lattice inc_lat = { IPA_BOTTOM, NULL };
-  struct ipcp_lattice new_lat = { IPA_BOTTOM, NULL };
-  struct ipcp_lattice *dest_lat;
   struct cgraph_edge *cs;
-  struct ipa_jump_func *jump_func;
   struct ipa_func_list *wl;
-  int count;
 
   ipa_check_create_node_params ();
   ipa_check_create_edge_args ();
@@ -822,35 +958,13 @@ ipcp_propagate_stage (void)
   while (wl)
     {
       struct cgraph_node *node = ipa_pop_func_from_list (&wl);
-      struct ipa_node_params *info = IPA_NODE_REF (node);
 
       for (cs = node->callees; cs; cs = cs->next_callee)
 	{
 	  struct ipa_node_params *callee_info = IPA_NODE_REF (cs->callee);
-	  struct ipa_edge_args *args = IPA_EDGE_REF (cs);
-
-	  if (ipa_is_called_with_var_arguments (callee_info)
-	      || !cs->callee->analyzed
-	      || ipa_is_called_with_var_arguments (callee_info))
-	    continue;
-
-	  count = ipa_get_cs_argument_count (args);
-	  for (i = 0; i < count; i++)
-	    {
-	      jump_func = ipa_get_ith_jump_func (args, i);
-	      ipcp_lattice_from_jfunc (info, &inc_lat, jump_func);
-	      dest_lat = ipcp_get_lattice (callee_info, i);
-	      ipa_lattice_meet (&new_lat, &inc_lat, dest_lat);
-	      if (ipcp_lattice_changed (&new_lat, dest_lat))
-		{
-		  dest_lat->type = new_lat.type;
-		  dest_lat->constant = new_lat.constant;
-		  ipa_push_func_to_list (&wl, cs->callee);
-		}
 
-	      if (ipcp_propagate_types (info, callee_info, jump_func, i))
-		ipa_push_func_to_list (&wl, cs->callee);
-	    }
+	  if (ipcp_propagate_across_edge (cs, callee_info, true, true))
+	    ipa_push_func_to_list (&wl, cs->callee);
 	}
     }
 }
@@ -1017,12 +1131,13 @@ ipcp_need_redirect_p (struct cgraph_edge *cs)
     {
       struct ipcp_lattice *lat = ipcp_get_lattice (orig_callee_info, i);
       struct ipa_jump_func *jump_func;
+      struct ipcp_type_lattice *type_lat;
 
       jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
+      type_lat = ipcp_get_type_lattice (orig_callee_info, i);
       if ((ipcp_lat_is_const (lat)
 	   && jump_func->type != IPA_JF_CONST)
-	  || (!ipa_param_cannot_devirtualize_p (orig_callee_info, i)
-	      && !ipa_param_types_vec_empty (orig_callee_info, i)
+	  || (type_lat->type == IPA_CONST_VALUE
 	      && jump_func->type != IPA_JF_CONST
 	      && jump_func->type != IPA_JF_KNOWN_TYPE))
 	return true;
@@ -1191,57 +1306,71 @@ ipcp_estimate_cloning_cost (struct cgraph_node *node)
   return cost + 1;
 }
 
+/* Try devirtualize polymorphic edge IE.  Use data in INFO to infer types
+   that reach IE.
+   Return true on success and set TARGET_PTR and DELTA_PTR to credentials of
+   the direct call.  */
+bool
+ipcp_try_devirtualize_edge (struct cgraph_edge *ie,
+			    struct ipa_node_params *info,
+			    tree *target_ptr, tree *delta_ptr)
+{
+  int param_index;
+  unsigned j;
+  HOST_WIDE_INT token;
+  tree target, delta, binfo;
+  struct ipcp_type_lattice *type_lat;
+
+  if (!ie->indirect_info->polymorphic)
+    return false;
+  param_index = ie->indirect_info->param_index;
+  type_lat = ipcp_get_type_lattice (info, param_index);
+  if (param_index == -1
+      || type_lat->type != IPA_CONST_VALUE)
+    return false;
+
+  token = ie->indirect_info->otr_token;
+  target = NULL_TREE;
+  delta = NULL_TREE;
+  FOR_EACH_VEC_ELT (tree, type_lat->types, j, binfo)
+    {
+      tree d;
+      tree t = gimple_get_virt_mehtod_for_binfo (token, binfo, &d, true);
+
+      if (!t)
+	return false;
+      else if (!target)
+	{
+	  target = t;
+	  delta = d;
+	}
+      else if (target != t || !tree_int_cst_equal (delta, d))
+	return false;
+    }
+
+  gcc_assert (target != NULL_TREE && delta != NULL_TREE);
+  if (target_ptr)
+    *target_ptr = target;
+  if (delta_ptr)
+    *delta_ptr = delta;
+  return true;
+}
+
 /* Walk indirect calls of NODE and if any polymorphic can be turned into a
    direct one now, do so.  */
 
 static void
 ipcp_process_devirtualization_opportunities (struct cgraph_node *node)
 {
-  struct ipa_node_params *info = IPA_NODE_REF (node);
   struct cgraph_edge *ie, *next_ie;
 
   for (ie = node->indirect_calls; ie; ie = next_ie)
     {
-      int param_index, types_count, j;
-      HOST_WIDE_INT token;
       tree target, delta;
 
       next_ie = ie->next_callee;
-      if (!ie->indirect_info->polymorphic)
-	continue;
-      param_index = ie->indirect_info->param_index;
-      if (param_index == -1
-	  || ipa_param_cannot_devirtualize_p (info, param_index)
-	  || ipa_param_types_vec_empty (info, param_index))
-	continue;
-
-      token = ie->indirect_info->otr_token;
-      target = NULL_TREE;
-      types_count = VEC_length (tree, info->params[param_index].types);
-      for (j = 0; j < types_count; j++)
-	{
-	  tree binfo = VEC_index (tree, info->params[param_index].types, j);
-	  tree d;
-	  tree t = gimple_get_virt_mehtod_for_binfo (token, binfo, &d, true);
-
-	  if (!t)
-	    {
-	      target = NULL_TREE;
-	      break;
-	    }
-	  else if (!target)
-	    {
-	      target = t;
-	      delta = d;
-	    }
-	  else if (target != t || !tree_int_cst_equal (delta, d))
-	    {
-	      target = NULL_TREE;
-	      break;
-	    }
-	}
 
-      if (target)
+      if (ipcp_try_devirtualize_edge (ie, IPA_NODE_REF (node), &target, &delta))
 	ipa_make_edge_direct_to_target (ie, target, delta);
     }
 }
@@ -1258,11 +1387,11 @@ ipcp_const_param_count (struct cgraph_node *node)
   for (i = 0; i < count; i++)
     {
       struct ipcp_lattice *lat = ipcp_get_lattice (info, i);
+      struct ipcp_type_lattice *type_lat = ipcp_get_type_lattice (info, i);
       if ((ipcp_lat_is_insertable (lat)
 	  /* Do not count obviously unused arguments.  */
 	   && ipa_is_param_used (info, i))
-	  || (!ipa_param_cannot_devirtualize_p (info, i)
-	      && !ipa_param_types_vec_empty (info, i)))
+	  || type_lat->type == IPA_CONST_VALUE)
 	const_param++;
     }
   return const_param;
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index b6e3f37..4b2cde8 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -1820,18 +1820,13 @@ ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
     bitmap_set_bit (iinlining_processed_edges, dst->uid);
 }
 
-/* Hook that is called by cgraph.c when a node is duplicated.  */
-
-static void
-ipa_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
-			   __attribute__((unused)) void *data)
+/* Copy node parameters' information.  */
+void
+ipa_copy_node_params (struct ipa_node_params *new_info,
+		      struct ipa_node_params *old_info)
 {
-  struct ipa_node_params *old_info, *new_info;
   int param_count, i;
 
-  ipa_check_create_node_params ();
-  old_info = IPA_NODE_REF (src);
-  new_info = IPA_NODE_REF (dst);
   param_count = ipa_get_param_count (old_info);
 
   ipa_set_param_count (new_info, param_count);
@@ -1839,8 +1834,13 @@ ipa_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
     duplicate_array (old_info->params,
 		     sizeof (struct ipa_param_descriptor) * param_count);
   for (i = 0; i < param_count; i++)
-    new_info->params[i].types = VEC_copy (tree, heap,
- 					  old_info->params[i].types);
+    {
+      struct ipcp_type_lattice *new_lat = ipcp_get_type_lattice (new_info, i);
+      /* Unshare new_lat->types.  */
+      new_lat->types = NULL;
+      ipcp_copy_type_lattice (new_lat,
+			      ipcp_get_type_lattice (old_info, i));
+    }
   new_info->ipcp_orig_node = old_info->ipcp_orig_node;
   new_info->count_scale = old_info->count_scale;
 
@@ -1849,6 +1849,21 @@ ipa_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
   new_info->node_enqueued = old_info->node_enqueued;
 }
 
+/* Hook that is called by cgraph.c when a node is duplicated.  */
+
+static void
+ipa_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
+			   __attribute__((unused)) void *data)
+{
+  struct ipa_node_params *old_info, *new_info;
+
+  ipa_check_create_node_params ();
+  old_info = IPA_NODE_REF (src);
+  new_info = IPA_NODE_REF (dst);
+
+  ipa_copy_node_params (new_info, old_info);
+}
+
 /* Register our cgraph hooks if they are not already there.  */
 
 void
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 9fd2a39..8107e17 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -156,21 +156,28 @@ struct ipcp_lattice
   tree constant;
 };
 
+/* All formal parameters in the program have their possible types computed by
+   the interprocedural stage of IPCP. See enum ipa_lattice_type for
+   the various types of lattices supported */
+struct ipcp_type_lattice
+{
+  enum ipa_lattice_type type;
+  /* Vector of BINFOs of types that this argument might encounter.
+     Non-null if TYPE is IPA_CONST_VALUE.  */
+  VEC (tree, heap) *types;
+};
+
 /* Structure describing a single formal parameter.  */
 struct ipa_param_descriptor
 {
-  /* IPA-CP lattice.  */
+  /* IPA-CP value lattice.  */
   struct ipcp_lattice ipcp_lattice;
+  /* IPA-CP type lattice.  */
+  struct ipcp_type_lattice ipcp_type_lattice;
   /* PARAM_DECL of this parameter.  */
   tree decl;
-  /* Vector of BINFOs of types that this argument might encounter.  NULL
-     basically means a top value, bottom is marked by the cannot_devirtualize
-     flag below.*/
-  VEC (tree, heap) *types;
   /* The parameter is used.  */
   unsigned used : 1;
-  /* Set when parameter type cannot be used for devirtualization.  */
-  unsigned cannot_devirtualize : 1;
 };
 
 /* ipa_node_params stores information related to formal parameters of functions
@@ -240,25 +247,6 @@ ipa_is_param_used (struct ipa_node_params *info, int i)
   return info->params[i].used;
 }
 
-/* Return the cannot_devirtualize flag corresponding to the Ith formal
-   parameter of the function associated with INFO.  The corresponding function
-   to set the flag is ipa_set_param_cannot_devirtualize.  */
-
-static inline bool
-ipa_param_cannot_devirtualize_p (struct ipa_node_params *info, int i)
-{
-  return info->params[i].cannot_devirtualize;
-}
-
-/* Return true iff the vector of possible types of the Ith formal parameter of
-   the function associated with INFO is empty.  */
-
-static inline bool
-ipa_param_types_vec_empty (struct ipa_node_params *info, int i)
-{
-  return info->params[i].types == NULL;
-}
-
 /* Flag this node as having callers with variable number of arguments.  */
 
 static inline void
@@ -352,6 +340,7 @@ void ipa_free_all_edge_args (void);
 void ipa_create_all_structures_for_iinln (void);
 void ipa_free_all_structures_after_ipa_cp (void);
 void ipa_free_all_structures_after_iinln (void);
+void ipa_copy_node_params (struct ipa_node_params *, struct ipa_node_params *);
 void ipa_register_cgraph_hooks (void);
 
 /* This function ensures the array of node param infos is big enough to
@@ -429,6 +418,14 @@ void ipa_initialize_node_params (struct cgraph_node *node);
 bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
 					VEC (cgraph_edge_p, heap) **new_edges);
 
+/* Tracking of type information for function formal parameters.  */
+struct ipcp_type_lattice * ipcp_get_type_lattice (struct ipa_node_params *,
+						  int);
+void ipcp_set_type_lattice_to (struct ipcp_type_lattice *,
+			       enum ipa_lattice_type);
+void ipcp_copy_type_lattice (struct ipcp_type_lattice *,
+			     struct ipcp_type_lattice *);
+
 /* Indirect edge and binfo processing.  */
 struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree,
 						    tree);
@@ -520,4 +517,10 @@ void ipa_update_after_lto_read (void);
 tree build_ref_for_offset (location_t, tree, HOST_WIDE_INT, tree,
 			   gimple_stmt_iterator *, bool);
 
+bool ipcp_propagate_across_edge (struct cgraph_edge *,
+				 struct ipa_node_params *,
+				 bool, bool);
+bool ipcp_try_devirtualize_edge (struct cgraph_edge *,
+				 struct ipa_node_params *, tree *, tree *);
+
 #endif /* IPA_PROP_H */
-- 
1.6.2.4

