This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Fix OBJ_TYPE_REF handling in ipa-cp
- From: Jan Hubicka <hubicka at ucw dot cz>
- To: gcc-patches at gcc dot gnu dot org, mjambor at suse dot cz
- Date: Thu, 22 Aug 2013 17:33:50 +0200
- Subject: Fix OBJ_TYPE_REF handling in ipa-cp
Hi,
this problem was noticed by my verifier that binfo walks are not across type
hiearchy. ipa_intraprocedural_devirtualization is one remaining place where we
take class of object from OBJ_TYPE_REF_OBJECT instead of
obj_type_ref_class_type.
Unforutnately I noticed that this problem is propagated quite further across ipa-prop
design. We assume that types of pointers taken from gimple call arguments
are types of pointers to classes pass down to the callee. This is not true
after propagation.
I did not fix the all places, only places needed to get parameter for
ipa_set_jf_known_type and detect_type_change_ssa right. Also I modified
ipa_set_jf_known_type to not record non-polymorphic type. It is a waste
of memory and LTO streaming bandwidth.
Bootstrapped/regtesed x86_64-linux. Martin, please can you review the change?
* ipa-prop.c (ipa_set_jf_known_type): Check that component type
is a record type with BINFO.
(detect_type_change_ssa): Add comp_type argument.
(compute_complex_assign_jump_func): Add param_type argument; pass
it down to detect_type_change_ssa.
(compute_known_type_jump_func): Add expected_type parameter.
Do not bother tracking a non-polymorphic type.
(ipa_get_callee_param_type): New function.
(ipa_compute_jump_functions_for_edge): Pass down calle parm types.
(ipa_analyze_virtual_call_uses): Use class typee as argument
of detect_type_change_1.
(ipa_intraprocedural_devirtualization): Pass down class type.
Index: ipa-prop.c
===================================================================
--- ipa-prop.c (revision 201919)
+++ ipa-prop.c (working copy)
@@ -367,6 +367,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;
@@ -674,20 +676,18 @@ detect_type_change (tree arg, tree base,
/* 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). */
+ be zero). COMP_TYPE is type of object being tracked. */
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)
return false;
- comp_type = TREE_TYPE (TREE_TYPE (arg));
arg = build2 (MEM_REF, ptr_type_node, arg,
build_int_cst (ptr_type_node, 0));
@@ -961,13 +961,16 @@ ipa_load_from_parm_agg (struct ipa_node_
INFO is the structure describing individual parameters access different
stages of IPA optimizations. PARMS_AINFO contains the information that is
- only needed for intraprocedural analysis. */
+ only needed for intraprocedural analysis.
+
+ PARAM_TYPE is type of the parameter, NULL if not available. */
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;
@@ -1006,7 +1009,10 @@ compute_complex_assign_jump_func (struct
gimple_assign_rhs_code (stmt));
}
else if (gimple_assign_single_p (stmt)
- && !detect_type_change_ssa (tc_ssa, call, jfunc))
+ && param_type
+ && !detect_type_change_ssa (tc_ssa,
+ TREE_TYPE (param_type),
+ call, jfunc))
{
bool agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
call, tc_ssa);
@@ -1171,18 +1177,25 @@ compute_complex_ancestor_jump_func (stru
/* 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
+ /* Do not bother to track types that are not polymorphic.
+ We use type knowledge only for devirtualization. */
+ || !expected_type
+ || TREE_CODE (expected_type) != RECORD_TYPE
+ || !TYPE_BINFO (expected_type)
+ || !BINFO_VTABLE (TYPE_BINFO (expected_type)))
return;
op = TREE_OPERAND (op, 0);
@@ -1194,11 +1207,11 @@ compute_known_type_jump_func (tree op, s
|| is_global_var (base))
return;
- if (!TYPE_BINFO (TREE_TYPE (base))
- || detect_type_change (op, base, call, jfunc, offset))
+ if (detect_type_change_1 (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
@@ -1469,6 +1482,42 @@ determine_known_aggregate_parts (gimple
}
}
+/* Return type of I-th parameter of callee of E. This may differ from
+ type of I-th argument of call operand of E->call_stmt because
+ pointer conversions are considered useless. For devirtualization
+ we really need the type of object being passed. */
+
+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. */
@@ -1493,6 +1542,7 @@ ipa_compute_jump_functions_for_edge (str
{
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);
@@ -1517,7 +1567,8 @@ ipa_compute_jump_functions_for_edge (str
{
int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg));
if (index >= 0
- && !detect_type_change_ssa (arg, call, jfunc))
+ && !detect_type_change_ssa (arg, TREE_TYPE (TREE_TYPE (arg)),
+ call, jfunc))
{
bool agg_p;
agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
@@ -1530,14 +1581,17 @@ ipa_compute_jump_functions_for_edge (str
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);
}
}
else
- compute_known_type_jump_func (arg, jfunc, call);
+ compute_known_type_jump_func (arg, jfunc, call,
+ param_type
+ ? TREE_TYPE (param_type)
+ : NULL);
if ((jfunc->type != IPA_JF_PASS_THROUGH
|| !ipa_get_jf_pass_through_agg_preserved (jfunc))
@@ -1881,7 +1935,8 @@ ipa_analyze_virtual_call_uses (struct cg
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
@@ -1895,7 +1950,8 @@ ipa_analyze_virtual_call_uses (struct cg
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_1 (obj, expr, obj_type_ref_class (target),
+ call, &jfunc, anc_offset))
return;
}
@@ -2107,7 +2163,7 @@ ipa_intraprocedural_devirtualization (gi
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);