This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH 2/3] Incorporate aggregate jump functions into inlining analysis
- From: Martin Jambor <mjambor at suse dot cz>
- To: Jan Hubicka <hubicka at ucw dot cz>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 10 Aug 2012 16:39:44 +0200
- Subject: 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" } }