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  <mjam...@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" } }

Reply via email to