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:
parent
8e1ba78f1b
commit
6f8091fc3e
|
@ -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
|
||||
|
|
16
gcc/cgraph.c
16
gcc/cgraph.c
|
@ -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;
|
||||
|
|
|
@ -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 ");
|
||||
|
|
|
@ -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,
|
||||
|
|
256
gcc/ipa-devirt.c
256
gcc/ipa-devirt.c
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue