re PR ipa/59831 (ice in cgraph_speculative_call_info with -O3)
PR ipa/59831 * g++.dg/ipa/devirt-24.C: New testcase. * ipa-cp.c (ipa_get_indirect_edge_target_1): Give up on -fno-devirtualize; Try to devirtualize by the knowledge of virtual table pointer given by aggregate propagation. * ipa-prop.c (try_make_edge_direct_virtual_call): Likewise. ipa_print_node_jump_functions): Dump also offset that is relevant for polymorphic calls. (determine_known_aggregate_parts): Add arg_type parameter; use it instead of determining the type from pointer type. (ipa_compute_jump_functions_for_edge): Update call of determine_known_aggregate_parts. * gimple-fold.c (gimple_get_virt_method_for_vtable): Break out from ... (gimple_get_virt_method_for_binfo): ... here; simplify using vtable_pointer_value_to_vtable. * gimple-fold.h (gimple_get_virt_method_for_vtable): Declare. * ipa-devirt.c (subbinfo_with_vtable_at_offset): Turn OFFSET parameter to unsigned HOST_WIDE_INT; Use vtable_pointer_value_to_vtable. (vtable_pointer_value_to_vtable): Break out from ...; handle also POINTER_PLUS_EXPR. (vtable_pointer_value_to_binfo): ... here. * ipa-utils.h (vtable_pointer_value_to_vtable): Declare. From-SVN: r207439
This commit is contained in:
parent
bddc974e71
commit
85942f45e9
|
@ -1,3 +1,27 @@
|
||||||
|
2014-02-03 Jan Hubicka <hubicka@ucw.cz>
|
||||||
|
|
||||||
|
PR ipa/59831
|
||||||
|
* ipa-cp.c (ipa_get_indirect_edge_target_1): Give up on -fno-devirtualize;
|
||||||
|
Try to devirtualize by the knowledge of virtual table pointer given by
|
||||||
|
aggregate propagation.
|
||||||
|
* ipa-prop.c (try_make_edge_direct_virtual_call): Likewise.
|
||||||
|
ipa_print_node_jump_functions): Dump also offset that
|
||||||
|
is relevant for polymorphic calls.
|
||||||
|
(determine_known_aggregate_parts): Add arg_type parameter; use it
|
||||||
|
instead of determining the type from pointer type.
|
||||||
|
(ipa_compute_jump_functions_for_edge): Update call of
|
||||||
|
determine_known_aggregate_parts.
|
||||||
|
* gimple-fold.c (gimple_get_virt_method_for_vtable): Break out from ...
|
||||||
|
(gimple_get_virt_method_for_binfo): ... here; simplify using
|
||||||
|
vtable_pointer_value_to_vtable.
|
||||||
|
* gimple-fold.h (gimple_get_virt_method_for_vtable): Declare.
|
||||||
|
* ipa-devirt.c (subbinfo_with_vtable_at_offset): Turn OFFSET parameter
|
||||||
|
to unsigned HOST_WIDE_INT; Use vtable_pointer_value_to_vtable.
|
||||||
|
(vtable_pointer_value_to_vtable): Break out from ...; handle also
|
||||||
|
POINTER_PLUS_EXPR.
|
||||||
|
(vtable_pointer_value_to_binfo): ... here.
|
||||||
|
* ipa-utils.h (vtable_pointer_value_to_vtable): Declare.
|
||||||
|
|
||||||
2014-02-03 Teresa Johnson <tejohnson@google.com>
|
2014-02-03 Teresa Johnson <tejohnson@google.com>
|
||||||
|
|
||||||
* tree-vect-slp.c (vect_supported_load_permutation_p): Avoid
|
* tree-vect-slp.c (vect_supported_load_permutation_p): Avoid
|
||||||
|
|
|
@ -3236,33 +3236,16 @@ fold_const_aggregate_ref (tree t)
|
||||||
return fold_const_aggregate_ref_1 (t, NULL);
|
return fold_const_aggregate_ref_1 (t, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a declaration of a function which an OBJ_TYPE_REF references. TOKEN
|
/* Lookup virtual method with index TOKEN in a virtual table V
|
||||||
is integer form of OBJ_TYPE_REF_TOKEN of the reference expression.
|
at OFFSET. */
|
||||||
KNOWN_BINFO carries the binfo describing the true type of
|
|
||||||
OBJ_TYPE_REF_OBJECT(REF). */
|
|
||||||
|
|
||||||
tree
|
tree
|
||||||
gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo)
|
gimple_get_virt_method_for_vtable (HOST_WIDE_INT token,
|
||||||
|
tree v,
|
||||||
|
unsigned HOST_WIDE_INT offset)
|
||||||
{
|
{
|
||||||
unsigned HOST_WIDE_INT offset, size;
|
tree vtable = v, init, fn;
|
||||||
tree v, fn, vtable, init;
|
unsigned HOST_WIDE_INT size;
|
||||||
|
|
||||||
vtable = v = BINFO_VTABLE (known_binfo);
|
|
||||||
/* If there is no virtual methods table, leave the OBJ_TYPE_REF alone. */
|
|
||||||
if (!v)
|
|
||||||
return NULL_TREE;
|
|
||||||
|
|
||||||
if (TREE_CODE (v) == POINTER_PLUS_EXPR)
|
|
||||||
{
|
|
||||||
offset = tree_to_uhwi (TREE_OPERAND (v, 1)) * BITS_PER_UNIT;
|
|
||||||
v = TREE_OPERAND (v, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
offset = 0;
|
|
||||||
|
|
||||||
if (TREE_CODE (v) != ADDR_EXPR)
|
|
||||||
return NULL_TREE;
|
|
||||||
v = TREE_OPERAND (v, 0);
|
|
||||||
|
|
||||||
if (TREE_CODE (v) != VAR_DECL
|
if (TREE_CODE (v) != VAR_DECL
|
||||||
|| !DECL_VIRTUAL_P (v))
|
|| !DECL_VIRTUAL_P (v))
|
||||||
|
@ -3281,6 +3264,7 @@ gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo)
|
||||||
}
|
}
|
||||||
gcc_checking_assert (TREE_CODE (TREE_TYPE (v)) == ARRAY_TYPE);
|
gcc_checking_assert (TREE_CODE (TREE_TYPE (v)) == ARRAY_TYPE);
|
||||||
size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (TREE_TYPE (v))));
|
size = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (TREE_TYPE (v))));
|
||||||
|
offset *= BITS_PER_UNIT;
|
||||||
offset += token * size;
|
offset += token * size;
|
||||||
fn = fold_ctor_reference (TREE_TYPE (TREE_TYPE (v)), init,
|
fn = fold_ctor_reference (TREE_TYPE (TREE_TYPE (v)), init,
|
||||||
offset, size, v);
|
offset, size, v);
|
||||||
|
@ -3306,6 +3290,28 @@ gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo)
|
||||||
return fn;
|
return fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return a declaration of a function which an OBJ_TYPE_REF references. TOKEN
|
||||||
|
is integer form of OBJ_TYPE_REF_TOKEN of the reference expression.
|
||||||
|
KNOWN_BINFO carries the binfo describing the true type of
|
||||||
|
OBJ_TYPE_REF_OBJECT(REF). */
|
||||||
|
|
||||||
|
tree
|
||||||
|
gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo)
|
||||||
|
{
|
||||||
|
unsigned HOST_WIDE_INT offset;
|
||||||
|
tree v;
|
||||||
|
|
||||||
|
v = BINFO_VTABLE (known_binfo);
|
||||||
|
/* If there is no virtual methods table, leave the OBJ_TYPE_REF alone. */
|
||||||
|
if (!v)
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
|
if (!vtable_pointer_value_to_vtable (v, &v, &offset))
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
|
return gimple_get_virt_method_for_vtable (token, v, offset);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return true iff VAL is a gimple expression that is known to be
|
/* Return true iff VAL is a gimple expression that is known to be
|
||||||
non-negative. Restricted to floating-point inputs. */
|
non-negative. Restricted to floating-point inputs. */
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,8 @@ extern tree gimple_fold_stmt_to_constant (gimple, tree (*) (tree));
|
||||||
extern tree fold_const_aggregate_ref_1 (tree, tree (*) (tree));
|
extern tree fold_const_aggregate_ref_1 (tree, tree (*) (tree));
|
||||||
extern tree fold_const_aggregate_ref (tree);
|
extern tree fold_const_aggregate_ref (tree);
|
||||||
extern tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree);
|
extern tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree);
|
||||||
|
extern tree gimple_get_virt_method_for_vtable (HOST_WIDE_INT, tree,
|
||||||
|
unsigned HOST_WIDE_INT);
|
||||||
extern bool gimple_val_nonnegative_real_p (tree);
|
extern bool gimple_val_nonnegative_real_p (tree);
|
||||||
extern tree gimple_fold_indirect_ref (tree);
|
extern tree gimple_fold_indirect_ref (tree);
|
||||||
extern bool arith_code_with_undefined_signed_overflow (tree_code);
|
extern bool arith_code_with_undefined_signed_overflow (tree_code);
|
||||||
|
|
43
gcc/ipa-cp.c
43
gcc/ipa-cp.c
|
@ -1479,7 +1479,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
|
||||||
HOST_WIDE_INT token, anc_offset;
|
HOST_WIDE_INT token, anc_offset;
|
||||||
tree otr_type;
|
tree otr_type;
|
||||||
tree t;
|
tree t;
|
||||||
tree target;
|
tree target = NULL;
|
||||||
|
|
||||||
if (param_index == -1
|
if (param_index == -1
|
||||||
|| known_vals.length () <= (unsigned int) param_index)
|
|| known_vals.length () <= (unsigned int) param_index)
|
||||||
|
@ -1527,14 +1527,53 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
|
||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!flag_devirtualize)
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
gcc_assert (!ie->indirect_info->agg_contents);
|
gcc_assert (!ie->indirect_info->agg_contents);
|
||||||
token = ie->indirect_info->otr_token;
|
token = ie->indirect_info->otr_token;
|
||||||
anc_offset = ie->indirect_info->offset;
|
anc_offset = ie->indirect_info->offset;
|
||||||
otr_type = ie->indirect_info->otr_type;
|
otr_type = ie->indirect_info->otr_type;
|
||||||
|
|
||||||
t = known_vals[param_index];
|
t = NULL;
|
||||||
|
|
||||||
|
/* Try to work out value of virtual table pointer value in replacemnets. */
|
||||||
|
if (!t && agg_reps && !ie->indirect_info->by_ref)
|
||||||
|
{
|
||||||
|
while (agg_reps)
|
||||||
|
{
|
||||||
|
if (agg_reps->index == param_index
|
||||||
|
&& agg_reps->offset == ie->indirect_info->offset
|
||||||
|
&& agg_reps->by_ref)
|
||||||
|
{
|
||||||
|
t = agg_reps->value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
agg_reps = agg_reps->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to work out value of virtual table pointer value in known
|
||||||
|
aggregate values. */
|
||||||
|
if (!t && known_aggs.length () > (unsigned int) param_index
|
||||||
|
&& !ie->indirect_info->by_ref)
|
||||||
|
{
|
||||||
|
struct ipa_agg_jump_function *agg;
|
||||||
|
agg = known_aggs[param_index];
|
||||||
|
t = ipa_find_agg_cst_for_param (agg, ie->indirect_info->offset,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we found the virtual table pointer, lookup the binfo. */
|
||||||
|
if (t)
|
||||||
|
t = vtable_pointer_value_to_binfo (t);
|
||||||
|
|
||||||
|
/* Did we work out BINFO via type propagation? */
|
||||||
if (!t && known_binfos.length () > (unsigned int) param_index)
|
if (!t && known_binfos.length () > (unsigned int) param_index)
|
||||||
t = known_binfos[param_index];
|
t = known_binfos[param_index];
|
||||||
|
/* Or do we know the constant value of pointer? */
|
||||||
|
if (!t)
|
||||||
|
t = known_vals[param_index];
|
||||||
if (!t)
|
if (!t)
|
||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
|
|
||||||
|
|
|
@ -975,17 +975,24 @@ contains_type_p (tree outer_type, HOST_WIDE_INT offset,
|
||||||
/* Lookup base of BINFO that has virtual table VTABLE with OFFSET. */
|
/* Lookup base of BINFO that has virtual table VTABLE with OFFSET. */
|
||||||
|
|
||||||
static tree
|
static tree
|
||||||
subbinfo_with_vtable_at_offset (tree binfo, tree offset, tree vtable)
|
subbinfo_with_vtable_at_offset (tree binfo, unsigned HOST_WIDE_INT offset,
|
||||||
|
tree vtable)
|
||||||
{
|
{
|
||||||
tree v = BINFO_VTABLE (binfo);
|
tree v = BINFO_VTABLE (binfo);
|
||||||
int i;
|
int i;
|
||||||
tree base_binfo;
|
tree base_binfo;
|
||||||
|
unsigned HOST_WIDE_INT this_offset;
|
||||||
|
|
||||||
gcc_assert (!v || TREE_CODE (v) == POINTER_PLUS_EXPR);
|
if (v)
|
||||||
|
{
|
||||||
|
if (!vtable_pointer_value_to_vtable (v, &v, &this_offset))
|
||||||
|
gcc_unreachable ();
|
||||||
|
|
||||||
|
if (offset == this_offset
|
||||||
|
&& DECL_ASSEMBLER_NAME (v) == DECL_ASSEMBLER_NAME (vtable))
|
||||||
|
return binfo;
|
||||||
|
}
|
||||||
|
|
||||||
if (v && tree_int_cst_equal (TREE_OPERAND (v, 1), offset)
|
|
||||||
&& TREE_OPERAND (TREE_OPERAND (v, 0), 0) == vtable)
|
|
||||||
return binfo;
|
|
||||||
for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
|
for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
|
||||||
if (polymorphic_type_binfo_p (base_binfo))
|
if (polymorphic_type_binfo_p (base_binfo))
|
||||||
{
|
{
|
||||||
|
@ -996,11 +1003,12 @@ subbinfo_with_vtable_at_offset (tree binfo, tree offset, tree vtable)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* T is known constant value of virtual table pointer. Return BINFO of the
|
/* T is known constant value of virtual table pointer.
|
||||||
instance type. */
|
Store virtual table to V and its offset to OFFSET.
|
||||||
|
Return false if T does not look like virtual table reference. */
|
||||||
|
|
||||||
tree
|
bool
|
||||||
vtable_pointer_value_to_binfo (tree t)
|
vtable_pointer_value_to_vtable (tree t, tree *v, unsigned HOST_WIDE_INT *offset)
|
||||||
{
|
{
|
||||||
/* We expect &MEM[(void *)&virtual_table + 16B].
|
/* We expect &MEM[(void *)&virtual_table + 16B].
|
||||||
We obtain object's BINFO from the context of the virtual table.
|
We obtain object's BINFO from the context of the virtual table.
|
||||||
|
@ -1011,7 +1019,7 @@ vtable_pointer_value_to_binfo (tree t)
|
||||||
In the case of virtual inheritance, the virtual tables may
|
In the case of virtual inheritance, the virtual tables may
|
||||||
be nested, i.e. the offset may be different from 16 and we may
|
be nested, i.e. the offset may be different from 16 and we may
|
||||||
need to dive into the type representation. */
|
need to dive into the type representation. */
|
||||||
if (t && TREE_CODE (t) == ADDR_EXPR
|
if (TREE_CODE (t) == ADDR_EXPR
|
||||||
&& TREE_CODE (TREE_OPERAND (t, 0)) == MEM_REF
|
&& TREE_CODE (TREE_OPERAND (t, 0)) == MEM_REF
|
||||||
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 0)) == ADDR_EXPR
|
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 0)) == ADDR_EXPR
|
||||||
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 1)) == INTEGER_CST
|
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 1)) == INTEGER_CST
|
||||||
|
@ -1020,20 +1028,47 @@ vtable_pointer_value_to_binfo (tree t)
|
||||||
&& DECL_VIRTUAL_P (TREE_OPERAND (TREE_OPERAND
|
&& DECL_VIRTUAL_P (TREE_OPERAND (TREE_OPERAND
|
||||||
(TREE_OPERAND (t, 0), 0), 0)))
|
(TREE_OPERAND (t, 0), 0), 0)))
|
||||||
{
|
{
|
||||||
tree vtable = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (t, 0), 0), 0);
|
*v = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (t, 0), 0), 0);
|
||||||
tree offset = TREE_OPERAND (TREE_OPERAND (t, 0), 1);
|
*offset = tree_to_uhwi (TREE_OPERAND (TREE_OPERAND (t, 0), 1));
|
||||||
tree binfo = TYPE_BINFO (DECL_CONTEXT (vtable));
|
return true;
|
||||||
|
|
||||||
binfo = subbinfo_with_vtable_at_offset (binfo, offset, vtable);
|
|
||||||
|
|
||||||
/* FIXME: for stores of construction vtables we return NULL,
|
|
||||||
because we do not have BINFO for those. Eventually we should fix
|
|
||||||
our representation to allow this case to be handled, too.
|
|
||||||
In the case we see store of BINFO we however may assume
|
|
||||||
that standard folding will be ale to cope with it. */
|
|
||||||
return binfo;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
|
/* Alternative representation, used by C++ frontend is POINTER_PLUS_EXPR.
|
||||||
|
We need to handle it when T comes from static variable initializer or
|
||||||
|
BINFO. */
|
||||||
|
if (TREE_CODE (t) == POINTER_PLUS_EXPR)
|
||||||
|
{
|
||||||
|
*offset = tree_to_uhwi (TREE_OPERAND (t, 1));
|
||||||
|
t = TREE_OPERAND (t, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*offset = 0;
|
||||||
|
|
||||||
|
if (TREE_CODE (t) != ADDR_EXPR)
|
||||||
|
return false;
|
||||||
|
*v = TREE_OPERAND (t, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* T is known constant value of virtual table pointer. Return BINFO of the
|
||||||
|
instance type. */
|
||||||
|
|
||||||
|
tree
|
||||||
|
vtable_pointer_value_to_binfo (tree t)
|
||||||
|
{
|
||||||
|
tree vtable;
|
||||||
|
unsigned HOST_WIDE_INT offset;
|
||||||
|
|
||||||
|
if (!vtable_pointer_value_to_vtable (t, &vtable, &offset))
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
|
/* FIXME: for stores of construction vtables we return NULL,
|
||||||
|
because we do not have BINFO for those. Eventually we should fix
|
||||||
|
our representation to allow this case to be handled, too.
|
||||||
|
In the case we see store of BINFO we however may assume
|
||||||
|
that standard folding will be ale to cope with it. */
|
||||||
|
return subbinfo_with_vtable_at_offset (TYPE_BINFO (DECL_CONTEXT (vtable)),
|
||||||
|
offset, vtable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Given REF call in FNDECL, determine class of the polymorphic
|
/* Given REF call in FNDECL, determine class of the polymorphic
|
||||||
|
|
|
@ -355,8 +355,10 @@ ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
|
||||||
ii->param_index, ii->offset,
|
ii->param_index, ii->offset,
|
||||||
ii->by_ref ? "by reference" : "by_value");
|
ii->by_ref ? "by reference" : "by_value");
|
||||||
else
|
else
|
||||||
fprintf (f, " indirect %s callsite, calling param %i",
|
fprintf (f, " indirect %s callsite, calling param %i, "
|
||||||
ii->polymorphic ? "polymorphic" : "simple", ii->param_index);
|
"offset " HOST_WIDE_INT_PRINT_DEC,
|
||||||
|
ii->polymorphic ? "polymorphic" : "simple", ii->param_index,
|
||||||
|
ii->offset);
|
||||||
|
|
||||||
if (cs->call_stmt)
|
if (cs->call_stmt)
|
||||||
{
|
{
|
||||||
|
@ -1332,11 +1334,11 @@ struct ipa_known_agg_contents_list
|
||||||
|
|
||||||
/* Traverse statements from CALL backwards, scanning whether an aggregate given
|
/* Traverse statements from CALL backwards, scanning whether an aggregate given
|
||||||
in ARG is filled in with constant values. ARG can either be an aggregate
|
in ARG is filled in with constant values. ARG can either be an aggregate
|
||||||
expression or a pointer to an aggregate. JFUNC is the jump function into
|
expression or a pointer to an aggregate. ARG_TYPE is the type of the aggregate.
|
||||||
which the constants are subsequently stored. */
|
JFUNC is the jump function into which the constants are subsequently stored. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
determine_known_aggregate_parts (gimple call, tree arg,
|
determine_known_aggregate_parts (gimple call, tree arg, tree arg_type,
|
||||||
struct ipa_jump_func *jfunc)
|
struct ipa_jump_func *jfunc)
|
||||||
{
|
{
|
||||||
struct ipa_known_agg_contents_list *list = NULL;
|
struct ipa_known_agg_contents_list *list = NULL;
|
||||||
|
@ -1351,18 +1353,18 @@ determine_known_aggregate_parts (gimple call, tree arg,
|
||||||
arg_base and arg_offset based on what is actually passed as an actual
|
arg_base and arg_offset based on what is actually passed as an actual
|
||||||
argument. */
|
argument. */
|
||||||
|
|
||||||
if (POINTER_TYPE_P (TREE_TYPE (arg)))
|
if (POINTER_TYPE_P (arg_type))
|
||||||
{
|
{
|
||||||
by_ref = true;
|
by_ref = true;
|
||||||
if (TREE_CODE (arg) == SSA_NAME)
|
if (TREE_CODE (arg) == SSA_NAME)
|
||||||
{
|
{
|
||||||
tree type_size;
|
tree type_size;
|
||||||
if (!tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (TREE_TYPE (arg)))))
|
if (!tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (arg_type))))
|
||||||
return;
|
return;
|
||||||
check_ref = true;
|
check_ref = true;
|
||||||
arg_base = arg;
|
arg_base = arg;
|
||||||
arg_offset = 0;
|
arg_offset = 0;
|
||||||
type_size = TYPE_SIZE (TREE_TYPE (TREE_TYPE (arg)));
|
type_size = TYPE_SIZE (TREE_TYPE (arg_type));
|
||||||
arg_size = tree_to_uhwi (type_size);
|
arg_size = tree_to_uhwi (type_size);
|
||||||
ao_ref_init_from_ptr_and_size (&r, arg_base, NULL_TREE);
|
ao_ref_init_from_ptr_and_size (&r, arg_base, NULL_TREE);
|
||||||
}
|
}
|
||||||
|
@ -1645,13 +1647,22 @@ ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_ainfo,
|
||||||
? TREE_TYPE (param_type)
|
? TREE_TYPE (param_type)
|
||||||
: NULL);
|
: NULL);
|
||||||
|
|
||||||
|
/* If ARG is pointer, we can not use its type to determine the type of aggregate
|
||||||
|
passed (because type conversions are ignored in gimple). Usually we can
|
||||||
|
safely get type from function declaration, but in case of K&R prototypes or
|
||||||
|
variadic functions we can try our luck with type of the pointer passed.
|
||||||
|
TODO: Since we look for actual initialization of the memory object, we may better
|
||||||
|
work out the type based on the memory stores we find. */
|
||||||
|
if (!param_type)
|
||||||
|
param_type = TREE_TYPE (arg);
|
||||||
|
|
||||||
if ((jfunc->type != IPA_JF_PASS_THROUGH
|
if ((jfunc->type != IPA_JF_PASS_THROUGH
|
||||||
|| !ipa_get_jf_pass_through_agg_preserved (jfunc))
|
|| !ipa_get_jf_pass_through_agg_preserved (jfunc))
|
||||||
&& (jfunc->type != IPA_JF_ANCESTOR
|
&& (jfunc->type != IPA_JF_ANCESTOR
|
||||||
|| !ipa_get_jf_ancestor_agg_preserved (jfunc))
|
|| !ipa_get_jf_ancestor_agg_preserved (jfunc))
|
||||||
&& (AGGREGATE_TYPE_P (TREE_TYPE (arg))
|
&& (AGGREGATE_TYPE_P (TREE_TYPE (arg))
|
||||||
|| (POINTER_TYPE_P (TREE_TYPE (arg)))))
|
|| POINTER_TYPE_P (param_type)))
|
||||||
determine_known_aggregate_parts (call, arg, jfunc);
|
determine_known_aggregate_parts (call, arg, param_type, jfunc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2676,9 +2687,23 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
|
||||||
struct ipa_jump_func *jfunc,
|
struct ipa_jump_func *jfunc,
|
||||||
struct ipa_node_params *new_root_info)
|
struct ipa_node_params *new_root_info)
|
||||||
{
|
{
|
||||||
tree binfo, target;
|
tree binfo = NULL, target;
|
||||||
|
|
||||||
binfo = ipa_value_from_jfunc (new_root_info, jfunc);
|
if (!flag_devirtualize)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* First try to do lookup binfo via known virtual table pointer value. */
|
||||||
|
if (!ie->indirect_info->by_ref)
|
||||||
|
{
|
||||||
|
tree t = ipa_find_agg_cst_for_param (&jfunc->agg,
|
||||||
|
ie->indirect_info->offset,
|
||||||
|
true);
|
||||||
|
if (t)
|
||||||
|
binfo = vtable_pointer_value_to_binfo (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!binfo)
|
||||||
|
binfo = ipa_value_from_jfunc (new_root_info, jfunc);
|
||||||
|
|
||||||
if (!binfo)
|
if (!binfo)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2688,7 +2713,7 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
|
||||||
binfo = gimple_extract_devirt_binfo_from_cst
|
binfo = gimple_extract_devirt_binfo_from_cst
|
||||||
(binfo, ie->indirect_info->otr_type);
|
(binfo, ie->indirect_info->otr_type);
|
||||||
if (!binfo)
|
if (!binfo)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
|
binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
|
||||||
|
|
|
@ -88,6 +88,7 @@ tree get_polymorphic_call_info (tree, tree, tree *,
|
||||||
HOST_WIDE_INT *,
|
HOST_WIDE_INT *,
|
||||||
ipa_polymorphic_call_context *);
|
ipa_polymorphic_call_context *);
|
||||||
tree vtable_pointer_value_to_binfo (tree t);
|
tree vtable_pointer_value_to_binfo (tree t);
|
||||||
|
bool vtable_pointer_value_to_vtable (tree, tree *, unsigned HOST_WIDE_INT *);
|
||||||
|
|
||||||
/* Return vector containing possible targets of polymorphic call E.
|
/* Return vector containing possible targets of polymorphic call E.
|
||||||
If FINALP is non-NULL, store true if the list is complette.
|
If FINALP is non-NULL, store true if the list is complette.
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
2014-02-03 Jan Hubicka <hubicka@ucw.cz>
|
||||||
|
|
||||||
|
PR ipa/59831
|
||||||
|
* g++.dg/ipa/devirt-24.C: New testcase.
|
||||||
|
|
||||||
2014-02-03 Marc Glisse <marc.glisse@inria.fr>
|
2014-02-03 Marc Glisse <marc.glisse@inria.fr>
|
||||||
|
|
||||||
PR c++/53017
|
PR c++/53017
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O3 -fno-ipa-sra -fdump-ipa-inline -fdump-ipa-cp" } */
|
||||||
|
void pad(void);
|
||||||
|
class A {};
|
||||||
|
class B {
|
||||||
|
public:
|
||||||
|
A &operator[](int);
|
||||||
|
};
|
||||||
|
class C : B {
|
||||||
|
public:
|
||||||
|
virtual int m_fn1() { return 0; }
|
||||||
|
inline A &operator[](int p1) {
|
||||||
|
int a;
|
||||||
|
a = m_fn1();
|
||||||
|
static_cast<void>(__builtin_expect(a, 0) ?: 0);
|
||||||
|
return B::operator[](p1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int *e;
|
||||||
|
static void sort(C &p1, C &p2) {
|
||||||
|
for (int i=0;; i++) {
|
||||||
|
A c, d = p2[0];
|
||||||
|
pad();
|
||||||
|
pad();
|
||||||
|
pad();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int test ();
|
||||||
|
|
||||||
|
void update_sources() {
|
||||||
|
while (test()) {
|
||||||
|
C f;
|
||||||
|
C *b = new (C);
|
||||||
|
sort(f, *b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 1 "inline" } } */
|
||||||
|
/* { dg-final { cleanup-ipa-dump "inline" } } */
|
||||||
|
/* { dg-final { scan-ipa-dump-times "Aggregate passed by reference" 1 "cp" } } */
|
||||||
|
/* { dg-final { cleanup-ipa-dump "cp" } } */
|
Loading…
Reference in New Issue