diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index fdac1b2ca09ef575ad40599ec8f0e19a2057730b..c108ac2108d311aa427e669147f20b6fd7c458cd 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,42 @@
+2019-11-02  Jan Hubicka  <hubicka@ucw.cz>
+
+	* ipa-fnsummary.c (set_cond_stmt_execution_predicate,
+	set_switch_stmt_execution_predicate, compute_bb_predicates,
+	will_be_nonconstant_expr_predicate,
+	phi_result_unknown_predicate,
+	analyze_function_body): Pass arround params summary.
+	(ipa_call_context::duplicate_from): New comment;
+	only duplicate useful values.
+	(ipa_call_context::equal_to): Only compare useful values.
+	(remap_edge_summaries): Pass params_summary.
+	(remap_hint_predicate): Likewise.
+	(ipa_merge_fn_summary_after_inlining): Likewise.
+	(inline_read_section): Initialize params summary used flags.
+	* ipa-predicate.c (predicate::remap_after_inlining): Pass
+	around param_summary.
+	(add_condition): Initialized used params summary flags.
+	* ipa-predicate.h (inline_param_summary::equals_to): Make const.
+	(inline_param_summary::useless_p): New predicate.
+	(remap_after_inlining, add_condition): Update prototype
+	* ipa-prop.c (ipa_populate_param_decls): Watch overflow in
+	move_cost.
+	(ipa_note_param_call): Add parameter POLYMORPHIC; update params
+	summaries.
+	(ipa_analyze_indirect_call_uses): Update use of ipa_note_param_call.
+	(ipa_analyze_virtual_call_uses): Likewise.
+	(update_indirect_edges_after_inlining): Update param summaries.
+	(ipa_print_node_params): Print used flags.
+	(ipa_read_indirect_edge_info): Update param summareis.
+	* ipa-prop.h (ipa_param_descriptor): Add
+	used_by_ipa_predicates, used_by_indirect_call
+	and used_by_polymorphic_call.
+	(ipa_set_param_used_by_ipa_predicates,
+	ipa_set_param_used_by_indirect_call,
+	ipa_set_param_used_by_polymorphic_call,
+	ipa_is_param_used_by_ipa_predicates,
+	ipa_is_param_used_by_indirect_call,
+	ipa_is_param_used_by_polymorphic_call): New inline functions.
+
 2019-11-02  Jan Hubicka  <hubicka@ucw.cz>
 
 	* ipa-fnsummary.c (ipa_call_context::duplicate_from): New
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index eaf904cd4017462ab45d041a672c899d90b4359a..4a3cb760a265ba0b5b13eb785a84736b11b17db6 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -1312,6 +1312,7 @@ fail:
 static void
 set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi,
 				   class ipa_fn_summary *summary,
+				   class ipa_node_params *params_summary,
 				   basic_block bb)
 {
   gimple *last;
@@ -1354,7 +1355,8 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi,
 	      && !dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest))
 	    {
 	      predicate p
-		= add_condition (summary, index, param_type, &aggpos,
+		= add_condition (summary, params_summary, index,
+			       	 param_type, &aggpos,
 				 this_code, gimple_cond_rhs (last), param_ops);
 	      e->aux = edge_predicate_pool.allocate ();
 	      *(predicate *) e->aux = p;
@@ -1387,7 +1389,8 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi,
     return;
   FOR_EACH_EDGE (e, ei, bb->succs) if (e->flags & EDGE_FALSE_VALUE)
     {
-      predicate p = add_condition (summary, index, param_type, &aggpos,
+      predicate p = add_condition (summary, params_summary, index,
+		     		   param_type, &aggpos,
 				   predicate::is_not_constant, NULL_TREE);
       e->aux = edge_predicate_pool.allocate ();
       *(predicate *) e->aux = p;
@@ -1401,6 +1404,7 @@ set_cond_stmt_execution_predicate (struct ipa_func_body_info *fbi,
 static void
 set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
 				     class ipa_fn_summary *summary,
+				     class ipa_node_params *params_summary,
 				     basic_block bb)
 {
   gimple *lastg;
@@ -1470,15 +1474,15 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
       if (dominated_by_p (CDI_POST_DOMINATORS, bb, e->dest))
 	p = true;
       else if (min == max)
-	p = add_condition (summary, index, param_type, &aggpos, EQ_EXPR,
-			   min, param_ops);
+	p = add_condition (summary, params_summary, index, param_type,
+		           &aggpos, EQ_EXPR, min, param_ops);
       else
 	{
 	  predicate p1, p2;
-	  p1 = add_condition (summary, index, param_type, &aggpos, GE_EXPR,
-			      min, param_ops);
-	  p2 = add_condition (summary, index, param_type, &aggpos, LE_EXPR,
-			      max, param_ops);
+	  p1 = add_condition (summary, params_summary, index, param_type,
+			      &aggpos, GE_EXPR, min, param_ops);
+	  p2 = add_condition (summary,  params_summary,index, param_type,
+			      &aggpos, LE_EXPR, max, param_ops);
 	  p = p1 & p2;
 	}
       *(class predicate *) e->aux
@@ -1559,7 +1563,8 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
       tree max = ranges[i].second;
 
       if (min == max)
-	p_seg &= add_condition (summary, index, param_type, &aggpos, NE_EXPR,
+	p_seg &= add_condition (summary, params_summary, index,
+		       		param_type, &aggpos, NE_EXPR,
 				min, param_ops);
       else
 	{
@@ -1567,7 +1572,8 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
 	     of switch index.  */
 	  if (wi::lt_p (vr_wmin, wi::to_wide (min), TYPE_SIGN (type)))
 	    {
-	      p_seg &= add_condition (summary, index, param_type, &aggpos,
+	      p_seg &= add_condition (summary, params_summary, index,
+			     	      param_type, &aggpos,
 				      LT_EXPR, min, param_ops);
 	      p_all = p_all.or_with (summary->conds, p_seg);
 	    }
@@ -1580,7 +1586,8 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
 	      break;
 	    }
 
-	  p_seg = add_condition (summary, index, param_type, &aggpos, GT_EXPR,
+	  p_seg = add_condition (summary, params_summary, index,
+			 	 param_type, &aggpos, GT_EXPR,
 				 max, param_ops);
 	}
     }
@@ -1599,7 +1606,8 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
 static void
 compute_bb_predicates (struct ipa_func_body_info *fbi,
 		       struct cgraph_node *node,
-		       class ipa_fn_summary *summary)
+		       class ipa_fn_summary *summary,
+		       class ipa_node_params *params_summary)
 {
   struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
   bool done = false;
@@ -1607,8 +1615,8 @@ compute_bb_predicates (struct ipa_func_body_info *fbi,
 
   FOR_EACH_BB_FN (bb, my_function)
     {
-      set_cond_stmt_execution_predicate (fbi, summary, bb);
-      set_switch_stmt_execution_predicate (fbi, summary, bb);
+      set_cond_stmt_execution_predicate (fbi, summary, params_summary, bb);
+      set_switch_stmt_execution_predicate (fbi, summary, params_summary, bb);
     }
 
   /* Entry block is always executable.  */
@@ -1701,6 +1709,7 @@ compute_bb_predicates (struct ipa_func_body_info *fbi,
 static predicate
 will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
 				    class ipa_fn_summary *summary,
+				    class ipa_node_params *params_summary,
 				    tree expr,
 				    vec<predicate> nonconstant_names)
 {
@@ -1712,7 +1721,7 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
 
   parm = unmodified_parm (fbi, NULL, expr, NULL);
   if (parm && (index = ipa_get_param_decl_index (fbi->info, parm)) >= 0)
-    return add_condition (summary, index, TREE_TYPE (parm), NULL,
+    return add_condition (summary, params_summary, index, TREE_TYPE (parm), NULL,
 			  predicate::changed, NULL_TREE);
   if (is_gimple_min_invariant (expr))
     return false;
@@ -1722,6 +1731,7 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
     {
       predicate p1
 	= will_be_nonconstant_expr_predicate (fbi, summary,
+					      params_summary,
 					      TREE_OPERAND (expr, 0),
 					      nonconstant_names);
       if (p1 == true)
@@ -1729,6 +1739,7 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
 
       predicate p2
 	= will_be_nonconstant_expr_predicate (fbi, summary,
+					      params_summary,
 					      TREE_OPERAND (expr, 1),
 					      nonconstant_names);
       return p1.or_with (summary->conds, p2);
@@ -1737,6 +1748,7 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
     {
       predicate p1
 	= will_be_nonconstant_expr_predicate (fbi, summary,
+					      params_summary,
 					      TREE_OPERAND (expr, 0),
 					      nonconstant_names);
       if (p1 == true)
@@ -1744,12 +1756,14 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
 
       predicate p2
 	= will_be_nonconstant_expr_predicate (fbi, summary,
+					      params_summary,
 					      TREE_OPERAND (expr, 1),
 					      nonconstant_names);
       if (p2 == true)
 	return p2;
       p1 = p1.or_with (summary->conds, p2);
       p2 = will_be_nonconstant_expr_predicate (fbi, summary,
+					       params_summary,
 					       TREE_OPERAND (expr, 2),
 					       nonconstant_names);
       return p2.or_with (summary->conds, p1);
@@ -1771,6 +1785,7 @@ will_be_nonconstant_expr_predicate (ipa_func_body_info *fbi,
 static predicate
 will_be_nonconstant_predicate (struct ipa_func_body_info *fbi,
 			       class ipa_fn_summary *summary,
+			       class ipa_node_params *params_summary,
 			       gimple *stmt,
 			       vec<predicate> nonconstant_names)
 {
@@ -1828,7 +1843,8 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi,
 
   if (is_load)
     op_non_const =
-      add_condition (summary, base_index, param_type, &aggpos,
+      add_condition (summary, params_summary,
+		     base_index, param_type, &aggpos,
 		     predicate::changed, NULL_TREE);
   else
     op_non_const = false;
@@ -1840,7 +1856,8 @@ will_be_nonconstant_predicate (struct ipa_func_body_info *fbi,
       if (parm && (index = ipa_get_param_decl_index (fbi->info, parm)) >= 0)
 	{
 	  if (index != base_index)
-	    p = add_condition (summary, index, TREE_TYPE (parm), NULL,
+	    p = add_condition (summary, params_summary, index,
+			       TREE_TYPE (parm), NULL,
 			       predicate::changed, NULL_TREE);
 	  else
 	    continue;
@@ -2027,7 +2044,9 @@ param_change_prob (ipa_func_body_info *fbi, gimple *stmt, int i)
 
 static bool
 phi_result_unknown_predicate (ipa_func_body_info *fbi,
-			      ipa_fn_summary *summary, basic_block bb,
+			      ipa_fn_summary *summary,
+			      class ipa_node_params *params_summary,
+			      basic_block bb,
 			      predicate *p,
 			      vec<predicate> nonconstant_names)
 {
@@ -2071,7 +2090,7 @@ phi_result_unknown_predicate (ipa_func_body_info *fbi,
       || !is_gimple_ip_invariant (gimple_cond_rhs (stmt)))
     return false;
 
-  *p = will_be_nonconstant_expr_predicate (fbi, summary,
+  *p = will_be_nonconstant_expr_predicate (fbi, summary, params_summary,
 					   gimple_cond_lhs (stmt),
 					   nonconstant_names);
   if (*p == true)
@@ -2264,6 +2283,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
   struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
   sreal freq;
   class ipa_fn_summary *info = ipa_fn_summaries->get_create (node);
+  class ipa_node_params *params_summary = early ? NULL : IPA_NODE_REF (node);
   predicate bb_predicate;
   struct ipa_func_body_info fbi;
   vec<predicate> nonconstant_names = vNULL;
@@ -2329,7 +2349,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
 		           bb_predicate);
 
   if (fbi.info)
-    compute_bb_predicates (&fbi, node, info);
+    compute_bb_predicates (&fbi, node, info, params_summary);
   order = XNEWVEC (int, n_basic_blocks_for_fn (cfun));
   nblocks = pre_and_rev_post_order_compute (NULL, order, false);
   for (n = 0; n < nblocks; n++)
@@ -2371,7 +2391,9 @@ analyze_function_body (struct cgraph_node *node, bool early)
 	       gsi_next (&bsi))
 	    {
 	      if (first_phi
-		  && !phi_result_unknown_predicate (&fbi, info, bb,
+		  && !phi_result_unknown_predicate (&fbi, info,
+			  			    params_summary,
+			 			    bb,
 						    &phi_predicate,
 						    nonconstant_names))
 		break;
@@ -2469,7 +2491,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
 	     just maximum of the possible paths.  */
 	  if (fbi.info)
 	    will_be_nonconstant
-	      = will_be_nonconstant_predicate (&fbi, info,
+	      = will_be_nonconstant_predicate (&fbi, info, params_summary,
 					       stmt, nonconstant_names);
 	  else
 	    will_be_nonconstant = true;
@@ -2536,7 +2558,8 @@ analyze_function_body (struct cgraph_node *node, bool early)
 		    predicate p = bb_predicate;
 		    if (fbi.info)
 		      p = p & will_be_nonconstant_expr_predicate
-				 (&fbi, info, TREE_OPERAND (op, 1),
+				 (&fbi, info, params_summary,
+				  TREE_OPERAND (op, 1),
 			          nonconstant_names);
 		    if (p != false)
 		      {
@@ -2581,6 +2604,7 @@ analyze_function_body (struct cgraph_node *node, bool early)
 	    {
 	      predicate will_be_nonconstant
 		= will_be_nonconstant_expr_predicate (&fbi, info,
+						      params_summary,
 						      niter_desc.niter,
 						      nonconstant_names);
 	      if (will_be_nonconstant != true)
@@ -2625,7 +2649,9 @@ analyze_function_body (struct cgraph_node *node, bool early)
 		    continue;
 
 		  predicate will_be_nonconstant
-		    = will_be_nonconstant_expr_predicate (&fbi, info, iv.step,
+		    = will_be_nonconstant_expr_predicate (&fbi, info,
+				    			  params_summary,
+				   			  iv.step,
 							  nonconstant_names);
 		  if (will_be_nonconstant != true)
 		    will_be_nonconstant = bb_predicate & will_be_nonconstant;
@@ -2964,29 +2990,73 @@ ipa_call_context::ipa_call_context (cgraph_node *node,
 {
 }
 
+/* Set THIS to be a duplicate of CTX.  Copy all relevant info.  */
+
 void
 ipa_call_context::duplicate_from (const ipa_call_context &ctx)
 {
   m_node = ctx.m_node;
   m_possible_truths = ctx.m_possible_truths;
   m_nonspec_possible_truths = ctx.m_nonspec_possible_truths;
+  class ipa_node_params *params_summary = IPA_NODE_REF (m_node);
+  unsigned int nargs = ipa_get_param_count (params_summary);
 
+  m_inline_param_summary = vNULL;
+  /* Copy the info only if there is at least one useful entry.  */
   if (ctx.m_inline_param_summary.exists ())
-    m_inline_param_summary = ctx.m_inline_param_summary.copy ();
-  else
-    m_inline_param_summary = vNULL;
+    {
+      unsigned int n = MIN (ctx.m_inline_param_summary.length (), nargs);
+
+      for (unsigned int i = 0; i < n; i++)
+	if (ipa_is_param_used_by_ipa_predicates (params_summary, i)
+	    && !ctx.m_inline_param_summary[i].useless_p ())
+	  {
+            m_inline_param_summary
+		    = ctx.m_inline_param_summary.copy ();
+	    break;
+	  }
+    }
+  m_known_vals = vNULL;
   if (ctx.m_known_vals.exists ())
-    m_known_vals = ctx.m_known_vals.copy ();
-  else
-    m_known_vals = vNULL;
+    {
+      unsigned int n = MIN (ctx.m_known_vals.length (), nargs);
+
+      for (unsigned int i = 0; i < n; i++)
+	if (ipa_is_param_used_by_indirect_call (params_summary, i)
+	    && ctx.m_known_vals[i])
+	  {
+	    m_known_vals = ctx.m_known_vals.copy ();
+	    break;
+	  }
+    }
+
+  m_known_contexts = vNULL;
   if (ctx.m_known_contexts.exists ())
-    m_known_contexts = ctx.m_known_contexts.copy ();
-  else
-    m_known_contexts = vNULL;
+    {
+      unsigned int n = MIN (ctx.m_known_contexts.length (), nargs);
+
+      for (unsigned int i = 0; i < n; i++)
+	if (ipa_is_param_used_by_polymorphic_call (params_summary, i)
+	    && !ctx.m_known_contexts[i].useless_p ())
+	  {
+	    m_known_contexts = ctx.m_known_contexts.copy ();
+	    break;
+	  }
+    }
+
+  m_known_aggs = vNULL;
   if (ctx.m_known_aggs.exists ())
-    m_known_aggs = ctx.m_known_aggs.copy ();
-  else
-    m_known_aggs = vNULL;
+    {
+      unsigned int n = MIN (ctx.m_known_aggs.length (), nargs);
+
+      for (unsigned int i = 0; i < n; i++)
+	if (ipa_is_param_used_by_indirect_call (params_summary, i)
+	    && ctx.m_known_aggs[i])
+	  {
+	    m_known_aggs = ctx.m_known_aggs.copy ();
+	    break;
+	  }
+    }
 }
 
 /* Release memory used by known_vals/contexts/aggs vectors.
@@ -3016,49 +3086,107 @@ ipa_call_context::equal_to (const ipa_call_context &ctx)
       || m_possible_truths != ctx.m_possible_truths
       || m_nonspec_possible_truths != ctx.m_nonspec_possible_truths)
     return false;
-  if (m_inline_param_summary.exists () != ctx.m_inline_param_summary.exists ()
-      || m_known_vals.exists () != ctx.m_known_vals.exists()
-      || m_known_contexts.exists () != ctx.m_known_contexts.exists ()
-      || m_known_aggs.exists () != ctx.m_known_aggs.exists ())
-    return false;
-  if (m_inline_param_summary.exists ())
+
+  class ipa_node_params *params_summary = IPA_NODE_REF (m_node);
+  unsigned int nargs = ipa_get_param_count (params_summary);
+
+  if (m_inline_param_summary.exists () || ctx.m_inline_param_summary.exists ())
     {
-      if (m_inline_param_summary.length () != ctx.m_inline_param_summary.length ())
-	return false;
-      for (unsigned int i = 0; i < m_inline_param_summary.length (); i++)
-	if (!m_inline_param_summary[i].equal_to (ctx.m_inline_param_summary[i]))
-	  return false;
+      for (unsigned int i = 0; i < nargs; i++)
+	{
+	  if (!ipa_is_param_used_by_ipa_predicates (params_summary, i))
+	    continue;
+	  if (i >= m_inline_param_summary.length ()
+	      || m_inline_param_summary[i].useless_p ())
+	    {
+	      if (i < ctx.m_inline_param_summary.length ()
+		  && !ctx.m_inline_param_summary[i].useless_p ())
+		return false;
+	      continue;
+	    }
+	  if (i >= ctx.m_inline_param_summary.length ()
+	      || ctx.m_inline_param_summary[i].useless_p ())
+	    {
+	      if (i < m_inline_param_summary.length ()
+		  && !m_inline_param_summary[i].useless_p ())
+		return false;
+	      continue;
+	    }
+	  if (!m_inline_param_summary[i].equal_to
+	     	 (ctx.m_inline_param_summary[i]))
+	    return false;
+	}
     }
-  if (m_known_vals.exists ())
+  if (m_known_vals.exists () || ctx.m_known_vals.exists ())
     {
-      if (m_known_vals.length () != ctx.m_known_vals.length ())
-	return false;
-      for (unsigned int i = 0; i < m_known_vals.length (); i++)
+      for (unsigned int i = 0; i < nargs; i++)
 	{
-	  tree t1 = m_known_vals[i];
-	  tree t2 = ctx.m_known_vals[i];
-
-	  if (t1 != t2
-	      && (!t1 || !t2 || !operand_equal_p (m_known_vals[i],
-						  ctx.m_known_vals[i], 0)))
+	  if (!ipa_is_param_used_by_indirect_call (params_summary, i))
+	    continue;
+	  if (i >= m_known_vals.length () || !m_known_vals[i])
+	    {
+	      if (i < ctx.m_known_vals.length () && ctx.m_known_vals[i])
+		return false;
+	      continue;
+	    }
+	  if (i >= ctx.m_known_vals.length () || !ctx.m_known_vals[i])
+	    {
+	      if (i < m_known_vals.length () && m_known_vals[i])
+		return false;
+	      continue;
+	    }
+	  if (m_known_vals[i] != ctx.m_known_vals[i])
 	    return false;
 	}
     }
-  if (m_known_contexts.exists ())
+  if (m_known_contexts.exists () || ctx.m_known_contexts.exists ())
     {
-      if (m_known_contexts.length () != ctx.m_known_contexts.length ())
-	return false;
-      for (unsigned int i = 0; i < m_known_contexts.length (); i++)
-	if (!m_known_contexts[i].equal_to (ctx.m_known_contexts[i]))
-	  return false;
+      for (unsigned int i = 0; i < nargs; i++)
+	{
+	  if (!ipa_is_param_used_by_polymorphic_call (params_summary, i))
+	    continue;
+	  if (i >= m_known_contexts.length ()
+	      || m_known_contexts[i].useless_p ())
+	    {
+	      if (i < ctx.m_known_contexts.length ()
+		  && !ctx.m_known_contexts[i].useless_p ())
+		return false;
+	      continue;
+	    }
+	  if (i >= ctx.m_known_contexts.length ()
+	      || ctx.m_known_contexts[i].useless_p ())
+	    {
+	      if (i < m_known_contexts.length ()
+		  && !m_known_contexts[i].useless_p ())
+		return false;
+	      continue;
+	    }
+	  if (!m_known_contexts[i].equal_to
+	     	 (ctx.m_known_contexts[i]))
+	    return false;
+	}
     }
-  if (m_known_aggs.exists ())
+  if (m_known_aggs.exists () || ctx.m_known_aggs.exists ())
     {
-      if (m_known_aggs.length () != ctx.m_known_aggs.length ())
-	return false;
-      for (unsigned int i = 0; i < m_known_aggs.length (); i++)
-	if (!m_known_aggs[i]->equal_to (*ctx.m_known_aggs[i]))
-	  return false;
+      for (unsigned int i = 0; i < nargs; i++)
+	{
+	  if (!ipa_is_param_used_by_indirect_call (params_summary, i))
+	    continue;
+	  if (i >= m_known_aggs.length () || !m_known_aggs[i])
+	    {
+	      if (i < ctx.m_known_aggs.length () && ctx.m_known_aggs[i])
+		return false;
+	      continue;
+	    }
+	  if (i >= ctx.m_known_aggs.length () || !ctx.m_known_aggs[i])
+	    {
+	      if (i < m_known_aggs.length () && m_known_aggs[i])
+		return false;
+	      continue;
+	    }
+	  if (m_known_aggs[i] != ctx.m_known_aggs[i])
+	    return false;
+	}
     }
   return true;
 }
@@ -3319,6 +3447,7 @@ static void
 remap_edge_summaries (struct cgraph_edge *inlined_edge,
 		      struct cgraph_node *node,
 		      class ipa_fn_summary *info,
+		      class ipa_node_params *params_summary,
 		      class ipa_fn_summary *callee_info,
 		      vec<int> operand_map,
 		      vec<int> offset_map,
@@ -3339,7 +3468,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
 	  if (es->predicate)
 	    {
 	      p = es->predicate->remap_after_inlining
-				     (info, callee_info, operand_map,
+				     (info, params_summary,
+				      callee_info, operand_map,
 				      offset_map, possible_truths,
 				      *toplev_predicate);
 	      edge_set_predicate (e, &p);
@@ -3348,7 +3478,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
 	    edge_set_predicate (e, toplev_predicate);
 	}
       else
-	remap_edge_summaries (inlined_edge, e->callee, info, callee_info,
+	remap_edge_summaries (inlined_edge, e->callee, info,
+		              params_summary, callee_info,
 			      operand_map, offset_map, possible_truths,
 			      toplev_predicate);
     }
@@ -3362,7 +3493,8 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
       if (es->predicate)
 	{
 	  p = es->predicate->remap_after_inlining
-				 (info, callee_info, operand_map, offset_map,
+				 (info, params_summary,
+				  callee_info, operand_map, offset_map,
 			          possible_truths, *toplev_predicate);
 	  edge_set_predicate (e, &p);
 	}
@@ -3375,6 +3507,7 @@ remap_edge_summaries (struct cgraph_edge *inlined_edge,
 
 static void
 remap_hint_predicate (class ipa_fn_summary *info,
+		      class ipa_node_params *params_summary,
 		      class ipa_fn_summary *callee_info,
 		      predicate **hint,
 		      vec<int> operand_map,
@@ -3387,7 +3520,7 @@ remap_hint_predicate (class ipa_fn_summary *info,
   if (!*hint)
     return;
   p = (*hint)->remap_after_inlining
-			 (info, callee_info,
+			 (info, params_summary, callee_info,
 			  operand_map, offset_map,
 			  possible_truths, *toplev_predicate);
   if (p != false && p != true)
@@ -3415,6 +3548,8 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
   int i;
   predicate toplev_predicate;
   class ipa_call_summary *es = ipa_call_summaries->get (edge);
+  class ipa_node_params *params_summary = (ipa_node_params_sum
+		 			   ? IPA_NODE_REF (to) : NULL);
 
   if (es->predicate)
     toplev_predicate = *es->predicate;
@@ -3461,19 +3596,21 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
 		}
 	    }
 	  operand_map[i] = map;
-	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
+	  gcc_assert (map < ipa_get_param_count (params_summary));
 	}
     }
   for (i = 0; vec_safe_iterate (callee_info->size_time_table, i, &e); i++)
     {
       predicate p;
       p = e->exec_predicate.remap_after_inlining
-			     (info, callee_info, operand_map,
+			     (info, params_summary,
+			      callee_info, operand_map,
 			      offset_map, clause,
 			      toplev_predicate);
       predicate nonconstp;
       nonconstp = e->nonconst_predicate.remap_after_inlining
-				     (info, callee_info, operand_map,
+				     (info, params_summary,
+				      callee_info, operand_map,
 				      offset_map, clause,
 				      toplev_predicate);
       if (p != false && nonconstp != false)
@@ -3491,12 +3628,13 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge)
 	  info->account_size_time (e->size, add_time, p, nonconstp);
 	}
     }
-  remap_edge_summaries (edge, edge->callee, info, callee_info, operand_map,
+  remap_edge_summaries (edge, edge->callee, info, params_summary,
+		 	callee_info, operand_map,
 			offset_map, clause, &toplev_predicate);
-  remap_hint_predicate (info, callee_info,
+  remap_hint_predicate (info, params_summary, callee_info,
 			&callee_info->loop_iterations,
 			operand_map, offset_map, clause, &toplev_predicate);
-  remap_hint_predicate (info, callee_info,
+  remap_hint_predicate (info, params_summary, callee_info,
 			&callee_info->loop_stride,
 			operand_map, offset_map, clause, &toplev_predicate);
 
@@ -3687,6 +3825,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
       unsigned int index;
       struct cgraph_node *node;
       class ipa_fn_summary *info;
+      class ipa_node_params *params_summary;
       class ipa_size_summary *size_info;
       lto_symtab_encoder_t encoder;
       struct bitpack_d bp;
@@ -3698,6 +3837,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
       node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder,
 								index));
       info = node->prevailing_p () ? ipa_fn_summaries->get_create (node) : NULL;
+      params_summary = node->prevailing_p () ? IPA_NODE_REF (node) : NULL;
       size_info = node->prevailing_p ()
 		  ? ipa_size_summaries->get_create (node) : NULL;
 
@@ -3746,6 +3886,9 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
 	  c.param_ops = NULL;
 	  if (info)
 	    vec_safe_reserve_exact (c.param_ops, count3);
+	  if (params_summary)
+	    ipa_set_param_used_by_ipa_predicates
+		    (params_summary, c.operand_num, true);
 	  for (k = 0; k < count3; k++)
 	    {
 	      struct expr_eval_op op;
diff --git a/gcc/ipa-predicate.c b/gcc/ipa-predicate.c
index b5e3cf44323896849709e738962a93a0c5af9723..721f0957f9f9bfbf062cd0f826ab12fd3c54cfdc 100644
--- a/gcc/ipa-predicate.c
+++ b/gcc/ipa-predicate.c
@@ -505,6 +505,7 @@ predicate::remap_after_duplication (clause_t possible_truths)
 
 predicate
 predicate::remap_after_inlining (class ipa_fn_summary *info,
+				 class ipa_node_params *params_summary,
 				 class ipa_fn_summary *callee_info,
 				 vec<int> operand_map,
 				 vec<int> offset_map,
@@ -566,7 +567,7 @@ predicate::remap_after_inlining (class ipa_fn_summary *info,
 		    ap.offset = c->offset + offset_delta;
 		    ap.agg_contents = c->agg_contents;
 		    ap.by_ref = c->by_ref;
-		    cond_predicate = add_condition (info,
+		    cond_predicate = add_condition (info, params_summary,
 						    operand_map[c->operand_num],
 						    c->type, &ap, c->code,
 						    c->val, c->param_ops);
@@ -629,7 +630,9 @@ predicate::stream_out (struct output_block *ob)
    aggregate.  */
 
 predicate
-add_condition (class ipa_fn_summary *summary, int operand_num,
+add_condition (class ipa_fn_summary *summary,
+	       class ipa_node_params *params_summary,
+	       int operand_num,
 	       tree type, struct agg_position_info *aggpos,
 	       enum tree_code code, tree val, expr_eval_ops param_ops)
 {
@@ -640,6 +643,9 @@ add_condition (class ipa_fn_summary *summary, int operand_num,
   bool agg_contents, by_ref;
   expr_eval_op *op;
 
+  if (params_summary)
+    ipa_set_param_used_by_ipa_predicates (params_summary, operand_num, true);
+
   if (aggpos)
     {
       offset = aggpos->offset;
diff --git a/gcc/ipa-predicate.h b/gcc/ipa-predicate.h
index 2509b1e516217ac616b989f1343dcbce792a2e7a..25cd5f2797dd4c87e522e44d34ed00cb3295f731 100644
--- a/gcc/ipa-predicate.h
+++ b/gcc/ipa-predicate.h
@@ -77,10 +77,14 @@ struct inline_param_summary
 
      Value 0 is reserved for compile time invariants. */
   int change_prob;
-  bool equal_to (const inline_param_summary &other)
+  bool equal_to (const inline_param_summary &other) const
   {
     return change_prob == other.change_prob;
   }
+  bool useless_p (void) const
+  {
+    return change_prob == REG_BR_PROB_BASE;
+  }
 };
 
 typedef vec<condition, va_gc> *conditions;
@@ -233,6 +237,7 @@ public:
 
   /* Return predicate equal to THIS after inlining.  */
   predicate remap_after_inlining (class ipa_fn_summary *,
+		  		  class ipa_node_params *params_summary,
 			          class ipa_fn_summary *,
 			          vec<int>, vec<int>, clause_t, const predicate &);
 
@@ -254,7 +259,9 @@ private:
 };
 
 void dump_condition (FILE *f, conditions conditions, int cond);
-predicate add_condition (class ipa_fn_summary *summary, int operand_num,
+predicate add_condition (class ipa_fn_summary *summary,
+			 class ipa_node_params *params_summary,
+	       		 int operand_num,
 			 tree type, struct agg_position_info *aggpos,
 			 enum tree_code code, tree val,
 			 expr_eval_ops param_ops = NULL);
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 5491aee2fc6090819f86b029b10d1f8b9157112b..83cf4d1c7bacf94778e19b917aef21e83da9f535 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -227,8 +227,10 @@ ipa_populate_param_decls (struct cgraph_node *node,
   for (parm = fnargs; parm; parm = DECL_CHAIN (parm))
     {
       descriptors[param_num].decl_or_type = parm;
-      descriptors[param_num].move_cost = estimate_move_cost (TREE_TYPE (parm),
-							     true);
+      unsigned int cost = estimate_move_cost (TREE_TYPE (parm), true);
+      descriptors[param_num].move_cost = cost;
+      /* Watch overflow, move_cost is a bitfield.  */
+      gcc_checking_assert (cost == descriptors[param_num].move_cost);
       param_num++;
     }
 }
@@ -2116,11 +2118,12 @@ ipa_is_ssa_with_stmt_def (tree t)
 
 /* Find the indirect call graph edge corresponding to STMT and mark it as a
    call to a parameter number PARAM_INDEX.  NODE is the caller.  Return the
-   indirect call graph edge.  */
+   indirect call graph edge.
+   If POLYMORPHIC is true record is as a destination of polymorphic call.  */
 
 static struct cgraph_edge *
 ipa_note_param_call (struct cgraph_node *node, int param_index,
-		     gcall *stmt)
+		     gcall *stmt, bool polymorphic)
 {
   struct cgraph_edge *cs;
 
@@ -2129,6 +2132,11 @@ ipa_note_param_call (struct cgraph_node *node, int param_index,
   cs->indirect_info->agg_contents = 0;
   cs->indirect_info->member_ptr = 0;
   cs->indirect_info->guaranteed_unmodified = 0;
+  ipa_set_param_used_by_indirect_call (IPA_NODE_REF (node),
+					  param_index, true);
+  if (cs->indirect_info->polymorphic || polymorphic)
+    ipa_set_param_used_by_polymorphic_call
+	    (IPA_NODE_REF (node), param_index, true);
   return cs;
 }
 
@@ -2204,7 +2212,7 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
       tree var = SSA_NAME_VAR (target);
       int index = ipa_get_param_decl_index (info, var);
       if (index >= 0)
-	ipa_note_param_call (fbi->node, index, call);
+	ipa_note_param_call (fbi->node, index, call, false);
       return;
     }
 
@@ -2216,7 +2224,8 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
 				 gimple_assign_rhs1 (def), &index, &offset,
 				 NULL, &by_ref, &guaranteed_unmodified))
     {
-      struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
+      struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
+	 					    call, false);
       cs->indirect_info->offset = offset;
       cs->indirect_info->agg_contents = 1;
       cs->indirect_info->by_ref = by_ref;
@@ -2317,7 +2326,8 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
   if (index >= 0
       && parm_preserved_before_stmt_p (fbi, index, call, rec))
     {
-      struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
+      struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
+	 					    call, false);
       cs->indirect_info->offset = offset;
       cs->indirect_info->agg_contents = 1;
       cs->indirect_info->member_ptr = 1;
@@ -2377,7 +2387,8 @@ ipa_analyze_virtual_call_uses (struct ipa_func_body_info *fbi,
 	return;
     }
 
-  struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
+  struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
+     						call, true);
   class cgraph_indirect_call_info *ii = cs->indirect_info;
   ii->offset = anc_offset;
   ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
@@ -3510,6 +3521,11 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
 	      if (ici->polymorphic
 		  && !ipa_get_jf_pass_through_type_preserved (jfunc))
 		ici->vptr_changed = true;
+	      ipa_set_param_used_by_indirect_call (new_root_info,
+			     			   ici->param_index, true);
+	      if (ici->polymorphic)
+		ipa_set_param_used_by_polymorphic_call (new_root_info,
+						        ici->param_index, true);
 	    }
 	}
       else if (jfunc->type == IPA_JF_ANCESTOR)
@@ -4055,6 +4071,12 @@ ipa_print_node_params (FILE *f, struct cgraph_node *node)
       ipa_dump_param (f, info, i);
       if (ipa_is_param_used (info, i))
 	fprintf (f, " used");
+      if (ipa_is_param_used_by_ipa_predicates (info, i))
+	fprintf (f, " used_by_ipa_predicates");
+      if (ipa_is_param_used_by_indirect_call (info, i))
+	fprintf (f, " used_by_indirect_call");
+      if (ipa_is_param_used_by_polymorphic_call (info, i))
+	fprintf (f, " used_by_polymorphic_call");
       c = ipa_get_controlled_uses (info, i);
       if (c == IPA_UNDESCRIBED_USE)
 	fprintf (f, " undescribed_use");
@@ -4331,7 +4353,8 @@ ipa_write_indirect_edge_info (struct output_block *ob,
 static void
 ipa_read_indirect_edge_info (class lto_input_block *ib,
 			     class data_in *data_in,
-			     struct cgraph_edge *cs)
+			     struct cgraph_edge *cs,
+			     class ipa_node_params *info)
 {
   class cgraph_indirect_call_info *ii = cs->indirect_info;
   struct bitpack_d bp;
@@ -4354,6 +4377,14 @@ ipa_read_indirect_edge_info (class lto_input_block *ib,
       ii->otr_type = stream_read_tree (ib, data_in);
       ii->context.stream_in (ib, data_in);
     }
+  if (info && ii->param_index >= 0)
+    {
+      if (ii->polymorphic)
+	ipa_set_param_used_by_polymorphic_call (info,
+						ii->param_index , true);
+      ipa_set_param_used_by_indirect_call (info,
+					   ii->param_index, true);
+    }
 }
 
 /* Stream out NODE info to OB.  */
@@ -4523,7 +4554,7 @@ ipa_read_node_info (class lto_input_block *ib, struct cgraph_node *node,
   for (e = node->indirect_calls; e; e = e->next_callee)
     {
       ipa_read_edge_info (ib, data_in, e, prevails);
-      ipa_read_indirect_edge_info (ib, data_in, e);
+      ipa_read_indirect_edge_info (ib, data_in, e, info);
     }
 }
 
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 121d0f647b11a16f9b91442bb894edada26bb65c..9f2479e7fdc51b1a90c142dd617c94b5103de3f9 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -333,9 +333,12 @@ struct GTY(()) ipa_param_descriptor
      says how many there are.  If any use could not be described by means of
      ipa-prop structures, this is IPA_UNDESCRIBED_USE.  */
   int controlled_uses;
-  unsigned int move_cost : 31;
+  unsigned int move_cost : 28;
   /* The parameter is used.  */
   unsigned used : 1;
+  unsigned used_by_ipa_predicates : 1;
+  unsigned used_by_indirect_call : 1;
+  unsigned used_by_polymorphic_call : 1;
 };
 
 /* ipa_node_params stores information related to formal parameters of functions
@@ -519,6 +522,36 @@ ipa_set_param_used (class ipa_node_params *info, int i, bool val)
   (*info->descriptors)[i].used = val;
 }
 
+/* Set the used_by_ipa_predicates flag corresponding to the Ith formal
+   parameter of the function associated with INFO to VAL.  */
+
+static inline void
+ipa_set_param_used_by_ipa_predicates (class ipa_node_params *info, int i, bool val)
+{
+  gcc_checking_assert (info->descriptors);
+  (*info->descriptors)[i].used_by_ipa_predicates = val;
+}
+
+/* Set the used_by_indirect_call flag corresponding to the Ith formal
+   parameter of the function associated with INFO to VAL.  */
+
+static inline void
+ipa_set_param_used_by_indirect_call (class ipa_node_params *info, int i, bool val)
+{
+  gcc_checking_assert (info->descriptors);
+  (*info->descriptors)[i].used_by_indirect_call = val;
+}
+
+/* Set the .used_by_polymorphic_call flag corresponding to the Ith formal
+   parameter of the function associated with INFO to VAL.  */
+
+static inline void
+ipa_set_param_used_by_polymorphic_call (class ipa_node_params *info, int i, bool val)
+{
+  gcc_checking_assert (info->descriptors);
+  (*info->descriptors)[i].used_by_polymorphic_call = val;
+}
+
 /* Return how many uses described by ipa-prop a parameter has or
    IPA_UNDESCRIBED_USE if there is a use that is not described by these
    structures.  */
@@ -550,6 +583,36 @@ ipa_is_param_used (class ipa_node_params *info, int i)
   return (*info->descriptors)[i].used;
 }
 
+/* Return the used_by_ipa_predicates flag corresponding to the Ith formal
+   parameter of the function associated with INFO.  */
+
+static inline bool
+ipa_is_param_used_by_ipa_predicates (class ipa_node_params *info, int i)
+{
+  gcc_checking_assert (info->descriptors);
+  return (*info->descriptors)[i].used_by_ipa_predicates;
+}
+
+/* Return the used_by_indirect_call flag corresponding to the Ith formal
+   parameter of the function associated with INFO.  */
+
+static inline bool
+ipa_is_param_used_by_indirect_call (class ipa_node_params *info, int i)
+{
+  gcc_checking_assert (info->descriptors);
+  return (*info->descriptors)[i].used_by_indirect_call;
+}
+
+/* Return the used_by_polymorphic_call flag corresponding to the Ith formal
+   parameter of the function associated with INFO.  */
+
+static inline bool
+ipa_is_param_used_by_polymorphic_call (class ipa_node_params *info, int i)
+{
+  gcc_checking_assert (info->descriptors);
+  return (*info->descriptors)[i].used_by_polymorphic_call;
+}
+
 /* Information about replacements done in aggregates for a given node (each
    node has its linked list).  */
 struct GTY(()) ipa_agg_replacement_value