ipa-prop.c (ipa_set_jf_known_type): Check that we add only records.

* ipa-prop.c (ipa_set_jf_known_type): Check that we add
	only records.
	(detect_type_change_1): Rename to ...
	(detect_type_change): ... this one; early return on non-polymorphic
	types.
	(detect_type_change_ssa): Add comp_type parameter; update	
	use of detect_type_change.
	(compute_complex_assign_jump_func): Add param_type parameter;
	update use of detect_type_change_ssa.
	(compute_complex_ancestor_jump_func): Likewise.
	(ipa_get_callee_param_type): New function.
	(ipa_compute_jump_functions_for_edge): Compute parameter type;
	update calls to the jump function computation functions.

From-SVN: r202126
This commit is contained in:
Jan Hubicka 2013-08-31 14:26:32 +02:00 committed by Jan Hubicka
parent 600b5b1d5c
commit 06d6505030
2 changed files with 114 additions and 47 deletions

View file

@ -1,3 +1,19 @@
2013-08-30 Jan Hubicka <jh@suse.cz>
* ipa-prop.c (ipa_set_jf_known_type): Check that we add
only records.
(detect_type_change_1): Rename to ...
(detect_type_change): ... this one; early return on non-polymorphic
types.
(detect_type_change_ssa): Add comp_type parameter; update
use of detect_type_change.
(compute_complex_assign_jump_func): Add param_type parameter;
update use of detect_type_change_ssa.
(compute_complex_ancestor_jump_func): Likewise.
(ipa_get_callee_param_type): New function.
(ipa_compute_jump_functions_for_edge): Compute parameter type;
update calls to the jump function computation functions.
2013-08-30 Teresa Johnson <tejohnson@google.com>
Steven Bosscher <steven@gcc.gnu.org>

View file

@ -371,6 +371,8 @@ static void
ipa_set_jf_known_type (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset,
tree base_type, tree component_type)
{
gcc_assert (TREE_CODE (component_type) == RECORD_TYPE
&& TYPE_BINFO (component_type));
jfunc->type = IPA_JF_KNOWN_TYPE;
jfunc->value.known_type.offset = offset,
jfunc->value.known_type.base_type = base_type;
@ -633,13 +635,16 @@ check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
/* Like detect_type_change but with extra argument COMP_TYPE which will become
the component type part of new JFUNC of dynamic type change is detected and
the new base type is identified. */
/* Detect whether the dynamic type of ARG of COMP_TYPE has changed (before
callsite CALL) by looking for assignments to its virtual table pointer. If
it is, return true and fill in the jump function JFUNC with relevant type
information or set it to unknown. ARG is the object itself (not a pointer
to it, unless dereferenced). BASE is the base of the memory access as
returned by get_ref_base_and_extent, as is the offset. */
static bool
detect_type_change_1 (tree arg, tree base, tree comp_type, gimple call,
struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
detect_type_change (tree arg, tree base, tree comp_type, gimple call,
struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
{
struct type_change_info tci;
ao_ref ao;
@ -649,7 +654,12 @@ detect_type_change_1 (tree arg, tree base, tree comp_type, gimple call,
|| handled_component_p (arg));
/* Const calls cannot call virtual methods through VMT and so type changes do
not matter. */
if (!flag_devirtualize || !gimple_vuse (call))
if (!flag_devirtualize || !gimple_vuse (call)
/* Be sure expected_type is polymorphic. */
|| !comp_type
|| TREE_CODE (comp_type) != RECORD_TYPE
|| !TYPE_BINFO (comp_type)
|| !BINFO_VTABLE (TYPE_BINFO (comp_type)))
return false;
ao_ref_init (&ao, arg);
@ -679,40 +689,23 @@ detect_type_change_1 (tree arg, tree base, tree comp_type, gimple call,
return true;
}
/* Detect whether the dynamic type of ARG has changed (before callsite CALL) by
looking for assignments to its virtual table pointer. If it is, return true
and fill in the jump function JFUNC with relevant type information or set it
to unknown. ARG is the object itself (not a pointer to it, unless
dereferenced). BASE is the base of the memory access as returned by
get_ref_base_and_extent, as is the offset. */
static bool
detect_type_change (tree arg, tree base, gimple call,
struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
{
return detect_type_change_1 (arg, base, TREE_TYPE (arg), call, jfunc, offset);
}
/* Like detect_type_change but ARG is supposed to be a non-dereferenced pointer
SSA name (its dereference will become the base and the offset is assumed to
be zero). */
static bool
detect_type_change_ssa (tree arg, gimple call, struct ipa_jump_func *jfunc)
detect_type_change_ssa (tree arg, tree comp_type,
gimple call, struct ipa_jump_func *jfunc)
{
tree comp_type;
gcc_checking_assert (TREE_CODE (arg) == SSA_NAME);
if (!flag_devirtualize
|| !POINTER_TYPE_P (TREE_TYPE (arg))
|| TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != RECORD_TYPE)
|| !POINTER_TYPE_P (TREE_TYPE (arg)))
return false;
comp_type = TREE_TYPE (TREE_TYPE (arg));
arg = build2 (MEM_REF, ptr_type_node, arg,
build_int_cst (ptr_type_node, 0));
return detect_type_change_1 (arg, arg, comp_type, call, jfunc, 0);
return detect_type_change (arg, arg, comp_type, call, jfunc, 0);
}
/* Callback of walk_aliased_vdefs. Flags that it has been invoked to the
@ -988,7 +981,8 @@ static void
compute_complex_assign_jump_func (struct ipa_node_params *info,
struct param_analysis_info *parms_ainfo,
struct ipa_jump_func *jfunc,
gimple call, gimple stmt, tree name)
gimple call, gimple stmt, tree name,
tree param_type)
{
HOST_WIDE_INT offset, size, max_size;
tree op1, tc_ssa, base, ssa;
@ -1030,7 +1024,11 @@ compute_complex_assign_jump_func (struct ipa_node_params *info,
{
bool agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
call, tc_ssa);
bool type_p = !detect_type_change_ssa (tc_ssa, call, jfunc);
bool type_p = false;
if (param_type && POINTER_TYPE_P (param_type))
type_p = !detect_type_change_ssa (tc_ssa, TREE_TYPE (param_type),
call, jfunc);
if (type_p || jfunc->type == IPA_JF_UNKNOWN)
ipa_set_jf_simple_pass_through (jfunc, index, agg_p, type_p);
}
@ -1057,9 +1055,10 @@ compute_complex_assign_jump_func (struct ipa_node_params *info,
/* Dynamic types are changed in constructors and destructors. */
index = ipa_get_param_decl_index (info, SSA_NAME_VAR (ssa));
if (index >= 0)
if (index >= 0 && param_type && POINTER_TYPE_P (param_type))
{
bool type_p = !detect_type_change (op1, base, call, jfunc, offset);
bool type_p = !detect_type_change (op1, base, TREE_TYPE (param_type),
call, jfunc, offset);
if (type_p || jfunc->type == IPA_JF_UNKNOWN)
ipa_set_ancestor_jf (jfunc, offset, TREE_TYPE (op1), index,
parm_ref_data_pass_through_p (&parms_ainfo[index],
@ -1137,7 +1136,7 @@ static void
compute_complex_ancestor_jump_func (struct ipa_node_params *info,
struct param_analysis_info *parms_ainfo,
struct ipa_jump_func *jfunc,
gimple call, gimple phi)
gimple call, gimple phi, tree param_type)
{
HOST_WIDE_INT offset;
gimple assign, cond;
@ -1188,7 +1187,10 @@ compute_complex_ancestor_jump_func (struct ipa_node_params *info,
return;
}
bool type_p = !detect_type_change (obj, expr, call, jfunc, offset);
bool type_p = false;
if (param_type && POINTER_TYPE_P (param_type))
type_p = !detect_type_change (obj, expr, TREE_TYPE (param_type),
call, jfunc, offset);
if (type_p || jfunc->type == IPA_JF_UNKNOWN)
ipa_set_ancestor_jf (jfunc, offset, TREE_TYPE (obj), index,
parm_ref_data_pass_through_p (&parms_ainfo[index],
@ -1197,18 +1199,24 @@ compute_complex_ancestor_jump_func (struct ipa_node_params *info,
/* Given OP which is passed as an actual argument to a called function,
determine if it is possible to construct a KNOWN_TYPE jump function for it
and if so, create one and store it to JFUNC. */
and if so, create one and store it to JFUNC.
EXPECTED_TYPE represents a type the argument should be in */
static void
compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc,
gimple call)
gimple call, tree expected_type)
{
HOST_WIDE_INT offset, size, max_size;
tree base;
if (!flag_devirtualize
|| TREE_CODE (op) != ADDR_EXPR
|| TREE_CODE (TREE_TYPE (TREE_TYPE (op))) != RECORD_TYPE)
|| TREE_CODE (TREE_TYPE (TREE_TYPE (op))) != RECORD_TYPE
/* Be sure expected_type is polymorphic. */
|| !expected_type
|| TREE_CODE (expected_type) != RECORD_TYPE
|| !TYPE_BINFO (expected_type)
|| !BINFO_VTABLE (TYPE_BINFO (expected_type)))
return;
op = TREE_OPERAND (op, 0);
@ -1220,11 +1228,11 @@ compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc,
|| is_global_var (base))
return;
if (!TYPE_BINFO (TREE_TYPE (base))
|| detect_type_change (op, base, call, jfunc, offset))
if (detect_type_change (op, base, expected_type, call, jfunc, offset))
return;
ipa_set_jf_known_type (jfunc, offset, TREE_TYPE (base), TREE_TYPE (op));
ipa_set_jf_known_type (jfunc, offset, TREE_TYPE (base),
expected_type);
}
/* Inspect the given TYPE and return true iff it has the same structure (the
@ -1495,6 +1503,37 @@ determine_known_aggregate_parts (gimple call, tree arg,
}
}
static tree
ipa_get_callee_param_type (struct cgraph_edge *e, int i)
{
int n;
tree type = (e->callee
? TREE_TYPE (e->callee->symbol.decl)
: gimple_call_fntype (e->call_stmt));
tree t = TYPE_ARG_TYPES (type);
for (n = 0; n < i; n++)
{
if (!t)
break;
t = TREE_CHAIN (t);
}
if (t)
return TREE_VALUE (t);
if (!e->callee)
return NULL;
t = DECL_ARGUMENTS (e->callee->symbol.decl);
for (n = 0; n < i; n++)
{
if (!t)
return NULL;
t = TREE_CHAIN (t);
}
if (t)
return TREE_TYPE (t);
return NULL;
}
/* Compute jump function for all arguments of callsite CS and insert the
information in the jump_functions array in the ipa_edge_args corresponding
to this callsite. */
@ -1519,6 +1558,7 @@ ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_ainfo,
{
struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, n);
tree arg = gimple_call_arg (call, n);
tree param_type = ipa_get_callee_param_type (cs, n);
if (is_gimple_ip_invariant (arg))
ipa_set_jf_constant (jfunc, arg, cs);
@ -1547,9 +1587,14 @@ ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_ainfo,
bool agg_p, type_p;
agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
call, arg);
type_p = !detect_type_change_ssa (arg, call, jfunc);
if (param_type && POINTER_TYPE_P (param_type))
type_p = !detect_type_change_ssa (arg, TREE_TYPE (param_type),
call, jfunc);
else
type_p = false;
if (type_p || jfunc->type == IPA_JF_UNKNOWN)
ipa_set_jf_simple_pass_through (jfunc, index, agg_p, type_p);
ipa_set_jf_simple_pass_through (jfunc, index, agg_p,
type_p);
}
}
else
@ -1557,14 +1602,18 @@ ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_ainfo,
gimple stmt = SSA_NAME_DEF_STMT (arg);
if (is_gimple_assign (stmt))
compute_complex_assign_jump_func (info, parms_ainfo, jfunc,
call, stmt, arg);
call, stmt, arg, param_type);
else if (gimple_code (stmt) == GIMPLE_PHI)
compute_complex_ancestor_jump_func (info, parms_ainfo, jfunc,
call, stmt);
call, stmt, param_type);
}
}
else
compute_known_type_jump_func (arg, jfunc, call);
compute_known_type_jump_func (arg, jfunc, call,
param_type
&& POINTER_TYPE_P (param_type)
? TREE_TYPE (param_type)
: NULL);
if ((jfunc->type != IPA_JF_PASS_THROUGH
|| !ipa_get_jf_pass_through_agg_preserved (jfunc))
@ -1908,7 +1957,8 @@ ipa_analyze_virtual_call_uses (struct cgraph_node *node,
anc_offset = 0;
index = ipa_get_param_decl_index (info, SSA_NAME_VAR (obj));
gcc_assert (index >= 0);
if (detect_type_change_ssa (obj, call, &jfunc))
if (detect_type_change_ssa (obj, obj_type_ref_class (target),
call, &jfunc))
return;
}
else
@ -1922,7 +1972,8 @@ ipa_analyze_virtual_call_uses (struct cgraph_node *node,
index = ipa_get_param_decl_index (info,
SSA_NAME_VAR (TREE_OPERAND (expr, 0)));
gcc_assert (index >= 0);
if (detect_type_change (obj, expr, call, &jfunc, anc_offset))
if (detect_type_change (obj, expr, obj_type_ref_class (target),
call, &jfunc, anc_offset))
return;
}
@ -2134,7 +2185,7 @@ ipa_intraprocedural_devirtualization (gimple call)
jfunc.type = IPA_JF_UNKNOWN;
compute_known_type_jump_func (OBJ_TYPE_REF_OBJECT (otr), &jfunc,
call);
call, obj_type_ref_class (otr));
if (jfunc.type != IPA_JF_KNOWN_TYPE)
return NULL_TREE;
binfo = ipa_binfo_from_known_type_jfunc (&jfunc);