public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis
@ 2012-08-02 19:28 Martin Jambor
  2012-08-03 15:50 ` Martin Jambor
  2012-08-29 15:45 ` H.J. Lu
  0 siblings, 2 replies; 10+ messages in thread
From: Martin Jambor @ 2012-08-02 19:28 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jan Hubicka

Hi,

this patch uses the aggregate jump functions created by the previous
patch in the series to determine benefits of inlining a particular
call graph edge.  It has not changed much since the last time I posted
it, except for the presence of by_ref flags and removal of checks
required by TBAA which we now do not use.

The patch works in fairly straightforward way.  It ads two flags to
struct condition to specify it actually refers to an aggregate passed
by value or something passed by reference, in both cases at a
particular 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 functions 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.

This patch alone makes us inline the function bar in testcase of PR
48636 in comment #4.  It also passes bootstrap and testing on
x86_64-linux.  I successfully LTO-built Firefox with it too.

Thanks for all comments and suggestions,

Martin


2012-07-31  Martin Jambor  <mjambor@suse.cz>

	PR fortran/48636
	* ipa-inline.h (condition): New fields offset, agg_contents and by_ref.
	* ipa-inline-analysis.c (agg_position_info): New type.
	(add_condition): New parameter aggpos, also store agg_contents, by_ref
	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.

	* testsuite/gfortran.dg/pr48636.f90: New test.


Index: src/gcc/ipa-inline.h
===================================================================
*** src.orig/gcc/ipa-inline.h
--- src/gcc/ipa-inline.h
*************** along with GCC; see the file COPYING3.
*** 28,36 ****
--- 28,45 ----
  
  typedef struct GTY(()) condition
    {
+     /* If agg_contents is set, this is the offset from which the used data was
+        loaded.  */
+     HOST_WIDE_INT offset;
      tree val;
      int operand_num;
      enum tree_code code;
+     /* Set if the used data were loaded from an aggregate parameter or from
+        data received by reference.  */
+     unsigned agg_contents : 1;
+     /* If agg_contents is set, this differentiates between loads from data
+        passed by reference and by value.  */
+     unsigned by_ref : 1;
    } 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
*************** not_inlined_predicate (void)
*** 203,224 ****
    return single_cond_predicate (predicate_not_inlined_condition);
  }
  
  
! /* Add condition to condition list CONDS.  */
  
  static struct predicate
  add_condition (struct inline_summary *summary, int operand_num,
  	       enum tree_code code, tree val)
  {
    int i;
    struct condition *c;
    struct condition new_cond;
  
    for (i = 0; VEC_iterate (condition, summary->conds, i, c); i++)
      {
        if (c->operand_num == operand_num
  	  && c->code == code
! 	  && c->val == val)
          return single_cond_predicate (i + predicate_first_dynamic_condition);
      }
    /* Too many conditions.  Give up and return constant true.  */
--- 203,256 ----
    return single_cond_predicate (predicate_not_inlined_condition);
  }
  
+ /* Simple description of whether a memory load or a condition refers to a load
+    from an aggregate and if so, how and where from in the aggregate.
+    Individual fields have the same meaning like fields with the same name in
+    struct condition.  */
+ 
+ struct agg_position_info
+ {
+   HOST_WIDE_INT offset;
+   bool agg_contents;
+   bool by_ref;
+ };
  
! /* Add condition to condition list CONDS.  AGGPOS describes whether the used
!    oprand is loaded from an aggregate and where in the aggregate it is.  It can
!    be NULL, which means this not a load from an aggregate.  */
  
  static struct predicate
  add_condition (struct inline_summary *summary, int operand_num,
+ 	       struct agg_position_info *aggpos,
  	       enum tree_code code, tree val)
  {
    int i;
    struct condition *c;
    struct condition new_cond;
+   HOST_WIDE_INT offset;
+   bool agg_contents, by_ref;
+ 
+   if (aggpos)
+     {
+       offset = aggpos->offset;
+       agg_contents = aggpos->agg_contents;
+       by_ref = aggpos->by_ref;
+     }
+   else
+     {
+       offset = 0;
+       agg_contents = false;
+       by_ref = false;
+     }
  
+   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->agg_contents == agg_contents
! 	  && (!agg_contents || (c->offset == offset && c->by_ref == by_ref)))
          return single_cond_predicate (i + predicate_first_dynamic_condition);
      }
    /* Too many conditions.  Give up and return constant true.  */
*************** add_condition (struct inline_summary *su
*** 228,233 ****
--- 260,268 ----
    new_cond.operand_num = operand_num;
    new_cond.code = code;
    new_cond.val = val;
+   new_cond.agg_contents = agg_contents;
+   new_cond.by_ref = by_ref;
+   new_cond.offset = offset;
    VEC_safe_push (condition, gc, summary->conds, &new_cond);
    return single_cond_predicate (i + predicate_first_dynamic_condition);
  }
*************** dump_condition (FILE *f, conditions cond
*** 519,524 ****
--- 554,561 ----
        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");
*************** edge_set_predicate (struct cgraph_edge *
*** 659,673 ****
  
  
  /* KNOWN_VALS is partial mapping of parameters of NODE to constant values.
!    Return clause of possible truths. When INLINE_P is true, assume that
!    we are inlining. 
  
     ERROR_MARK means compile time invariant.  */
  
  static clause_t
  evaluate_conditions_for_known_args (struct cgraph_node *node,
! 				    bool inline_p,
! 				    VEC (tree, heap) *known_vals)
  {
    clause_t clause = inline_p ? 0 : 1 << predicate_not_inlined_condition;
    struct inline_summary *info = inline_summary (node);
--- 696,712 ----
  
  
  /* KNOWN_VALS is partial mapping of parameters of NODE to constant values.
!    KNOWN_AGGS is a vector of aggreggate jump functions for each parameter.
!    Return clause of possible truths. When INLINE_P is true, assume that we are
!    inlining.
  
     ERROR_MARK means compile time invariant.  */
  
  static clause_t
  evaluate_conditions_for_known_args (struct cgraph_node *node,
! 				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);
*************** evaluate_conditions_for_known_args (stru
*** 679,694 ****
        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;
  
!       if (val == error_mark_node && c->code != CHANGED)
! 	val = NULL;
  
        if (!val)
  	{
--- 718,761 ----
        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 (we assume
! 	 known_aggs vector, if non-NULL, has the same length as
! 	 known_vals).  */
!       gcc_assert (!known_aggs
! 		  || (VEC_length (tree, known_vals)
! 		      == VEC_length (ipa_agg_jump_function_p, known_aggs)));
!       if (c->operand_num >= (int) VEC_length (tree, known_vals))
! 	{
! 	  clause |= 1 << (i + predicate_first_dynamic_condition);
! 	  continue;
! 	}
  
!       if (c->agg_contents)
! 	{
! 	  struct ipa_agg_jump_function *agg;
! 
! 	  if (c->code == CHANGED
! 	      && !c->by_ref
! 	      && (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, c->by_ref);
! 	    }
! 	  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)
  	{
*************** evaluate_conditions_for_known_args (stru
*** 711,723 ****
  
  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)
  {
    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;
  
    if (clause_ptr)
      *clause_ptr = inline_p ? 0 : 1 << predicate_not_inlined_condition;
--- 778,792 ----
  
  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,
! 			   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;
*************** evaluate_properties_for_edge (struct cgr
*** 742,754 ****
  
        if (count && (info->conds || known_vals_ptr))
  	VEC_safe_grow_cleared (tree, heap, known_vals, 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));
  	  if (cst)
  	    {
  	      if (known_vals && TREE_CODE (cst) != TREE_BINFO)
--- 811,826 ----
  
        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++)
  	{
! 	  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)
*************** evaluate_properties_for_edge (struct cgr
*** 761,777 ****
  				  es->param,
  				  i)->change_prob)
  	    VEC_replace (tree, known_vals, i, error_mark_node);
  	}
      }
  
    if (clause_ptr)
      *clause_ptr = evaluate_conditions_for_known_args (callee, inline_p,
! 						      known_vals);
  
    if (known_vals_ptr)
      *known_vals_ptr = known_vals;
    else
      VEC_free (tree, heap, known_vals);
  }
  
  
--- 833,857 ----
  				  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_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);
  }
  
  
*************** inline_node_duplication_hook (struct cgr
*** 917,924 ****
  		}
  	    }
  	}
!       possible_truths = evaluate_conditions_for_known_args (dst,
! 							    false, known_vals);
        VEC_free (tree, heap, known_vals);
  
        account_size_time (info, 0, 0, &true_pred);
--- 997,1004 ----
  		}
  	    }
  	}
!       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);
*************** mark_modified (ao_ref *ao ATTRIBUTE_UNUS
*** 1262,1272 ****
    return true;
  }
  
! /* If OP reffers to value of function parameter, return 
!    the corresponding parameter.  */
  
  static tree
! unmodified_parm (gimple stmt, tree op)
  {
    /* SSA_NAME referring to parm default def?  */
    if (TREE_CODE (op) == SSA_NAME
--- 1342,1352 ----
    return true;
  }
  
! /* If OP refers to value of function parameter, return the corresponding
!    parameter.  */
  
  static tree
! unmodified_parm_1 (gimple stmt, tree op)
  {
    /* SSA_NAME referring to parm default def?  */
    if (TREE_CODE (op) == SSA_NAME
*************** unmodified_parm (gimple stmt, tree op)
*** 1285,1297 ****
        if (!modified)
  	return op;
      }
!   /* Assignment from a parameter?  */
    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;
  }
  
  /* See if statement might disappear after inlining.
--- 1365,1430 ----
        if (!modified)
  	return op;
      }
!   return NULL_TREE;
! }
! 
! /* If OP refers to value of function parameter, return the corresponding
!    parameter.  Also traverse chains of SSA register assignments.  */
! 
! 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_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 and information whether
!    and how it has been loaded from an aggregate into *AGGPOS.  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,
! 				  struct agg_position_info *aggpos)
! {
!   tree res = unmodified_parm_1 (stmt, op);
! 
!   gcc_checking_assert (aggpos);
!   if (res)
!     {
!       *index_p = ipa_get_param_decl_index (info, res);
!       if (*index_p < 0)
! 	return false;
!       aggpos->agg_contents = 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 (!REFERENCE_CLASS_P (op))
! 	return unmodified_parm_or_parm_agg_item (info, stmt, op, index_p,
! 						 aggpos);
!     }
! 
!   aggpos->agg_contents = true;
!   return ipa_load_from_parm_agg (info, stmt, op, index_p, &aggpos->offset,
! 				 &aggpos->by_ref);
  }
  
  /* See if statement might disappear after inlining.
*************** set_cond_stmt_execution_predicate (struc
*** 1422,1427 ****
--- 1555,1561 ----
    gimple last;
    tree op;
    int index;
+   struct agg_position_info aggpos;
    enum tree_code code, inverted_code;
    edge e;
    edge_iterator ei;
*************** set_cond_stmt_execution_predicate (struc
*** 1440,1451 ****
    /* TODO: handle conditionals like
       var = op0 < 4;
       if (var != 0).  */
!   parm = unmodified_parm (last, op);
!   if (parm)
      {
-       index = ipa_get_param_decl_index (info, parm);
-       if (index == -1)
- 	return;
        code = gimple_cond_code (last);
        inverted_code
  	 = invert_tree_comparison (code,
--- 1574,1581 ----
    /* TODO: handle conditionals like
       var = op0 < 4;
       if (var != 0).  */
!   if (unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
      {
        code = gimple_cond_code (last);
        inverted_code
  	 = invert_tree_comparison (code,
*************** set_cond_stmt_execution_predicate (struc
*** 1453,1460 ****
  
        FOR_EACH_EDGE (e, ei, bb->succs)
  	{
! 	  struct predicate p = add_condition (summary,
! 					      index,
  					      e->flags & EDGE_TRUE_VALUE
  					      ? code : inverted_code,
  					      gimple_cond_rhs (last));
--- 1583,1589 ----
  
        FOR_EACH_EDGE (e, ei, bb->succs)
  	{
! 	  struct predicate p = add_condition (summary, index, &aggpos,
  					      e->flags & EDGE_TRUE_VALUE
  					      ? code : inverted_code,
  					      gimple_cond_rhs (last));
*************** set_cond_stmt_execution_predicate (struc
*** 1480,1485 ****
--- 1609,1615 ----
        || gimple_call_num_args (set_stmt) != 1)
      return;
    op2 = gimple_call_arg (set_stmt, 0);
+   /* TODO: Use unmodified_parm_or_parm_agg_item also here.  */
    base = get_base_address (op2);
    parm = unmodified_parm (set_stmt, base ? base : op2);
    if (!parm)
*************** set_cond_stmt_execution_predicate (struc
*** 1493,1502 ****
    FOR_EACH_EDGE (e, ei, bb->succs)
      if (e->flags & EDGE_FALSE_VALUE)
        {
! 	struct predicate p = add_condition (summary,
! 					    index,
! 					    IS_NOT_CONSTANT,
! 					    NULL);
  	e->aux = pool_alloc (edge_predicate_pool);
  	*(struct predicate *)e->aux = p;
        }
--- 1623,1630 ----
    FOR_EACH_EDGE (e, ei, bb->succs)
      if (e->flags & EDGE_FALSE_VALUE)
        {
! 	struct predicate p = add_condition (summary, index, NULL,
! 					    IS_NOT_CONSTANT, NULL_TREE);
  	e->aux = pool_alloc (edge_predicate_pool);
  	*(struct predicate *)e->aux = p;
        }
*************** set_switch_stmt_execution_predicate (str
*** 1514,1535 ****
    gimple last;
    tree op;
    int index;
    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)
      return;
  
    FOR_EACH_EDGE (e, ei, bb->succs)
--- 1642,1659 ----
    gimple last;
    tree op;
    int index;
+   struct agg_position_info aggpos;
    edge e;
    edge_iterator ei;
    size_t n;
    size_t case_idx;
  
    last = last_stmt (bb);
    if (!last
        || gimple_code (last) != GIMPLE_SWITCH)
      return;
    op = gimple_switch_index (last);
!   if (!unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
      return;
  
    FOR_EACH_EDGE (e, ei, bb->succs)
*************** set_switch_stmt_execution_predicate (str
*** 1554,1571 ****
        if (!min && !max)
  	p = true_predicate ();
        else if (!max)
! 	p = add_condition (summary, index,
! 			   EQ_EXPR,
! 			   min);
        else
  	{
  	  struct predicate p1, p2;
! 	  p1 = add_condition (summary, index,
! 			      GE_EXPR,
! 			      min);
! 	  p2 = add_condition (summary, index,
! 			      LE_EXPR,
! 			      max);
  	  p = and_predicates (summary->conds, &p1, &p2);
  	}
        *(struct predicate *)e->aux
--- 1678,1689 ----
        if (!min && !max)
  	p = true_predicate ();
        else if (!max)
! 	p = add_condition (summary, index, &aggpos, EQ_EXPR, min);
        else
  	{
  	  struct predicate p1, p2;
! 	  p1 = add_condition (summary, index, &aggpos, GE_EXPR, min);
! 	  p2 = add_condition (summary, index, &aggpos, LE_EXPR, max);
  	  p = and_predicates (summary->conds, &p1, &p2);
  	}
        *(struct predicate *)e->aux
*************** will_be_nonconstant_predicate (struct ip
*** 1659,1671 ****
  			       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;
  
    /* What statments might be optimized away
       when their arguments are constant
--- 1777,1790 ----
  			       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;
+   int base_index;
+   struct agg_position_info aggpos;
  
    /* What statments might be optimized away
       when their arguments are constant
*************** will_be_nonconstant_predicate (struct ip
*** 1681,1703 ****
      return p;
  
    is_load = gimple_vuse (stmt) != NULL;
- 
    /* 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;
! 
        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)
  	return p;
      }
  
    /* See if we understand all operands before we start
       adding conditionals.  */
--- 1800,1817 ----
      return p;
  
    is_load = gimple_vuse (stmt) != NULL;
    /* Loads can be optimized when the value is known.  */
    if (is_load)
      {
!       tree op;
        gcc_assert (gimple_assign_single_p (stmt));
!       op = gimple_assign_rhs1 (stmt);
!       if (!unmodified_parm_or_parm_agg_item (info, stmt, op, &base_index,
! 					     &aggpos))
  	return p;
      }
+   else
+     base_index = -1;
  
    /* See if we understand all operands before we start
       adding conditionals.  */
*************** will_be_nonconstant_predicate (struct ip
*** 1716,1738 ****
  	continue;
        return p;
      }
!   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),
! 			 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);
        else
  	p = *VEC_index (predicate_t, nonconstant_names,
  			SSA_NAME_VERSION (use));
--- 1830,1853 ----
  	continue;
        return p;
      }
! 
    if (is_load)
!     op_non_const = add_condition (summary, base_index, &aggpos, CHANGED, NULL);
!   else
!     op_non_const = false_predicate ();
    FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
      {
        tree parm = unmodified_parm (stmt, use);
!       int index;
! 
!       if (parm
! 	  && (index = ipa_get_param_decl_index (info, parm)) >= 0)
! 	{
! 	  if (index != base_index)
! 	    p = add_condition (summary, index, NULL, CHANGED, NULL_TREE);
! 	  else
! 	    continue;
! 	}
        else
  	p = *VEC_index (predicate_t, nonconstant_names,
  			SSA_NAME_VERSION (use));
*************** static void
*** 2194,2200 ****
  estimate_edge_devirt_benefit (struct cgraph_edge *ie,
  			      int *size, int *time, int prob,
  			      VEC (tree, heap) *known_vals,
! 			      VEC (tree, heap) *known_binfos)
  {
    tree target;
    int time_diff, size_diff;
--- 2309,2316 ----
  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 (ipa_agg_jump_function_p, heap) *known_aggs)
  {
    tree target;
    int time_diff, size_diff;
*************** estimate_edge_devirt_benefit (struct cgr
*** 2202,2208 ****
    if (!known_vals && !known_binfos)
      return;
  
!   target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos);
    if (!target)
      return;
  
--- 2318,2325 ----
    if (!known_vals && !known_binfos)
      return;
  
!   target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos,
! 					 known_aggs);
    if (!target)
      return;
  
*************** static void
*** 2259,2265 ****
  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)
  {
    struct cgraph_edge *e;
    for (e = node->callees; e; e = e->next_callee)
--- 2376,2383 ----
  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 (ipa_agg_jump_function_p, heap) *known_aggs)
  {
    struct cgraph_edge *e;
    for (e = node->callees; e; e = e->next_callee)
*************** estimate_calls_size_and_time (struct cgr
*** 2276,2282 ****
  	  else
  	    estimate_calls_size_and_time (e->callee, size, time,
  					  possible_truths,
! 					  known_vals, known_binfos);
  	}
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
--- 2394,2400 ----
  	  else
  	    estimate_calls_size_and_time (e->callee, size, time,
  					  possible_truths,
! 					  known_vals, known_binfos, known_aggs);
  	}
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
*************** estimate_calls_size_and_time (struct cgr
*** 2286,2292 ****
  	{
  	  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);
  	}
      }
  }
--- 2404,2410 ----
  	{
  	  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_aggs);
  	}
      }
  }
*************** estimate_node_size_and_time (struct cgra
*** 2301,2306 ****
--- 2419,2425 ----
  			     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)
*************** estimate_node_size_and_time (struct cgra
*** 2352,2358 ****
      time = MAX_TIME * INLINE_TIME_SCALE;
  
    estimate_calls_size_and_time (node, &size, &time, possible_truths,
! 				known_vals, known_binfos);
    time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  
--- 2471,2477 ----
      time = MAX_TIME * INLINE_TIME_SCALE;
  
    estimate_calls_size_and_time (node, &size, &time, possible_truths,
! 				known_vals, known_binfos, known_aggs);
    time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  
*************** estimate_ipcp_clone_size_and_time (struc
*** 2381,2407 ****
  {
    clause_t clause;
  
!   clause = evaluate_conditions_for_known_args (node, false, known_vals);
!   estimate_node_size_and_time (node, clause, known_vals, known_binfos,
  			       ret_size, ret_time,
  			       NULL);
  }
  
- 
  /* Translate all conditions from callee representation into caller
     representation and symbolically evaluate predicate P into new predicate.
  
!    INFO is inline_summary of function we are adding predicate into,
!    CALLEE_INFO is summary of function predicate P is from. OPERAND_MAP is
!    array giving callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is
!    clausule of all callee conditions that may be true in caller context.
!    TOPLEV_PREDICATE is predicate under which callee is executed.  */
  
  static struct predicate
  remap_predicate (struct inline_summary *info,
  		 struct inline_summary *callee_info,
  		 struct predicate *p,
  		 VEC (int, heap) *operand_map,
  		 clause_t possible_truths,
  		 struct predicate *toplev_predicate)
  {
--- 2500,2530 ----
  {
    clause_t clause;
  
!   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.
  
!    INFO is inline_summary of function we are adding predicate into, CALLEE_INFO
!    is summary of function predicate P is from. OPERAND_MAP is array giving
!    callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clausule of all
!    callee conditions that may be true in caller context.  TOPLEV_PREDICATE is
!    predicate under which callee is executed.  OFFSET_MAP is an array of of
!    offsets that need to be added to conditions, negative offset means that
!    conditions relying on values passed by reference have to be discarded
!    because they might not be preserved (and should be considered offset zero
!    for other purposes).  */
  
  static struct predicate
  remap_predicate (struct inline_summary *info,
  		 struct inline_summary *callee_info,
  		 struct predicate *p,
  		 VEC (int, heap) *operand_map,
+ 		 VEC (int, heap) *offset_map,
  		 clause_t possible_truths,
  		 struct predicate *toplev_predicate)
  {
*************** remap_predicate (struct inline_summary *
*** 2436,2448 ****
  		    Otherwise give up.  */
  		 if (!operand_map
  		     || (int)VEC_length (int, operand_map) <= c->operand_num
! 		     || VEC_index (int, operand_map, c->operand_num) == -1)
  		   cond_predicate = true_predicate ();
  		 else
! 		   cond_predicate = add_condition (info,
! 						   VEC_index (int, operand_map,
! 							      c->operand_num),
! 						   c->code, c->val);
  	      }
  	    /* Fixed conditions remains same, construct single
  	       condition predicate.  */
--- 2559,2592 ----
  		    Otherwise give up.  */
  		 if (!operand_map
  		     || (int)VEC_length (int, operand_map) <= c->operand_num
! 		     || VEC_index (int, operand_map, c->operand_num) == -1
! 		     || (!c->agg_contents
! 			 && VEC_index (int, offset_map, c->operand_num) != 0)
! 		     || (c->agg_contents && c->by_ref
! 			 && VEC_index (int, offset_map, c->operand_num) < 0))
  		   cond_predicate = true_predicate ();
  		 else
! 		   {
! 		     struct agg_position_info ap;
! 		     HOST_WIDE_INT offset_delta = VEC_index (int, offset_map,
! 							     c->operand_num);
! 		     if (offset_delta < 0)
! 		       {
! 			 gcc_checking_assert (!c->agg_contents || !c->by_ref);
! 			 offset_delta = 0;
! 		       }
! 		     gcc_assert (!c->agg_contents
! 				 || c->by_ref
! 				 || offset_delta == 0);
! 		     ap.offset = c->offset + offset_delta;
! 		     ap.agg_contents = c->agg_contents;
! 		     ap.by_ref = c->by_ref;
! 		     cond_predicate = add_condition (info,
! 						     VEC_index (int,
! 								operand_map,
! 								c->operand_num),
! 						     &ap, c->code, c->val);
! 		   }
  	      }
  	    /* Fixed conditions remains same, construct single
  	       condition predicate.  */
*************** remap_edge_summaries  (struct cgraph_edg
*** 2549,2554 ****
--- 2693,2699 ----
  		       struct inline_summary *info,
  		       struct inline_summary *callee_info,
  		       VEC (int, heap) *operand_map,
+ 		       VEC (int, heap) *offset_map,
  		       clause_t possible_truths,
  		       struct predicate *toplev_predicate)
  {
*************** remap_edge_summaries  (struct cgraph_edg
*** 2565,2571 ****
  	  if (es->predicate)
  	    {
  	      p = remap_predicate (info, callee_info,
! 				   es->predicate, operand_map, possible_truths,
  				   toplev_predicate);
  	      edge_set_predicate (e, &p);
  	      /* TODO: We should remove the edge for code that will be
--- 2710,2717 ----
  	  if (es->predicate)
  	    {
  	      p = remap_predicate (info, callee_info,
! 				   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
*************** remap_edge_summaries  (struct cgraph_edg
*** 2582,2588 ****
  	}
        else
  	remap_edge_summaries (inlined_edge, e->callee, info, callee_info,
! 			      operand_map, possible_truths, toplev_predicate);
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
      {
--- 2728,2735 ----
  	}
        else
  	remap_edge_summaries (inlined_edge, e->callee, info, callee_info,
! 			      operand_map, offset_map, possible_truths,
! 			      toplev_predicate);
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
      {
*************** remap_edge_summaries  (struct cgraph_edg
*** 2593,2600 ****
        if (es->predicate)
  	{
  	  p = remap_predicate (info, callee_info,
! 			       es->predicate, operand_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.
--- 2740,2747 ----
        if (es->predicate)
  	{
  	  p = remap_predicate (info, callee_info,
! 			       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.
*************** inline_merge_summary (struct cgraph_edge
*** 2623,2628 ****
--- 2770,2776 ----
    clause_t clause = 0;		/* not_inline is known to be false.  */
    size_time_entry *e;
    VEC (int, heap) *operand_map = NULL;
+   VEC (int, heap) *offset_map = NULL;
    int i;
    struct predicate toplev_predicate;
    struct predicate true_p = true_predicate ();
*************** inline_merge_summary (struct cgraph_edge
*** 2639,2655 ****
        int count = ipa_get_cs_argument_count (args);
        int i;
  
!       evaluate_properties_for_edge (edge, true, &clause, NULL, NULL);
        if (count)
! 	VEC_safe_grow_cleared (int, heap, operand_map, count);
        for (i = 0; i < count; i++)
  	{
  	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
  	  int map = -1;
  	  /* TODO: handle non-NOPs when merging.  */
! 	  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);
  	  VEC_replace (int, operand_map, i, map);
  	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
  	}
--- 2787,2821 ----
        int count = ipa_get_cs_argument_count (args);
        int i;
  
!       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, offset_map, count);
! 	}
        for (i = 0; i < count; i++)
  	{
  	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
  	  int map = -1;
+ 
  	  /* TODO: handle non-NOPs when merging.  */
! 	  if (jfunc->type == IPA_JF_PASS_THROUGH)
! 	    {
! 	      if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
! 		map = ipa_get_jf_pass_through_formal_id (jfunc);
! 	      if (!ipa_get_jf_pass_through_agg_preserved (jfunc))
! 		VEC_replace (int, offset_map, i, -1);
! 	    }
! 	  else if (jfunc->type == IPA_JF_ANCESTOR)
! 	    {
! 	      HOST_WIDE_INT offset = ipa_get_jf_ancestor_offset (jfunc);
! 	      if (offset >= 0 && offset < INT_MAX)
! 		{
! 		  map = ipa_get_jf_ancestor_formal_id (jfunc);
! 		  if (!ipa_get_jf_ancestor_agg_preserved (jfunc))
! 		    offset = -1;
! 		}
! 	    }
  	  VEC_replace (int, operand_map, i, map);
  	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
  	}
*************** inline_merge_summary (struct cgraph_edge
*** 2657,2663 ****
    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,
  					    &toplev_predicate);
        if (!false_predicate_p (&p))
  	{
--- 2823,2830 ----
    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,
! 					    offset_map, clause,
  					    &toplev_predicate);
        if (!false_predicate_p (&p))
  	{
*************** inline_merge_summary (struct cgraph_edge
*** 2679,2692 ****
  	}
      }
    remap_edge_summaries (edge, edge->callee, info, callee_info, operand_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);
  
    inline_update_callee_summaries (edge->callee,
  				  inline_edge_summary (edge)->loop_depth);
--- 2846,2859 ----
  	}
      }
    remap_edge_summaries (edge, edge->callee, info, callee_info, operand_map,
! 			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);
  
    inline_update_callee_summaries (edge->callee,
  				  inline_edge_summary (edge)->loop_depth);
*************** inline_merge_summary (struct cgraph_edge
*** 2696,2701 ****
--- 2863,2869 ----
    /* Similarly remove param summaries.  */
    VEC_free (inline_param_summary_t, heap, es->param);
    VEC_free (int, heap, operand_map);
+   VEC_free (int, 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;
*************** do_estimate_edge_time (struct cgraph_edg
*** 2719,2735 ****
    clause_t clause;
    VEC (tree, heap) *known_vals;
    VEC (tree, heap) *known_binfos;
    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);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       &size, &time, es->param);
    VEC_free (tree, heap, known_vals);
    VEC_free (tree, heap, known_binfos);
  
    ret = (((gcov_type)time
  	   - es->call_stmt_time) * edge->frequency
--- 2887,2906 ----
    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,
! 				&known_aggs);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       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
*************** do_estimate_edge_growth (struct cgraph_e
*** 2766,2771 ****
--- 2937,2943 ----
    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.  */
  
*************** do_estimate_edge_growth (struct cgraph_e
*** 2784,2794 ****
    /* 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);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       &size, NULL, NULL);
    VEC_free (tree, heap, known_vals);
    VEC_free (tree, heap, known_binfos);
    gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size);
    return size - inline_edge_summary (edge)->call_stmt_size;
  }
--- 2956,2968 ----
    /* 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,
! 				&known_aggs);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       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;
  }
*************** inline_read_section (struct lto_file_dec
*** 3068,3073 ****
--- 3242,3252 ----
  	  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);
+ 	  c.by_ref = 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);
*************** inline_write_summary (cgraph_node_set se
*** 3211,3216 ****
--- 3390,3401 ----
  	      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);
+ 	      bp_pack_value (&bp, c->by_ref, 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
*************** propagate_constants_accross_call (struct
*** 1084,1090 ****
  tree
  ipa_get_indirect_edge_target (struct cgraph_edge *ie,
  			      VEC (tree, heap) *known_vals,
! 			      VEC (tree, heap) *known_binfos)
  {
    int param_index = ie->indirect_info->param_index;
    HOST_WIDE_INT token, anc_offset;
--- 1084,1091 ----
  tree
  ipa_get_indirect_edge_target (struct cgraph_edge *ie,
  			      VEC (tree, heap) *known_vals,
! 			      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;
*************** ipa_get_indirect_edge_target (struct cgr
*** 1096,1103 ****
  
    if (!ie->indirect_info->polymorphic)
      {
!       tree 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)
--- 1097,1122 ----
  
    if (!ie->indirect_info->polymorphic)
      {
!       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->indirect_info->by_ref);
! 	    }
! 	  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)
*************** ipa_get_indirect_edge_target (struct cgr
*** 1106,1111 ****
--- 1125,1131 ----
  	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;
*************** devirtualization_time_bonus (struct cgra
*** 1156,1162 ****
        struct inline_summary *isummary;
        tree target;
  
!       target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos);
        if (!target)
  	continue;
  
--- 1176,1183 ----
        struct inline_summary *isummary;
        tree target;
  
!       target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos,
! 					     NULL);
        if (!target)
  	continue;
  
*************** ipcp_discover_new_direct_edges (struct c
*** 1673,1679 ****
        tree target;
  
        next_ie = ie->next_callee;
!       target = ipa_get_indirect_edge_target (ie, known_vals, NULL);
        if (target)
  	ipa_make_edge_direct_to_target (ie, target);
      }
--- 1694,1700 ----
        tree target;
  
        next_ie = ie->next_callee;
!       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
*************** bool ipa_propagate_indirect_call_infos (
*** 494,501 ****
  
  /* 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);
  struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
  
  /* Functions related to both.  */
--- 494,502 ----
  
  /* Indirect edge and binfo processing.  */
  tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
! 				   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: src/gcc/testsuite/gfortran.dg/pr48636.f90
===================================================================
*** /dev/null
--- src/gcc/testsuite/gfortran.dg/pr48636.f90
***************
*** 0 ****
--- 1,37 ----
+ ! { dg-do compile }
+ ! { dg-options "-O3 -fdump-ipa-inline" }
+ 
+ module foo
+   implicit none
+ contains
+   subroutine bar(a,x)
+     real, dimension(:,:), intent(in) :: a
+     real, intent(out) :: x
+     integer :: i,j
+ 
+     x = 0
+     do j=1,ubound(a,2)
+        do i=1,ubound(a,1)
+           x = x + a(i,j)**2
+        end do
+     end do
+   end subroutine bar
+ end module foo
+ 
+ program main
+   use foo
+   implicit none
+   real, dimension(2,3) :: a
+   real :: x
+   integer :: i
+ 
+   data a /1.0, 2.0, 3.0, -1.0, -2.0, -3.0/
+ 
+   do i=1,2000000
+      call bar(a,x)
+   end do
+   print *,x
+ end program main
+ 
+ ! { dg-final { scan-ipa-dump "bar\[^\\n\]*inline copy in MAIN" "inline" } }
+ ! { dg-final { cleanup-ipa-dump "inline" } }

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis
  2012-08-02 19:28 [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis Martin Jambor
@ 2012-08-03 15:50 ` Martin Jambor
  2012-08-10  3:12   ` Jan Hubicka
  2012-08-10  3:17   ` Jan Hubicka
  2012-08-29 15:45 ` H.J. Lu
  1 sibling, 2 replies; 10+ messages in thread
From: Martin Jambor @ 2012-08-03 15:50 UTC (permalink / raw)
  To: GCC Patches, Jan Hubicka

On Thu, Aug 02, 2012 at 09:28:11PM +0200, Martin Jambor wrote:
> Hi,
> 
> this patch uses the aggregate jump functions created by the previous
> patch in the series to determine benefits of inlining a particular
> call graph edge.  It has not changed much since the last time I posted
> it, except for the presence of by_ref flags and removal of checks
> required by TBAA which we now do not use.
> 
> The patch works in fairly straightforward way.  It ads two flags to
> struct condition to specify it actually refers to an aggregate passed
> by value or something passed by reference, in both cases at a
> particular 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 functions 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.
> 
> This patch alone makes us inline the function bar in testcase of PR
> 48636 in comment #4.  It also passes bootstrap and testing on
> x86_64-linux.  I successfully LTO-built Firefox with it too.
> 

And this version even passes (C, C++ and Fortran) LTO bootstrap
because it does not stream bits with undefined values
(condition->by_ref).

Thanks for all comments and suggestions,
 
Martin
 
 
2012-07-31  Martin Jambor  <mjambor@suse.cz>

	PR fortran/48636
	* ipa-inline.h (condition): New fields offset, agg_contents and by_ref.
	* ipa-inline-analysis.c (agg_position_info): New type.
	(add_condition): New parameter aggpos, also store agg_contents, by_ref
	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.

	* testsuite/gfortran.dg/pr48636.f90: New test.

Index: src/gcc/ipa-inline.h
===================================================================
*** src.orig/gcc/ipa-inline.h
--- src/gcc/ipa-inline.h
*************** along with GCC; see the file COPYING3.
*** 28,36 ****
--- 28,45 ----
  
  typedef struct GTY(()) condition
    {
+     /* If agg_contents is set, this is the offset from which the used data was
+        loaded.  */
+     HOST_WIDE_INT offset;
      tree val;
      int operand_num;
      enum tree_code code;
+     /* Set if the used data were loaded from an aggregate parameter or from
+        data received by reference.  */
+     unsigned agg_contents : 1;
+     /* If agg_contents is set, this differentiates between loads from data
+        passed by reference and by value.  */
+     unsigned by_ref : 1;
    } 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
*************** not_inlined_predicate (void)
*** 203,224 ****
    return single_cond_predicate (predicate_not_inlined_condition);
  }
  
  
! /* Add condition to condition list CONDS.  */
  
  static struct predicate
  add_condition (struct inline_summary *summary, int operand_num,
  	       enum tree_code code, tree val)
  {
    int i;
    struct condition *c;
    struct condition new_cond;
  
    for (i = 0; VEC_iterate (condition, summary->conds, i, c); i++)
      {
        if (c->operand_num == operand_num
  	  && c->code == code
! 	  && c->val == val)
          return single_cond_predicate (i + predicate_first_dynamic_condition);
      }
    /* Too many conditions.  Give up and return constant true.  */
--- 203,256 ----
    return single_cond_predicate (predicate_not_inlined_condition);
  }
  
+ /* Simple description of whether a memory load or a condition refers to a load
+    from an aggregate and if so, how and where from in the aggregate.
+    Individual fields have the same meaning like fields with the same name in
+    struct condition.  */
+ 
+ struct agg_position_info
+ {
+   HOST_WIDE_INT offset;
+   bool agg_contents;
+   bool by_ref;
+ };
  
! /* Add condition to condition list CONDS.  AGGPOS describes whether the used
!    oprand is loaded from an aggregate and where in the aggregate it is.  It can
!    be NULL, which means this not a load from an aggregate.  */
  
  static struct predicate
  add_condition (struct inline_summary *summary, int operand_num,
+ 	       struct agg_position_info *aggpos,
  	       enum tree_code code, tree val)
  {
    int i;
    struct condition *c;
    struct condition new_cond;
+   HOST_WIDE_INT offset;
+   bool agg_contents, by_ref;
+ 
+   if (aggpos)
+     {
+       offset = aggpos->offset;
+       agg_contents = aggpos->agg_contents;
+       by_ref = aggpos->by_ref;
+     }
+   else
+     {
+       offset = 0;
+       agg_contents = false;
+       by_ref = false;
+     }
  
+   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->agg_contents == agg_contents
! 	  && (!agg_contents || (c->offset == offset && c->by_ref == by_ref)))
          return single_cond_predicate (i + predicate_first_dynamic_condition);
      }
    /* Too many conditions.  Give up and return constant true.  */
*************** add_condition (struct inline_summary *su
*** 228,233 ****
--- 260,268 ----
    new_cond.operand_num = operand_num;
    new_cond.code = code;
    new_cond.val = val;
+   new_cond.agg_contents = agg_contents;
+   new_cond.by_ref = by_ref;
+   new_cond.offset = offset;
    VEC_safe_push (condition, gc, summary->conds, &new_cond);
    return single_cond_predicate (i + predicate_first_dynamic_condition);
  }
*************** dump_condition (FILE *f, conditions cond
*** 519,524 ****
--- 554,561 ----
        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");
*************** edge_set_predicate (struct cgraph_edge *
*** 659,673 ****
  
  
  /* KNOWN_VALS is partial mapping of parameters of NODE to constant values.
!    Return clause of possible truths. When INLINE_P is true, assume that
!    we are inlining. 
  
     ERROR_MARK means compile time invariant.  */
  
  static clause_t
  evaluate_conditions_for_known_args (struct cgraph_node *node,
! 				    bool inline_p,
! 				    VEC (tree, heap) *known_vals)
  {
    clause_t clause = inline_p ? 0 : 1 << predicate_not_inlined_condition;
    struct inline_summary *info = inline_summary (node);
--- 696,712 ----
  
  
  /* KNOWN_VALS is partial mapping of parameters of NODE to constant values.
!    KNOWN_AGGS is a vector of aggreggate jump functions for each parameter.
!    Return clause of possible truths. When INLINE_P is true, assume that we are
!    inlining.
  
     ERROR_MARK means compile time invariant.  */
  
  static clause_t
  evaluate_conditions_for_known_args (struct cgraph_node *node,
! 				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);
*************** evaluate_conditions_for_known_args (stru
*** 679,694 ****
        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;
  
!       if (val == error_mark_node && c->code != CHANGED)
! 	val = NULL;
  
        if (!val)
  	{
--- 718,761 ----
        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 (we assume
! 	 known_aggs vector, if non-NULL, has the same length as
! 	 known_vals).  */
!       gcc_assert (!known_aggs
! 		  || (VEC_length (tree, known_vals)
! 		      == VEC_length (ipa_agg_jump_function_p, known_aggs)));
!       if (c->operand_num >= (int) VEC_length (tree, known_vals))
! 	{
! 	  clause |= 1 << (i + predicate_first_dynamic_condition);
! 	  continue;
! 	}
  
!       if (c->agg_contents)
! 	{
! 	  struct ipa_agg_jump_function *agg;
! 
! 	  if (c->code == CHANGED
! 	      && !c->by_ref
! 	      && (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, c->by_ref);
! 	    }
! 	  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)
  	{
*************** evaluate_conditions_for_known_args (stru
*** 711,723 ****
  
  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)
  {
    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;
  
    if (clause_ptr)
      *clause_ptr = inline_p ? 0 : 1 << predicate_not_inlined_condition;
--- 778,792 ----
  
  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,
! 			   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;
*************** evaluate_properties_for_edge (struct cgr
*** 742,754 ****
  
        if (count && (info->conds || known_vals_ptr))
  	VEC_safe_grow_cleared (tree, heap, known_vals, 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));
  	  if (cst)
  	    {
  	      if (known_vals && TREE_CODE (cst) != TREE_BINFO)
--- 811,826 ----
  
        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++)
  	{
! 	  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)
*************** evaluate_properties_for_edge (struct cgr
*** 761,777 ****
  				  es->param,
  				  i)->change_prob)
  	    VEC_replace (tree, known_vals, i, error_mark_node);
  	}
      }
  
    if (clause_ptr)
      *clause_ptr = evaluate_conditions_for_known_args (callee, inline_p,
! 						      known_vals);
  
    if (known_vals_ptr)
      *known_vals_ptr = known_vals;
    else
      VEC_free (tree, heap, known_vals);
  }
  
  
--- 833,857 ----
  				  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_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);
  }
  
  
*************** inline_node_duplication_hook (struct cgr
*** 917,924 ****
  		}
  	    }
  	}
!       possible_truths = evaluate_conditions_for_known_args (dst,
! 							    false, known_vals);
        VEC_free (tree, heap, known_vals);
  
        account_size_time (info, 0, 0, &true_pred);
--- 997,1004 ----
  		}
  	    }
  	}
!       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);
*************** mark_modified (ao_ref *ao ATTRIBUTE_UNUS
*** 1262,1272 ****
    return true;
  }
  
! /* If OP reffers to value of function parameter, return 
!    the corresponding parameter.  */
  
  static tree
! unmodified_parm (gimple stmt, tree op)
  {
    /* SSA_NAME referring to parm default def?  */
    if (TREE_CODE (op) == SSA_NAME
--- 1342,1352 ----
    return true;
  }
  
! /* If OP refers to value of function parameter, return the corresponding
!    parameter.  */
  
  static tree
! unmodified_parm_1 (gimple stmt, tree op)
  {
    /* SSA_NAME referring to parm default def?  */
    if (TREE_CODE (op) == SSA_NAME
*************** unmodified_parm (gimple stmt, tree op)
*** 1285,1297 ****
        if (!modified)
  	return op;
      }
!   /* Assignment from a parameter?  */
    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;
  }
  
  /* See if statement might disappear after inlining.
--- 1365,1431 ----
        if (!modified)
  	return op;
      }
!   return NULL_TREE;
! }
! 
! /* If OP refers to value of function parameter, return the corresponding
!    parameter.  Also traverse chains of SSA register assignments.  */
! 
! 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_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 and information whether
!    and how it has been loaded from an aggregate into *AGGPOS.  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,
! 				  struct agg_position_info *aggpos)
! {
!   tree res = unmodified_parm_1 (stmt, op);
! 
!   gcc_checking_assert (aggpos);
!   if (res)
!     {
!       *index_p = ipa_get_param_decl_index (info, res);
!       if (*index_p < 0)
! 	return false;
!       aggpos->agg_contents = false;
!       aggpos->by_ref = 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 (!REFERENCE_CLASS_P (op))
! 	return unmodified_parm_or_parm_agg_item (info, stmt, op, index_p,
! 						 aggpos);
!     }
! 
!   aggpos->agg_contents = true;
!   return ipa_load_from_parm_agg (info, stmt, op, index_p, &aggpos->offset,
! 				 &aggpos->by_ref);
  }
  
  /* See if statement might disappear after inlining.
*************** set_cond_stmt_execution_predicate (struc
*** 1422,1427 ****
--- 1556,1562 ----
    gimple last;
    tree op;
    int index;
+   struct agg_position_info aggpos;
    enum tree_code code, inverted_code;
    edge e;
    edge_iterator ei;
*************** set_cond_stmt_execution_predicate (struc
*** 1440,1451 ****
    /* TODO: handle conditionals like
       var = op0 < 4;
       if (var != 0).  */
!   parm = unmodified_parm (last, op);
!   if (parm)
      {
-       index = ipa_get_param_decl_index (info, parm);
-       if (index == -1)
- 	return;
        code = gimple_cond_code (last);
        inverted_code
  	 = invert_tree_comparison (code,
--- 1575,1582 ----
    /* TODO: handle conditionals like
       var = op0 < 4;
       if (var != 0).  */
!   if (unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
      {
        code = gimple_cond_code (last);
        inverted_code
  	 = invert_tree_comparison (code,
*************** set_cond_stmt_execution_predicate (struc
*** 1453,1460 ****
  
        FOR_EACH_EDGE (e, ei, bb->succs)
  	{
! 	  struct predicate p = add_condition (summary,
! 					      index,
  					      e->flags & EDGE_TRUE_VALUE
  					      ? code : inverted_code,
  					      gimple_cond_rhs (last));
--- 1584,1590 ----
  
        FOR_EACH_EDGE (e, ei, bb->succs)
  	{
! 	  struct predicate p = add_condition (summary, index, &aggpos,
  					      e->flags & EDGE_TRUE_VALUE
  					      ? code : inverted_code,
  					      gimple_cond_rhs (last));
*************** set_cond_stmt_execution_predicate (struc
*** 1480,1485 ****
--- 1610,1616 ----
        || gimple_call_num_args (set_stmt) != 1)
      return;
    op2 = gimple_call_arg (set_stmt, 0);
+   /* TODO: Use unmodified_parm_or_parm_agg_item also here.  */
    base = get_base_address (op2);
    parm = unmodified_parm (set_stmt, base ? base : op2);
    if (!parm)
*************** set_cond_stmt_execution_predicate (struc
*** 1493,1502 ****
    FOR_EACH_EDGE (e, ei, bb->succs)
      if (e->flags & EDGE_FALSE_VALUE)
        {
! 	struct predicate p = add_condition (summary,
! 					    index,
! 					    IS_NOT_CONSTANT,
! 					    NULL);
  	e->aux = pool_alloc (edge_predicate_pool);
  	*(struct predicate *)e->aux = p;
        }
--- 1624,1631 ----
    FOR_EACH_EDGE (e, ei, bb->succs)
      if (e->flags & EDGE_FALSE_VALUE)
        {
! 	struct predicate p = add_condition (summary, index, NULL,
! 					    IS_NOT_CONSTANT, NULL_TREE);
  	e->aux = pool_alloc (edge_predicate_pool);
  	*(struct predicate *)e->aux = p;
        }
*************** set_switch_stmt_execution_predicate (str
*** 1514,1535 ****
    gimple last;
    tree op;
    int index;
    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)
      return;
  
    FOR_EACH_EDGE (e, ei, bb->succs)
--- 1643,1660 ----
    gimple last;
    tree op;
    int index;
+   struct agg_position_info aggpos;
    edge e;
    edge_iterator ei;
    size_t n;
    size_t case_idx;
  
    last = last_stmt (bb);
    if (!last
        || gimple_code (last) != GIMPLE_SWITCH)
      return;
    op = gimple_switch_index (last);
!   if (!unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
      return;
  
    FOR_EACH_EDGE (e, ei, bb->succs)
*************** set_switch_stmt_execution_predicate (str
*** 1554,1571 ****
        if (!min && !max)
  	p = true_predicate ();
        else if (!max)
! 	p = add_condition (summary, index,
! 			   EQ_EXPR,
! 			   min);
        else
  	{
  	  struct predicate p1, p2;
! 	  p1 = add_condition (summary, index,
! 			      GE_EXPR,
! 			      min);
! 	  p2 = add_condition (summary, index,
! 			      LE_EXPR,
! 			      max);
  	  p = and_predicates (summary->conds, &p1, &p2);
  	}
        *(struct predicate *)e->aux
--- 1679,1690 ----
        if (!min && !max)
  	p = true_predicate ();
        else if (!max)
! 	p = add_condition (summary, index, &aggpos, EQ_EXPR, min);
        else
  	{
  	  struct predicate p1, p2;
! 	  p1 = add_condition (summary, index, &aggpos, GE_EXPR, min);
! 	  p2 = add_condition (summary, index, &aggpos, LE_EXPR, max);
  	  p = and_predicates (summary->conds, &p1, &p2);
  	}
        *(struct predicate *)e->aux
*************** will_be_nonconstant_predicate (struct ip
*** 1659,1671 ****
  			       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;
  
    /* What statments might be optimized away
       when their arguments are constant
--- 1778,1791 ----
  			       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;
+   int base_index;
+   struct agg_position_info aggpos;
  
    /* What statments might be optimized away
       when their arguments are constant
*************** will_be_nonconstant_predicate (struct ip
*** 1681,1703 ****
      return p;
  
    is_load = gimple_vuse (stmt) != NULL;
- 
    /* 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;
! 
        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)
  	return p;
      }
  
    /* See if we understand all operands before we start
       adding conditionals.  */
--- 1801,1818 ----
      return p;
  
    is_load = gimple_vuse (stmt) != NULL;
    /* Loads can be optimized when the value is known.  */
    if (is_load)
      {
!       tree op;
        gcc_assert (gimple_assign_single_p (stmt));
!       op = gimple_assign_rhs1 (stmt);
!       if (!unmodified_parm_or_parm_agg_item (info, stmt, op, &base_index,
! 					     &aggpos))
  	return p;
      }
+   else
+     base_index = -1;
  
    /* See if we understand all operands before we start
       adding conditionals.  */
*************** will_be_nonconstant_predicate (struct ip
*** 1716,1738 ****
  	continue;
        return p;
      }
!   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),
! 			 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);
        else
  	p = *VEC_index (predicate_t, nonconstant_names,
  			SSA_NAME_VERSION (use));
--- 1831,1854 ----
  	continue;
        return p;
      }
! 
    if (is_load)
!     op_non_const = add_condition (summary, base_index, &aggpos, CHANGED, NULL);
!   else
!     op_non_const = false_predicate ();
    FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
      {
        tree parm = unmodified_parm (stmt, use);
!       int index;
! 
!       if (parm
! 	  && (index = ipa_get_param_decl_index (info, parm)) >= 0)
! 	{
! 	  if (index != base_index)
! 	    p = add_condition (summary, index, NULL, CHANGED, NULL_TREE);
! 	  else
! 	    continue;
! 	}
        else
  	p = *VEC_index (predicate_t, nonconstant_names,
  			SSA_NAME_VERSION (use));
*************** static void
*** 2194,2200 ****
  estimate_edge_devirt_benefit (struct cgraph_edge *ie,
  			      int *size, int *time, int prob,
  			      VEC (tree, heap) *known_vals,
! 			      VEC (tree, heap) *known_binfos)
  {
    tree target;
    int time_diff, size_diff;
--- 2310,2317 ----
  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 (ipa_agg_jump_function_p, heap) *known_aggs)
  {
    tree target;
    int time_diff, size_diff;
*************** estimate_edge_devirt_benefit (struct cgr
*** 2202,2208 ****
    if (!known_vals && !known_binfos)
      return;
  
!   target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos);
    if (!target)
      return;
  
--- 2319,2326 ----
    if (!known_vals && !known_binfos)
      return;
  
!   target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos,
! 					 known_aggs);
    if (!target)
      return;
  
*************** static void
*** 2259,2265 ****
  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)
  {
    struct cgraph_edge *e;
    for (e = node->callees; e; e = e->next_callee)
--- 2377,2384 ----
  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 (ipa_agg_jump_function_p, heap) *known_aggs)
  {
    struct cgraph_edge *e;
    for (e = node->callees; e; e = e->next_callee)
*************** estimate_calls_size_and_time (struct cgr
*** 2276,2282 ****
  	  else
  	    estimate_calls_size_and_time (e->callee, size, time,
  					  possible_truths,
! 					  known_vals, known_binfos);
  	}
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
--- 2395,2401 ----
  	  else
  	    estimate_calls_size_and_time (e->callee, size, time,
  					  possible_truths,
! 					  known_vals, known_binfos, known_aggs);
  	}
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
*************** estimate_calls_size_and_time (struct cgr
*** 2286,2292 ****
  	{
  	  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);
  	}
      }
  }
--- 2405,2411 ----
  	{
  	  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_aggs);
  	}
      }
  }
*************** estimate_node_size_and_time (struct cgra
*** 2301,2306 ****
--- 2420,2426 ----
  			     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)
*************** estimate_node_size_and_time (struct cgra
*** 2352,2358 ****
      time = MAX_TIME * INLINE_TIME_SCALE;
  
    estimate_calls_size_and_time (node, &size, &time, possible_truths,
! 				known_vals, known_binfos);
    time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  
--- 2472,2478 ----
      time = MAX_TIME * INLINE_TIME_SCALE;
  
    estimate_calls_size_and_time (node, &size, &time, possible_truths,
! 				known_vals, known_binfos, known_aggs);
    time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  
*************** estimate_ipcp_clone_size_and_time (struc
*** 2381,2407 ****
  {
    clause_t clause;
  
!   clause = evaluate_conditions_for_known_args (node, false, known_vals);
!   estimate_node_size_and_time (node, clause, known_vals, known_binfos,
  			       ret_size, ret_time,
  			       NULL);
  }
  
- 
  /* Translate all conditions from callee representation into caller
     representation and symbolically evaluate predicate P into new predicate.
  
!    INFO is inline_summary of function we are adding predicate into,
!    CALLEE_INFO is summary of function predicate P is from. OPERAND_MAP is
!    array giving callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is
!    clausule of all callee conditions that may be true in caller context.
!    TOPLEV_PREDICATE is predicate under which callee is executed.  */
  
  static struct predicate
  remap_predicate (struct inline_summary *info,
  		 struct inline_summary *callee_info,
  		 struct predicate *p,
  		 VEC (int, heap) *operand_map,
  		 clause_t possible_truths,
  		 struct predicate *toplev_predicate)
  {
--- 2501,2531 ----
  {
    clause_t clause;
  
!   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.
  
!    INFO is inline_summary of function we are adding predicate into, CALLEE_INFO
!    is summary of function predicate P is from. OPERAND_MAP is array giving
!    callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clausule of all
!    callee conditions that may be true in caller context.  TOPLEV_PREDICATE is
!    predicate under which callee is executed.  OFFSET_MAP is an array of of
!    offsets that need to be added to conditions, negative offset means that
!    conditions relying on values passed by reference have to be discarded
!    because they might not be preserved (and should be considered offset zero
!    for other purposes).  */
  
  static struct predicate
  remap_predicate (struct inline_summary *info,
  		 struct inline_summary *callee_info,
  		 struct predicate *p,
  		 VEC (int, heap) *operand_map,
+ 		 VEC (int, heap) *offset_map,
  		 clause_t possible_truths,
  		 struct predicate *toplev_predicate)
  {
*************** remap_predicate (struct inline_summary *
*** 2436,2448 ****
  		    Otherwise give up.  */
  		 if (!operand_map
  		     || (int)VEC_length (int, operand_map) <= c->operand_num
! 		     || VEC_index (int, operand_map, c->operand_num) == -1)
  		   cond_predicate = true_predicate ();
  		 else
! 		   cond_predicate = add_condition (info,
! 						   VEC_index (int, operand_map,
! 							      c->operand_num),
! 						   c->code, c->val);
  	      }
  	    /* Fixed conditions remains same, construct single
  	       condition predicate.  */
--- 2560,2593 ----
  		    Otherwise give up.  */
  		 if (!operand_map
  		     || (int)VEC_length (int, operand_map) <= c->operand_num
! 		     || VEC_index (int, operand_map, c->operand_num) == -1
! 		     || (!c->agg_contents
! 			 && VEC_index (int, offset_map, c->operand_num) != 0)
! 		     || (c->agg_contents && c->by_ref
! 			 && VEC_index (int, offset_map, c->operand_num) < 0))
  		   cond_predicate = true_predicate ();
  		 else
! 		   {
! 		     struct agg_position_info ap;
! 		     HOST_WIDE_INT offset_delta = VEC_index (int, offset_map,
! 							     c->operand_num);
! 		     if (offset_delta < 0)
! 		       {
! 			 gcc_checking_assert (!c->agg_contents || !c->by_ref);
! 			 offset_delta = 0;
! 		       }
! 		     gcc_assert (!c->agg_contents
! 				 || c->by_ref
! 				 || offset_delta == 0);
! 		     ap.offset = c->offset + offset_delta;
! 		     ap.agg_contents = c->agg_contents;
! 		     ap.by_ref = c->by_ref;
! 		     cond_predicate = add_condition (info,
! 						     VEC_index (int,
! 								operand_map,
! 								c->operand_num),
! 						     &ap, c->code, c->val);
! 		   }
  	      }
  	    /* Fixed conditions remains same, construct single
  	       condition predicate.  */
*************** remap_edge_summaries  (struct cgraph_edg
*** 2549,2554 ****
--- 2694,2700 ----
  		       struct inline_summary *info,
  		       struct inline_summary *callee_info,
  		       VEC (int, heap) *operand_map,
+ 		       VEC (int, heap) *offset_map,
  		       clause_t possible_truths,
  		       struct predicate *toplev_predicate)
  {
*************** remap_edge_summaries  (struct cgraph_edg
*** 2565,2571 ****
  	  if (es->predicate)
  	    {
  	      p = remap_predicate (info, callee_info,
! 				   es->predicate, operand_map, possible_truths,
  				   toplev_predicate);
  	      edge_set_predicate (e, &p);
  	      /* TODO: We should remove the edge for code that will be
--- 2711,2718 ----
  	  if (es->predicate)
  	    {
  	      p = remap_predicate (info, callee_info,
! 				   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
*************** remap_edge_summaries  (struct cgraph_edg
*** 2582,2588 ****
  	}
        else
  	remap_edge_summaries (inlined_edge, e->callee, info, callee_info,
! 			      operand_map, possible_truths, toplev_predicate);
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
      {
--- 2729,2736 ----
  	}
        else
  	remap_edge_summaries (inlined_edge, e->callee, info, callee_info,
! 			      operand_map, offset_map, possible_truths,
! 			      toplev_predicate);
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
      {
*************** remap_edge_summaries  (struct cgraph_edg
*** 2593,2600 ****
        if (es->predicate)
  	{
  	  p = remap_predicate (info, callee_info,
! 			       es->predicate, operand_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.
--- 2741,2748 ----
        if (es->predicate)
  	{
  	  p = remap_predicate (info, callee_info,
! 			       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.
*************** inline_merge_summary (struct cgraph_edge
*** 2623,2628 ****
--- 2771,2777 ----
    clause_t clause = 0;		/* not_inline is known to be false.  */
    size_time_entry *e;
    VEC (int, heap) *operand_map = NULL;
+   VEC (int, heap) *offset_map = NULL;
    int i;
    struct predicate toplev_predicate;
    struct predicate true_p = true_predicate ();
*************** inline_merge_summary (struct cgraph_edge
*** 2639,2655 ****
        int count = ipa_get_cs_argument_count (args);
        int i;
  
!       evaluate_properties_for_edge (edge, true, &clause, NULL, NULL);
        if (count)
! 	VEC_safe_grow_cleared (int, heap, operand_map, count);
        for (i = 0; i < count; i++)
  	{
  	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
  	  int map = -1;
  	  /* TODO: handle non-NOPs when merging.  */
! 	  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);
  	  VEC_replace (int, operand_map, i, map);
  	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
  	}
--- 2788,2822 ----
        int count = ipa_get_cs_argument_count (args);
        int i;
  
!       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, offset_map, count);
! 	}
        for (i = 0; i < count; i++)
  	{
  	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
  	  int map = -1;
+ 
  	  /* TODO: handle non-NOPs when merging.  */
! 	  if (jfunc->type == IPA_JF_PASS_THROUGH)
! 	    {
! 	      if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
! 		map = ipa_get_jf_pass_through_formal_id (jfunc);
! 	      if (!ipa_get_jf_pass_through_agg_preserved (jfunc))
! 		VEC_replace (int, offset_map, i, -1);
! 	    }
! 	  else if (jfunc->type == IPA_JF_ANCESTOR)
! 	    {
! 	      HOST_WIDE_INT offset = ipa_get_jf_ancestor_offset (jfunc);
! 	      if (offset >= 0 && offset < INT_MAX)
! 		{
! 		  map = ipa_get_jf_ancestor_formal_id (jfunc);
! 		  if (!ipa_get_jf_ancestor_agg_preserved (jfunc))
! 		    offset = -1;
! 		}
! 	    }
  	  VEC_replace (int, operand_map, i, map);
  	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
  	}
*************** inline_merge_summary (struct cgraph_edge
*** 2657,2663 ****
    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,
  					    &toplev_predicate);
        if (!false_predicate_p (&p))
  	{
--- 2824,2831 ----
    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,
! 					    offset_map, clause,
  					    &toplev_predicate);
        if (!false_predicate_p (&p))
  	{
*************** inline_merge_summary (struct cgraph_edge
*** 2679,2692 ****
  	}
      }
    remap_edge_summaries (edge, edge->callee, info, callee_info, operand_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);
  
    inline_update_callee_summaries (edge->callee,
  				  inline_edge_summary (edge)->loop_depth);
--- 2847,2860 ----
  	}
      }
    remap_edge_summaries (edge, edge->callee, info, callee_info, operand_map,
! 			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);
  
    inline_update_callee_summaries (edge->callee,
  				  inline_edge_summary (edge)->loop_depth);
*************** inline_merge_summary (struct cgraph_edge
*** 2696,2701 ****
--- 2864,2870 ----
    /* Similarly remove param summaries.  */
    VEC_free (inline_param_summary_t, heap, es->param);
    VEC_free (int, heap, operand_map);
+   VEC_free (int, 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;
*************** do_estimate_edge_time (struct cgraph_edg
*** 2719,2735 ****
    clause_t clause;
    VEC (tree, heap) *known_vals;
    VEC (tree, heap) *known_binfos;
    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);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       &size, &time, es->param);
    VEC_free (tree, heap, known_vals);
    VEC_free (tree, heap, known_binfos);
  
    ret = (((gcov_type)time
  	   - es->call_stmt_time) * edge->frequency
--- 2888,2907 ----
    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,
! 				&known_aggs);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       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
*************** do_estimate_edge_growth (struct cgraph_e
*** 2766,2771 ****
--- 2938,2944 ----
    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.  */
  
*************** do_estimate_edge_growth (struct cgraph_e
*** 2784,2794 ****
    /* 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);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       &size, NULL, NULL);
    VEC_free (tree, heap, known_vals);
    VEC_free (tree, heap, known_binfos);
    gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size);
    return size - inline_edge_summary (edge)->call_stmt_size;
  }
--- 2957,2969 ----
    /* 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,
! 				&known_aggs);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       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;
  }
*************** inline_read_section (struct lto_file_dec
*** 3068,3073 ****
--- 3243,3253 ----
  	  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);
+ 	  c.by_ref = 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);
*************** inline_write_summary (cgraph_node_set se
*** 3211,3216 ****
--- 3391,3402 ----
  	      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);
+ 	      bp_pack_value (&bp, c->by_ref, 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
*************** propagate_constants_accross_call (struct
*** 1084,1090 ****
  tree
  ipa_get_indirect_edge_target (struct cgraph_edge *ie,
  			      VEC (tree, heap) *known_vals,
! 			      VEC (tree, heap) *known_binfos)
  {
    int param_index = ie->indirect_info->param_index;
    HOST_WIDE_INT token, anc_offset;
--- 1084,1091 ----
  tree
  ipa_get_indirect_edge_target (struct cgraph_edge *ie,
  			      VEC (tree, heap) *known_vals,
! 			      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;
*************** ipa_get_indirect_edge_target (struct cgr
*** 1096,1103 ****
  
    if (!ie->indirect_info->polymorphic)
      {
!       tree 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)
--- 1097,1122 ----
  
    if (!ie->indirect_info->polymorphic)
      {
!       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->indirect_info->by_ref);
! 	    }
! 	  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)
*************** ipa_get_indirect_edge_target (struct cgr
*** 1106,1111 ****
--- 1125,1131 ----
  	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;
*************** devirtualization_time_bonus (struct cgra
*** 1156,1162 ****
        struct inline_summary *isummary;
        tree target;
  
!       target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos);
        if (!target)
  	continue;
  
--- 1176,1183 ----
        struct inline_summary *isummary;
        tree target;
  
!       target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos,
! 					     NULL);
        if (!target)
  	continue;
  
*************** ipcp_discover_new_direct_edges (struct c
*** 1673,1679 ****
        tree target;
  
        next_ie = ie->next_callee;
!       target = ipa_get_indirect_edge_target (ie, known_vals, NULL);
        if (target)
  	ipa_make_edge_direct_to_target (ie, target);
      }
--- 1694,1700 ----
        tree target;
  
        next_ie = ie->next_callee;
!       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
*************** bool ipa_propagate_indirect_call_infos (
*** 494,501 ****
  
  /* 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);
  struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
  
  /* Functions related to both.  */
--- 494,502 ----
  
  /* Indirect edge and binfo processing.  */
  tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
! 				   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: src/gcc/testsuite/gfortran.dg/pr48636.f90
===================================================================
*** /dev/null
--- src/gcc/testsuite/gfortran.dg/pr48636.f90
***************
*** 0 ****
--- 1,37 ----
+ ! { dg-do compile }
+ ! { dg-options "-O3 -fdump-ipa-inline" }
+ 
+ module foo
+   implicit none
+ contains
+   subroutine bar(a,x)
+     real, dimension(:,:), intent(in) :: a
+     real, intent(out) :: x
+     integer :: i,j
+ 
+     x = 0
+     do j=1,ubound(a,2)
+        do i=1,ubound(a,1)
+           x = x + a(i,j)**2
+        end do
+     end do
+   end subroutine bar
+ end module foo
+ 
+ program main
+   use foo
+   implicit none
+   real, dimension(2,3) :: a
+   real :: x
+   integer :: i
+ 
+   data a /1.0, 2.0, 3.0, -1.0, -2.0, -3.0/
+ 
+   do i=1,2000000
+      call bar(a,x)
+   end do
+   print *,x
+ end program main
+ 
+ ! { dg-final { scan-ipa-dump "bar\[^\\n\]*inline copy in MAIN" "inline" } }
+ ! { dg-final { cleanup-ipa-dump "inline" } }

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis
  2012-08-03 15:50 ` Martin Jambor
@ 2012-08-10  3:12   ` Jan Hubicka
  2012-08-10 14:40     ` Martin Jambor
  2012-08-15 15:34     ` Martin Jambor
  2012-08-10  3:17   ` Jan Hubicka
  1 sibling, 2 replies; 10+ messages in thread
From: Jan Hubicka @ 2012-08-10  3:12 UTC (permalink / raw)
  To: GCC Patches, Jan Hubicka

> Hi,
> 
> this patch uses the aggregate jump functions created by the previous
> patch in the series to determine benefits of inlining a particular
> call graph edge.  It has not changed much since the last time I posted
> it, except for the presence of by_ref flags and removal of checks
> required by TBAA which we now do not use.
> 
> The patch works in fairly straightforward way.  It ads two flags to
> struct condition to specify it actually refers to an aggregate passed
> by value or something passed by reference, in both cases at a
> particular 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 functions 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.
> 
> This patch alone makes us inline the function bar in testcase of PR
> 48636 in comment #4.  It also passes bootstrap and testing on
> x86_64-linux.  I successfully LTO-built Firefox with it too.
> 
> Thanks for all comments and suggestions,
> 
> Martin
> 
> 
> 2012-07-31  Martin Jambor  <mjambor@suse.cz>
> 
> 	PR fortran/48636
> 	* ipa-inline.h (condition): New fields offset, agg_contents and by_ref.
> 	* ipa-inline-analysis.c (agg_position_info): New type.
> 	(add_condition): New parameter aggpos, also store agg_contents, by_ref
> 	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.
> 
> 	* testsuite/gfortran.dg/pr48636.f90: New test.

OK with the following changes.

I plan to push out my inline hints code, so it would be nice if you commited soon 
so I cn resolve conflicts on my side.
> Index: src/gcc/ipa-inline.h
> ===================================================================
> *** src.orig/gcc/ipa-inline.h
> --- src/gcc/ipa-inline.h
> *************** along with GCC; see the file COPYING3.
> *** 28,36 ****
> --- 28,45 ----
>   
>   typedef struct GTY(()) condition
>     {
> +     /* If agg_contents is set, this is the offset from which the used data was
> +        loaded.  */
> +     HOST_WIDE_INT offset;
>       tree val;
>       int operand_num;
>       enum tree_code code;
> +     /* Set if the used data were loaded from an aggregate parameter or from
> +        data received by reference.  */
> +     unsigned agg_contents : 1;
> +     /* If agg_contents is set, this differentiates between loads from data
> +        passed by reference and by value.  */
> +     unsigned by_ref : 1;

Do you have any data on memory usage?  I was originally concerned about memory use of the
whole predicate thingy on WPA level.  Eventually we could add simple inheritance on
conditions and sort them into mutiple vectors if needed. But I assume it is OK or we
will work out on Mozilla builds soonish.

One obvious thing is to patch CODE and the bitfields so we fit in 3 64bit words.
> *************** dump_condition (FILE *f, conditions cond
> *** 519,524 ****
> --- 554,561 ----
>         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);
Dumping of by_ref?
>         if (c->code == IS_NOT_CONSTANT)
>   	{
>   	  fprintf (f, " not constant");
> --- 718,761 ----
>         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 (we assume
> ! 	 known_aggs vector, if non-NULL, has the same length as
> ! 	 known_vals).  */
> !       gcc_assert (!known_aggs
Perhaps checking_assert. This tends to be hot path of WPA inliner.
> --- 833,857 ----
>   				  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);

By merging of arggregate functions you meen propagating from caller to callee?
> ! /* 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 and information whether
> !    and how it has been loaded from an aggregate into *AGGPOS.  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,
> ! 				  struct agg_position_info *aggpos)

I assume this follows the same startegy as the ipa-cp code, right?
> *************** set_cond_stmt_execution_predicate (struc
> *** 1480,1485 ****
> --- 1609,1615 ----
>         || gimple_call_num_args (set_stmt) != 1)
>       return;
>     op2 = gimple_call_arg (set_stmt, 0);
> +   /* TODO: Use unmodified_parm_or_parm_agg_item also here.  */

Why it is TODO?
>     base = get_base_address (op2);
>     parm = unmodified_parm (set_stmt, base ? base : op2);
>     if (!parm)
> --- 1800,1817 ----
>       return p;
>   
>     is_load = gimple_vuse (stmt) != NULL;
>     /* Loads can be optimized when the value is known.  */
>     if (is_load)
>       {
> !       tree op;
>         gcc_assert (gimple_assign_single_p (stmt));
> !       op = gimple_assign_rhs1 (stmt);
> !       if (!unmodified_parm_or_parm_agg_item (info, stmt, op, &base_index,
> ! 					     &aggpos))
>   	return p;
>       }
> +   else
> +     base_index = -1;

Don't we miss the actual check that the load is load of known aggregate value on this path?
>   /* Translate all conditions from callee representation into caller
>      representation and symbolically evaluate predicate P into new predicate.
>   
> !    INFO is inline_summary of function we are adding predicate into, CALLEE_INFO
> !    is summary of function predicate P is from. OPERAND_MAP is array giving
> !    callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clausule of all
> !    callee conditions that may be true in caller context.  TOPLEV_PREDICATE is
> !    predicate under which callee is executed.  OFFSET_MAP is an array of of
> !    offsets that need to be added to conditions, negative offset means that
> !    conditions relying on values passed by reference have to be discarded
> !    because they might not be preserved (and should be considered offset zero
> !    for other purposes).  */

Do you handle cases like arg passed by value turning into arg passed by reference?
If not, just add an TODO.
Where do we verify that by_reference flags match?

Thanks,
Honza

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis
  2012-08-03 15:50 ` Martin Jambor
  2012-08-10  3:12   ` Jan Hubicka
@ 2012-08-10  3:17   ` Jan Hubicka
  1 sibling, 0 replies; 10+ messages in thread
From: Jan Hubicka @ 2012-08-10  3:17 UTC (permalink / raw)
  To: GCC Patches, Jan Hubicka

> *************** inline_merge_summary (struct cgraph_edge
> *** 2639,2655 ****
>         int count = ipa_get_cs_argument_count (args);
>         int i;
>   
> !       evaluate_properties_for_edge (edge, true, &clause, NULL, NULL);
>         if (count)
> ! 	VEC_safe_grow_cleared (int, heap, operand_map, count);
>         for (i = 0; i < count; i++)
>   	{
>   	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
>   	  int map = -1;
>   	  /* TODO: handle non-NOPs when merging.  */
> ! 	  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);
>   	  VEC_replace (int, operand_map, i, map);
>   	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
>   	}
> --- 2788,2822 ----
>         int count = ipa_get_cs_argument_count (args);
>         int i;
>   
> !       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, offset_map, count);
> ! 	}
>         for (i = 0; i < count; i++)
>   	{
>   	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
>   	  int map = -1;
> + 
>   	  /* TODO: handle non-NOPs when merging.  */
> ! 	  if (jfunc->type == IPA_JF_PASS_THROUGH)
> ! 	    {
> ! 	      if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
> ! 		map = ipa_get_jf_pass_through_formal_id (jfunc);
> ! 	      if (!ipa_get_jf_pass_through_agg_preserved (jfunc))
> ! 		VEC_replace (int, offset_map, i, -1);
> ! 	    }
> ! 	  else if (jfunc->type == IPA_JF_ANCESTOR)
> ! 	    {
> ! 	      HOST_WIDE_INT offset = ipa_get_jf_ancestor_offset (jfunc);
> ! 	      if (offset >= 0 && offset < INT_MAX)
> ! 		{
> ! 		  map = ipa_get_jf_ancestor_formal_id (jfunc);
> ! 		  if (!ipa_get_jf_ancestor_agg_preserved (jfunc))
> ! 		    offset = -1;
> ! 		}
Missing VEC_replace (int, offset_map, i, offset) here?
So we do not handle cases where operand is unpacked from aggregate and so on.
But it seems you are missing some matching of the aggregate flags here.

Honza

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis
  2012-08-10  3:12   ` Jan Hubicka
@ 2012-08-10 14:40     ` Martin Jambor
  2012-08-11 10:59       ` Martin Jambor
  2012-08-15 15:34     ` Martin Jambor
  1 sibling, 1 reply; 10+ messages in thread
From: Martin Jambor @ 2012-08-10 14:40 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: GCC Patches

Hi,

On Fri, Aug 10, 2012 at 05:12:31AM +0200, Jan Hubicka wrote:
> > Hi,
> > 

...

> > 
> > 2012-07-31  Martin Jambor  <mjambor@suse.cz>
> > 
> > 	PR fortran/48636
> > 	* ipa-inline.h (condition): New fields offset, agg_contents and by_ref.
> > 	* ipa-inline-analysis.c (agg_position_info): New type.
> > 	(add_condition): New parameter aggpos, also store agg_contents, by_ref
> > 	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.
> > 
> > 	* testsuite/gfortran.dg/pr48636.f90: New test.
> 
> OK with the following changes.
> 
> I plan to push out my inline hints code, so it would be nice if you commited soon 
> so I cn resolve conflicts on my side.
> > Index: src/gcc/ipa-inline.h
> > ===================================================================
> > *** src.orig/gcc/ipa-inline.h
> > --- src/gcc/ipa-inline.h
> > *************** along with GCC; see the file COPYING3.
> > *** 28,36 ****
> > --- 28,45 ----
> >   
> >   typedef struct GTY(()) condition
> >     {
> > +     /* If agg_contents is set, this is the offset from which the used data was
> > +        loaded.  */
> > +     HOST_WIDE_INT offset;
> >       tree val;
> >       int operand_num;
> >       enum tree_code code;
> > +     /* Set if the used data were loaded from an aggregate parameter or from
> > +        data received by reference.  */
> > +     unsigned agg_contents : 1;
> > +     /* If agg_contents is set, this differentiates between loads from data
> > +        passed by reference and by value.  */
> > +     unsigned by_ref : 1;
> 

> Do you have any data on memory usage?  I was originally concerned
> about memory use of the whole predicate thingy on WPA level.
> Eventually we could add simple inheritance on conditions and sort
> them into mutiple vectors if needed. But I assume it is OK or we
> will work out on Mozilla builds soonish.
> 
> One obvious thing is to patch CODE and the bitfields so we fit in 3
> 64bit words.

OK, I made it an enum, I will look at memory consumption in a while.

> > *************** dump_condition (FILE *f, conditions cond
> > *** 519,524 ****
> > --- 554,561 ----
> >         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);
> Dumping of by_ref?

I added that.

> >         if (c->code == IS_NOT_CONSTANT)
> >   	{
> >   	  fprintf (f, " not constant");
> > --- 718,761 ----
> >         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 (we assume
> > ! 	 known_aggs vector, if non-NULL, has the same length as
> > ! 	 known_vals).  */
> > !       gcc_assert (!known_aggs
> Perhaps checking_assert. This tends to be hot path of WPA inliner.

OK

> > --- 833,857 ----
> >   				  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);
> 
> By merging of arggregate functions you meen propagating from caller to callee?

Yes, and merging of constants flowing from different callees.  I added
the verb propagating to the todo.

> > ! /* 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 and information whether
> > !    and how it has been loaded from an aggregate into *AGGPOS.  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,
> > ! 				  struct agg_position_info *aggpos)
> 
> I assume this follows the same startegy as the ipa-cp code, right?

As indirect inlining, yes.  ipa_load_from_parm_agg is used by both.

> > *************** set_cond_stmt_execution_predicate (struc
> > *** 1480,1485 ****
> > --- 1609,1615 ----
> >         || gimple_call_num_args (set_stmt) != 1)
> >       return;
> >     op2 = gimple_call_arg (set_stmt, 0);
> > +   /* TODO: Use unmodified_parm_or_parm_agg_item also here.  */
> 
> Why it is TODO?

I'm not sure, I simply left it for later but I have converted it now.

> >   /* Translate all conditions from callee representation into caller
> >      representation and symbolically evaluate predicate P into new predicate.
> >   
> > !    INFO is inline_summary of function we are adding predicate into, CALLEE_INFO
> > !    is summary of function predicate P is from. OPERAND_MAP is array giving
> > !    callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clausule of all
> > !    callee conditions that may be true in caller context.  TOPLEV_PREDICATE is
> > !    predicate under which callee is executed.  OFFSET_MAP is an array of of
> > !    offsets that need to be added to conditions, negative offset means that
> > !    conditions relying on values passed by reference have to be discarded
> > !    because they might not be preserved (and should be considered offset zero
> > !    for other purposes).  */
> 
> Do you handle cases like arg passed by value turning into arg passed
> by reference?  If not, just add an TODO.  Where do we verify that
> by_reference flags match?

No, there isn't a jump function for that.  I will add a todo to
ipa-prop.h to my local modifications.

On Fri, Aug 10, 2012 at 05:17:23AM +0200, Jan Hubicka wrote:
> > *************** inline_merge_summary (struct cgraph_edge
> > *** 2639,2655 ****
> >         int count = ipa_get_cs_argument_count (args);
> >         int i;
> >   
> > !       evaluate_properties_for_edge (edge, true, &clause, NULL, NULL);
> >         if (count)
> > ! 	VEC_safe_grow_cleared (int, heap, operand_map, count);
> >         for (i = 0; i < count; i++)
> >   	{
> >   	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
> >   	  int map = -1;
> >   	  /* TODO: handle non-NOPs when merging.  */
> > ! 	  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);
> >   	  VEC_replace (int, operand_map, i, map);
> >   	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
> >   	}
> > --- 2788,2822 ----
> >         int count = ipa_get_cs_argument_count (args);
> >         int i;
> >   
> > !       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, offset_map, count);
> > ! 	}
> >         for (i = 0; i < count; i++)
> >   	{
> >   	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
> >   	  int map = -1;
> > + 
> >   	  /* TODO: handle non-NOPs when merging.  */
> > ! 	  if (jfunc->type == IPA_JF_PASS_THROUGH)
> > ! 	    {
> > ! 	      if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
> > ! 		map = ipa_get_jf_pass_through_formal_id (jfunc);
> > ! 	      if (!ipa_get_jf_pass_through_agg_preserved (jfunc))
> > ! 		VEC_replace (int, offset_map, i, -1);
> > ! 	    }
> > ! 	  else if (jfunc->type == IPA_JF_ANCESTOR)
> > ! 	    {
> > ! 	      HOST_WIDE_INT offset = ipa_get_jf_ancestor_offset (jfunc);
> > ! 	      if (offset >= 0 && offset < INT_MAX)
> > ! 		{
> > ! 		  map = ipa_get_jf_ancestor_formal_id (jfunc);
> > ! 		  if (!ipa_get_jf_ancestor_agg_preserved (jfunc))
> > ! 		    offset = -1;
> > ! 		}
> Missing VEC_replace (int, offset_map, i, offset) here?

Right, I added it.

> So we do not handle cases where operand is unpacked from aggregate and so on.

No, again, we'd need a special jump function for that.

> But it seems you are missing some matching of the aggregate flags here.

I believe I do that in remap_predicate into which the operand_map and
offset_map are passed.

I'm now testing the following patch, I will commit it to trunk if
tests go fine.  The change log is the same.

Thanks a lot,

Martin


Index: src/gcc/ipa-inline.h
===================================================================
*** src.orig/gcc/ipa-inline.h
--- src/gcc/ipa-inline.h
*************** along with GCC; see the file COPYING3.
*** 28,36 ****
  
  typedef struct GTY(()) condition
    {
      tree val;
      int operand_num;
!     enum tree_code code;
    } condition;
  
  DEF_VEC_O (condition);
--- 28,45 ----
  
  typedef struct GTY(()) condition
    {
+     /* If agg_contents is set, this is the offset from which the used data was
+        loaded.  */
+     HOST_WIDE_INT offset;
      tree val;
      int operand_num;
!     ENUM_BITFIELD(tree_code) code : 16;
!     /* Set if the used data were loaded from an aggregate parameter or from
!        data received by reference.  */
!     unsigned agg_contents : 1;
!     /* If agg_contents is set, this differentiates between loads from data
!        passed by reference and by value.  */
!     unsigned by_ref : 1;
    } 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
*************** not_inlined_predicate (void)
*** 203,224 ****
    return single_cond_predicate (predicate_not_inlined_condition);
  }
  
  
! /* Add condition to condition list CONDS.  */
  
  static struct predicate
  add_condition (struct inline_summary *summary, int operand_num,
  	       enum tree_code code, tree val)
  {
    int i;
    struct condition *c;
    struct condition new_cond;
  
    for (i = 0; VEC_iterate (condition, summary->conds, i, c); i++)
      {
        if (c->operand_num == operand_num
  	  && c->code == code
! 	  && c->val == val)
          return single_cond_predicate (i + predicate_first_dynamic_condition);
      }
    /* Too many conditions.  Give up and return constant true.  */
--- 203,256 ----
    return single_cond_predicate (predicate_not_inlined_condition);
  }
  
+ /* Simple description of whether a memory load or a condition refers to a load
+    from an aggregate and if so, how and where from in the aggregate.
+    Individual fields have the same meaning like fields with the same name in
+    struct condition.  */
+ 
+ struct agg_position_info
+ {
+   HOST_WIDE_INT offset;
+   bool agg_contents;
+   bool by_ref;
+ };
  
! /* Add condition to condition list CONDS.  AGGPOS describes whether the used
!    oprand is loaded from an aggregate and where in the aggregate it is.  It can
!    be NULL, which means this not a load from an aggregate.  */
  
  static struct predicate
  add_condition (struct inline_summary *summary, int operand_num,
+ 	       struct agg_position_info *aggpos,
  	       enum tree_code code, tree val)
  {
    int i;
    struct condition *c;
    struct condition new_cond;
+   HOST_WIDE_INT offset;
+   bool agg_contents, by_ref;
+ 
+   if (aggpos)
+     {
+       offset = aggpos->offset;
+       agg_contents = aggpos->agg_contents;
+       by_ref = aggpos->by_ref;
+     }
+   else
+     {
+       offset = 0;
+       agg_contents = false;
+       by_ref = false;
+     }
  
+   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->agg_contents == agg_contents
! 	  && (!agg_contents || (c->offset == offset && c->by_ref == by_ref)))
          return single_cond_predicate (i + predicate_first_dynamic_condition);
      }
    /* Too many conditions.  Give up and return constant true.  */
*************** add_condition (struct inline_summary *su
*** 228,233 ****
--- 260,268 ----
    new_cond.operand_num = operand_num;
    new_cond.code = code;
    new_cond.val = val;
+   new_cond.agg_contents = agg_contents;
+   new_cond.by_ref = by_ref;
+   new_cond.offset = offset;
    VEC_safe_push (condition, gc, summary->conds, &new_cond);
    return single_cond_predicate (i + predicate_first_dynamic_condition);
  }
*************** dump_condition (FILE *f, conditions cond
*** 519,524 ****
--- 554,562 ----
        c = VEC_index (condition, conditions,
  		     cond - predicate_first_dynamic_condition);
        fprintf (f, "op%i", c->operand_num);
+       if (c->agg_contents)
+ 	fprintf (f, "[%soffset: " HOST_WIDE_INT_PRINT_DEC "]",
+ 		 c->by_ref ? "ref " : "", c->offset);
        if (c->code == IS_NOT_CONSTANT)
  	{
  	  fprintf (f, " not constant");
*************** edge_set_predicate (struct cgraph_edge *
*** 659,673 ****
  
  
  /* KNOWN_VALS is partial mapping of parameters of NODE to constant values.
!    Return clause of possible truths. When INLINE_P is true, assume that
!    we are inlining. 
  
     ERROR_MARK means compile time invariant.  */
  
  static clause_t
  evaluate_conditions_for_known_args (struct cgraph_node *node,
! 				    bool inline_p,
! 				    VEC (tree, heap) *known_vals)
  {
    clause_t clause = inline_p ? 0 : 1 << predicate_not_inlined_condition;
    struct inline_summary *info = inline_summary (node);
--- 697,713 ----
  
  
  /* KNOWN_VALS is partial mapping of parameters of NODE to constant values.
!    KNOWN_AGGS is a vector of aggreggate jump functions for each parameter.
!    Return clause of possible truths. When INLINE_P is true, assume that we are
!    inlining.
  
     ERROR_MARK means compile time invariant.  */
  
  static clause_t
  evaluate_conditions_for_known_args (struct cgraph_node *node,
! 				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);
*************** evaluate_conditions_for_known_args (stru
*** 679,694 ****
        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;
  
!       if (val == error_mark_node && c->code != CHANGED)
! 	val = NULL;
  
        if (!val)
  	{
--- 719,763 ----
        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 (we assume
! 	 known_aggs vector, if non-NULL, has the same length as
! 	 known_vals).  */
!       gcc_checking_assert (!known_aggs
! 			   || (VEC_length (tree, known_vals)
! 			       == VEC_length (ipa_agg_jump_function_p,
! 					      known_aggs)));
!       if (c->operand_num >= (int) VEC_length (tree, known_vals))
! 	{
! 	  clause |= 1 << (i + predicate_first_dynamic_condition);
! 	  continue;
! 	}
! 
!       if (c->agg_contents)
! 	{
! 	  struct ipa_agg_jump_function *agg;
! 
! 	  if (c->code == CHANGED
! 	      && !c->by_ref
! 	      && (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, c->by_ref);
! 	    }
! 	  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)
  	{
*************** evaluate_conditions_for_known_args (stru
*** 711,723 ****
  
  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)
  {
    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;
  
    if (clause_ptr)
      *clause_ptr = inline_p ? 0 : 1 << predicate_not_inlined_condition;
--- 780,794 ----
  
  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,
! 			   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;
*************** evaluate_properties_for_edge (struct cgr
*** 742,754 ****
  
        if (count && (info->conds || known_vals_ptr))
  	VEC_safe_grow_cleared (tree, heap, known_vals, 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));
  	  if (cst)
  	    {
  	      if (known_vals && TREE_CODE (cst) != TREE_BINFO)
--- 813,828 ----
  
        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++)
  	{
! 	  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)
*************** evaluate_properties_for_edge (struct cgr
*** 761,777 ****
  				  es->param,
  				  i)->change_prob)
  	    VEC_replace (tree, known_vals, i, error_mark_node);
  	}
      }
  
    if (clause_ptr)
      *clause_ptr = evaluate_conditions_for_known_args (callee, inline_p,
! 						      known_vals);
  
    if (known_vals_ptr)
      *known_vals_ptr = known_vals;
    else
      VEC_free (tree, heap, known_vals);
  }
  
  
--- 835,860 ----
  				  es->param,
  				  i)->change_prob)
  	    VEC_replace (tree, known_vals, i, error_mark_node);
+ 	  /* TODO: When IPA-CP starts propagating and 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_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);
  }
  
  
*************** inline_node_duplication_hook (struct cgr
*** 917,924 ****
  		}
  	    }
  	}
!       possible_truths = evaluate_conditions_for_known_args (dst,
! 							    false, known_vals);
        VEC_free (tree, heap, known_vals);
  
        account_size_time (info, 0, 0, &true_pred);
--- 1000,1007 ----
  		}
  	    }
  	}
!       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);
*************** mark_modified (ao_ref *ao ATTRIBUTE_UNUS
*** 1262,1272 ****
    return true;
  }
  
! /* If OP reffers to value of function parameter, return 
!    the corresponding parameter.  */
  
  static tree
! unmodified_parm (gimple stmt, tree op)
  {
    /* SSA_NAME referring to parm default def?  */
    if (TREE_CODE (op) == SSA_NAME
--- 1345,1355 ----
    return true;
  }
  
! /* If OP refers to value of function parameter, return the corresponding
!    parameter.  */
  
  static tree
! unmodified_parm_1 (gimple stmt, tree op)
  {
    /* SSA_NAME referring to parm default def?  */
    if (TREE_CODE (op) == SSA_NAME
*************** unmodified_parm (gimple stmt, tree op)
*** 1285,1297 ****
        if (!modified)
  	return op;
      }
!   /* Assignment from a parameter?  */
    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;
  }
  
  /* See if statement might disappear after inlining.
--- 1368,1434 ----
        if (!modified)
  	return op;
      }
!   return NULL_TREE;
! }
! 
! /* If OP refers to value of function parameter, return the corresponding
!    parameter.  Also traverse chains of SSA register assignments.  */
! 
! 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_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 and information whether
!    and how it has been loaded from an aggregate into *AGGPOS.  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,
! 				  struct agg_position_info *aggpos)
! {
!   tree res = unmodified_parm_1 (stmt, op);
! 
!   gcc_checking_assert (aggpos);
!   if (res)
!     {
!       *index_p = ipa_get_param_decl_index (info, res);
!       if (*index_p < 0)
! 	return false;
!       aggpos->agg_contents = false;
!       aggpos->by_ref = 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 (!REFERENCE_CLASS_P (op))
! 	return unmodified_parm_or_parm_agg_item (info, stmt, op, index_p,
! 						 aggpos);
!     }
! 
!   aggpos->agg_contents = true;
!   return ipa_load_from_parm_agg (info, stmt, op, index_p, &aggpos->offset,
! 				 &aggpos->by_ref);
  }
  
  /* See if statement might disappear after inlining.
*************** set_cond_stmt_execution_predicate (struc
*** 1422,1434 ****
    gimple last;
    tree op;
    int index;
    enum tree_code code, inverted_code;
    edge e;
    edge_iterator ei;
    gimple set_stmt;
    tree op2;
-   tree parm;
-   tree base;
  
    last = last_stmt (bb);
    if (!last
--- 1559,1570 ----
    gimple last;
    tree op;
    int index;
+   struct agg_position_info aggpos;
    enum tree_code code, inverted_code;
    edge e;
    edge_iterator ei;
    gimple set_stmt;
    tree op2;
  
    last = last_stmt (bb);
    if (!last
*************** set_cond_stmt_execution_predicate (struc
*** 1440,1451 ****
    /* TODO: handle conditionals like
       var = op0 < 4;
       if (var != 0).  */
!   parm = unmodified_parm (last, op);
!   if (parm)
      {
-       index = ipa_get_param_decl_index (info, parm);
-       if (index == -1)
- 	return;
        code = gimple_cond_code (last);
        inverted_code
  	 = invert_tree_comparison (code,
--- 1576,1583 ----
    /* TODO: handle conditionals like
       var = op0 < 4;
       if (var != 0).  */
!   if (unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
      {
        code = gimple_cond_code (last);
        inverted_code
  	 = invert_tree_comparison (code,
*************** set_cond_stmt_execution_predicate (struc
*** 1453,1460 ****
  
        FOR_EACH_EDGE (e, ei, bb->succs)
  	{
! 	  struct predicate p = add_condition (summary,
! 					      index,
  					      e->flags & EDGE_TRUE_VALUE
  					      ? code : inverted_code,
  					      gimple_cond_rhs (last));
--- 1585,1591 ----
  
        FOR_EACH_EDGE (e, ei, bb->succs)
  	{
! 	  struct predicate p = add_condition (summary, index, &aggpos,
  					      e->flags & EDGE_TRUE_VALUE
  					      ? code : inverted_code,
  					      gimple_cond_rhs (last));
*************** set_cond_stmt_execution_predicate (struc
*** 1475,1502 ****
       for this and also the constant code is not known to be
       optimized away when inliner doen't see operand is constant.
       Other optimizers might think otherwise.  */
    set_stmt = SSA_NAME_DEF_STMT (op);
    if (!gimple_call_builtin_p (set_stmt, BUILT_IN_CONSTANT_P)
        || gimple_call_num_args (set_stmt) != 1)
      return;
    op2 = gimple_call_arg (set_stmt, 0);
!   base = get_base_address (op2);
!   parm = unmodified_parm (set_stmt, base ? base : op2);
!   if (!parm)
!     return;
!   index = ipa_get_param_decl_index (info, parm);
!   if (index == -1)
!     return;
!   if (gimple_cond_code (last) != NE_EXPR
!       || !integer_zerop (gimple_cond_rhs (last)))
      return;
    FOR_EACH_EDGE (e, ei, bb->succs)
      if (e->flags & EDGE_FALSE_VALUE)
        {
! 	struct predicate p = add_condition (summary,
! 					    index,
! 					    IS_NOT_CONSTANT,
! 					    NULL);
  	e->aux = pool_alloc (edge_predicate_pool);
  	*(struct predicate *)e->aux = p;
        }
--- 1606,1627 ----
       for this and also the constant code is not known to be
       optimized away when inliner doen't see operand is constant.
       Other optimizers might think otherwise.  */
+   if (gimple_cond_code (last) != NE_EXPR
+       || !integer_zerop (gimple_cond_rhs (last)))
+     return;
    set_stmt = SSA_NAME_DEF_STMT (op);
    if (!gimple_call_builtin_p (set_stmt, BUILT_IN_CONSTANT_P)
        || gimple_call_num_args (set_stmt) != 1)
      return;
    op2 = gimple_call_arg (set_stmt, 0);
!   /* TODO: Use unmodified_parm_or_parm_agg_item also here.  */
!   if (!unmodified_parm_or_parm_agg_item (info, set_stmt, op2, &index, &aggpos))
      return;
    FOR_EACH_EDGE (e, ei, bb->succs)
      if (e->flags & EDGE_FALSE_VALUE)
        {
! 	struct predicate p = add_condition (summary, index, &aggpos,
! 					    IS_NOT_CONSTANT, NULL_TREE);
  	e->aux = pool_alloc (edge_predicate_pool);
  	*(struct predicate *)e->aux = p;
        }
*************** set_switch_stmt_execution_predicate (str
*** 1514,1535 ****
    gimple last;
    tree op;
    int index;
    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)
      return;
  
    FOR_EACH_EDGE (e, ei, bb->succs)
--- 1639,1656 ----
    gimple last;
    tree op;
    int index;
+   struct agg_position_info aggpos;
    edge e;
    edge_iterator ei;
    size_t n;
    size_t case_idx;
  
    last = last_stmt (bb);
    if (!last
        || gimple_code (last) != GIMPLE_SWITCH)
      return;
    op = gimple_switch_index (last);
!   if (!unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
      return;
  
    FOR_EACH_EDGE (e, ei, bb->succs)
*************** set_switch_stmt_execution_predicate (str
*** 1554,1571 ****
        if (!min && !max)
  	p = true_predicate ();
        else if (!max)
! 	p = add_condition (summary, index,
! 			   EQ_EXPR,
! 			   min);
        else
  	{
  	  struct predicate p1, p2;
! 	  p1 = add_condition (summary, index,
! 			      GE_EXPR,
! 			      min);
! 	  p2 = add_condition (summary, index,
! 			      LE_EXPR,
! 			      max);
  	  p = and_predicates (summary->conds, &p1, &p2);
  	}
        *(struct predicate *)e->aux
--- 1675,1686 ----
        if (!min && !max)
  	p = true_predicate ();
        else if (!max)
! 	p = add_condition (summary, index, &aggpos, EQ_EXPR, min);
        else
  	{
  	  struct predicate p1, p2;
! 	  p1 = add_condition (summary, index, &aggpos, GE_EXPR, min);
! 	  p2 = add_condition (summary, index, &aggpos, LE_EXPR, max);
  	  p = and_predicates (summary->conds, &p1, &p2);
  	}
        *(struct predicate *)e->aux
*************** will_be_nonconstant_predicate (struct ip
*** 1659,1671 ****
  			       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;
  
    /* What statments might be optimized away
       when their arguments are constant
--- 1774,1787 ----
  			       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;
+   int base_index;
+   struct agg_position_info aggpos;
  
    /* What statments might be optimized away
       when their arguments are constant
*************** will_be_nonconstant_predicate (struct ip
*** 1681,1703 ****
      return p;
  
    is_load = gimple_vuse (stmt) != NULL;
- 
    /* 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;
! 
        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)
  	return p;
      }
  
    /* See if we understand all operands before we start
       adding conditionals.  */
--- 1797,1814 ----
      return p;
  
    is_load = gimple_vuse (stmt) != NULL;
    /* Loads can be optimized when the value is known.  */
    if (is_load)
      {
!       tree op;
        gcc_assert (gimple_assign_single_p (stmt));
!       op = gimple_assign_rhs1 (stmt);
!       if (!unmodified_parm_or_parm_agg_item (info, stmt, op, &base_index,
! 					     &aggpos))
  	return p;
      }
+   else
+     base_index = -1;
  
    /* See if we understand all operands before we start
       adding conditionals.  */
*************** will_be_nonconstant_predicate (struct ip
*** 1716,1738 ****
  	continue;
        return p;
      }
!   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),
! 			 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);
        else
  	p = *VEC_index (predicate_t, nonconstant_names,
  			SSA_NAME_VERSION (use));
--- 1827,1850 ----
  	continue;
        return p;
      }
! 
    if (is_load)
!     op_non_const = add_condition (summary, base_index, &aggpos, CHANGED, NULL);
!   else
!     op_non_const = false_predicate ();
    FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
      {
        tree parm = unmodified_parm (stmt, use);
!       int index;
! 
!       if (parm
! 	  && (index = ipa_get_param_decl_index (info, parm)) >= 0)
! 	{
! 	  if (index != base_index)
! 	    p = add_condition (summary, index, NULL, CHANGED, NULL_TREE);
! 	  else
! 	    continue;
! 	}
        else
  	p = *VEC_index (predicate_t, nonconstant_names,
  			SSA_NAME_VERSION (use));
*************** static void
*** 2194,2200 ****
  estimate_edge_devirt_benefit (struct cgraph_edge *ie,
  			      int *size, int *time, int prob,
  			      VEC (tree, heap) *known_vals,
! 			      VEC (tree, heap) *known_binfos)
  {
    tree target;
    int time_diff, size_diff;
--- 2306,2313 ----
  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 (ipa_agg_jump_function_p, heap) *known_aggs)
  {
    tree target;
    int time_diff, size_diff;
*************** estimate_edge_devirt_benefit (struct cgr
*** 2202,2208 ****
    if (!known_vals && !known_binfos)
      return;
  
!   target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos);
    if (!target)
      return;
  
--- 2315,2322 ----
    if (!known_vals && !known_binfos)
      return;
  
!   target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos,
! 					 known_aggs);
    if (!target)
      return;
  
*************** static void
*** 2259,2265 ****
  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)
  {
    struct cgraph_edge *e;
    for (e = node->callees; e; e = e->next_callee)
--- 2373,2380 ----
  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 (ipa_agg_jump_function_p, heap) *known_aggs)
  {
    struct cgraph_edge *e;
    for (e = node->callees; e; e = e->next_callee)
*************** estimate_calls_size_and_time (struct cgr
*** 2276,2282 ****
  	  else
  	    estimate_calls_size_and_time (e->callee, size, time,
  					  possible_truths,
! 					  known_vals, known_binfos);
  	}
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
--- 2391,2397 ----
  	  else
  	    estimate_calls_size_and_time (e->callee, size, time,
  					  possible_truths,
! 					  known_vals, known_binfos, known_aggs);
  	}
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
*************** estimate_calls_size_and_time (struct cgr
*** 2286,2292 ****
  	{
  	  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);
  	}
      }
  }
--- 2401,2407 ----
  	{
  	  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_aggs);
  	}
      }
  }
*************** estimate_node_size_and_time (struct cgra
*** 2301,2306 ****
--- 2416,2422 ----
  			     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)
*************** estimate_node_size_and_time (struct cgra
*** 2352,2358 ****
      time = MAX_TIME * INLINE_TIME_SCALE;
  
    estimate_calls_size_and_time (node, &size, &time, possible_truths,
! 				known_vals, known_binfos);
    time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  
--- 2468,2474 ----
      time = MAX_TIME * INLINE_TIME_SCALE;
  
    estimate_calls_size_and_time (node, &size, &time, possible_truths,
! 				known_vals, known_binfos, known_aggs);
    time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  
*************** estimate_ipcp_clone_size_and_time (struc
*** 2381,2407 ****
  {
    clause_t clause;
  
!   clause = evaluate_conditions_for_known_args (node, false, known_vals);
!   estimate_node_size_and_time (node, clause, known_vals, known_binfos,
  			       ret_size, ret_time,
  			       NULL);
  }
  
- 
  /* Translate all conditions from callee representation into caller
     representation and symbolically evaluate predicate P into new predicate.
  
!    INFO is inline_summary of function we are adding predicate into,
!    CALLEE_INFO is summary of function predicate P is from. OPERAND_MAP is
!    array giving callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is
!    clausule of all callee conditions that may be true in caller context.
!    TOPLEV_PREDICATE is predicate under which callee is executed.  */
  
  static struct predicate
  remap_predicate (struct inline_summary *info,
  		 struct inline_summary *callee_info,
  		 struct predicate *p,
  		 VEC (int, heap) *operand_map,
  		 clause_t possible_truths,
  		 struct predicate *toplev_predicate)
  {
--- 2497,2527 ----
  {
    clause_t clause;
  
!   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.
  
!    INFO is inline_summary of function we are adding predicate into, CALLEE_INFO
!    is summary of function predicate P is from. OPERAND_MAP is array giving
!    callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clausule of all
!    callee conditions that may be true in caller context.  TOPLEV_PREDICATE is
!    predicate under which callee is executed.  OFFSET_MAP is an array of of
!    offsets that need to be added to conditions, negative offset means that
!    conditions relying on values passed by reference have to be discarded
!    because they might not be preserved (and should be considered offset zero
!    for other purposes).  */
  
  static struct predicate
  remap_predicate (struct inline_summary *info,
  		 struct inline_summary *callee_info,
  		 struct predicate *p,
  		 VEC (int, heap) *operand_map,
+ 		 VEC (int, heap) *offset_map,
  		 clause_t possible_truths,
  		 struct predicate *toplev_predicate)
  {
*************** remap_predicate (struct inline_summary *
*** 2436,2448 ****
  		    Otherwise give up.  */
  		 if (!operand_map
  		     || (int)VEC_length (int, operand_map) <= c->operand_num
! 		     || VEC_index (int, operand_map, c->operand_num) == -1)
  		   cond_predicate = true_predicate ();
  		 else
! 		   cond_predicate = add_condition (info,
! 						   VEC_index (int, operand_map,
! 							      c->operand_num),
! 						   c->code, c->val);
  	      }
  	    /* Fixed conditions remains same, construct single
  	       condition predicate.  */
--- 2556,2589 ----
  		    Otherwise give up.  */
  		 if (!operand_map
  		     || (int)VEC_length (int, operand_map) <= c->operand_num
! 		     || VEC_index (int, operand_map, c->operand_num) == -1
! 		     || (!c->agg_contents
! 			 && VEC_index (int, offset_map, c->operand_num) != 0)
! 		     || (c->agg_contents && c->by_ref
! 			 && VEC_index (int, offset_map, c->operand_num) < 0))
  		   cond_predicate = true_predicate ();
  		 else
! 		   {
! 		     struct agg_position_info ap;
! 		     HOST_WIDE_INT offset_delta = VEC_index (int, offset_map,
! 							     c->operand_num);
! 		     if (offset_delta < 0)
! 		       {
! 			 gcc_checking_assert (!c->agg_contents || !c->by_ref);
! 			 offset_delta = 0;
! 		       }
! 		     gcc_assert (!c->agg_contents
! 				 || c->by_ref
! 				 || offset_delta == 0);
! 		     ap.offset = c->offset + offset_delta;
! 		     ap.agg_contents = c->agg_contents;
! 		     ap.by_ref = c->by_ref;
! 		     cond_predicate = add_condition (info,
! 						     VEC_index (int,
! 								operand_map,
! 								c->operand_num),
! 						     &ap, c->code, c->val);
! 		   }
  	      }
  	    /* Fixed conditions remains same, construct single
  	       condition predicate.  */
*************** remap_edge_summaries  (struct cgraph_edg
*** 2549,2554 ****
--- 2690,2696 ----
  		       struct inline_summary *info,
  		       struct inline_summary *callee_info,
  		       VEC (int, heap) *operand_map,
+ 		       VEC (int, heap) *offset_map,
  		       clause_t possible_truths,
  		       struct predicate *toplev_predicate)
  {
*************** remap_edge_summaries  (struct cgraph_edg
*** 2565,2571 ****
  	  if (es->predicate)
  	    {
  	      p = remap_predicate (info, callee_info,
! 				   es->predicate, operand_map, possible_truths,
  				   toplev_predicate);
  	      edge_set_predicate (e, &p);
  	      /* TODO: We should remove the edge for code that will be
--- 2707,2714 ----
  	  if (es->predicate)
  	    {
  	      p = remap_predicate (info, callee_info,
! 				   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
*************** remap_edge_summaries  (struct cgraph_edg
*** 2582,2588 ****
  	}
        else
  	remap_edge_summaries (inlined_edge, e->callee, info, callee_info,
! 			      operand_map, possible_truths, toplev_predicate);
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
      {
--- 2725,2732 ----
  	}
        else
  	remap_edge_summaries (inlined_edge, e->callee, info, callee_info,
! 			      operand_map, offset_map, possible_truths,
! 			      toplev_predicate);
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
      {
*************** remap_edge_summaries  (struct cgraph_edg
*** 2593,2600 ****
        if (es->predicate)
  	{
  	  p = remap_predicate (info, callee_info,
! 			       es->predicate, operand_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.
--- 2737,2744 ----
        if (es->predicate)
  	{
  	  p = remap_predicate (info, callee_info,
! 			       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.
*************** inline_merge_summary (struct cgraph_edge
*** 2623,2628 ****
--- 2767,2773 ----
    clause_t clause = 0;		/* not_inline is known to be false.  */
    size_time_entry *e;
    VEC (int, heap) *operand_map = NULL;
+   VEC (int, heap) *offset_map = NULL;
    int i;
    struct predicate toplev_predicate;
    struct predicate true_p = true_predicate ();
*************** inline_merge_summary (struct cgraph_edge
*** 2639,2655 ****
        int count = ipa_get_cs_argument_count (args);
        int i;
  
!       evaluate_properties_for_edge (edge, true, &clause, NULL, NULL);
        if (count)
! 	VEC_safe_grow_cleared (int, heap, operand_map, count);
        for (i = 0; i < count; i++)
  	{
  	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
  	  int map = -1;
  	  /* TODO: handle non-NOPs when merging.  */
! 	  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);
  	  VEC_replace (int, operand_map, i, map);
  	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
  	}
--- 2784,2819 ----
        int count = ipa_get_cs_argument_count (args);
        int i;
  
!       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, offset_map, count);
! 	}
        for (i = 0; i < count; i++)
  	{
  	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
  	  int map = -1;
+ 
  	  /* TODO: handle non-NOPs when merging.  */
! 	  if (jfunc->type == IPA_JF_PASS_THROUGH)
! 	    {
! 	      if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
! 		map = ipa_get_jf_pass_through_formal_id (jfunc);
! 	      if (!ipa_get_jf_pass_through_agg_preserved (jfunc))
! 		VEC_replace (int, offset_map, i, -1);
! 	    }
! 	  else if (jfunc->type == IPA_JF_ANCESTOR)
! 	    {
! 	      HOST_WIDE_INT offset = ipa_get_jf_ancestor_offset (jfunc);
! 	      if (offset >= 0 && offset < INT_MAX)
! 		{
! 		  map = ipa_get_jf_ancestor_formal_id (jfunc);
! 		  if (!ipa_get_jf_ancestor_agg_preserved (jfunc))
! 		    offset = -1;
! 		  VEC_replace (int, offset_map, i, offset);
! 		}
! 	    }
  	  VEC_replace (int, operand_map, i, map);
  	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
  	}
*************** inline_merge_summary (struct cgraph_edge
*** 2657,2663 ****
    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,
  					    &toplev_predicate);
        if (!false_predicate_p (&p))
  	{
--- 2821,2828 ----
    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,
! 					    offset_map, clause,
  					    &toplev_predicate);
        if (!false_predicate_p (&p))
  	{
*************** inline_merge_summary (struct cgraph_edge
*** 2679,2692 ****
  	}
      }
    remap_edge_summaries (edge, edge->callee, info, callee_info, operand_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);
  
    inline_update_callee_summaries (edge->callee,
  				  inline_edge_summary (edge)->loop_depth);
--- 2844,2857 ----
  	}
      }
    remap_edge_summaries (edge, edge->callee, info, callee_info, operand_map,
! 			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);
  
    inline_update_callee_summaries (edge->callee,
  				  inline_edge_summary (edge)->loop_depth);
*************** inline_merge_summary (struct cgraph_edge
*** 2696,2701 ****
--- 2861,2867 ----
    /* Similarly remove param summaries.  */
    VEC_free (inline_param_summary_t, heap, es->param);
    VEC_free (int, heap, operand_map);
+   VEC_free (int, 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;
*************** do_estimate_edge_time (struct cgraph_edg
*** 2719,2735 ****
    clause_t clause;
    VEC (tree, heap) *known_vals;
    VEC (tree, heap) *known_binfos;
    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);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       &size, &time, es->param);
    VEC_free (tree, heap, known_vals);
    VEC_free (tree, heap, known_binfos);
  
    ret = (((gcov_type)time
  	   - es->call_stmt_time) * edge->frequency
--- 2885,2904 ----
    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,
! 				&known_aggs);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       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
*************** do_estimate_edge_growth (struct cgraph_e
*** 2766,2771 ****
--- 2935,2941 ----
    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.  */
  
*************** do_estimate_edge_growth (struct cgraph_e
*** 2784,2794 ****
    /* 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);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       &size, NULL, NULL);
    VEC_free (tree, heap, known_vals);
    VEC_free (tree, heap, known_binfos);
    gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size);
    return size - inline_edge_summary (edge)->call_stmt_size;
  }
--- 2954,2966 ----
    /* 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,
! 				&known_aggs);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       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;
  }
*************** inline_read_section (struct lto_file_dec
*** 3068,3073 ****
--- 3240,3250 ----
  	  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);
+ 	  c.by_ref = 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);
*************** inline_write_summary (cgraph_node_set se
*** 3211,3216 ****
--- 3388,3399 ----
  	      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);
+ 	      bp_pack_value (&bp, c->by_ref, 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
*************** propagate_constants_accross_call (struct
*** 1084,1090 ****
  tree
  ipa_get_indirect_edge_target (struct cgraph_edge *ie,
  			      VEC (tree, heap) *known_vals,
! 			      VEC (tree, heap) *known_binfos)
  {
    int param_index = ie->indirect_info->param_index;
    HOST_WIDE_INT token, anc_offset;
--- 1084,1091 ----
  tree
  ipa_get_indirect_edge_target (struct cgraph_edge *ie,
  			      VEC (tree, heap) *known_vals,
! 			      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;
*************** ipa_get_indirect_edge_target (struct cgr
*** 1096,1103 ****
  
    if (!ie->indirect_info->polymorphic)
      {
!       tree 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)
--- 1097,1122 ----
  
    if (!ie->indirect_info->polymorphic)
      {
!       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->indirect_info->by_ref);
! 	    }
! 	  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)
*************** ipa_get_indirect_edge_target (struct cgr
*** 1106,1111 ****
--- 1125,1131 ----
  	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;
*************** devirtualization_time_bonus (struct cgra
*** 1156,1162 ****
        struct inline_summary *isummary;
        tree target;
  
!       target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos);
        if (!target)
  	continue;
  
--- 1176,1183 ----
        struct inline_summary *isummary;
        tree target;
  
!       target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos,
! 					     NULL);
        if (!target)
  	continue;
  
*************** ipcp_discover_new_direct_edges (struct c
*** 1673,1679 ****
        tree target;
  
        next_ie = ie->next_callee;
!       target = ipa_get_indirect_edge_target (ie, known_vals, NULL);
        if (target)
  	ipa_make_edge_direct_to_target (ie, target);
      }
--- 1694,1700 ----
        tree target;
  
        next_ie = ie->next_callee;
!       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
*************** bool ipa_propagate_indirect_call_infos (
*** 494,501 ****
  
  /* 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);
  struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
  
  /* Functions related to both.  */
--- 494,502 ----
  
  /* Indirect edge and binfo processing.  */
  tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
! 				   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: src/gcc/testsuite/gfortran.dg/pr48636.f90
===================================================================
*** /dev/null
--- src/gcc/testsuite/gfortran.dg/pr48636.f90
***************
*** 0 ****
--- 1,37 ----
+ ! { dg-do compile }
+ ! { dg-options "-O3 -fdump-ipa-inline" }
+ 
+ module foo
+   implicit none
+ contains
+   subroutine bar(a,x)
+     real, dimension(:,:), intent(in) :: a
+     real, intent(out) :: x
+     integer :: i,j
+ 
+     x = 0
+     do j=1,ubound(a,2)
+        do i=1,ubound(a,1)
+           x = x + a(i,j)**2
+        end do
+     end do
+   end subroutine bar
+ end module foo
+ 
+ program main
+   use foo
+   implicit none
+   real, dimension(2,3) :: a
+   real :: x
+   integer :: i
+ 
+   data a /1.0, 2.0, 3.0, -1.0, -2.0, -3.0/
+ 
+   do i=1,2000000
+      call bar(a,x)
+   end do
+   print *,x
+ end program main
+ 
+ ! { dg-final { scan-ipa-dump "bar\[^\\n\]*inline copy in MAIN" "inline" } }
+ ! { dg-final { cleanup-ipa-dump "inline" } }

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis
  2012-08-10 14:40     ` Martin Jambor
@ 2012-08-11 10:59       ` Martin Jambor
  2012-08-11 16:39         ` Jan Hubicka
  0 siblings, 1 reply; 10+ messages in thread
From: Martin Jambor @ 2012-08-11 10:59 UTC (permalink / raw)
  To: Jan Hubicka, GCC Patches

Hi,

On Fri, Aug 10, 2012 at 04:39:44PM +0200, Martin Jambor wrote:
> On Fri, Aug 10, 2012 at 05:12:31AM +0200, Jan Hubicka wrote:
> > > Hi,
> > > 
> 
> ...
> 
> > > 
> > > 2012-07-31  Martin Jambor  <mjambor@suse.cz>
> > > 
> > > 	PR fortran/48636
> > > 	* ipa-inline.h (condition): New fields offset, agg_contents and by_ref.
> > > 	* ipa-inline-analysis.c (agg_position_info): New type.
> > > 	(add_condition): New parameter aggpos, also store agg_contents, by_ref
> > > 	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.
> > > 
> > > 	* testsuite/gfortran.dg/pr48636.f90: New test.
> > 
> > OK with the following changes.
> > 
> > I plan to push out my inline hints code, so it would be nice if you commited soon 
> > so I cn resolve conflicts on my side.
> > > Index: src/gcc/ipa-inline.h
> > > ===================================================================
> > > *** src.orig/gcc/ipa-inline.h
> > > --- src/gcc/ipa-inline.h
> > > *************** along with GCC; see the file COPYING3.
> > > *** 28,36 ****
> > > --- 28,45 ----
> > >   
> > >   typedef struct GTY(()) condition
> > >     {
> > > +     /* If agg_contents is set, this is the offset from which the used data was
> > > +        loaded.  */
> > > +     HOST_WIDE_INT offset;
> > >       tree val;
> > >       int operand_num;
> > >       enum tree_code code;
> > > +     /* Set if the used data were loaded from an aggregate parameter or from
> > > +        data received by reference.  */
> > > +     unsigned agg_contents : 1;
> > > +     /* If agg_contents is set, this differentiates between loads from data
> > > +        passed by reference and by value.  */
> > > +     unsigned by_ref : 1;
> > 
> 
> > Do you have any data on memory usage?  I was originally concerned
> > about memory use of the whole predicate thingy on WPA level.
> > Eventually we could add simple inheritance on conditions and sort
> > them into mutiple vectors if needed. But I assume it is OK or we
> > will work out on Mozilla builds soonish.
> > 
> > One obvious thing is to patch CODE and the bitfields so we fit in 3
> > 64bit words.
> 
> OK, I made it an enum, I will look at memory consumption in a while.

This is the patch I have committed after resolving a conflict (and
another round of bootstrapping and testing).  The ChangeLog is still
the same.

The previous version of the patch (but with tree code already
converted to an enum), the aggregate jump functions together with
enlarged inlining predicates increased Mozilla Firefox LTO WPA memory
consumption by 1.2% (6775287 kb -> 6855035 kb as measured by
maxmem2.sh).  On Monday I will make another measurement with jump
functions completely switched off.

Thanks,

Martin


Index: src/gcc/ipa-inline.h
===================================================================
*** src.orig/gcc/ipa-inline.h
--- src/gcc/ipa-inline.h
*************** along with GCC; see the file COPYING3.
*** 28,36 ****
  
  typedef struct GTY(()) condition
    {
      tree val;
      int operand_num;
!     enum tree_code code;
    } condition;
  
  DEF_VEC_O (condition);
--- 28,45 ----
  
  typedef struct GTY(()) condition
    {
+     /* If agg_contents is set, this is the offset from which the used data was
+        loaded.  */
+     HOST_WIDE_INT offset;
      tree val;
      int operand_num;
!     ENUM_BITFIELD(tree_code) code : 16;
!     /* Set if the used data were loaded from an aggregate parameter or from
!        data received by reference.  */
!     unsigned agg_contents : 1;
!     /* If agg_contents is set, this differentiates between loads from data
!        passed by reference and by value.  */
!     unsigned by_ref : 1;
    } 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
*************** not_inlined_predicate (void)
*** 203,224 ****
    return single_cond_predicate (predicate_not_inlined_condition);
  }
  
  
! /* Add condition to condition list CONDS.  */
  
  static struct predicate
  add_condition (struct inline_summary *summary, int operand_num,
  	       enum tree_code code, tree val)
  {
    int i;
    struct condition *c;
    struct condition new_cond;
  
    for (i = 0; VEC_iterate (condition, summary->conds, i, c); i++)
      {
        if (c->operand_num == operand_num
  	  && c->code == code
! 	  && c->val == val)
          return single_cond_predicate (i + predicate_first_dynamic_condition);
      }
    /* Too many conditions.  Give up and return constant true.  */
--- 203,256 ----
    return single_cond_predicate (predicate_not_inlined_condition);
  }
  
+ /* Simple description of whether a memory load or a condition refers to a load
+    from an aggregate and if so, how and where from in the aggregate.
+    Individual fields have the same meaning like fields with the same name in
+    struct condition.  */
+ 
+ struct agg_position_info
+ {
+   HOST_WIDE_INT offset;
+   bool agg_contents;
+   bool by_ref;
+ };
  
! /* Add condition to condition list CONDS.  AGGPOS describes whether the used
!    oprand is loaded from an aggregate and where in the aggregate it is.  It can
!    be NULL, which means this not a load from an aggregate.  */
  
  static struct predicate
  add_condition (struct inline_summary *summary, int operand_num,
+ 	       struct agg_position_info *aggpos,
  	       enum tree_code code, tree val)
  {
    int i;
    struct condition *c;
    struct condition new_cond;
+   HOST_WIDE_INT offset;
+   bool agg_contents, by_ref;
+ 
+   if (aggpos)
+     {
+       offset = aggpos->offset;
+       agg_contents = aggpos->agg_contents;
+       by_ref = aggpos->by_ref;
+     }
+   else
+     {
+       offset = 0;
+       agg_contents = false;
+       by_ref = false;
+     }
  
+   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->agg_contents == agg_contents
! 	  && (!agg_contents || (c->offset == offset && c->by_ref == by_ref)))
          return single_cond_predicate (i + predicate_first_dynamic_condition);
      }
    /* Too many conditions.  Give up and return constant true.  */
*************** add_condition (struct inline_summary *su
*** 228,233 ****
--- 260,268 ----
    new_cond.operand_num = operand_num;
    new_cond.code = code;
    new_cond.val = val;
+   new_cond.agg_contents = agg_contents;
+   new_cond.by_ref = by_ref;
+   new_cond.offset = offset;
    VEC_safe_push (condition, gc, summary->conds, &new_cond);
    return single_cond_predicate (i + predicate_first_dynamic_condition);
  }
*************** dump_condition (FILE *f, conditions cond
*** 519,524 ****
--- 554,562 ----
        c = VEC_index (condition, conditions,
  		     cond - predicate_first_dynamic_condition);
        fprintf (f, "op%i", c->operand_num);
+       if (c->agg_contents)
+ 	fprintf (f, "[%soffset: " HOST_WIDE_INT_PRINT_DEC "]",
+ 		 c->by_ref ? "ref " : "", c->offset);
        if (c->code == IS_NOT_CONSTANT)
  	{
  	  fprintf (f, " not constant");
*************** edge_set_predicate (struct cgraph_edge *
*** 659,673 ****
  
  
  /* KNOWN_VALS is partial mapping of parameters of NODE to constant values.
!    Return clause of possible truths. When INLINE_P is true, assume that
!    we are inlining. 
  
     ERROR_MARK means compile time invariant.  */
  
  static clause_t
  evaluate_conditions_for_known_args (struct cgraph_node *node,
! 				    bool inline_p,
! 				    VEC (tree, heap) *known_vals)
  {
    clause_t clause = inline_p ? 0 : 1 << predicate_not_inlined_condition;
    struct inline_summary *info = inline_summary (node);
--- 697,713 ----
  
  
  /* KNOWN_VALS is partial mapping of parameters of NODE to constant values.
!    KNOWN_AGGS is a vector of aggreggate jump functions for each parameter.
!    Return clause of possible truths. When INLINE_P is true, assume that we are
!    inlining.
  
     ERROR_MARK means compile time invariant.  */
  
  static clause_t
  evaluate_conditions_for_known_args (struct cgraph_node *node,
! 				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);
*************** evaluate_conditions_for_known_args (stru
*** 679,694 ****
        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;
  
!       if (val == error_mark_node && c->code != CHANGED)
! 	val = NULL;
  
        if (!val)
  	{
--- 719,763 ----
        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 (we assume
! 	 known_aggs vector, if non-NULL, has the same length as
! 	 known_vals).  */
!       gcc_checking_assert (!known_aggs
! 			   || (VEC_length (tree, known_vals)
! 			       == VEC_length (ipa_agg_jump_function_p,
! 					      known_aggs)));
!       if (c->operand_num >= (int) VEC_length (tree, known_vals))
! 	{
! 	  clause |= 1 << (i + predicate_first_dynamic_condition);
! 	  continue;
! 	}
! 
!       if (c->agg_contents)
! 	{
! 	  struct ipa_agg_jump_function *agg;
! 
! 	  if (c->code == CHANGED
! 	      && !c->by_ref
! 	      && (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, c->by_ref);
! 	    }
! 	  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)
  	{
*************** evaluate_conditions_for_known_args (stru
*** 711,723 ****
  
  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)
  {
    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;
  
    if (clause_ptr)
      *clause_ptr = inline_p ? 0 : 1 << predicate_not_inlined_condition;
--- 780,794 ----
  
  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,
! 			   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;
*************** evaluate_properties_for_edge (struct cgr
*** 742,754 ****
  
        if (count && (info->conds || known_vals_ptr))
  	VEC_safe_grow_cleared (tree, heap, known_vals, 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));
  	  if (cst)
  	    {
  	      if (known_vals && TREE_CODE (cst) != TREE_BINFO)
--- 813,828 ----
  
        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++)
  	{
! 	  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)
*************** evaluate_properties_for_edge (struct cgr
*** 761,777 ****
  				  es->param,
  				  i)->change_prob)
  	    VEC_replace (tree, known_vals, i, error_mark_node);
  	}
      }
  
    if (clause_ptr)
      *clause_ptr = evaluate_conditions_for_known_args (callee, inline_p,
! 						      known_vals);
  
    if (known_vals_ptr)
      *known_vals_ptr = known_vals;
    else
      VEC_free (tree, heap, known_vals);
  }
  
  
--- 835,860 ----
  				  es->param,
  				  i)->change_prob)
  	    VEC_replace (tree, known_vals, i, error_mark_node);
+ 	  /* TODO: When IPA-CP starts propagating and 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_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);
  }
  
  
*************** inline_node_duplication_hook (struct cgr
*** 917,924 ****
  		}
  	    }
  	}
!       possible_truths = evaluate_conditions_for_known_args (dst,
! 							    false, known_vals);
        VEC_free (tree, heap, known_vals);
  
        account_size_time (info, 0, 0, &true_pred);
--- 1000,1007 ----
  		}
  	    }
  	}
!       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);
*************** mark_modified (ao_ref *ao ATTRIBUTE_UNUS
*** 1262,1272 ****
    return true;
  }
  
! /* If OP reffers to value of function parameter, return 
!    the corresponding parameter.  */
  
  static tree
! unmodified_parm (gimple stmt, tree op)
  {
    /* SSA_NAME referring to parm default def?  */
    if (TREE_CODE (op) == SSA_NAME
--- 1345,1355 ----
    return true;
  }
  
! /* If OP refers to value of function parameter, return the corresponding
!    parameter.  */
  
  static tree
! unmodified_parm_1 (gimple stmt, tree op)
  {
    /* SSA_NAME referring to parm default def?  */
    if (TREE_CODE (op) == SSA_NAME
*************** unmodified_parm (gimple stmt, tree op)
*** 1285,1297 ****
        if (!modified)
  	return op;
      }
!   /* Assignment from a parameter?  */
    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;
  }
  
  /* See if statement might disappear after inlining.
--- 1368,1434 ----
        if (!modified)
  	return op;
      }
!   return NULL_TREE;
! }
! 
! /* If OP refers to value of function parameter, return the corresponding
!    parameter.  Also traverse chains of SSA register assignments.  */
! 
! 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_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 and information whether
!    and how it has been loaded from an aggregate into *AGGPOS.  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,
! 				  struct agg_position_info *aggpos)
! {
!   tree res = unmodified_parm_1 (stmt, op);
! 
!   gcc_checking_assert (aggpos);
!   if (res)
!     {
!       *index_p = ipa_get_param_decl_index (info, res);
!       if (*index_p < 0)
! 	return false;
!       aggpos->agg_contents = false;
!       aggpos->by_ref = 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 (!REFERENCE_CLASS_P (op))
! 	return unmodified_parm_or_parm_agg_item (info, stmt, op, index_p,
! 						 aggpos);
!     }
! 
!   aggpos->agg_contents = true;
!   return ipa_load_from_parm_agg (info, stmt, op, index_p, &aggpos->offset,
! 				 &aggpos->by_ref);
  }
  
  /* See if statement might disappear after inlining.
*************** set_cond_stmt_execution_predicate (struc
*** 1422,1434 ****
    gimple last;
    tree op;
    int index;
    enum tree_code code, inverted_code;
    edge e;
    edge_iterator ei;
    gimple set_stmt;
    tree op2;
-   tree parm;
-   tree base;
  
    last = last_stmt (bb);
    if (!last
--- 1559,1570 ----
    gimple last;
    tree op;
    int index;
+   struct agg_position_info aggpos;
    enum tree_code code, inverted_code;
    edge e;
    edge_iterator ei;
    gimple set_stmt;
    tree op2;
  
    last = last_stmt (bb);
    if (!last
*************** set_cond_stmt_execution_predicate (struc
*** 1440,1451 ****
    /* TODO: handle conditionals like
       var = op0 < 4;
       if (var != 0).  */
!   parm = unmodified_parm (last, op);
!   if (parm)
      {
-       index = ipa_get_param_decl_index (info, parm);
-       if (index == -1)
- 	return;
        code = gimple_cond_code (last);
        inverted_code
  	 = invert_tree_comparison (code,
--- 1576,1583 ----
    /* TODO: handle conditionals like
       var = op0 < 4;
       if (var != 0).  */
!   if (unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
      {
        code = gimple_cond_code (last);
        inverted_code
  	 = invert_tree_comparison (code,
*************** set_cond_stmt_execution_predicate (struc
*** 1453,1460 ****
  
        FOR_EACH_EDGE (e, ei, bb->succs)
  	{
! 	  struct predicate p = add_condition (summary,
! 					      index,
  					      e->flags & EDGE_TRUE_VALUE
  					      ? code : inverted_code,
  					      gimple_cond_rhs (last));
--- 1585,1591 ----
  
        FOR_EACH_EDGE (e, ei, bb->succs)
  	{
! 	  struct predicate p = add_condition (summary, index, &aggpos,
  					      e->flags & EDGE_TRUE_VALUE
  					      ? code : inverted_code,
  					      gimple_cond_rhs (last));
*************** set_cond_stmt_execution_predicate (struc
*** 1475,1502 ****
       for this and also the constant code is not known to be
       optimized away when inliner doen't see operand is constant.
       Other optimizers might think otherwise.  */
    set_stmt = SSA_NAME_DEF_STMT (op);
    if (!gimple_call_builtin_p (set_stmt, BUILT_IN_CONSTANT_P)
        || gimple_call_num_args (set_stmt) != 1)
      return;
    op2 = gimple_call_arg (set_stmt, 0);
!   base = get_base_address (op2);
!   parm = unmodified_parm (set_stmt, base ? base : op2);
!   if (!parm)
!     return;
!   index = ipa_get_param_decl_index (info, parm);
!   if (index == -1)
!     return;
!   if (gimple_cond_code (last) != NE_EXPR
!       || !integer_zerop (gimple_cond_rhs (last)))
      return;
    FOR_EACH_EDGE (e, ei, bb->succs)
      if (e->flags & EDGE_FALSE_VALUE)
        {
! 	struct predicate p = add_condition (summary,
! 					    index,
! 					    IS_NOT_CONSTANT,
! 					    NULL);
  	e->aux = pool_alloc (edge_predicate_pool);
  	*(struct predicate *)e->aux = p;
        }
--- 1606,1626 ----
       for this and also the constant code is not known to be
       optimized away when inliner doen't see operand is constant.
       Other optimizers might think otherwise.  */
+   if (gimple_cond_code (last) != NE_EXPR
+       || !integer_zerop (gimple_cond_rhs (last)))
+     return;
    set_stmt = SSA_NAME_DEF_STMT (op);
    if (!gimple_call_builtin_p (set_stmt, BUILT_IN_CONSTANT_P)
        || gimple_call_num_args (set_stmt) != 1)
      return;
    op2 = gimple_call_arg (set_stmt, 0);
!   if (!unmodified_parm_or_parm_agg_item (info, set_stmt, op2, &index, &aggpos))
      return;
    FOR_EACH_EDGE (e, ei, bb->succs)
      if (e->flags & EDGE_FALSE_VALUE)
        {
! 	struct predicate p = add_condition (summary, index, &aggpos,
! 					    IS_NOT_CONSTANT, NULL_TREE);
  	e->aux = pool_alloc (edge_predicate_pool);
  	*(struct predicate *)e->aux = p;
        }
*************** set_switch_stmt_execution_predicate (str
*** 1514,1535 ****
    gimple last;
    tree op;
    int index;
    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)
      return;
  
    FOR_EACH_EDGE (e, ei, bb->succs)
--- 1638,1655 ----
    gimple last;
    tree op;
    int index;
+   struct agg_position_info aggpos;
    edge e;
    edge_iterator ei;
    size_t n;
    size_t case_idx;
  
    last = last_stmt (bb);
    if (!last
        || gimple_code (last) != GIMPLE_SWITCH)
      return;
    op = gimple_switch_index (last);
!   if (!unmodified_parm_or_parm_agg_item (info, last, op, &index, &aggpos))
      return;
  
    FOR_EACH_EDGE (e, ei, bb->succs)
*************** set_switch_stmt_execution_predicate (str
*** 1554,1571 ****
        if (!min && !max)
  	p = true_predicate ();
        else if (!max)
! 	p = add_condition (summary, index,
! 			   EQ_EXPR,
! 			   min);
        else
  	{
  	  struct predicate p1, p2;
! 	  p1 = add_condition (summary, index,
! 			      GE_EXPR,
! 			      min);
! 	  p2 = add_condition (summary, index,
! 			      LE_EXPR,
! 			      max);
  	  p = and_predicates (summary->conds, &p1, &p2);
  	}
        *(struct predicate *)e->aux
--- 1674,1685 ----
        if (!min && !max)
  	p = true_predicate ();
        else if (!max)
! 	p = add_condition (summary, index, &aggpos, EQ_EXPR, min);
        else
  	{
  	  struct predicate p1, p2;
! 	  p1 = add_condition (summary, index, &aggpos, GE_EXPR, min);
! 	  p2 = add_condition (summary, index, &aggpos, LE_EXPR, max);
  	  p = and_predicates (summary->conds, &p1, &p2);
  	}
        *(struct predicate *)e->aux
*************** will_be_nonconstant_predicate (struct ip
*** 1659,1671 ****
  			       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;
  
    /* What statments might be optimized away
       when their arguments are constant
--- 1773,1786 ----
  			       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;
+   int base_index;
+   struct agg_position_info aggpos;
  
    /* What statments might be optimized away
       when their arguments are constant
*************** will_be_nonconstant_predicate (struct ip
*** 1681,1703 ****
      return p;
  
    is_load = gimple_vuse (stmt) != NULL;
- 
    /* 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;
! 
        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)
  	return p;
      }
  
    /* See if we understand all operands before we start
       adding conditionals.  */
--- 1796,1813 ----
      return p;
  
    is_load = gimple_vuse (stmt) != NULL;
    /* Loads can be optimized when the value is known.  */
    if (is_load)
      {
!       tree op;
        gcc_assert (gimple_assign_single_p (stmt));
!       op = gimple_assign_rhs1 (stmt);
!       if (!unmodified_parm_or_parm_agg_item (info, stmt, op, &base_index,
! 					     &aggpos))
  	return p;
      }
+   else
+     base_index = -1;
  
    /* See if we understand all operands before we start
       adding conditionals.  */
*************** will_be_nonconstant_predicate (struct ip
*** 1716,1738 ****
  	continue;
        return p;
      }
!   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),
! 			 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);
        else
  	p = *VEC_index (predicate_t, nonconstant_names,
  			SSA_NAME_VERSION (use));
--- 1826,1849 ----
  	continue;
        return p;
      }
! 
    if (is_load)
!     op_non_const = add_condition (summary, base_index, &aggpos, CHANGED, NULL);
!   else
!     op_non_const = false_predicate ();
    FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
      {
        tree parm = unmodified_parm (stmt, use);
!       int index;
! 
!       if (parm
! 	  && (index = ipa_get_param_decl_index (info, parm)) >= 0)
! 	{
! 	  if (index != base_index)
! 	    p = add_condition (summary, index, NULL, CHANGED, NULL_TREE);
! 	  else
! 	    continue;
! 	}
        else
  	p = *VEC_index (predicate_t, nonconstant_names,
  			SSA_NAME_VERSION (use));
*************** static void
*** 2194,2200 ****
  estimate_edge_devirt_benefit (struct cgraph_edge *ie,
  			      int *size, int *time, int prob,
  			      VEC (tree, heap) *known_vals,
! 			      VEC (tree, heap) *known_binfos)
  {
    tree target;
    int time_diff, size_diff;
--- 2305,2312 ----
  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 (ipa_agg_jump_function_p, heap) *known_aggs)
  {
    tree target;
    int time_diff, size_diff;
*************** estimate_edge_devirt_benefit (struct cgr
*** 2202,2208 ****
    if (!known_vals && !known_binfos)
      return;
  
!   target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos);
    if (!target)
      return;
  
--- 2314,2321 ----
    if (!known_vals && !known_binfos)
      return;
  
!   target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos,
! 					 known_aggs);
    if (!target)
      return;
  
*************** static void
*** 2259,2265 ****
  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)
  {
    struct cgraph_edge *e;
    for (e = node->callees; e; e = e->next_callee)
--- 2372,2379 ----
  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 (ipa_agg_jump_function_p, heap) *known_aggs)
  {
    struct cgraph_edge *e;
    for (e = node->callees; e; e = e->next_callee)
*************** estimate_calls_size_and_time (struct cgr
*** 2276,2282 ****
  	  else
  	    estimate_calls_size_and_time (e->callee, size, time,
  					  possible_truths,
! 					  known_vals, known_binfos);
  	}
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
--- 2390,2396 ----
  	  else
  	    estimate_calls_size_and_time (e->callee, size, time,
  					  possible_truths,
! 					  known_vals, known_binfos, known_aggs);
  	}
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
*************** estimate_calls_size_and_time (struct cgr
*** 2286,2292 ****
  	{
  	  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);
  	}
      }
  }
--- 2400,2406 ----
  	{
  	  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_aggs);
  	}
      }
  }
*************** estimate_node_size_and_time (struct cgra
*** 2301,2306 ****
--- 2415,2421 ----
  			     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)
*************** estimate_node_size_and_time (struct cgra
*** 2352,2358 ****
      time = MAX_TIME * INLINE_TIME_SCALE;
  
    estimate_calls_size_and_time (node, &size, &time, possible_truths,
! 				known_vals, known_binfos);
    time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  
--- 2467,2473 ----
      time = MAX_TIME * INLINE_TIME_SCALE;
  
    estimate_calls_size_and_time (node, &size, &time, possible_truths,
! 				known_vals, known_binfos, known_aggs);
    time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  
*************** estimate_ipcp_clone_size_and_time (struc
*** 2381,2407 ****
  {
    clause_t clause;
  
!   clause = evaluate_conditions_for_known_args (node, false, known_vals);
!   estimate_node_size_and_time (node, clause, known_vals, known_binfos,
  			       ret_size, ret_time,
  			       NULL);
  }
  
- 
  /* Translate all conditions from callee representation into caller
     representation and symbolically evaluate predicate P into new predicate.
  
!    INFO is inline_summary of function we are adding predicate into,
!    CALLEE_INFO is summary of function predicate P is from. OPERAND_MAP is
!    array giving callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is
!    clausule of all callee conditions that may be true in caller context.
!    TOPLEV_PREDICATE is predicate under which callee is executed.  */
  
  static struct predicate
  remap_predicate (struct inline_summary *info,
  		 struct inline_summary *callee_info,
  		 struct predicate *p,
  		 VEC (int, heap) *operand_map,
  		 clause_t possible_truths,
  		 struct predicate *toplev_predicate)
  {
--- 2496,2526 ----
  {
    clause_t clause;
  
!   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.
  
!    INFO is inline_summary of function we are adding predicate into, CALLEE_INFO
!    is summary of function predicate P is from. OPERAND_MAP is array giving
!    callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clausule of all
!    callee conditions that may be true in caller context.  TOPLEV_PREDICATE is
!    predicate under which callee is executed.  OFFSET_MAP is an array of of
!    offsets that need to be added to conditions, negative offset means that
!    conditions relying on values passed by reference have to be discarded
!    because they might not be preserved (and should be considered offset zero
!    for other purposes).  */
  
  static struct predicate
  remap_predicate (struct inline_summary *info,
  		 struct inline_summary *callee_info,
  		 struct predicate *p,
  		 VEC (int, heap) *operand_map,
+ 		 VEC (int, heap) *offset_map,
  		 clause_t possible_truths,
  		 struct predicate *toplev_predicate)
  {
*************** remap_predicate (struct inline_summary *
*** 2436,2448 ****
  		    Otherwise give up.  */
  		 if (!operand_map
  		     || (int)VEC_length (int, operand_map) <= c->operand_num
! 		     || VEC_index (int, operand_map, c->operand_num) == -1)
  		   cond_predicate = true_predicate ();
  		 else
! 		   cond_predicate = add_condition (info,
! 						   VEC_index (int, operand_map,
! 							      c->operand_num),
! 						   c->code, c->val);
  	      }
  	    /* Fixed conditions remains same, construct single
  	       condition predicate.  */
--- 2555,2588 ----
  		    Otherwise give up.  */
  		 if (!operand_map
  		     || (int)VEC_length (int, operand_map) <= c->operand_num
! 		     || VEC_index (int, operand_map, c->operand_num) == -1
! 		     || (!c->agg_contents
! 			 && VEC_index (int, offset_map, c->operand_num) != 0)
! 		     || (c->agg_contents && c->by_ref
! 			 && VEC_index (int, offset_map, c->operand_num) < 0))
  		   cond_predicate = true_predicate ();
  		 else
! 		   {
! 		     struct agg_position_info ap;
! 		     HOST_WIDE_INT offset_delta = VEC_index (int, offset_map,
! 							     c->operand_num);
! 		     if (offset_delta < 0)
! 		       {
! 			 gcc_checking_assert (!c->agg_contents || !c->by_ref);
! 			 offset_delta = 0;
! 		       }
! 		     gcc_assert (!c->agg_contents
! 				 || c->by_ref
! 				 || offset_delta == 0);
! 		     ap.offset = c->offset + offset_delta;
! 		     ap.agg_contents = c->agg_contents;
! 		     ap.by_ref = c->by_ref;
! 		     cond_predicate = add_condition (info,
! 						     VEC_index (int,
! 								operand_map,
! 								c->operand_num),
! 						     &ap, c->code, c->val);
! 		   }
  	      }
  	    /* Fixed conditions remains same, construct single
  	       condition predicate.  */
*************** remap_edge_summaries  (struct cgraph_edg
*** 2549,2554 ****
--- 2689,2695 ----
  		       struct inline_summary *info,
  		       struct inline_summary *callee_info,
  		       VEC (int, heap) *operand_map,
+ 		       VEC (int, heap) *offset_map,
  		       clause_t possible_truths,
  		       struct predicate *toplev_predicate)
  {
*************** remap_edge_summaries  (struct cgraph_edg
*** 2565,2571 ****
  	  if (es->predicate)
  	    {
  	      p = remap_predicate (info, callee_info,
! 				   es->predicate, operand_map, possible_truths,
  				   toplev_predicate);
  	      edge_set_predicate (e, &p);
  	      /* TODO: We should remove the edge for code that will be
--- 2706,2713 ----
  	  if (es->predicate)
  	    {
  	      p = remap_predicate (info, callee_info,
! 				   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
*************** remap_edge_summaries  (struct cgraph_edg
*** 2582,2588 ****
  	}
        else
  	remap_edge_summaries (inlined_edge, e->callee, info, callee_info,
! 			      operand_map, possible_truths, toplev_predicate);
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
      {
--- 2724,2731 ----
  	}
        else
  	remap_edge_summaries (inlined_edge, e->callee, info, callee_info,
! 			      operand_map, offset_map, possible_truths,
! 			      toplev_predicate);
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
      {
*************** remap_edge_summaries  (struct cgraph_edg
*** 2593,2600 ****
        if (es->predicate)
  	{
  	  p = remap_predicate (info, callee_info,
! 			       es->predicate, operand_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.
--- 2736,2743 ----
        if (es->predicate)
  	{
  	  p = remap_predicate (info, callee_info,
! 			       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.
*************** inline_merge_summary (struct cgraph_edge
*** 2623,2628 ****
--- 2766,2772 ----
    clause_t clause = 0;		/* not_inline is known to be false.  */
    size_time_entry *e;
    VEC (int, heap) *operand_map = NULL;
+   VEC (int, heap) *offset_map = NULL;
    int i;
    struct predicate toplev_predicate;
    struct predicate true_p = true_predicate ();
*************** inline_merge_summary (struct cgraph_edge
*** 2639,2655 ****
        int count = ipa_get_cs_argument_count (args);
        int i;
  
!       evaluate_properties_for_edge (edge, true, &clause, NULL, NULL);
        if (count)
! 	VEC_safe_grow_cleared (int, heap, operand_map, count);
        for (i = 0; i < count; i++)
  	{
  	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
  	  int map = -1;
  	  /* TODO: handle non-NOPs when merging.  */
! 	  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);
  	  VEC_replace (int, operand_map, i, map);
  	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
  	}
--- 2783,2818 ----
        int count = ipa_get_cs_argument_count (args);
        int i;
  
!       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, offset_map, count);
! 	}
        for (i = 0; i < count; i++)
  	{
  	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
  	  int map = -1;
+ 
  	  /* TODO: handle non-NOPs when merging.  */
! 	  if (jfunc->type == IPA_JF_PASS_THROUGH)
! 	    {
! 	      if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
! 		map = ipa_get_jf_pass_through_formal_id (jfunc);
! 	      if (!ipa_get_jf_pass_through_agg_preserved (jfunc))
! 		VEC_replace (int, offset_map, i, -1);
! 	    }
! 	  else if (jfunc->type == IPA_JF_ANCESTOR)
! 	    {
! 	      HOST_WIDE_INT offset = ipa_get_jf_ancestor_offset (jfunc);
! 	      if (offset >= 0 && offset < INT_MAX)
! 		{
! 		  map = ipa_get_jf_ancestor_formal_id (jfunc);
! 		  if (!ipa_get_jf_ancestor_agg_preserved (jfunc))
! 		    offset = -1;
! 		  VEC_replace (int, offset_map, i, offset);
! 		}
! 	    }
  	  VEC_replace (int, operand_map, i, map);
  	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
  	}
*************** inline_merge_summary (struct cgraph_edge
*** 2657,2663 ****
    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,
  					    &toplev_predicate);
        if (!false_predicate_p (&p))
  	{
--- 2820,2827 ----
    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,
! 					    offset_map, clause,
  					    &toplev_predicate);
        if (!false_predicate_p (&p))
  	{
*************** inline_merge_summary (struct cgraph_edge
*** 2679,2685 ****
  	}
      }
    remap_edge_summaries (edge, edge->callee, info, callee_info, operand_map,
! 			clause, &toplev_predicate);
  
    inline_update_callee_summaries (edge->callee,
  				  inline_edge_summary (edge)->loop_depth);
--- 2843,2849 ----
  	}
      }
    remap_edge_summaries (edge, edge->callee, info, callee_info, operand_map,
! 			offset_map, clause, &toplev_predicate);
  
    inline_update_callee_summaries (edge->callee,
  				  inline_edge_summary (edge)->loop_depth);
*************** inline_merge_summary (struct cgraph_edge
*** 2689,2694 ****
--- 2853,2859 ----
    /* Similarly remove param summaries.  */
    VEC_free (inline_param_summary_t, heap, es->param);
    VEC_free (int, heap, operand_map);
+   VEC_free (int, heap, offset_map);
  }
  
  /* For performance reasons inline_merge_summary is not updating overall size
*************** inline_update_overall_summary (struct cg
*** 2707,2713 ****
      info->size += e->size, info->time += e->time;
    estimate_calls_size_and_time (node, &info->size, &info->time,
  				~(clause_t)(1 << predicate_false_condition),
! 				NULL, NULL);
    info->time = (info->time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    info->size = (info->size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  }
--- 2872,2878 ----
      info->size += e->size, info->time += e->time;
    estimate_calls_size_and_time (node, &info->size, &info->time,
  				~(clause_t)(1 << predicate_false_condition),
! 				NULL, NULL, NULL);
    info->time = (info->time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    info->size = (info->size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  }
*************** do_estimate_edge_time (struct cgraph_edg
*** 2729,2745 ****
    clause_t clause;
    VEC (tree, heap) *known_vals;
    VEC (tree, heap) *known_binfos;
    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);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       &size, &time, es->param);
    VEC_free (tree, heap, known_vals);
    VEC_free (tree, heap, known_binfos);
  
    ret = (((gcov_type)time
  	   - es->call_stmt_time) * edge->frequency
--- 2894,2913 ----
    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,
! 				&known_aggs);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       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
*************** do_estimate_edge_growth (struct cgraph_e
*** 2776,2781 ****
--- 2944,2950 ----
    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.  */
  
*************** do_estimate_edge_growth (struct cgraph_e
*** 2794,2804 ****
    /* 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);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       &size, NULL, NULL);
    VEC_free (tree, heap, known_vals);
    VEC_free (tree, heap, known_binfos);
    gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size);
    return size - inline_edge_summary (edge)->call_stmt_size;
  }
--- 2963,2975 ----
    /* 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,
! 				&known_aggs);
    estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
! 			       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;
  }
*************** inline_read_section (struct lto_file_dec
*** 3078,3083 ****
--- 3249,3259 ----
  	  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);
+ 	  c.by_ref = 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);
*************** inline_write_summary (cgraph_node_set se
*** 3221,3226 ****
--- 3397,3408 ----
  	      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);
+ 	      bp_pack_value (&bp, c->by_ref, 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
*************** propagate_constants_accross_call (struct
*** 1084,1090 ****
  tree
  ipa_get_indirect_edge_target (struct cgraph_edge *ie,
  			      VEC (tree, heap) *known_vals,
! 			      VEC (tree, heap) *known_binfos)
  {
    int param_index = ie->indirect_info->param_index;
    HOST_WIDE_INT token, anc_offset;
--- 1084,1091 ----
  tree
  ipa_get_indirect_edge_target (struct cgraph_edge *ie,
  			      VEC (tree, heap) *known_vals,
! 			      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;
*************** ipa_get_indirect_edge_target (struct cgr
*** 1096,1103 ****
  
    if (!ie->indirect_info->polymorphic)
      {
!       tree 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)
--- 1097,1122 ----
  
    if (!ie->indirect_info->polymorphic)
      {
!       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->indirect_info->by_ref);
! 	    }
! 	  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)
*************** ipa_get_indirect_edge_target (struct cgr
*** 1106,1111 ****
--- 1125,1131 ----
  	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;
*************** devirtualization_time_bonus (struct cgra
*** 1156,1162 ****
        struct inline_summary *isummary;
        tree target;
  
!       target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos);
        if (!target)
  	continue;
  
--- 1176,1183 ----
        struct inline_summary *isummary;
        tree target;
  
!       target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos,
! 					     NULL);
        if (!target)
  	continue;
  
*************** ipcp_discover_new_direct_edges (struct c
*** 1673,1679 ****
        tree target;
  
        next_ie = ie->next_callee;
!       target = ipa_get_indirect_edge_target (ie, known_vals, NULL);
        if (target)
  	ipa_make_edge_direct_to_target (ie, target);
      }
--- 1694,1700 ----
        tree target;
  
        next_ie = ie->next_callee;
!       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
*************** bool ipa_propagate_indirect_call_infos (
*** 494,501 ****
  
  /* 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);
  struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
  
  /* Functions related to both.  */
--- 494,502 ----
  
  /* Indirect edge and binfo processing.  */
  tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
! 				   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: src/gcc/testsuite/gfortran.dg/pr48636.f90
===================================================================
*** /dev/null
--- src/gcc/testsuite/gfortran.dg/pr48636.f90
***************
*** 0 ****
--- 1,37 ----
+ ! { dg-do compile }
+ ! { dg-options "-O3 -fdump-ipa-inline" }
+ 
+ module foo
+   implicit none
+ contains
+   subroutine bar(a,x)
+     real, dimension(:,:), intent(in) :: a
+     real, intent(out) :: x
+     integer :: i,j
+ 
+     x = 0
+     do j=1,ubound(a,2)
+        do i=1,ubound(a,1)
+           x = x + a(i,j)**2
+        end do
+     end do
+   end subroutine bar
+ end module foo
+ 
+ program main
+   use foo
+   implicit none
+   real, dimension(2,3) :: a
+   real :: x
+   integer :: i
+ 
+   data a /1.0, 2.0, 3.0, -1.0, -2.0, -3.0/
+ 
+   do i=1,2000000
+      call bar(a,x)
+   end do
+   print *,x
+ end program main
+ 
+ ! { dg-final { scan-ipa-dump "bar\[^\\n\]*inline copy in MAIN" "inline" } }
+ ! { dg-final { cleanup-ipa-dump "inline" } }

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis
  2012-08-11 10:59       ` Martin Jambor
@ 2012-08-11 16:39         ` Jan Hubicka
  0 siblings, 0 replies; 10+ messages in thread
From: Jan Hubicka @ 2012-08-11 16:39 UTC (permalink / raw)
  To: Jan Hubicka, GCC Patches

> This is the patch I have committed after resolving a conflict (and
> another round of bootstrapping and testing).  The ChangeLog is still
> the same.
> 
> The previous version of the patch (but with tree code already
> converted to an enum), the aggregate jump functions together with
> enlarged inlining predicates increased Mozilla Firefox LTO WPA memory
> consumption by 1.2% (6775287 kb -> 6855035 kb as measured by
> maxmem2.sh).  On Monday I will make another measurement with jump
> functions completely switched off.

Thanks!  I did bit of static analysis on Mozilla, we increase number of
predicated instructions by about 30% that is quite good. We seem to be weaker
on actually using the predicates however, about 1% of inline decisions lead to
using those predicates.  I guess there is room for improvements in jump
functions  construction/propagation, right? :)
Looking at the dumps we get some quit interesting matches like memset call when
the destination argument is known to be zero already etc. 

Honza

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis
  2012-08-10  3:12   ` Jan Hubicka
  2012-08-10 14:40     ` Martin Jambor
@ 2012-08-15 15:34     ` Martin Jambor
  1 sibling, 0 replies; 10+ messages in thread
From: Martin Jambor @ 2012-08-15 15:34 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: GCC Patches

Hi,

On Fri, Aug 10, 2012 at 05:12:31AM +0200, Jan Hubicka wrote:
> 
> Do you have any data on memory usage?  I was originally concerned
> about memory use of the whole predicate thingy on WPA level.
> Eventually we could add simple inheritance on conditions and sort
> them into mutiple vectors if needed. But I assume it is OK or we
> will work out on Mozilla builds soonish.
> 

When I have completely disabled computation of jump functions, the
number of expression trees reported by detailed -fmem-report in the
WPA stage dropped from 2253872 to 2124732, i.e. by 5.7%.

Martin

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis
  2012-08-02 19:28 [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis Martin Jambor
  2012-08-03 15:50 ` Martin Jambor
@ 2012-08-29 15:45 ` H.J. Lu
  1 sibling, 0 replies; 10+ messages in thread
From: H.J. Lu @ 2012-08-29 15:45 UTC (permalink / raw)
  To: GCC Patches, Jan Hubicka

On Thu, Aug 2, 2012 at 12:28 PM, Martin Jambor <mjambor@suse.cz> wrote:
> Hi,
>
> this patch uses the aggregate jump functions created by the previous
> patch in the series to determine benefits of inlining a particular
> call graph edge.  It has not changed much since the last time I posted
> it, except for the presence of by_ref flags and removal of checks
> required by TBAA which we now do not use.
>
> The patch works in fairly straightforward way.  It ads two flags to
> struct condition to specify it actually refers to an aggregate passed
> by value or something passed by reference, in both cases at a
> particular 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 functions 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.
>
> This patch alone makes us inline the function bar in testcase of PR
> 48636 in comment #4.  It also passes bootstrap and testing on
> x86_64-linux.  I successfully LTO-built Firefox with it too.
>
> Thanks for all comments and suggestions,
>
> Martin
>
>
> 2012-07-31  Martin Jambor  <mjambor@suse.cz>
>
>         PR fortran/48636
>         * ipa-inline.h (condition): New fields offset, agg_contents and by_ref.
>         * ipa-inline-analysis.c (agg_position_info): New type.
>         (add_condition): New parameter aggpos, also store agg_contents, by_ref
>         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.
>

This caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54409


H.J.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis
@ 2012-07-02 17:11 Martin Jambor
  0 siblings, 0 replies; 10+ messages in thread
From: Martin Jambor @ 2012-07-02 17:11 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jan Hubicka

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.

The patch 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-06-29  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.

	* testsuite/gfortran.dg/pr48636.f90: New test.


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");
@@ -661,14 +669,15 @@ edge_set_predicate (struct cgraph_edge *
 
 /* KNOWN_VALS is partial mapping of parameters of NODE to constant values.
    Return clause of possible truths. When INLINE_P is true, assume that
-   we are inlining. 
+   we are inlining.
 
    ERROR_MARK means compile time invariant.  */
 
 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),
+							    c->operand_num)))
+	      && (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,27 @@ 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.
+	     When we do that, we must not forget to check also
+	     ipa_jf_propagates_agg_p.  */
+	  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 +969,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 +1314,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 +1337,64 @@ 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 chains of SSA register assignments.  */
+
+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 res = unmodified_parm_1 (stmt, op);
+
+  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 (!REFERENCE_CLASS_P (op))
+	return unmodified_parm_or_parm_agg_item (info, stmt, op, index_p,
+						 agg_contents_p, offset_p);
+    }
+
+  *agg_contents_p = true;
+  return ipa_load_from_parm_agg (info, stmt, op, index_p, offset_p);
 }
 
 /* See if statement might disappear after inlining.
@@ -1423,6 +1525,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 +1545,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 +1556,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 +1582,7 @@ set_cond_stmt_execution_predicate (struc
       || gimple_call_num_args (set_stmt) != 1)
     return;
   op2 = gimple_call_arg (set_stmt, 0);
+  /* TODO: Use unmodified_parm_or_parm_agg_item also here.  */
   base = get_base_address (op2);
   parm = unmodified_parm (set_stmt, base ? base : op2);
   if (!parm)
@@ -1495,7 +1597,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 +1617,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 +1655,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 +1760,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,23 +1783,18 @@ will_be_nonconstant_predicate (struct ip
     return p;
 
   is_load = gimple_vuse (stmt) != NULL;
-
   /* 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.  */
@@ -1717,23 +1813,25 @@ will_be_nonconstant_predicate (struct ip
 	continue;
       return p;
     }
-  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),
-			 CHANGED, NULL);
-      op_non_const = or_predicates (summary->conds, &p, &op_non_const);
-    }
+    op_non_const = add_condition (summary, base_index, agg_contents, offset,
+				  CHANGED, NULL);
+  else
+    op_non_const = false_predicate ();
   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
+	    continue;
+	}
       else
 	p = *VEC_index (predicate_t, nonconstant_names,
 			SSA_NAME_VERSION (use));
@@ -2195,7 +2293,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 +2302,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 +2360,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 +2378,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 +2388,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 +2403,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 +2455,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,27 +2484,29 @@ 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.
 
-   INFO is inline_summary of function we are adding predicate into,
-   CALLEE_INFO is summary of function predicate P is from. OPERAND_MAP is
-   array giving callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is
-   clausule of all callee conditions that may be true in caller context.
-   TOPLEV_PREDICATE is predicate under which callee is executed.  */
+   INFO is inline_summary of function we are adding predicate into, CALLEE_INFO
+   is summary of function predicate P is from. OPERAND_MAP is array giving
+   callee formal IDs the caller formal IDs. POSSSIBLE_TRUTHS is clausule of all
+   callee conditions that may be true in caller context.  TOPLEV_PREDICATE is
+   predicate under which callee is executed.  OFFSET_MAP is an array of of
+   offsets that need to be added to conditions, negative offset means that
+   conditions have to be discarded because of ipa_jf_propagates_agg_p.  */
 
 static struct predicate
 remap_predicate (struct inline_summary *info,
 		 struct inline_summary *callee_info,
 		 struct predicate *p,
 		 VEC (int, heap) *operand_map,
+		 VEC (int, heap) *offset_map,
 		 clause_t possible_truths,
 		 struct predicate *toplev_predicate)
 {
@@ -2437,13 +2541,26 @@ 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 (int, offset_map, c->operand_num) != 0)
+		     || (c->agg_contents
+			 && VEC_index (int, 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 (int, 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 +2667,7 @@ remap_edge_summaries  (struct cgraph_edg
 		       struct inline_summary *info,
 		       struct inline_summary *callee_info,
 		       VEC (int, heap) *operand_map,
+		       VEC (int, heap) *offset_map,
 		       clause_t possible_truths,
 		       struct predicate *toplev_predicate)
 {
@@ -2566,7 +2684,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 +2702,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 +2714,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 +2744,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 (int, heap) *offset_map = NULL;
   int i;
   struct predicate toplev_predicate;
   struct predicate true_p = true_predicate ();
@@ -2640,9 +2761,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 (int, heap, offset_map, count);
+	}
       for (i = 0; i < count; i++)
 	{
 	  struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
@@ -2651,6 +2775,17 @@ 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);
+	  if (!ipa_jf_propagates_agg_p (edge, jfunc, i))
+	    VEC_replace (int, offset_map, i, -1);
+	  else if (jfunc->type == IPA_JF_ANCESTOR)
+	    {
+	      HOST_WIDE_INT offset = ipa_get_jf_ancestor_offset (jfunc);
+	      if (offset >= 0 && offset < INT_MAX)
+		{
+		  map = ipa_get_jf_ancestor_formal_id (jfunc);
+		  VEC_replace (int, offset_map, i, (int) offset);
+		}
+	    }
 	  VEC_replace (int, operand_map, i, map);
 	  gcc_assert (map < ipa_get_param_count (IPA_NODE_REF (to)));
 	}
@@ -2658,7 +2793,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 +2816,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 +2833,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 (int, 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 +2857,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 +2907,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 +2926,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 +3212,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 +3359,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
@@ -495,8 +495,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: src/gcc/testsuite/gfortran.dg/pr48636.f90
===================================================================
--- /dev/null
+++ src/gcc/testsuite/gfortran.dg/pr48636.f90
@@ -0,0 +1,37 @@
+! { dg-do compile }
+! { dg-options "-O3 -fdump-ipa-inline" }
+
+module foo
+  implicit none
+contains
+  subroutine bar(a,x)
+    real, dimension(:,:), intent(in) :: a
+    real, intent(out) :: x
+    integer :: i,j
+
+    x = 0
+    do j=1,ubound(a,2)
+       do i=1,ubound(a,1)
+          x = x + a(i,j)**2
+       end do
+    end do
+  end subroutine bar
+end module foo
+
+program main
+  use foo
+  implicit none
+  real, dimension(2,3) :: a
+  real :: x
+  integer :: i
+
+  data a /1.0, 2.0, 3.0, -1.0, -2.0, -3.0/
+
+  do i=1,2000000
+     call bar(a,x)
+  end do
+  print *,x
+end program main
+
+! { dg-final { scan-ipa-dump "bar\[^\\n\]*inline copy in MAIN" "inline" } }
+! { dg-final { cleanup-ipa-dump "inline" } }

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2012-08-29 15:45 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-02 19:28 [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis Martin Jambor
2012-08-03 15:50 ` Martin Jambor
2012-08-10  3:12   ` Jan Hubicka
2012-08-10 14:40     ` Martin Jambor
2012-08-11 10:59       ` Martin Jambor
2012-08-11 16:39         ` Jan Hubicka
2012-08-15 15:34     ` Martin Jambor
2012-08-10  3:17   ` Jan Hubicka
2012-08-29 15:45 ` H.J. Lu
  -- strict thread matches above, loose matches on Subject: below --
2012-07-02 17:11 Martin Jambor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).