ipa-utils.h (ipa_polymorphic_call_context): Turn into class; add ctors.

* ipa-utils.h (ipa_polymorphic_call_context): Turn into class; add ctors.
	(possible_polymorphic_call_targets, dump_possible_polymorphic_call_targets,
	possible_polymorphic_call_target_p, possible_polymorphic_call_target_p): Simplify.
	(get_dynamic_type): Remove.
	* ipa-devirt.c (ipa_dummy_polymorphic_call_context): Remove.
	(clear_speculation): Bring to ipa-deivrt.h
	(get_class_context): Rename to ...
	(ipa_polymorphic_call_context::restrict_to_inner_class): ... this one.
	(contains_type_p): Update.
	(get_dynamic_type): Rename to ...
	ipa_polymorphic_call_context::get_dynamic_type(): ... this one.
	(possible_polymorphic_call_targets): UPdate.
	* tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): Update.
	* ipa-prop.c (ipa_analyze_call_uses): Update.

From-SVN: r215418
This commit is contained in:
Jan Hubicka 2014-09-20 08:22:58 +02:00 committed by Jan Hubicka
parent 8e1ba78f1b
commit 6f8091fc3e
8 changed files with 222 additions and 190 deletions

View File

@ -1,3 +1,20 @@
2014-09-19 Jan Hubicka <hubicka@ucw.cz>
* ipa-utils.h (ipa_polymorphic_call_context): Turn into class; add ctors.
(possible_polymorphic_call_targets, dump_possible_polymorphic_call_targets,
possible_polymorphic_call_target_p, possible_polymorphic_call_target_p): Simplify.
(get_dynamic_type): Remove.
* ipa-devirt.c (ipa_dummy_polymorphic_call_context): Remove.
(clear_speculation): Bring to ipa-deivrt.h
(get_class_context): Rename to ...
(ipa_polymorphic_call_context::restrict_to_inner_class): ... this one.
(contains_type_p): Update.
(get_dynamic_type): Rename to ...
ipa_polymorphic_call_context::get_dynamic_type(): ... this one.
(possible_polymorphic_call_targets): UPdate.
* tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): Update.
* ipa-prop.c (ipa_analyze_call_uses): Update.
2014-09-19 Jan Hubicka <hubicka@ucw.cz>
* ipa-visibility.c (varpool_node::externally_visible_p): Do not

View File

@ -884,21 +884,15 @@ cgraph_node::create_indirect_edge (gimple call_stmt, int ecf_flags,
&& (target = gimple_call_fn (call_stmt))
&& virtual_method_call_p (target))
{
tree otr_type;
HOST_WIDE_INT otr_token;
ipa_polymorphic_call_context context;
get_polymorphic_call_info (decl,
target,
&otr_type, &otr_token,
&context, call_stmt);
ipa_polymorphic_call_context context (decl, target, call_stmt);
/* Only record types can have virtual calls. */
gcc_assert (TREE_CODE (otr_type) == RECORD_TYPE);
edge->indirect_info->polymorphic = true;
edge->indirect_info->param_index = -1;
edge->indirect_info->otr_token = otr_token;
edge->indirect_info->otr_type = otr_type;
edge->indirect_info->otr_token
= tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
edge->indirect_info->otr_type = obj_type_ref_class (target);
gcc_assert (TREE_CODE (edge->indirect_info->otr_type) == RECORD_TYPE);
edge->indirect_info->outer_type = context.outer_type;
edge->indirect_info->speculative_outer_type
= context.speculative_outer_type;

View File

@ -2563,8 +2563,8 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
{
if (dump_file && virtual_method_call_p (callee)
&& !possible_polymorphic_call_target_p
(callee, cgraph_node::get (gimple_call_addr_fndecl
(OBJ_TYPE_REF_EXPR (callee)))))
(callee, stmt, cgraph_node::get (gimple_call_addr_fndecl
(OBJ_TYPE_REF_EXPR (callee)))))
{
fprintf (dump_file,
"Type inheritance inconsistent devirtualization of ");

View File

@ -1618,14 +1618,11 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
if (TREE_CODE (t) != TREE_BINFO)
{
ipa_polymorphic_call_context context;
ipa_polymorphic_call_context context (t, ie->indirect_info->otr_type,
anc_offset);
vec <cgraph_node *>targets;
bool final;
if (!get_polymorphic_call_info_from_invariant
(&context, t, ie->indirect_info->otr_type,
anc_offset))
return NULL_TREE;
targets = possible_polymorphic_call_targets
(ie->indirect_info->otr_type,
ie->indirect_info->otr_token,

View File

@ -2400,41 +2400,43 @@ decl_maybe_in_construction_p (tree base, tree outer_type,
}
/* Proudce polymorphic call context for call method of instance
that is located within BASE (that is assumed to be a decl) at OFFSET. */
that is located within BASE (that is assumed to be a decl) at offset OFF. */
static void
get_polymorphic_call_info_for_decl (ipa_polymorphic_call_context *context,
tree base, HOST_WIDE_INT offset)
void
ipa_polymorphic_call_context::set_by_decl (tree base, HOST_WIDE_INT off)
{
gcc_assert (DECL_P (base));
context->outer_type = TYPE_MAIN_VARIANT (TREE_TYPE (base));
context->offset = offset;
context->speculative_outer_type = NULL;
context->speculative_offset = 0;
context->speculative_maybe_derived_type = true;
outer_type = TYPE_MAIN_VARIANT (TREE_TYPE (base));
offset = off;
clear_speculation ();
/* Make very conservative assumption that all objects
may be in construction.
TODO: ipa-prop already contains code to tell better.
merge it later. */
context->maybe_in_construction = true;
context->maybe_derived_type = false;
maybe_in_construction = true;
maybe_derived_type = false;
}
/* CST is an invariant (address of decl), try to get meaningful
polymorphic call context for polymorphic call of method
if instance of OTR_TYPE that is located at OFFSET of this invariant.
if instance of OTR_TYPE that is located at offset OFF of this invariant.
Return FALSE if nothing meaningful can be found. */
bool
get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *context,
tree cst,
tree otr_type,
HOST_WIDE_INT offset)
ipa_polymorphic_call_context::set_by_invariant (tree cst,
tree otr_type,
HOST_WIDE_INT off)
{
HOST_WIDE_INT offset2, size, max_size;
tree base;
invalid = false;
off = 0;
outer_type = NULL;
maybe_in_construction = true;
maybe_derived_type = true;
if (TREE_CODE (cst) != ADDR_EXPR)
return false;
@ -2445,10 +2447,13 @@ get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *context,
/* Only type inconsistent programs can have otr_type that is
not part of outer type. */
if (!contains_type_p (TREE_TYPE (base), offset, otr_type))
return false;
if (otr_type && !contains_type_p (TREE_TYPE (base), off, otr_type))
{
invalid = true;
return false;
}
get_polymorphic_call_info_for_decl (context, base, offset);
set_by_decl (base, off);
return true;
}
@ -2472,34 +2477,46 @@ walk_ssa_copies (tree op)
return op;
}
/* Given REF call in FNDECL, determine class of the polymorphic
call (OTR_TYPE), its token (OTR_TOKEN) and CONTEXT.
CALL is optional argument giving the actual statement (usually call) where
the context is used.
Return pointer to object described by the context or an declaration if
we found the instance to be stored in the static storage. */
/* Create polymorphic call context from IP invariant CST.
This is typically &global_var.
OTR_TYPE specify type of polymorphic call or NULL if unknown, OFF
is offset of call. */
tree
get_polymorphic_call_info (tree fndecl,
tree ref,
tree *otr_type,
HOST_WIDE_INT *otr_token,
ipa_polymorphic_call_context *context,
gimple call)
ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree cst,
tree otr_type,
HOST_WIDE_INT off)
{
clear_speculation ();
set_by_invariant (cst, otr_type, off);
}
/* Build context for pointer REF contained in FNDECL at statement STMT.
if INSTANCE is non-NULL, return pointer to the object described by
the context or DECL where context is contained in. */
ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
tree ref,
gimple stmt,
tree *instance)
{
tree otr_type = NULL;
tree base_pointer;
*otr_type = obj_type_ref_class (ref);
*otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (ref));
if (TREE_CODE (ref) == OBJ_TYPE_REF)
{
otr_type = obj_type_ref_class (ref);
base_pointer = OBJ_TYPE_REF_OBJECT (ref);
}
else
base_pointer = ref;
/* Set up basic info in case we find nothing interesting in the analysis. */
context->speculative_outer_type = NULL;
context->speculative_offset = 0;
context->speculative_maybe_derived_type = true;
context->outer_type = TYPE_MAIN_VARIANT (*otr_type);
context->offset = 0;
base_pointer = OBJ_TYPE_REF_OBJECT (ref);
context->maybe_derived_type = true;
context->maybe_in_construction = true;
clear_speculation ();
outer_type = TYPE_MAIN_VARIANT (otr_type);
offset = 0;
maybe_derived_type = true;
maybe_in_construction = true;
invalid = false;
/* Walk SSA for outer object. */
do
@ -2522,9 +2539,9 @@ get_polymorphic_call_info (tree fndecl,
if (TREE_CODE (base) == MEM_REF)
{
base_pointer = TREE_OPERAND (base, 0);
context->offset
offset
+= offset2 + mem_ref_offset (base).to_short_addr () * BITS_PER_UNIT;
context->outer_type = NULL;
outer_type = NULL;
}
/* We found base object. In this case the outer_type
is known. */
@ -2534,24 +2551,25 @@ get_polymorphic_call_info (tree fndecl,
/* Only type inconsistent programs can have otr_type that is
not part of outer type. */
if (!contains_type_p (TREE_TYPE (base),
context->offset + offset2, *otr_type))
if (otr_type
&& !contains_type_p (TREE_TYPE (base),
offset + offset2, otr_type))
{
/* Use OTR_TOKEN = INT_MAX as a marker of probably type inconsistent
code sequences; we arrange the calls to be builtin_unreachable
later. */
*otr_token = INT_MAX;
return base_pointer;
invalid = true;
if (instance)
*instance = base_pointer;
return;
}
get_polymorphic_call_info_for_decl (context, base,
context->offset + offset2);
if (context->maybe_in_construction && call)
context->maybe_in_construction
set_by_decl (base, offset + offset2);
if (maybe_in_construction && stmt)
maybe_in_construction
= decl_maybe_in_construction_p (base,
context->outer_type,
call,
outer_type,
stmt,
fndecl);
return base;
if (instance)
*instance = base;
return;
}
else
break;
@ -2562,7 +2580,7 @@ get_polymorphic_call_info (tree fndecl,
else if (TREE_CODE (base_pointer) == POINTER_PLUS_EXPR
&& tree_fits_uhwi_p (TREE_OPERAND (base_pointer, 1)))
{
context->offset += tree_to_shwi (TREE_OPERAND (base_pointer, 1))
offset += tree_to_shwi (TREE_OPERAND (base_pointer, 1))
* BITS_PER_UNIT;
base_pointer = TREE_OPERAND (base_pointer, 0);
}
@ -2580,19 +2598,22 @@ get_polymorphic_call_info (tree fndecl,
if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE
&& SSA_NAME_VAR (base_pointer) == DECL_ARGUMENTS (fndecl))
{
context->outer_type
outer_type
= TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (base_pointer)));
gcc_assert (TREE_CODE (context->outer_type) == RECORD_TYPE);
gcc_assert (TREE_CODE (outer_type) == RECORD_TYPE);
/* Dynamic casting has possibly upcasted the type
in the hiearchy. In this case outer type is less
informative than inner type and we should forget
about it. */
if (!contains_type_p (context->outer_type, context->offset,
*otr_type))
if (otr_type
&& !contains_type_p (outer_type, offset,
otr_type))
{
context->outer_type = NULL;
return base_pointer;
outer_type = NULL;
if (instance)
*instance = base_pointer;
return;
}
/* If the function is constructor or destructor, then
@ -2601,38 +2622,41 @@ get_polymorphic_call_info (tree fndecl,
if (DECL_CXX_CONSTRUCTOR_P (fndecl)
|| DECL_CXX_DESTRUCTOR_P (fndecl))
{
context->maybe_in_construction = true;
context->maybe_derived_type = false;
maybe_in_construction = true;
maybe_derived_type = false;
}
else
{
context->maybe_derived_type = true;
context->maybe_in_construction = false;
maybe_derived_type = true;
maybe_in_construction = false;
}
return base_pointer;
if (instance)
*instance = base_pointer;
return;
}
/* Non-PODs passed by value are really passed by invisible
reference. In this case we also know the type of the
object. */
if (DECL_BY_REFERENCE (SSA_NAME_VAR (base_pointer)))
{
context->outer_type
outer_type
= TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (base_pointer)));
gcc_assert (!POINTER_TYPE_P (context->outer_type));
gcc_assert (!POINTER_TYPE_P (outer_type));
/* Only type inconsistent programs can have otr_type that is
not part of outer type. */
if (!contains_type_p (context->outer_type, context->offset,
*otr_type))
if (!contains_type_p (outer_type, offset,
otr_type))
{
/* Use OTR_TOKEN = INT_MAX as a marker of probably type inconsistent
code sequences; we arrange the calls to be builtin_unreachable
later. */
*otr_token = INT_MAX;
return base_pointer;
invalid = true;
if (instance)
*instance = base_pointer;
return;
}
context->maybe_derived_type = false;
context->maybe_in_construction = false;
return base_pointer;
maybe_derived_type = false;
maybe_in_construction = false;
if (instance)
*instance = base_pointer;
return;
}
}
@ -2642,11 +2666,10 @@ get_polymorphic_call_info (tree fndecl,
&& SSA_NAME_IS_DEFAULT_DEF (base_pointer)
&& TREE_CODE (SSA_NAME_VAR (base_pointer)) != PARM_DECL)
{
/* Use OTR_TOKEN = INT_MAX as a marker of probably type inconsistent
code sequences; we arrange the calls to be builtin_unreachable
later. */
*otr_token = INT_MAX;
return base_pointer;
invalid = true;
if (instance)
*instance = base_pointer;
return;
}
if (TREE_CODE (base_pointer) == SSA_NAME
&& SSA_NAME_DEF_STMT (base_pointer)
@ -2655,19 +2678,22 @@ get_polymorphic_call_info (tree fndecl,
(SSA_NAME_DEF_STMT (base_pointer)));
if (POINTER_TYPE_P (base_type)
&& contains_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (base_type)),
context->offset,
*otr_type))
&& (otr_type
|| !contains_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (base_type)),
offset,
otr_type)))
{
context->speculative_outer_type = TYPE_MAIN_VARIANT
speculative_outer_type = TYPE_MAIN_VARIANT
(TREE_TYPE (base_type));
context->speculative_offset = context->offset;
context->speculative_maybe_derived_type = true;
speculative_offset = offset;
speculative_maybe_derived_type = true;
}
/* TODO: There are multiple ways to derive a type. For instance
if BASE_POINTER is passed to an constructor call prior our refernece.
We do not make this type of flow sensitive analysis yet. */
return base_pointer;
if (instance)
*instance = base_pointer;
return;
}
/* Structure to be passed in between detect_type_change and
@ -3404,9 +3430,6 @@ struct final_warning_record *final_warning_records;
temporarily change to one of base types. INCLUDE_DERIVER_TYPES make
us to walk the inheritance graph for all derivations.
OTR_TOKEN == INT_MAX is used to mark calls that are provably
undefined and should be redirected to unreachable.
If COMPLETEP is non-NULL, store true if the list is complete.
CACHE_TOKEN (if non-NULL) will get stored to an unique ID of entry
in the target cache. If user needs to visit every target list
@ -3443,23 +3466,12 @@ possible_polymorphic_call_targets (tree otr_type,
otr_type = TYPE_MAIN_VARIANT (otr_type);
/* If ODR is not initialized, return empty incomplete list. */
if (!odr_hash)
/* If ODR is not initialized or the constext is invalid, return empty
incomplete list. */
if (!odr_hash || context.invalid)
{
if (completep)
*completep = false;
if (cache_token)
*cache_token = NULL;
if (speculative_targetsp)
*speculative_targetsp = 0;
return nodes;
}
/* If we hit type inconsistency, just return empty list of targets. */
if (otr_token == INT_MAX)
{
if (completep)
*completep = true;
*completep = context.invalid;
if (cache_token)
*cache_token = NULL;
if (speculative_targetsp)
@ -3853,6 +3865,26 @@ possible_polymorphic_call_target_p (tree otr_type,
}
/* Return true if N can be possibly target of a polymorphic call of
OBJ_TYPE_REF expression REF in STMT. */
bool
possible_polymorphic_call_target_p (tree ref,
gimple stmt,
struct cgraph_node *n)
{
ipa_polymorphic_call_context context (current_function_decl, ref, stmt);
tree call_fn = gimple_call_fn (stmt);
return possible_polymorphic_call_target_p (obj_type_ref_class (call_fn),
tree_to_uhwi
(OBJ_TYPE_REF_TOKEN (call_fn)),
context,
n);
}
/* After callgraph construction new external nodes may appear.
Add them into the graph. */

View File

@ -2347,14 +2347,13 @@ ipa_analyze_call_uses (struct func_body_info *fbi, gimple call)
{
tree otr_type;
HOST_WIDE_INT otr_token;
ipa_polymorphic_call_context context;
tree instance;
tree target = gimple_call_fn (call);
ipa_polymorphic_call_context context (current_function_decl,
target, call, &instance);
instance = get_polymorphic_call_info (current_function_decl,
target,
&otr_type, &otr_token,
&context, call);
otr_type = obj_type_ref_class (target);
otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
if (context.get_dynamic_type (instance,
OBJ_TYPE_REF_OBJECT (target),
@ -2609,7 +2608,7 @@ ipa_intraprocedural_devirtualization (gimple call)
#ifdef ENABLE_CHECKING
if (fndecl)
gcc_assert (possible_polymorphic_call_target_p
(otr, cgraph_node::get (fndecl)));
(otr, call, cgraph_node::get (fndecl)));
#endif
return fndecl;
}
@ -3121,14 +3120,12 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
if (TREE_CODE (binfo) != TREE_BINFO)
{
ipa_polymorphic_call_context context;
ipa_polymorphic_call_context context (binfo,
ie->indirect_info->otr_type,
ie->indirect_info->offset);
vec <cgraph_node *>targets;
bool final;
if (!get_polymorphic_call_info_from_invariant
(&context, binfo, ie->indirect_info->otr_type,
ie->indirect_info->offset))
return NULL;
targets = possible_polymorphic_call_targets
(ie->indirect_info->otr_type,
ie->indirect_info->otr_token,

View File

@ -53,12 +53,28 @@ public:
/* True if speculative outer object may be of derived type. We always
speculate that construction does not happen. */
bool speculative_maybe_derived_type;
/* True if the context is invalid and all calls should be redirected
to BUILTIN_UNREACHABLE. */
bool invalid;
/* Build empty "I know nothing" context. */
ipa_polymorphic_call_context ();
/* Build polymorphic call context for indirect call E. */
ipa_polymorphic_call_context (cgraph_edge *e);
/* Build polymorphic call context for IP invariant CST.
If specified, OTR_TYPE specify the type of polymorphic call
that takes CST+OFFSET as a prameter. */
ipa_polymorphic_call_context (tree cst, tree otr_type = NULL,
HOST_WIDE_INT offset = 0);
/* Build context for pointer REF contained in FNDECL at statement STMT.
if INSTANCE is non-NULL, return pointer to the object described by
the context. */
ipa_polymorphic_call_context (tree fndecl, tree ref, gimple stmt,
tree *instance = NULL);
/* Look for vtable stores or constructor calls to work out dynamic type
of memory location. */
bool get_dynamic_type (tree, tree, tree, gimple);
/* Make context non-speculative. */
void clear_speculation ();
@ -67,9 +83,9 @@ public:
containing EXPECTED_TYPE as base class. */
bool restrict_to_inner_class (tree expected_type);
/* Look for vtable stores or constructor calls to work out dynamic type
of memory location. */
bool get_dynamic_type (tree, tree, tree, gimple);
private:
void set_by_decl (tree, HOST_WIDE_INT);
bool set_by_invariant (tree, tree, HOST_WIDE_INT);
};
/* Build polymorphic call context for indirect call E. */
@ -77,6 +93,8 @@ public:
inline
ipa_polymorphic_call_context::ipa_polymorphic_call_context (cgraph_edge *e)
{
gcc_checking_assert (e->indirect_info->polymorphic);
offset = e->indirect_info->offset;
speculative_offset = e->indirect_info->speculative_offset;
outer_type = e->indirect_info->outer_type;
@ -84,16 +102,22 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (cgraph_edge *e)
maybe_in_construction = e->indirect_info->maybe_in_construction;
maybe_derived_type = e->indirect_info->maybe_derived_type;
speculative_maybe_derived_type = e->indirect_info->speculative_maybe_derived_type;
invalid = false;
}
/* Build empty "I know nothing" context. */
inline
ipa_polymorphic_call_context::ipa_polymorphic_call_context ()
: offset(0), speculative_offset(0), outer_type(NULL),
speculative_outer_type(NULL), maybe_in_construction(false),
maybe_derived_type(false), speculative_maybe_derived_type(false)
{
offset = 0;
speculative_offset = 0;
outer_type = NULL;
speculative_outer_type = NULL;
maybe_in_construction = true;
maybe_derived_type = true;
speculative_maybe_derived_type = false;
invalid = false;
}
/* Make context non-speculative. */
@ -131,22 +155,17 @@ void update_type_inheritance_graph (void);
vec <cgraph_node *>
possible_polymorphic_call_targets (tree, HOST_WIDE_INT,
ipa_polymorphic_call_context,
bool *final = NULL,
bool *copletep = NULL,
void **cache_token = NULL,
int *nonconstruction_targets = NULL);
odr_type get_odr_type (tree, bool insert = false);
bool possible_polymorphic_call_target_p (tree ref, gimple stmt, struct cgraph_node *n);
void dump_possible_polymorphic_call_targets (FILE *, tree, HOST_WIDE_INT,
const ipa_polymorphic_call_context &);
bool possible_polymorphic_call_target_p (tree, HOST_WIDE_INT,
const ipa_polymorphic_call_context &,
struct cgraph_node *);
tree method_class_type (const_tree);
tree get_polymorphic_call_info (tree, tree, tree *,
HOST_WIDE_INT *,
ipa_polymorphic_call_context *,
gimple call = NULL);
bool get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *,
tree, tree, HOST_WIDE_INT);
bool decl_maybe_in_construction_p (tree, tree, gimple, tree);
tree vtable_pointer_value_to_binfo (const_tree);
bool vtable_pointer_value_to_vtable (const_tree, tree *, unsigned HOST_WIDE_INT *);
@ -155,7 +174,7 @@ bool contains_polymorphic_type_p (const_tree);
void register_odr_type (tree);
/* Return vector containing possible targets of polymorphic call E.
If FINALP is non-NULL, store true if the list is complette.
If COMPLETEP is non-NULL, store true if the list is complette.
CACHE_TOKEN (if non-NULL) will get stored to an unique ID of entry
in the target cache. If user needs to visit every target list
just once, it can memoize them.
@ -166,16 +185,16 @@ void register_odr_type (tree);
inline vec <cgraph_node *>
possible_polymorphic_call_targets (struct cgraph_edge *e,
bool *final = NULL,
bool *completep = NULL,
void **cache_token = NULL,
int *nonconstruction_targets = NULL)
{
gcc_checking_assert (e->indirect_info->polymorphic);
ipa_polymorphic_call_context context(e);
return possible_polymorphic_call_targets (e->indirect_info->otr_type,
e->indirect_info->otr_token,
context,
final, cache_token,
completep, cache_token,
nonconstruction_targets);
}
@ -184,21 +203,16 @@ possible_polymorphic_call_targets (struct cgraph_edge *e,
inline vec <cgraph_node *>
possible_polymorphic_call_targets (tree ref,
gimple call,
bool *final = NULL,
bool *completep = NULL,
void **cache_token = NULL)
{
tree otr_type;
HOST_WIDE_INT otr_token;
ipa_polymorphic_call_context context;
ipa_polymorphic_call_context context (current_function_decl, ref, call);
get_polymorphic_call_info (current_function_decl,
ref,
&otr_type, &otr_token, &context, call);
return possible_polymorphic_call_targets (obj_type_ref_class (ref),
tree_to_uhwi
(OBJ_TYPE_REF_TOKEN (ref)),
context,
final, cache_token);
completep, cache_token);
}
/* Dump possible targets of a polymorphic call E into F. */
@ -206,8 +220,8 @@ possible_polymorphic_call_targets (tree ref,
inline void
dump_possible_polymorphic_call_targets (FILE *f, struct cgraph_edge *e)
{
gcc_checking_assert (e->indirect_info->polymorphic);
ipa_polymorphic_call_context context(e);
dump_possible_polymorphic_call_targets (f, e->indirect_info->otr_type,
e->indirect_info->otr_token,
context);
@ -221,26 +235,12 @@ possible_polymorphic_call_target_p (struct cgraph_edge *e,
struct cgraph_node *n)
{
ipa_polymorphic_call_context context(e);
return possible_polymorphic_call_target_p (e->indirect_info->otr_type,
e->indirect_info->otr_token,
context, n);
}
/* Return true if N can be possibly target of a polymorphic call of
OBJ_TYPE_REF expression CALL. */
inline bool
possible_polymorphic_call_target_p (tree call,
struct cgraph_node *n)
{
ipa_polymorphic_call_context context;
return possible_polymorphic_call_target_p (obj_type_ref_class (call),
tree_to_uhwi
(OBJ_TYPE_REF_TOKEN (call)),
context,
n);
}
/* Return true of T is type with One Definition Rule info attached.
It means that either it is anonymous type or it has assembler name
set. */

View File

@ -4277,16 +4277,11 @@ eliminate_dom_walker::before_dom_children (basic_block b)
&& flag_devirtualize
&& virtual_method_call_p (fn))
{
tree otr_type;
HOST_WIDE_INT otr_token;
ipa_polymorphic_call_context context;
tree otr_type = obj_type_ref_class (fn);
tree instance;
ipa_polymorphic_call_context context (current_function_decl, fn, stmt, &instance);
bool final;
instance = get_polymorphic_call_info (current_function_decl,
fn,
&otr_type, &otr_token, &context, stmt);
context.get_dynamic_type (instance, OBJ_TYPE_REF_OBJECT (fn), otr_type, stmt);
vec <cgraph_node *>targets