aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <hubicka@ucw.cz>2014-09-20 08:22:58 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2014-09-20 06:22:58 +0000
commit6f8091fc3ed9d3cfa7a6dee7e9f9a34eb4308b2a (patch)
tree369013d698ddb409805fffaae30510b6caa5d22f
parent8e1ba78f1b8eedd6c65c6f0e6d6d09a801de5d3d (diff)
downloadgcc-6f8091fc3ed9d3cfa7a6dee7e9f9a34eb4308b2a.zip
gcc-6f8091fc3ed9d3cfa7a6dee7e9f9a34eb4308b2a.tar.gz
gcc-6f8091fc3ed9d3cfa7a6dee7e9f9a34eb4308b2a.tar.bz2
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
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/cgraph.c16
-rw-r--r--gcc/gimple-fold.c4
-rw-r--r--gcc/ipa-cp.c7
-rw-r--r--gcc/ipa-devirt.c256
-rw-r--r--gcc/ipa-prop.c19
-rw-r--r--gcc/ipa-utils.h84
-rw-r--r--gcc/tree-ssa-pre.c9
8 files changed, 222 insertions, 190 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 87907fd..87b5e00 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,22 @@
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
privatize dynamic TLS variables.
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 99e0076..8f04284 100644
--- a/gcc/cgraph.c
+++ b/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;
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 3d5e3b9..dc2c942 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -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 ");
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index d365634..2ff3b9c 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -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,
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index 774275b..af42c6d 100644
--- a/gcc/ipa-devirt.c
+++ b/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. */
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index bbb417d..9223f3a 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -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,
diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h
index 9c81d5c..c81232c 100644
--- a/gcc/ipa-utils.h
+++ b/gcc/ipa-utils.h
@@ -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. */
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index 5f32b59..235846f 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -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