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


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

Re: [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis


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" } }


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