===================================================================
@@ -884,21 +884,15 @@
&& (target = gimple_call_fn (call_stmt))
&& virtual_method_call_p (target))
{
- tree otr_type;
- HOST_WIDE_INT otr_token;
- ipa_polymorphic_call_context context;
+ ipa_polymorphic_call_context context (decl, target, call_stmt);
- get_polymorphic_call_info (decl,
- target,
- &otr_type, &otr_token,
- &context, 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;
===================================================================
@@ -2563,8 +2563,8 @@
{
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 ");
===================================================================
@@ -1618,14 +1618,11 @@
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,
===================================================================
@@ -2400,41 +2400,43 @@
}
/* 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 @@
/* 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 @@
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 @@
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 @@
/* 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 @@
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 @@
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,15 +2622,17 @@
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
@@ -2616,23 +2639,24 @@
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 @@
&& 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 @@
(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 @@
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,11 +3466,12 @@
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;
+ *completep = context.invalid;
if (cache_token)
*cache_token = NULL;
if (speculative_targetsp)
@@ -3455,18 +3479,6 @@
return nodes;
}
- /* If we hit type inconsistency, just return empty list of targets. */
- if (otr_token == INT_MAX)
- {
- if (completep)
- *completep = true;
- if (cache_token)
- *cache_token = NULL;
- if (speculative_targetsp)
- *speculative_targetsp = 0;
- return nodes;
- }
-
/* Do not bother to compute speculative info when user do not asks for it. */
if (!speculative_targetsp || !context.speculative_outer_type)
context.clear_speculation ();
@@ -3853,6 +3865,26 @@
}
+
+/* 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. */
===================================================================
@@ -2347,14 +2347,13 @@
{
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 @@
#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 @@
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,
===================================================================
@@ -53,13 +53,29 @@
/* 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 @@
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 @@
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,6 +102,7 @@
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. */
@@ -90,10 +109,15 @@
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,10 +155,11 @@
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,
@@ -141,12 +166,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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. */
===================================================================
@@ -4277,16 +4277,11 @@
&& 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