Indirect inlining of targets from references of global constants
2016-05-18 Martin Jambor <mjambor@suse.cz> PR ipa/69708 * cgraph.h (cgraph_indirect_call_info): New field guaranteed_unmodified. * ipa-cp.c (ipa_get_indirect_edge_target_1): Also pass parameter value to ipa_find_agg_cst_for_param, check guaranteed_unmodified when appropriate. * ipa-inline-analysis.c (evaluate_conditions_for_known_args): Also pass the parameter value to ipa_find_agg_cst_for_param. * ipa-prop.c (ipa_load_from_parm_agg): New parameter guaranteed_unmodified, store AA results there instead of bailing out if present. (ipa_note_param_call): Also initialize guaranteed_unmodified flag. (ipa_analyze_indirect_call_uses): Also set guaranteed_unmodified flag. (find_constructor_constant_at_offset): New function. (ipa_find_agg_cst_from_init): Likewise. (ipa_find_agg_cst_for_param): Also seearch for aggregate values in static initializers of contants, report back through a new paameter from_global_constant if that was the case. (try_make_edge_direct_simple_call): Also pass parameter value to ipa_find_agg_cst_for_param, check guaranteed_unmodified when appropriate. (ipa_write_indirect_edge_info): Stream new flag guaranteed_unmodified. (ipa_read_indirect_edge_info): Likewise. * ipa-prop.h (ipa_find_agg_cst_for_param): Update declaration. (ipa_load_from_parm_agg): Likewise. testsuite/ * gcc.dg/ipa/iinline-cstagg-1.c: New test. * gcc.dg/ipa/ipcp-cstagg-1.c: Likewise. * gcc.dg/ipa/ipcp-cstagg-2.c: Likewise. * gcc.dg/ipa/ipcp-cstagg-3.c: Likewise. * gcc.dg/ipa/ipcp-cstagg-4.c: Likewise. From-SVN: r236416
This commit is contained in:
parent
c584aca60c
commit
91bb9f80e5
@ -1,3 +1,31 @@
|
|||||||
|
2016-05-18 Martin Jambor <mjambor@suse.cz>
|
||||||
|
|
||||||
|
PR ipa/69708
|
||||||
|
* cgraph.h (cgraph_indirect_call_info): New field
|
||||||
|
guaranteed_unmodified.
|
||||||
|
* ipa-cp.c (ipa_get_indirect_edge_target_1): Also pass parameter value
|
||||||
|
to ipa_find_agg_cst_for_param, check guaranteed_unmodified when
|
||||||
|
appropriate.
|
||||||
|
* ipa-inline-analysis.c (evaluate_conditions_for_known_args): Also
|
||||||
|
pass the parameter value to ipa_find_agg_cst_for_param.
|
||||||
|
* ipa-prop.c (ipa_load_from_parm_agg): New parameter
|
||||||
|
guaranteed_unmodified, store AA results there instead of bailing out
|
||||||
|
if present.
|
||||||
|
(ipa_note_param_call): Also initialize guaranteed_unmodified flag.
|
||||||
|
(ipa_analyze_indirect_call_uses): Also set guaranteed_unmodified flag.
|
||||||
|
(find_constructor_constant_at_offset): New function.
|
||||||
|
(ipa_find_agg_cst_from_init): Likewise.
|
||||||
|
(ipa_find_agg_cst_for_param): Also seearch for aggregate values in
|
||||||
|
static initializers of contants, report back through a new paameter
|
||||||
|
from_global_constant if that was the case.
|
||||||
|
(try_make_edge_direct_simple_call): Also pass parameter value to
|
||||||
|
ipa_find_agg_cst_for_param, check guaranteed_unmodified when
|
||||||
|
appropriate.
|
||||||
|
(ipa_write_indirect_edge_info): Stream new flag guaranteed_unmodified.
|
||||||
|
(ipa_read_indirect_edge_info): Likewise.
|
||||||
|
* ipa-prop.h (ipa_find_agg_cst_for_param): Update declaration.
|
||||||
|
(ipa_load_from_parm_agg): Likewise.
|
||||||
|
|
||||||
2016-05-18 Jiong Wang <jiong.wang@arm.com>
|
2016-05-18 Jiong Wang <jiong.wang@arm.com>
|
||||||
|
|
||||||
PR rtl-optimization/71150
|
PR rtl-optimization/71150
|
||||||
|
@ -1579,9 +1579,14 @@ struct GTY(()) cgraph_indirect_call_info
|
|||||||
unsigned agg_contents : 1;
|
unsigned agg_contents : 1;
|
||||||
/* Set when this is a call through a member pointer. */
|
/* Set when this is a call through a member pointer. */
|
||||||
unsigned member_ptr : 1;
|
unsigned member_ptr : 1;
|
||||||
/* When the previous bit is set, this one determines whether the destination
|
/* When the agg_contents bit is set, this one determines whether the
|
||||||
is loaded from a parameter passed by reference. */
|
destination is loaded from a parameter passed by reference. */
|
||||||
unsigned by_ref : 1;
|
unsigned by_ref : 1;
|
||||||
|
/* When the agg_contents bit is set, this one determines whether we can
|
||||||
|
deduce from the function body that the loaded value from the reference is
|
||||||
|
never modified between the invocation of the function and the load
|
||||||
|
point. */
|
||||||
|
unsigned guaranteed_unmodified : 1;
|
||||||
/* For polymorphic calls this specify whether the virtual table pointer
|
/* For polymorphic calls this specify whether the virtual table pointer
|
||||||
may have changed in between function entry and the call. */
|
may have changed in between function entry and the call. */
|
||||||
unsigned vptr_changed : 1;
|
unsigned vptr_changed : 1;
|
||||||
|
26
gcc/ipa-cp.c
26
gcc/ipa-cp.c
@ -1999,9 +1999,9 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
|
|||||||
|
|
||||||
if (ie->indirect_info->agg_contents)
|
if (ie->indirect_info->agg_contents)
|
||||||
{
|
{
|
||||||
if (agg_reps)
|
t = NULL;
|
||||||
|
if (agg_reps && ie->indirect_info->guaranteed_unmodified)
|
||||||
{
|
{
|
||||||
t = NULL;
|
|
||||||
while (agg_reps)
|
while (agg_reps)
|
||||||
{
|
{
|
||||||
if (agg_reps->index == param_index
|
if (agg_reps->index == param_index
|
||||||
@ -2014,15 +2014,22 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
|
|||||||
agg_reps = agg_reps->next;
|
agg_reps = agg_reps->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (known_aggs.length () > (unsigned int) param_index)
|
if (!t)
|
||||||
{
|
{
|
||||||
struct ipa_agg_jump_function *agg;
|
struct ipa_agg_jump_function *agg;
|
||||||
agg = known_aggs[param_index];
|
if (known_aggs.length () > (unsigned int) param_index)
|
||||||
t = ipa_find_agg_cst_for_param (agg, ie->indirect_info->offset,
|
agg = known_aggs[param_index];
|
||||||
ie->indirect_info->by_ref);
|
else
|
||||||
|
agg = NULL;
|
||||||
|
bool from_global_constant;
|
||||||
|
t = ipa_find_agg_cst_for_param (agg, known_csts[param_index],
|
||||||
|
ie->indirect_info->offset,
|
||||||
|
ie->indirect_info->by_ref,
|
||||||
|
&from_global_constant);
|
||||||
|
if (!from_global_constant
|
||||||
|
&& !ie->indirect_info->guaranteed_unmodified)
|
||||||
|
t = NULL_TREE;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
t = NULL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
t = known_csts[param_index];
|
t = known_csts[param_index];
|
||||||
@ -2066,7 +2073,8 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
|
|||||||
{
|
{
|
||||||
struct ipa_agg_jump_function *agg;
|
struct ipa_agg_jump_function *agg;
|
||||||
agg = known_aggs[param_index];
|
agg = known_aggs[param_index];
|
||||||
t = ipa_find_agg_cst_for_param (agg, ie->indirect_info->offset,
|
t = ipa_find_agg_cst_for_param (agg, known_csts[param_index],
|
||||||
|
ie->indirect_info->offset,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -853,7 +853,8 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
|
|||||||
if (known_aggs.exists ())
|
if (known_aggs.exists ())
|
||||||
{
|
{
|
||||||
agg = known_aggs[c->operand_num];
|
agg = known_aggs[c->operand_num];
|
||||||
val = ipa_find_agg_cst_for_param (agg, c->offset, c->by_ref);
|
val = ipa_find_agg_cst_for_param (agg, known_vals[c->operand_num],
|
||||||
|
c->offset, c->by_ref);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
val = NULL_TREE;
|
val = NULL_TREE;
|
||||||
|
179
gcc/ipa-prop.c
179
gcc/ipa-prop.c
@ -930,10 +930,15 @@ parm_ref_data_pass_through_p (struct ipa_func_body_info *fbi, int index,
|
|||||||
return !modified;
|
return !modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if we can prove that OP is a memory reference loading unmodified
|
/* Return true if we can prove that OP is a memory reference loading
|
||||||
data from an aggregate passed as a parameter and if the aggregate is passed
|
data from an aggregate passed as a parameter.
|
||||||
by reference, that the alias type of the load corresponds to the type of the
|
|
||||||
formal parameter (so that we can rely on this type for TBAA in callers).
|
The function works in two modes. If GUARANTEED_UNMODIFIED is NULL, it return
|
||||||
|
false if it cannot prove that the value has not been modified before the
|
||||||
|
load in STMT. If GUARANTEED_UNMODIFIED is not NULL, it will return true even
|
||||||
|
if it cannot prove the value has not been modified, in that case it will
|
||||||
|
store false to *GUARANTEED_UNMODIFIED, otherwise it will store true there.
|
||||||
|
|
||||||
INFO and PARMS_AINFO describe parameters of the current function (but the
|
INFO and PARMS_AINFO describe parameters of the current function (but the
|
||||||
latter can be NULL), STMT is the load statement. If function returns true,
|
latter can be NULL), STMT is the load statement. If function returns true,
|
||||||
*INDEX_P, *OFFSET_P and *BY_REF is filled with the parameter index, offset
|
*INDEX_P, *OFFSET_P and *BY_REF is filled with the parameter index, offset
|
||||||
@ -945,7 +950,7 @@ ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
|
|||||||
vec<ipa_param_descriptor> descriptors,
|
vec<ipa_param_descriptor> descriptors,
|
||||||
gimple *stmt, tree op, int *index_p,
|
gimple *stmt, tree op, int *index_p,
|
||||||
HOST_WIDE_INT *offset_p, HOST_WIDE_INT *size_p,
|
HOST_WIDE_INT *offset_p, HOST_WIDE_INT *size_p,
|
||||||
bool *by_ref_p)
|
bool *by_ref_p, bool *guaranteed_unmodified)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
HOST_WIDE_INT size, max_size;
|
HOST_WIDE_INT size, max_size;
|
||||||
@ -966,6 +971,8 @@ ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
|
|||||||
*by_ref_p = false;
|
*by_ref_p = false;
|
||||||
if (size_p)
|
if (size_p)
|
||||||
*size_p = size;
|
*size_p = size;
|
||||||
|
if (guaranteed_unmodified)
|
||||||
|
*guaranteed_unmodified = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1002,13 +1009,18 @@ ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
|
|||||||
index = load_from_unmodified_param (fbi, descriptors, def);
|
index = load_from_unmodified_param (fbi, descriptors, def);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index >= 0
|
if (index >= 0)
|
||||||
&& parm_ref_data_preserved_p (fbi, index, stmt, op))
|
|
||||||
{
|
{
|
||||||
|
bool data_preserved = parm_ref_data_preserved_p (fbi, index, stmt, op);
|
||||||
|
if (!data_preserved && !guaranteed_unmodified)
|
||||||
|
return false;
|
||||||
|
|
||||||
*index_p = index;
|
*index_p = index;
|
||||||
*by_ref_p = true;
|
*by_ref_p = true;
|
||||||
if (size_p)
|
if (size_p)
|
||||||
*size_p = size;
|
*size_p = size;
|
||||||
|
if (guaranteed_unmodified)
|
||||||
|
*guaranteed_unmodified = data_preserved;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1824,6 +1836,7 @@ ipa_note_param_call (struct cgraph_node *node, int param_index,
|
|||||||
cs->indirect_info->param_index = param_index;
|
cs->indirect_info->param_index = param_index;
|
||||||
cs->indirect_info->agg_contents = 0;
|
cs->indirect_info->agg_contents = 0;
|
||||||
cs->indirect_info->member_ptr = 0;
|
cs->indirect_info->member_ptr = 0;
|
||||||
|
cs->indirect_info->guaranteed_unmodified = 0;
|
||||||
return cs;
|
return cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1905,15 +1918,17 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
|
|||||||
|
|
||||||
int index;
|
int index;
|
||||||
gimple *def = SSA_NAME_DEF_STMT (target);
|
gimple *def = SSA_NAME_DEF_STMT (target);
|
||||||
|
bool guaranteed_unmodified;
|
||||||
if (gimple_assign_single_p (def)
|
if (gimple_assign_single_p (def)
|
||||||
&& ipa_load_from_parm_agg (fbi, info->descriptors, def,
|
&& ipa_load_from_parm_agg (fbi, info->descriptors, def,
|
||||||
gimple_assign_rhs1 (def), &index, &offset,
|
gimple_assign_rhs1 (def), &index, &offset,
|
||||||
NULL, &by_ref))
|
NULL, &by_ref, &guaranteed_unmodified))
|
||||||
{
|
{
|
||||||
struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
|
struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
|
||||||
cs->indirect_info->offset = offset;
|
cs->indirect_info->offset = offset;
|
||||||
cs->indirect_info->agg_contents = 1;
|
cs->indirect_info->agg_contents = 1;
|
||||||
cs->indirect_info->by_ref = by_ref;
|
cs->indirect_info->by_ref = by_ref;
|
||||||
|
cs->indirect_info->guaranteed_unmodified = guaranteed_unmodified;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2014,6 +2029,7 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
|
|||||||
cs->indirect_info->offset = offset;
|
cs->indirect_info->offset = offset;
|
||||||
cs->indirect_info->agg_contents = 1;
|
cs->indirect_info->agg_contents = 1;
|
||||||
cs->indirect_info->member_ptr = 1;
|
cs->indirect_info->member_ptr = 1;
|
||||||
|
cs->indirect_info->guaranteed_unmodified = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -2701,18 +2717,125 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
|
|||||||
return ie;
|
return ie;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve value from aggregate jump function AGG for the given OFFSET or
|
/* Attempt to locate an interprocedural constant at a given REQ_OFFSET in
|
||||||
return NULL if there is not any. BY_REF specifies whether the value has to
|
CONSTRUCTOR and return it. Return NULL if the search fails for some
|
||||||
be passed by reference or by value. */
|
reason. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
find_constructor_constant_at_offset (tree constructor, HOST_WIDE_INT req_offset)
|
||||||
|
{
|
||||||
|
tree type = TREE_TYPE (constructor);
|
||||||
|
if (TREE_CODE (type) != ARRAY_TYPE
|
||||||
|
&& TREE_CODE (type) != RECORD_TYPE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
unsigned ix;
|
||||||
|
tree index, val;
|
||||||
|
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (constructor), ix, index, val)
|
||||||
|
{
|
||||||
|
HOST_WIDE_INT elt_offset;
|
||||||
|
if (TREE_CODE (type) == ARRAY_TYPE)
|
||||||
|
{
|
||||||
|
offset_int off;
|
||||||
|
tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (type));
|
||||||
|
gcc_assert (TREE_CODE (unit_size) == INTEGER_CST);
|
||||||
|
|
||||||
|
if (index)
|
||||||
|
{
|
||||||
|
off = wi::to_offset (index);
|
||||||
|
if (TYPE_DOMAIN (type) && TYPE_MIN_VALUE (TYPE_DOMAIN (type)))
|
||||||
|
{
|
||||||
|
tree low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
|
||||||
|
gcc_assert (TREE_CODE (unit_size) == INTEGER_CST);
|
||||||
|
off = wi::sext (off - wi::to_offset (low_bound),
|
||||||
|
TYPE_PRECISION (TREE_TYPE (index)));
|
||||||
|
}
|
||||||
|
off *= wi::to_offset (unit_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
off = wi::to_offset (unit_size) * ix;
|
||||||
|
|
||||||
|
off = wi::lshift (off, LOG2_BITS_PER_UNIT);
|
||||||
|
if (!wi::fits_shwi_p (off) || wi::neg_p (off))
|
||||||
|
continue;
|
||||||
|
elt_offset = off.to_shwi ();
|
||||||
|
}
|
||||||
|
else if (TREE_CODE (type) == RECORD_TYPE)
|
||||||
|
{
|
||||||
|
gcc_checking_assert (index && TREE_CODE (index) == FIELD_DECL);
|
||||||
|
if (DECL_BIT_FIELD (index))
|
||||||
|
continue;
|
||||||
|
elt_offset = int_bit_position (index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gcc_unreachable ();
|
||||||
|
|
||||||
|
if (elt_offset > req_offset)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (TREE_CODE (val) == CONSTRUCTOR)
|
||||||
|
return find_constructor_constant_at_offset (val,
|
||||||
|
req_offset - elt_offset);
|
||||||
|
|
||||||
|
if (elt_offset == req_offset
|
||||||
|
&& is_gimple_reg_type (TREE_TYPE (val))
|
||||||
|
&& is_gimple_ip_invariant (val))
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check whether SCALAR could be used to look up an aggregate interprocedural
|
||||||
|
invariant from a static constructor and if so, return it. Otherwise return
|
||||||
|
NULL. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset, bool by_ref)
|
||||||
|
{
|
||||||
|
if (by_ref)
|
||||||
|
{
|
||||||
|
if (TREE_CODE (scalar) != ADDR_EXPR)
|
||||||
|
return NULL;
|
||||||
|
scalar = TREE_OPERAND (scalar, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TREE_CODE (scalar) != VAR_DECL
|
||||||
|
|| !is_global_var (scalar)
|
||||||
|
|| !TREE_READONLY (scalar)
|
||||||
|
|| !DECL_INITIAL (scalar)
|
||||||
|
|| TREE_CODE (DECL_INITIAL (scalar)) != CONSTRUCTOR)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return find_constructor_constant_at_offset (DECL_INITIAL (scalar), offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrieve value from aggregate jump function AGG or static initializer of
|
||||||
|
SCALAR (which can be NULL) for the given OFFSET or return NULL if there is
|
||||||
|
none. BY_REF specifies whether the value has to be passed by reference or
|
||||||
|
by value. If FROM_GLOBAL_CONSTANT is non-NULL, then the boolean it points
|
||||||
|
to is set to true if the value comes from an initializer of a constant. */
|
||||||
|
|
||||||
tree
|
tree
|
||||||
ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg,
|
ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg, tree scalar,
|
||||||
HOST_WIDE_INT offset, bool by_ref)
|
HOST_WIDE_INT offset, bool by_ref,
|
||||||
|
bool *from_global_constant)
|
||||||
{
|
{
|
||||||
struct ipa_agg_jf_item *item;
|
struct ipa_agg_jf_item *item;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (by_ref != agg->by_ref)
|
if (scalar)
|
||||||
|
{
|
||||||
|
tree res = ipa_find_agg_cst_from_init (scalar, offset, by_ref);
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
if (from_global_constant)
|
||||||
|
*from_global_constant = true;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!agg
|
||||||
|
|| by_ref != agg->by_ref)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
FOR_EACH_VEC_SAFE_ELT (agg->items, i, item)
|
FOR_EACH_VEC_SAFE_ELT (agg->items, i, item)
|
||||||
@ -2721,6 +2844,8 @@ ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg,
|
|||||||
/* Currently we do not have clobber values, return NULL for them once
|
/* Currently we do not have clobber values, return NULL for them once
|
||||||
we do. */
|
we do. */
|
||||||
gcc_checking_assert (is_gimple_ip_invariant (item->value));
|
gcc_checking_assert (is_gimple_ip_invariant (item->value));
|
||||||
|
if (from_global_constant)
|
||||||
|
*from_global_constant = false;
|
||||||
return item->value;
|
return item->value;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -2819,13 +2944,21 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie,
|
|||||||
struct cgraph_edge *cs;
|
struct cgraph_edge *cs;
|
||||||
tree target;
|
tree target;
|
||||||
bool agg_contents = ie->indirect_info->agg_contents;
|
bool agg_contents = ie->indirect_info->agg_contents;
|
||||||
|
tree scalar = ipa_value_from_jfunc (new_root_info, jfunc);
|
||||||
if (ie->indirect_info->agg_contents)
|
if (agg_contents)
|
||||||
target = ipa_find_agg_cst_for_param (&jfunc->agg,
|
{
|
||||||
ie->indirect_info->offset,
|
bool from_global_constant;
|
||||||
ie->indirect_info->by_ref);
|
target = ipa_find_agg_cst_for_param (&jfunc->agg, scalar,
|
||||||
|
ie->indirect_info->offset,
|
||||||
|
ie->indirect_info->by_ref,
|
||||||
|
&from_global_constant);
|
||||||
|
if (target
|
||||||
|
&& !from_global_constant
|
||||||
|
&& !ie->indirect_info->guaranteed_unmodified)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
target = ipa_value_from_jfunc (new_root_info, jfunc);
|
target = scalar;
|
||||||
if (!target)
|
if (!target)
|
||||||
return NULL;
|
return NULL;
|
||||||
cs = ipa_make_edge_direct_to_target (ie, target);
|
cs = ipa_make_edge_direct_to_target (ie, target);
|
||||||
@ -2893,7 +3026,9 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
|
|||||||
{
|
{
|
||||||
tree vtable;
|
tree vtable;
|
||||||
unsigned HOST_WIDE_INT offset;
|
unsigned HOST_WIDE_INT offset;
|
||||||
tree t = ipa_find_agg_cst_for_param (&jfunc->agg,
|
tree scalar = (jfunc->type == IPA_JF_CONST) ? ipa_get_jf_constant (jfunc)
|
||||||
|
: NULL;
|
||||||
|
tree t = ipa_find_agg_cst_for_param (&jfunc->agg, scalar,
|
||||||
ie->indirect_info->offset,
|
ie->indirect_info->offset,
|
||||||
true);
|
true);
|
||||||
if (t && vtable_pointer_value_to_vtable (t, &vtable, &offset))
|
if (t && vtable_pointer_value_to_vtable (t, &vtable, &offset))
|
||||||
@ -4560,6 +4695,7 @@ ipa_write_indirect_edge_info (struct output_block *ob,
|
|||||||
bp_pack_value (&bp, ii->agg_contents, 1);
|
bp_pack_value (&bp, ii->agg_contents, 1);
|
||||||
bp_pack_value (&bp, ii->member_ptr, 1);
|
bp_pack_value (&bp, ii->member_ptr, 1);
|
||||||
bp_pack_value (&bp, ii->by_ref, 1);
|
bp_pack_value (&bp, ii->by_ref, 1);
|
||||||
|
bp_pack_value (&bp, ii->guaranteed_unmodified, 1);
|
||||||
bp_pack_value (&bp, ii->vptr_changed, 1);
|
bp_pack_value (&bp, ii->vptr_changed, 1);
|
||||||
streamer_write_bitpack (&bp);
|
streamer_write_bitpack (&bp);
|
||||||
if (ii->agg_contents || ii->polymorphic)
|
if (ii->agg_contents || ii->polymorphic)
|
||||||
@ -4592,6 +4728,7 @@ ipa_read_indirect_edge_info (struct lto_input_block *ib,
|
|||||||
ii->agg_contents = bp_unpack_value (&bp, 1);
|
ii->agg_contents = bp_unpack_value (&bp, 1);
|
||||||
ii->member_ptr = bp_unpack_value (&bp, 1);
|
ii->member_ptr = bp_unpack_value (&bp, 1);
|
||||||
ii->by_ref = bp_unpack_value (&bp, 1);
|
ii->by_ref = bp_unpack_value (&bp, 1);
|
||||||
|
ii->guaranteed_unmodified = bp_unpack_value (&bp, 1);
|
||||||
ii->vptr_changed = bp_unpack_value (&bp, 1);
|
ii->vptr_changed = bp_unpack_value (&bp, 1);
|
||||||
if (ii->agg_contents || ii->polymorphic)
|
if (ii->agg_contents || ii->polymorphic)
|
||||||
ii->offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
|
ii->offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
|
||||||
|
@ -636,11 +636,14 @@ tree ipa_impossible_devirt_target (struct cgraph_edge *, tree);
|
|||||||
void ipa_analyze_node (struct cgraph_node *);
|
void ipa_analyze_node (struct cgraph_node *);
|
||||||
|
|
||||||
/* Aggregate jump function related functions. */
|
/* Aggregate jump function related functions. */
|
||||||
tree ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *, HOST_WIDE_INT,
|
tree ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg, tree scalar,
|
||||||
bool);
|
HOST_WIDE_INT offset, bool by_ref,
|
||||||
bool ipa_load_from_parm_agg (struct ipa_func_body_info *,
|
bool *from_global_constant = NULL);
|
||||||
vec<ipa_param_descriptor>, gimple *, tree, int *,
|
bool ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
|
||||||
HOST_WIDE_INT *, HOST_WIDE_INT *, bool *);
|
vec<ipa_param_descriptor> descriptors,
|
||||||
|
gimple *stmt, tree op, int *index_p,
|
||||||
|
HOST_WIDE_INT *offset_p, HOST_WIDE_INT *size_p,
|
||||||
|
bool *by_ref, bool *guaranteed_unmodified = NULL);
|
||||||
|
|
||||||
/* Debugging interface. */
|
/* Debugging interface. */
|
||||||
void ipa_print_node_params (FILE *, struct cgraph_node *node);
|
void ipa_print_node_params (FILE *, struct cgraph_node *node);
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
2016-05-18 Martin Jambor <mjambor@suse.cz>
|
||||||
|
|
||||||
|
PR ipa/69708
|
||||||
|
* gcc.dg/ipa/iinline-cstagg-1.c: New test.
|
||||||
|
* gcc.dg/ipa/ipcp-cstagg-1.c: Likewise.
|
||||||
|
* gcc.dg/ipa/ipcp-cstagg-2.c: Likewise.
|
||||||
|
* gcc.dg/ipa/ipcp-cstagg-3.c: Likewise.
|
||||||
|
* gcc.dg/ipa/ipcp-cstagg-4.c: Likewise.
|
||||||
|
|
||||||
2016-05-18 Paolo Carlini <paolo.carlini@oracle.com>
|
2016-05-18 Paolo Carlini <paolo.carlini@oracle.com>
|
||||||
|
|
||||||
PR c++/69793
|
PR c++/69793
|
||||||
|
37
gcc/testsuite/gcc.dg/ipa/iinline-cstagg-1.c
Normal file
37
gcc/testsuite/gcc.dg/ipa/iinline-cstagg-1.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O3 -fdump-ipa-inline-details -fno-early-inlining -fno-ipa-sra -fno-ipa-cp" } */
|
||||||
|
|
||||||
|
typedef struct S
|
||||||
|
{
|
||||||
|
int add_offset;
|
||||||
|
int (*call)(int);
|
||||||
|
} S;
|
||||||
|
|
||||||
|
static int
|
||||||
|
bar (const S *f, int x)
|
||||||
|
{
|
||||||
|
x = f->call(x);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
thisisthetarget (int x)
|
||||||
|
{
|
||||||
|
return x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const S s = {16, thisisthetarget};
|
||||||
|
|
||||||
|
int
|
||||||
|
outerfunction (int x)
|
||||||
|
{
|
||||||
|
return bar (&s, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
obfuscate (int x)
|
||||||
|
{
|
||||||
|
return bar ((S *) 0, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-ipa-dump "thisisthetarget\[^\\n\]*inline copy in outerfunction" "inline" } } */
|
42
gcc/testsuite/gcc.dg/ipa/ipcp-cstagg-1.c
Normal file
42
gcc/testsuite/gcc.dg/ipa/ipcp-cstagg-1.c
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O3 -fdump-ipa-cp-details" } */
|
||||||
|
|
||||||
|
typedef struct S
|
||||||
|
{
|
||||||
|
int add_offset;
|
||||||
|
int (*call)(int);
|
||||||
|
} S;
|
||||||
|
|
||||||
|
extern const S *gs;
|
||||||
|
|
||||||
|
static int __attribute__((noinline))
|
||||||
|
bar (const S *f, int x)
|
||||||
|
{
|
||||||
|
x = f->call(x);
|
||||||
|
x = f->call(x);
|
||||||
|
x = f->call(x);
|
||||||
|
gs = f;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sq (int x)
|
||||||
|
{
|
||||||
|
return x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const S s = {16, sq};
|
||||||
|
|
||||||
|
int
|
||||||
|
g (int x)
|
||||||
|
{
|
||||||
|
return bar (&s, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
obfuscate (int x)
|
||||||
|
{
|
||||||
|
return bar ((S *) 0, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-ipa-dump-times "Discovered an indirect call to a known target" 3 "cp" } } */
|
46
gcc/testsuite/gcc.dg/ipa/ipcp-cstagg-2.c
Normal file
46
gcc/testsuite/gcc.dg/ipa/ipcp-cstagg-2.c
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O3 -fdump-ipa-cp-details" } */
|
||||||
|
|
||||||
|
typedef struct S
|
||||||
|
{
|
||||||
|
int (*call)(int);
|
||||||
|
} S;
|
||||||
|
|
||||||
|
static int __attribute__((noinline))
|
||||||
|
bar (const S *f, int x)
|
||||||
|
{
|
||||||
|
x = f->call(x);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void impossible_aa (void);
|
||||||
|
|
||||||
|
static int __attribute__((noinline))
|
||||||
|
baz (const S *f, int x)
|
||||||
|
{
|
||||||
|
impossible_aa ();
|
||||||
|
return bar (f, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sq (int x)
|
||||||
|
{
|
||||||
|
return x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const S s = {sq};
|
||||||
|
|
||||||
|
int
|
||||||
|
g (int x)
|
||||||
|
{
|
||||||
|
return baz (&s, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
obfuscate (int x)
|
||||||
|
{
|
||||||
|
return baz ((S *) 0, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-ipa-dump "Discovered an indirect call to a known target" "cp" } } */
|
||||||
|
|
58
gcc/testsuite/gcc.dg/ipa/ipcp-cstagg-3.c
Normal file
58
gcc/testsuite/gcc.dg/ipa/ipcp-cstagg-3.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O3 -fdump-ipa-cp-details" } */
|
||||||
|
|
||||||
|
#define N 4
|
||||||
|
|
||||||
|
typedef int (* const A[N])(int);
|
||||||
|
|
||||||
|
extern const A *ga;
|
||||||
|
|
||||||
|
static int __attribute__((noinline))
|
||||||
|
bar (const A *f, int x)
|
||||||
|
{
|
||||||
|
x = (*f)[2](x);
|
||||||
|
x = (*f)[2](x);
|
||||||
|
x = (*f)[2](x);
|
||||||
|
ga = f;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
zero (int x)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addone (int x)
|
||||||
|
{
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sq (int x)
|
||||||
|
{
|
||||||
|
return x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cube (int x)
|
||||||
|
{
|
||||||
|
return x * x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const A a = {zero, addone, sq, cube};
|
||||||
|
|
||||||
|
int
|
||||||
|
g (int x)
|
||||||
|
{
|
||||||
|
return bar (&a, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
obfuscate (int x)
|
||||||
|
{
|
||||||
|
return bar ((A *) 0, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-ipa-dump-times "Discovered an indirect call to a known target" 3 "cp" } } */
|
64
gcc/testsuite/gcc.dg/ipa/ipcp-cstagg-4.c
Normal file
64
gcc/testsuite/gcc.dg/ipa/ipcp-cstagg-4.c
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O3 -fdump-ipa-cp-details" } */
|
||||||
|
|
||||||
|
#define N 4
|
||||||
|
|
||||||
|
typedef int (* const A[N])(int);
|
||||||
|
|
||||||
|
typedef struct S
|
||||||
|
{
|
||||||
|
int add_offset;
|
||||||
|
A a;
|
||||||
|
} S;
|
||||||
|
|
||||||
|
extern const S *gs;
|
||||||
|
|
||||||
|
static int __attribute__((noinline))
|
||||||
|
bar (const S *f, int x)
|
||||||
|
{
|
||||||
|
gs = f;
|
||||||
|
x = f->a[2](x);
|
||||||
|
x = f->a[2](x);
|
||||||
|
x = f->a[2](x);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
zero (int x)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addone (int x)
|
||||||
|
{
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sq (int x)
|
||||||
|
{
|
||||||
|
return x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cube (int x)
|
||||||
|
{
|
||||||
|
return x * x * x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const S s = {64, {zero, addone, sq, cube}};
|
||||||
|
|
||||||
|
int
|
||||||
|
g (int x)
|
||||||
|
{
|
||||||
|
return bar (&s, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
obfuscate (int x)
|
||||||
|
{
|
||||||
|
return bar ((S *) 0, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { dg-final { scan-ipa-dump-times "Discovered an indirect call to a known target" 3 "cp" } } */
|
Loading…
Reference in New Issue
Block a user