This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 4/5] Incorporate aggregate jump functions to inlining analysis


Hi,

this patch uses the aggregate jump functions created by a previous
patch to determine benefits of inlining a particular call graph edge.

It does so by fairly straightforward way.  It a flag to struct
condition to specify it is actually an aggregate value at an offset,
also newly stored in the structures.  Functions which build the
predicates specifying under which conditions CFG edges will be taken
or individual statements are actually executed, then simply also look
whether a value comes from an aggregate passed to us in a parameter
(either by value or reference) and if so, create appropriate
conditions.  Later on, predicates are evaluated as before, we only
also look at aggregate contents of the jump function of the edge we
are considering to inline when evaluating the predicates, and also
remap the offsets of the jump functions when remapping over an
ancestor jump function.

There are (at least ;-) two things which should be addressed before
this patch is committed.  First is also looking for aggregate loads
when handling built_in_constant_p built-in (clearly marked in the
patch).

Second is that we should most probably also do the type-comatibility
check we do in ipa_agg_types_propagatable_p when remaping predicates
after inlining.  Because this is inlining heuristics, this omission
currently leads only to bad estimates (which are going to be very rare
too), not miscompilations, but we should be consistent.

Otherwise, the patch, as is, passes bootstrap and testing on
x86_64-linux.  Also, this patch alone makes us inline the function bar
in testcase of PR 48636 in comment #4.

Thanks for all comments and suggestions,

Martin


2012-05-30  Martin Jambor  <mjambor@suse.cz>

	PR fortran/48636
	* ipa-inline.h (condition): New fields offset and agg_contents.

	* ipa-inline-analysis.c (add_condition): Also store agg_contents and
	offset .
	(dump_condition): Also dump aggregate conditions.
	(evaluate_conditions_for_known_args): Also handle aggregate
	conditions.  New parameter known_aggs.
	(evaluate_properties_for_edge): Gather known aggregate contents.
	(inline_node_duplication_hook): Pass NULL known_aggs to
	evaluate_conditions_for_known_args.
	(unmodified_parm): Split into unmodified_parm and unmodified_parm_1.
	(unmodified_parm_or_parm_agg_item): New function.
	(set_cond_stmt_execution_predicate): Handle values passed in
	aggregates.
	(set_switch_stmt_execution_predicate): Likewise.
	(will_be_nonconstant_predicate): Likewise.
	(estimate_edge_devirt_benefit): Pass new parameter known_aggs to
	ipa_get_indirect_edge_target.
	(estimate_calls_size_and_time): New parameter known_aggs, pass it
	recrsively to itself and to estimate_edge_devirt_benefit.
	(estimate_node_size_and_time): New vector known_aggs, pass it o
	functions which need it.
	(remap_predicate): New parameter offset_map, use it to remap aggregate
	conditions.
	(remap_edge_summaries): New parameter offset_map, pass it recursively
	to itself and to remap_predicate.
	(inline_merge_summary): Also create and populate vector offset_map.
	(do_estimate_edge_time): New vector of known aggregate contents,
	passed to functions which need it.
	(inline_read_section): Stream new fields of condition.
	(inline_write_summary): Likewise.

	* ipa-cp.c (ipa_get_indirect_edge_target): Also examine the aggregate
	contents.  Let all local callers pass NULL for known_aggs.


Index: src/gcc/ipa-inline.h
===================================================================
--- src.orig/gcc/ipa-inline.h
+++ src/gcc/ipa-inline.h
@@ -28,9 +28,11 @@ along with GCC; see the file COPYING3.
 
 typedef struct GTY(()) condition
   {
+    HOST_WIDE_INT offset;
     tree val;
     int operand_num;
     enum tree_code code;
+    bool agg_contents;
   } condition;
 
 DEF_VEC_O (condition);
Index: src/gcc/ipa-inline-analysis.c
===================================================================
--- src.orig/gcc/ipa-inline-analysis.c
+++ src/gcc/ipa-inline-analysis.c
@@ -209,17 +209,21 @@ not_inlined_predicate (void)
 
 static struct predicate
 add_condition (struct inline_summary *summary, int operand_num,
+	       bool agg_contents, HOST_WIDE_INT offset,
 	       enum tree_code code, tree val)
 {
   int i;
   struct condition *c;
   struct condition new_cond;
 
+  gcc_checking_assert (operand_num >= 0);
   for (i = 0; VEC_iterate (condition, summary->conds, i, c); i++)
     {
       if (c->operand_num == operand_num
 	  && c->code == code
-	  && c->val == val)
+	  && c->val == val
+	  && c->agg_contents == agg_contents
+	  && (!agg_contents || c->offset == offset))
         return single_cond_predicate (i + predicate_first_dynamic_condition);
     }
   /* Too many conditions.  Give up and return constant true.  */
@@ -229,6 +233,8 @@ add_condition (struct inline_summary *su
   new_cond.operand_num = operand_num;
   new_cond.code = code;
   new_cond.val = val;
+  new_cond.agg_contents = agg_contents;
+  new_cond.offset = offset;
   VEC_safe_push (condition, gc, summary->conds, &new_cond);
   return single_cond_predicate (i + predicate_first_dynamic_condition);
 }
@@ -520,6 +526,8 @@ dump_condition (FILE *f, conditions cond
       c = VEC_index (condition, conditions,
 		     cond - predicate_first_dynamic_condition);
       fprintf (f, "op%i", c->operand_num);
+      if (c->agg_contents)
+	fprintf (f, "[offset: " HOST_WIDE_INT_PRINT_DEC "]", c->offset);
       if (c->code == IS_NOT_CONSTANT)
 	{
 	  fprintf (f, " not constant");
@@ -667,8 +675,9 @@ edge_set_predicate (struct cgraph_edge *
 
 static clause_t
 evaluate_conditions_for_known_args (struct cgraph_node *node,
-				    bool inline_p,
-				    VEC (tree, heap) *known_vals)
+				bool inline_p,
+				VEC (tree, heap) *known_vals,
+				VEC (ipa_agg_jump_function_p, heap) *known_aggs)
 {
   clause_t clause = inline_p ? 0 : 1 << predicate_not_inlined_condition;
   struct inline_summary *info = inline_summary (node);
@@ -680,16 +689,43 @@ evaluate_conditions_for_known_args (stru
       tree val;
       tree res;
 
-      /* We allow call stmt to have fewer arguments than the callee
-	 function (especially for K&R style programs).  So bound
-	 check here.  */
-      if (c->operand_num < (int)VEC_length (tree, known_vals))
-        val = VEC_index (tree, known_vals, c->operand_num);
-      else
-	val = NULL;
+      /* We allow call stmt to have fewer arguments than the callee function
+	 (especially for K&R style programs).  So bound check here (we assume
+	 known_aggs vector, if non-NULL, has the same length as
+	 known_vals).  */
+      if (c->operand_num >= (int) VEC_length (tree, known_vals))
+	{
+	  clause |= 1 << (i + predicate_first_dynamic_condition);
+	  continue;
+	}
 
-      if (val == error_mark_node && c->code != CHANGED)
-	val = NULL;
+      if (c->agg_contents)
+	{
+	  struct ipa_agg_jump_function *agg;
+
+	  if (c->code == CHANGED
+	      && !POINTER_TYPE_P (TREE_TYPE (ipa_get_param (IPA_NODE_REF (node),
+							    0)))
+	      && (VEC_index (tree, known_vals, c->operand_num)
+		  == error_mark_node))
+	    continue;
+
+	  if (known_aggs)
+	    {
+	      agg = VEC_index (ipa_agg_jump_function_p, known_aggs,
+			       c->operand_num);
+	      val = ipa_find_agg_cst_for_param (agg, c->offset, node,
+						c->operand_num);
+	    }
+	  else
+	    val = NULL_TREE;
+	}
+      else
+	{
+	  val = VEC_index (tree, known_vals, c->operand_num);
+	  if (val == error_mark_node && c->code != CHANGED)
+	    val = NULL_TREE;
+	}
 
       if (!val)
 	{
@@ -712,13 +748,15 @@ evaluate_conditions_for_known_args (stru
 
 static void
 evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
-			      clause_t *clause_ptr,
-			      VEC (tree, heap) **known_vals_ptr,
-			      VEC (tree, heap) **known_binfos_ptr)
+			   clause_t *clause_ptr,
+			   VEC (tree, heap) **known_vals_ptr,
+			   VEC (tree, heap) **known_binfos_ptr,
+			   VEC (ipa_agg_jump_function_p, heap) **known_aggs_ptr)
 {
   struct cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, NULL);
   struct inline_summary *info = inline_summary (callee);
   VEC (tree, heap) *known_vals = NULL;
+  VEC (ipa_agg_jump_function_p, heap) *known_aggs = NULL;
 
   if (clause_ptr)
     *clause_ptr = inline_p ? 0 : 1 << predicate_not_inlined_condition;
@@ -743,13 +781,16 @@ evaluate_properties_for_edge (struct cgr
 
       if (count && (info->conds || known_vals_ptr))
 	VEC_safe_grow_cleared (tree, heap, known_vals, count);
+      if (count && (info->conds || known_aggs_ptr))
+	VEC_safe_grow_cleared (ipa_agg_jump_function_p, heap, known_aggs,
+			       count);
       if (count && known_binfos_ptr)
 	VEC_safe_grow_cleared (tree, heap, *known_binfos_ptr, count);
 
       for (i = 0; i < count; i++)
 	{
-	  tree cst = ipa_value_from_jfunc (parms_info,
-					   ipa_get_ith_jump_func (args, i));
+	  struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, i);
+	  tree cst = ipa_value_from_jfunc (parms_info, jf);
 	  if (cst)
 	    {
 	      if (known_vals && TREE_CODE (cst) != TREE_BINFO)
@@ -762,17 +803,25 @@ evaluate_properties_for_edge (struct cgr
 				  es->param,
 				  i)->change_prob)
 	    VEC_replace (tree, known_vals, i, error_mark_node);
+	  /* TODO: When IPA-CP starts merging aggregate jump functions, use its
+	     knowledge of the caller too, just like the scalar case above.  */
+	  VEC_replace (ipa_agg_jump_function_p, known_aggs, i, &jf->agg);
 	}
     }
 
   if (clause_ptr)
     *clause_ptr = evaluate_conditions_for_known_args (callee, inline_p,
-						      known_vals);
+						      known_vals, known_aggs);
 
   if (known_vals_ptr)
     *known_vals_ptr = known_vals;
   else
     VEC_free (tree, heap, known_vals);
+
+  if (known_aggs_ptr)
+    *known_aggs_ptr = known_aggs;
+  else
+    VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
 }
 
 
@@ -918,8 +967,8 @@ inline_node_duplication_hook (struct cgr
 		}
 	    }
 	}
-      possible_truths = evaluate_conditions_for_known_args (dst,
-							    false, known_vals);
+      possible_truths = evaluate_conditions_for_known_args (dst, false,
+							    known_vals, NULL);
       VEC_free (tree, heap, known_vals);
 
       account_size_time (info, 0, 0, &true_pred);
@@ -1263,11 +1312,11 @@ mark_modified (ao_ref *ao ATTRIBUTE_UNUS
   return true;
 }
 
-/* If OP reffers to value of function parameter, return 
+/* If OP refers to value of function parameter, return
    the corresponding parameter.  */
 
 static tree
-unmodified_parm (gimple stmt, tree op)
+unmodified_parm_1 (gimple stmt, tree op)
 {
   /* SSA_NAME referring to parm default def?  */
   if (TREE_CODE (op) == SSA_NAME
@@ -1286,13 +1335,109 @@ unmodified_parm (gimple stmt, tree op)
       if (!modified)
 	return op;
     }
-  /* Assignment from a parameter?  */
+  return NULL_TREE;
+}
+
+/* If OP refers to value of function parameter, return
+   the corresponding parameter.  Also traverse   */
+
+static tree
+unmodified_parm (gimple stmt, tree op)
+{
+  tree res = unmodified_parm_1 (stmt, op);
+  if (res)
+    return res;
+
   if (TREE_CODE (op) == SSA_NAME
       && !SSA_NAME_IS_DEFAULT_DEF (op)
       && gimple_assign_single_p (SSA_NAME_DEF_STMT (op)))
     return unmodified_parm (SSA_NAME_DEF_STMT (op),
 			    gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op)));
-  return NULL;
+  return NULL_TREE;
+}
+
+/* If OP refers to a value of a function parameter or value loaded from an
+   aggregate passed to a parameter (either by value or reference), return TRUE
+   and store the number of the parameter to *INDEX_P, whether it has been
+   loaded from an aggregate into *AGG_CONTENTS_P and if so, offset of the value
+   within the aggregate into *OFFSET_P.  INFO describes the function
+   parameters, STMT is the statement in which OP is used or loaded.  */
+
+static bool
+unmodified_parm_or_parm_agg_item (struct ipa_node_params *info,
+				  gimple stmt, tree op, int *index_p,
+				  bool *agg_contents_p, HOST_WIDE_INT *offset_p)
+{
+  tree base, res = unmodified_parm_1 (stmt, op);
+  HOST_WIDE_INT size, max_size;
+
+  if (res)
+    {
+      *index_p = ipa_get_param_decl_index (info, res);
+      if (*index_p < 0)
+	return false;
+      *agg_contents_p = false;
+      return true;
+    }
+
+  if (TREE_CODE (op) == SSA_NAME)
+    {
+      if (SSA_NAME_IS_DEFAULT_DEF (op)
+	  || !gimple_assign_single_p (SSA_NAME_DEF_STMT (op)))
+	return false;
+      stmt = SSA_NAME_DEF_STMT (op);
+      op = gimple_assign_rhs1 (stmt);
+      if (!handled_component_p (op)
+	  && TREE_CODE (op) == MEM_REF)
+	return unmodified_parm_or_parm_agg_item (info, stmt, op, index_p,
+						 agg_contents_p, offset_p);
+    }
+
+  base = get_ref_base_and_extent (op, offset_p, &size, &max_size);
+  if (max_size == -1 || max_size != size || *offset_p < 0)
+    return false;
+
+  if (TREE_CODE (base) == PARM_DECL)
+    {
+      bool modified = false;
+      ao_ref refd;
+
+      *index_p = ipa_get_param_decl_index (info, base);
+      if (*index_p < 0)
+	return false;
+
+      ao_ref_init (&refd, base);
+      walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified,
+			  NULL);
+      if (!modified)
+	{
+	  *agg_contents_p = true;
+	  return true;
+	}
+    }
+  else if (TREE_CODE (base) == MEM_REF
+	   && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
+	   && SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (base, 0))
+	   && integer_zerop (TREE_OPERAND (base, 1)))
+    {
+      ao_ref refd;
+      bool modified = false;
+
+      *index_p = ipa_get_param_decl_index (info,
+					   SSA_NAME_VAR (TREE_OPERAND (base,								       0)));
+      if (*index_p < 0)
+	return false;
+      ao_ref_init (&refd, base);
+      walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified,
+			  NULL);
+      if (!modified)
+	{
+	  *agg_contents_p = true;
+	  return true;
+	}
+    }
+
+  return false;
 }
 
 /* See if statement might disappear after inlining.
@@ -1423,6 +1568,8 @@ set_cond_stmt_execution_predicate (struc
   gimple last;
   tree op;
   int index;
+  bool agg_contents;
+  HOST_WIDE_INT offset;
   enum tree_code code, inverted_code;
   edge e;
   edge_iterator ei;
@@ -1441,12 +1588,9 @@ set_cond_stmt_execution_predicate (struc
   /* TODO: handle conditionals like
      var = op0 < 4;
      if (var != 0).  */
-  parm = unmodified_parm (last, op);
-  if (parm)
+  if (unmodified_parm_or_parm_agg_item (info, last, op, &index, &agg_contents,
+					&offset))
     {
-      index = ipa_get_param_decl_index (info, parm);
-      if (index == -1)
-	return;
       code = gimple_cond_code (last);
       inverted_code
 	 = invert_tree_comparison (code,
@@ -1455,7 +1599,7 @@ set_cond_stmt_execution_predicate (struc
       FOR_EACH_EDGE (e, ei, bb->succs)
 	{
 	  struct predicate p = add_condition (summary,
-					      index,
+					      index, agg_contents, offset,
 					      e->flags & EDGE_TRUE_VALUE
 					      ? code : inverted_code,
 					      gimple_cond_rhs (last));
@@ -1481,6 +1625,8 @@ set_cond_stmt_execution_predicate (struc
       || gimple_call_num_args (set_stmt) != 1)
     return;
   op2 = gimple_call_arg (set_stmt, 0);
+  /* !!! I am not sure what the get_base_address is supposed to do here.
+         Still, it might make sense to support aggregate values even here.  */
   base = get_base_address (op2);
   parm = unmodified_parm (set_stmt, base ? base : op2);
   if (!parm)
@@ -1495,7 +1641,7 @@ set_cond_stmt_execution_predicate (struc
     if (e->flags & EDGE_FALSE_VALUE)
       {
 	struct predicate p = add_condition (summary,
-					    index,
+					    index, false, 0,
 					    IS_NOT_CONSTANT,
 					    NULL);
 	e->aux = pool_alloc (edge_predicate_pool);
@@ -1515,22 +1661,20 @@ set_switch_stmt_execution_predicate (str
   gimple last;
   tree op;
   int index;
+  bool agg_contents;
+  HOST_WIDE_INT offset;
   edge e;
   edge_iterator ei;
   size_t n;
   size_t case_idx;
-  tree parm;
 
   last = last_stmt (bb);
   if (!last
       || gimple_code (last) != GIMPLE_SWITCH)
     return;
   op = gimple_switch_index (last);
-  parm = unmodified_parm (last, op);
-  if (!parm)
-    return;
-  index = ipa_get_param_decl_index (info, parm);
-  if (index == -1)
+  if (!unmodified_parm_or_parm_agg_item (info, last, op, &index, &agg_contents,
+					&offset))
     return;
 
   FOR_EACH_EDGE (e, ei, bb->succs)
@@ -1555,16 +1699,16 @@ set_switch_stmt_execution_predicate (str
       if (!min && !max)
 	p = true_predicate ();
       else if (!max)
-	p = add_condition (summary, index,
+	p = add_condition (summary, index, agg_contents, offset,
 			   EQ_EXPR,
 			   min);
       else
 	{
 	  struct predicate p1, p2;
-	  p1 = add_condition (summary, index,
+	  p1 = add_condition (summary, index, agg_contents, offset,
 			      GE_EXPR,
 			      min);
-	  p2 = add_condition (summary, index,
+	  p2 = add_condition (summary, index, agg_contents, offset,
 			      LE_EXPR,
 			      max);
 	  p = and_predicates (summary->conds, &p1, &p2);
@@ -1660,13 +1804,14 @@ will_be_nonconstant_predicate (struct ip
 			       struct inline_summary *summary,
 			       gimple stmt,
 			       VEC (predicate_t, heap) *nonconstant_names)
-			      
 {
   struct predicate p = true_predicate ();
   ssa_op_iter iter;
   tree use;
   struct predicate op_non_const;
-  bool is_load;
+  bool is_load, agg_contents;
+  int base_index;
+  HOST_WIDE_INT offset;
 
   /* What statments might be optimized away
      when their arguments are constant
@@ -1682,31 +1827,27 @@ will_be_nonconstant_predicate (struct ip
     return p;
 
   is_load = gimple_vuse (stmt) != NULL;
-
-  /* Loads can be optimized when the value is known.  */
+   /* Loads can be optimized when the value is known.  */
   if (is_load)
     {
-      tree op = gimple_assign_rhs1 (stmt);
-      tree base = get_base_address (op);
-      tree parm;
-
+      tree op;
       gcc_assert (gimple_assign_single_p (stmt));
-      if (!base)
-	return p;
-      parm = unmodified_parm (stmt, base);
-      if (!parm )
-	return p;
-      if (ipa_get_param_decl_index (info, parm) < 0)
+      op = gimple_assign_rhs1 (stmt);
+      if (!unmodified_parm_or_parm_agg_item (info, stmt, op, &base_index,
+					     &agg_contents, &offset))
 	return p;
     }
+  else
+    base_index = -1;
 
   /* See if we understand all operands before we start
      adding conditionals.  */
   FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
     {
       tree parm = unmodified_parm (stmt, use);
+      int index;
       /* For arguments we can build a condition.  */
-      if (parm && ipa_get_param_decl_index (info, parm) >= 0)
+      if (parm && (index = ipa_get_param_decl_index (info, parm)) >= 0)
 	continue;
       if (TREE_CODE (use) != SSA_NAME)
 	return p;
@@ -1720,20 +1861,21 @@ will_be_nonconstant_predicate (struct ip
   op_non_const = false_predicate ();
   if (is_load)
     {
-      tree parm = unmodified_parm
-		    (stmt, get_base_address (gimple_assign_rhs1 (stmt)));
-      p = add_condition (summary,
-			 ipa_get_param_decl_index (info, parm),
+      p = add_condition (summary, base_index, agg_contents, offset,
 			 CHANGED, NULL);
       op_non_const = or_predicates (summary->conds, &p, &op_non_const);
     }
   FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
     {
       tree parm = unmodified_parm (stmt, use);
-      if (parm && ipa_get_param_decl_index (info, parm) >= 0)
-	p = add_condition (summary,
-			   ipa_get_param_decl_index (info, parm),
-			   CHANGED, NULL);
+      int index;
+
+      if (parm
+	  && (index = ipa_get_param_decl_index (info, parm)) >= 0)
+	{
+	  if (index != base_index)
+	    p = add_condition (summary, index, false, 0, CHANGED, NULL);
+	}
       else
 	p = *VEC_index (predicate_t, nonconstant_names,
 			SSA_NAME_VERSION (use));
@@ -2195,7 +2337,8 @@ static void
 estimate_edge_devirt_benefit (struct cgraph_edge *ie,
 			      int *size, int *time, int prob,
 			      VEC (tree, heap) *known_vals,
-			      VEC (tree, heap) *known_binfos)
+			      VEC (tree, heap) *known_binfos,
+			      VEC (ipa_agg_jump_function_p, heap) *known_aggs)
 {
   tree target;
   int time_diff, size_diff;
@@ -2203,7 +2346,8 @@ estimate_edge_devirt_benefit (struct cgr
   if (!known_vals && !known_binfos)
     return;
 
-  target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos);
+  target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos,
+					 known_aggs);
   if (!target)
     return;
 
@@ -2260,7 +2404,8 @@ static void
 estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time,
 			      clause_t possible_truths,
 			      VEC (tree, heap) *known_vals,
-			      VEC (tree, heap) *known_binfos)
+			      VEC (tree, heap) *known_binfos,
+			      VEC (ipa_agg_jump_function_p, heap) *known_aggs)
 {
   struct cgraph_edge *e;
   for (e = node->callees; e; e = e->next_callee)
@@ -2277,7 +2422,7 @@ estimate_calls_size_and_time (struct cgr
 	  else
 	    estimate_calls_size_and_time (e->callee, size, time,
 					  possible_truths,
-					  known_vals, known_binfos);
+					  known_vals, known_binfos, known_aggs);
 	}
     }
   for (e = node->indirect_calls; e; e = e->next_callee)
@@ -2287,7 +2432,7 @@ estimate_calls_size_and_time (struct cgr
 	{
 	  estimate_edge_size_and_time (e, size, time, REG_BR_PROB_BASE);
 	  estimate_edge_devirt_benefit (e, size, time, REG_BR_PROB_BASE,
-					known_vals, known_binfos);
+					known_vals, known_binfos, known_aggs);
 	}
     }
 }
@@ -2302,6 +2447,7 @@ estimate_node_size_and_time (struct cgra
 			     clause_t possible_truths,
 			     VEC (tree, heap) *known_vals,
 			     VEC (tree, heap) *known_binfos,
+			     VEC (ipa_agg_jump_function_p, heap) *known_aggs,
 		       	     int *ret_size, int *ret_time,
 			     VEC (inline_param_summary_t, heap)
 			       *inline_param_summary)
@@ -2353,7 +2499,7 @@ estimate_node_size_and_time (struct cgra
     time = MAX_TIME * INLINE_TIME_SCALE;
 
   estimate_calls_size_and_time (node, &size, &time, possible_truths,
-				known_vals, known_binfos);
+				known_vals, known_binfos, known_aggs);
   time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
   size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
 
@@ -2382,13 +2528,12 @@ estimate_ipcp_clone_size_and_time (struc
 {
   clause_t clause;
 
-  clause = evaluate_conditions_for_known_args (node, false, known_vals);
-  estimate_node_size_and_time (node, clause, known_vals, known_binfos,
+  clause = evaluate_conditions_for_known_args (node, false, known_vals, NULL);
+  estimate_node_size_and_time (node, clause, known_vals, known_binfos, NULL,
 			       ret_size, ret_time,
 			       NULL);
 }
 
-
 /* Translate all conditions from callee representation into caller
    representation and symbolically evaluate predicate P into new predicate.
 
@@ -2403,6 +2548,7 @@ remap_predicate (struct inline_summary *
 		 struct inline_summary *callee_info,
 		 struct predicate *p,
 		 VEC (int, heap) *operand_map,
+		 VEC (unsigned, heap) *offset_map,
 		 clause_t possible_truths,
 		 struct predicate *toplev_predicate)
 {
@@ -2437,13 +2583,25 @@ remap_predicate (struct inline_summary *
 		    Otherwise give up.  */
 		 if (!operand_map
 		     || (int)VEC_length (int, operand_map) <= c->operand_num
-		     || VEC_index (int, operand_map, c->operand_num) == -1)
+		     || VEC_index (int, operand_map, c->operand_num) == -1
+		     || (!c->agg_contents
+			 && VEC_index (unsigned, offset_map,
+				       c->operand_num) != 0))
 		   cond_predicate = true_predicate ();
 		 else
-		   cond_predicate = add_condition (info,
-						   VEC_index (int, operand_map,
-							      c->operand_num),
-						   c->code, c->val);
+		   {
+		     HOST_WIDE_INT new_offset;
+
+		     new_offset = c->offset + VEC_index (unsigned, offset_map,
+							 c->operand_num);
+		     cond_predicate = add_condition (info,
+						     VEC_index (int,
+								operand_map,
+								c->operand_num),
+						     c->agg_contents,
+						     new_offset, c->code,
+						     c->val);
+		   }
 	      }
 	    /* Fixed conditions remains same, construct single
 	       condition predicate.  */
@@ -2550,6 +2708,7 @@ remap_edge_summaries  (struct cgraph_edg
 		       struct inline_summary *info,
 		       struct inline_summary *callee_info,
 		       VEC (int, heap) *operand_map,
+		       VEC (unsigned, heap) *offset_map,
 		       clause_t possible_truths,
 		       struct predicate *toplev_predicate)
 {
@@ -2566,7 +2725,8 @@ remap_edge_summaries  (struct cgraph_edg
 	  if (es->predicate)
 	    {
 	      p = remap_predicate (info, callee_info,
-				   es->predicate, operand_map, possible_truths,
+				   es->predicate, operand_map, offset_map,
+				   possible_truths,
 				   toplev_predicate);
 	      edge_set_predicate (e, &p);
 	      /* TODO: We should remove the edge for code that will be
@@ -2583,7 +2743,8 @@ remap_edge_summaries  (struct cgraph_edg
 	}
       else
 	remap_edge_summaries (inlined_edge, e->callee, info, callee_info,
-			      operand_map, possible_truths, toplev_predicate);
+			      operand_map, offset_map, possible_truths,
+			      toplev_predicate);
     }
   for (e = node->indirect_calls; e; e = e->next_callee)
     {
@@ -2594,8 +2755,8 @@ remap_edge_summaries  (struct cgraph_edg
       if (es->predicate)
 	{
 	  p = remap_predicate (info, callee_info,
-			       es->predicate, operand_map, possible_truths,
-			       toplev_predicate);
+			       es->predicate, operand_map, offset_map,
+			       possible_truths, toplev_predicate);
 	  edge_set_predicate (e, &p);
 	  /* TODO: We should remove the edge for code that will be optimized
 	     out, but we need to keep verifiers and tree-inline happy.
@@ -2624,6 +2785,7 @@ inline_merge_summary (struct cgraph_edge
   clause_t clause = 0;		/* not_inline is known to be false.  */
   size_time_entry *e;
   VEC (int, heap) *operand_map = NULL;
+  VEC (unsigned, heap) *offset_map = NULL;
   int i;
   struct predicate toplev_predicate;
   struct predicate true_p = true_predicate ();
@@ -2640,9 +2802,12 @@ inline_merge_summary (struct cgraph_edge
       int count = ipa_get_cs_argument_count (args);
       int i;
 
-      evaluate_properties_for_edge (edge, true, &clause, NULL, NULL);
+      evaluate_properties_for_edge (edge, true, &clause, NULL, NULL, NULL);
       if (count)
-	VEC_safe_grow_cleared (int, heap, operand_map, count);
+	{
+	  VEC_safe_grow_cleared (int, heap, operand_map, count);
+	  VEC_safe_grow_cleared (unsigned, heap, offset_map, count);
+	}
       for (i = 0; i < count; i++)
 	{
 	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
@@ -2651,6 +2816,15 @@ inline_merge_summary (struct cgraph_edge
 	  if (jfunc->type == IPA_JF_PASS_THROUGH
 	      && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
 	    map = ipa_get_jf_pass_through_formal_id (jfunc);
+	  else if (jfunc->type == IPA_JF_ANCESTOR)
+	    {
+	      HOST_WIDE_INT offset = ipa_get_jf_ancestor_offset (jfunc);
+	      if (offset >= 0 && offset < UINT_MAX)
+		{
+		  map = ipa_get_jf_ancestor_formal_id (jfunc);
+		  VEC_replace (unsigned, offset_map, i, (unsigned) offset);
+		}
+	    }
 	  VEC_replace (int, operand_map, i, map);
 	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
 	}
@@ -2658,7 +2832,8 @@ inline_merge_summary (struct cgraph_edge
   for (i = 0; VEC_iterate (size_time_entry, callee_info->entry, i, e); i++)
     {
       struct predicate p = remap_predicate (info, callee_info,
-					    &e->predicate, operand_map, clause,
+					    &e->predicate, operand_map,
+					    offset_map, clause,
 					    &toplev_predicate);
       if (!false_predicate_p (&p))
 	{
@@ -2680,14 +2855,14 @@ inline_merge_summary (struct cgraph_edge
 	}
     }
   remap_edge_summaries (edge, edge->callee, info, callee_info, operand_map,
-			clause, &toplev_predicate);
+			offset_map, clause, &toplev_predicate);
   info->size = 0;
   info->time = 0;
   for (i = 0; VEC_iterate (size_time_entry, info->entry, i, e); i++)
     info->size += e->size, info->time += e->time;
   estimate_calls_size_and_time (to, &info->size, &info->time,
 				~(clause_t)(1 << predicate_false_condition),
-				NULL, NULL);
+				NULL, NULL, NULL);
 
   inline_update_callee_summaries (edge->callee,
 				  inline_edge_summary (edge)->loop_depth);
@@ -2697,6 +2872,7 @@ inline_merge_summary (struct cgraph_edge
   /* Similarly remove param summaries.  */
   VEC_free (inline_param_summary_t, heap, es->param);
   VEC_free (int, heap, operand_map);
+  VEC_free (unsigned, heap, offset_map);
 
   info->time = (info->time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
   info->size = (info->size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
@@ -2720,17 +2896,20 @@ do_estimate_edge_time (struct cgraph_edg
   clause_t clause;
   VEC (tree, heap) *known_vals;
   VEC (tree, heap) *known_binfos;
+  VEC (ipa_agg_jump_function_p, heap) *known_aggs;
   struct inline_edge_summary *es = inline_edge_summary (edge);
 
   callee = cgraph_function_or_thunk_node (edge->callee, NULL);
 
   gcc_checking_assert (edge->inline_failed);
   evaluate_properties_for_edge (edge, true,
-				&clause, &known_vals, &known_binfos);
+				&clause, &known_vals, &known_binfos,
+				&known_aggs);
   estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
-			       &size, &time, es->param);
+			       known_aggs, &size, &time, es->param);
   VEC_free (tree, heap, known_vals);
   VEC_free (tree, heap, known_binfos);
+  VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
 
   ret = (((gcov_type)time
 	   - es->call_stmt_time) * edge->frequency
@@ -2767,6 +2946,7 @@ do_estimate_edge_growth (struct cgraph_e
   clause_t clause;
   VEC (tree, heap) *known_vals;
   VEC (tree, heap) *known_binfos;
+  VEC (ipa_agg_jump_function_p, heap) *known_aggs;
 
   /* When we do caching, use do_estimate_edge_time to populate the entry.  */
 
@@ -2785,11 +2965,13 @@ do_estimate_edge_growth (struct cgraph_e
   /* Early inliner runs without caching, go ahead and do the dirty work.  */
   gcc_checking_assert (edge->inline_failed);
   evaluate_properties_for_edge (edge, true,
-				&clause, &known_vals, &known_binfos);
+				&clause, &known_vals, &known_binfos,
+				&known_aggs);
   estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
-			       &size, NULL, NULL);
+			       known_aggs, &size, NULL, NULL);
   VEC_free (tree, heap, known_vals);
   VEC_free (tree, heap, known_binfos);
+  VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
   gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size);
   return size - inline_edge_summary (edge)->call_stmt_size;
 }
@@ -3069,6 +3251,10 @@ inline_read_section (struct lto_file_dec
 	  c.operand_num = streamer_read_uhwi (&ib);
 	  c.code = (enum tree_code) streamer_read_uhwi (&ib);
 	  c.val = stream_read_tree (&ib, data_in);
+	  bp = streamer_read_bitpack (&ib);
+	  c.agg_contents = bp_unpack_value (&bp, 1);
+	  if (c.agg_contents)
+	    c.offset = streamer_read_uhwi (&ib);
 	  VEC_safe_push (condition, gc, info->conds, &c);
 	}
       count2 = streamer_read_uhwi (&ib);
@@ -3212,6 +3398,11 @@ inline_write_summary (cgraph_node_set se
 	      streamer_write_uhwi (ob, c->operand_num);
 	      streamer_write_uhwi (ob, c->code);
 	      stream_write_tree (ob, c->val, true);
+	      bp = bitpack_create (ob->main_stream);
+	      bp_pack_value (&bp, c->agg_contents, 1);
+	      streamer_write_bitpack (&bp);
+	      if (c->agg_contents)
+		streamer_write_uhwi (ob, c->offset);
 	    }
 	  streamer_write_uhwi (ob, VEC_length (size_time_entry, info->entry));
 	  for (i = 0;
Index: src/gcc/ipa-cp.c
===================================================================
--- src.orig/gcc/ipa-cp.c
+++ src/gcc/ipa-cp.c
@@ -1087,7 +1087,8 @@ propagate_constants_accross_call (struct
 tree
 ipa_get_indirect_edge_target (struct cgraph_edge *ie,
 			      VEC (tree, heap) *known_vals,
-			      VEC (tree, heap) *known_binfos)
+			      VEC (tree, heap) *known_binfos,
+			      VEC (ipa_agg_jump_function_p, heap) *known_aggs)
 {
   int param_index = ie->indirect_info->param_index;
   HOST_WIDE_INT token, anc_offset;
@@ -1099,8 +1100,26 @@ ipa_get_indirect_edge_target (struct cgr
 
   if (!ie->indirect_info->polymorphic)
     {
-      tree t = (VEC_length (tree, known_vals) > (unsigned int) param_index
-	        ? VEC_index (tree, known_vals, param_index) : NULL);
+      tree t;
+
+      if (ie->indirect_info->agg_contents)
+	{
+	  if (VEC_length (ipa_agg_jump_function_p, known_aggs)
+	      > (unsigned int) param_index)
+	    {
+	      struct ipa_agg_jump_function *agg;
+	      agg = VEC_index (ipa_agg_jump_function_p, known_aggs,
+			       param_index);
+	      t = ipa_find_agg_cst_for_param (agg, ie->indirect_info->offset,
+					      ie->caller, param_index);
+	    }
+	  else
+	    t = NULL;
+	}
+      else
+	t = (VEC_length (tree, known_vals) > (unsigned int) param_index
+	     ? VEC_index (tree, known_vals, param_index) : NULL);
+
       if (t &&
 	  TREE_CODE (t) == ADDR_EXPR
 	  && TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL)
@@ -1109,6 +1128,7 @@ ipa_get_indirect_edge_target (struct cgr
 	return NULL_TREE;
     }
 
+  gcc_assert (!ie->indirect_info->agg_contents);
   token = ie->indirect_info->otr_token;
   anc_offset = ie->indirect_info->offset;
   otr_type = ie->indirect_info->otr_type;
@@ -1159,7 +1179,8 @@ devirtualization_time_bonus (struct cgra
       struct inline_summary *isummary;
       tree target;
 
-      target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos);
+      target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos,
+					     NULL);
       if (!target)
 	continue;
 
@@ -1676,7 +1697,7 @@ ipcp_discover_new_direct_edges (struct c
       tree target;
 
       next_ie = ie->next_callee;
-      target = ipa_get_indirect_edge_target (ie, known_vals, NULL);
+      target = ipa_get_indirect_edge_target (ie, known_vals, NULL, NULL);
       if (target)
 	ipa_make_edge_direct_to_target (ie, target);
     }
Index: src/gcc/ipa-prop.h
===================================================================
--- src.orig/gcc/ipa-prop.h
+++ src/gcc/ipa-prop.h
@@ -500,8 +500,9 @@ bool ipa_propagate_indirect_call_infos (
 
 /* Indirect edge and binfo processing.  */
 tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
-				   VEC (tree, heap) *known_csts,
-				   VEC (tree, heap) *known_binfs);
+				   VEC (tree, heap) *,
+				   VEC (tree, heap) *,
+				   VEC (ipa_agg_jump_function_p, heap) *);
 struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
 
 /* Functions related to both.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]