summaryrefslogtreecommitdiff
path: root/gcc/ipa-devirt.c
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2014-09-20 06:22:58 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2014-09-20 06:22:58 +0000
commit379f66984633fc584760b802d804d03f2714a0da (patch)
tree369013d698ddb409805fffaae30510b6caa5d22f /gcc/ipa-devirt.c
parent78eb5b700d6ef59c9357dfa56547b48fcc4d593a (diff)
downloadgcc-379f66984633fc584760b802d804d03f2714a0da.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@215418 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/ipa-devirt.c')
-rw-r--r--gcc/ipa-devirt.c256
1 files changed, 144 insertions, 112 deletions
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index 774275b2269..af42c6d6bff 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. */