diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-09-20 06:22:58 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-09-20 06:22:58 +0000 |
commit | 379f66984633fc584760b802d804d03f2714a0da (patch) | |
tree | 369013d698ddb409805fffaae30510b6caa5d22f /gcc/ipa-devirt.c | |
parent | 78eb5b700d6ef59c9357dfa56547b48fcc4d593a (diff) | |
download | gcc-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.c | 256 |
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. */ |