diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-07-05 17:22:44 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-07-05 17:22:44 +0000 |
commit | 1b613a0a58dc17898dd6313de1ed9b2ff26f20c9 (patch) | |
tree | a316c1d813e71ce225a70f30c867801face3d5aa /gcc/ipa-devirt.c | |
parent | e3f4ccee578cd80d9117d50fcec2ab80372b61ed (diff) | |
download | gcc-1b613a0a58dc17898dd6313de1ed9b2ff26f20c9.tar.gz |
* cgraph.c (cgraph_create_indirect_edge): Update call of
get_polymorphic_call_info.
* ipa-utils.h (get_polymorphic_call_info): Add parameter CALL.
(possible_polymorphic_call_targets): Add parameter call.
(decl_maybe_in_construction_p): New predicate.
(get_polymorphic_call_info): Add parameter call;
use decl_maybe_in_construction_p.
* gimple-fold.c (fold_gimple_assign): Update use of
possible_polymorphic_call_targets.
(gimple_fold_call): Likewise.
* ipa-prop.c: Inlcude calls.h
(ipa_binfo_from_known_type_jfunc): Check that known type is record.
(param_type_may_change_p): New predicate.
(detect_type_change_from_memory_writes): Break out from ...
(detect_type_change): ... this one; use
param_type_may_change_p.
(detect_type_change_ssa): Use param_type_may_change_p.
(compute_known_type_jump_func): Use decl_maybe_in_construction_p.
* g++.dg/ipa/devirt-26.C: Update testcase.
* g++.dg/ipa/imm-devirt-1.C: Update testcase.
* g++.dg/ipa/imm-devirt-2.C: Update testcase.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@212304 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/ipa-devirt.c')
-rw-r--r-- | gcc/ipa-devirt.c | 104 |
1 files changed, 103 insertions, 1 deletions
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index f7418f175f6..da8dfcfee71 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -1438,6 +1438,99 @@ vtable_pointer_value_to_binfo (const_tree t) offset, vtable); } +/* We know that the instance is stored in variable or parameter + (not dynamically allocated) and we want to disprove the fact + that it may be in construction at invocation of CALL. + + For the variable to be in construction we actually need to + be in constructor of corresponding global variable or + the inline stack of CALL must contain the constructor. + Check this condition. This check works safely only before + IPA passes, because inline stacks may become out of date + later. */ + +bool +decl_maybe_in_construction_p (tree base, tree outer_type, + gimple call, tree function) +{ + outer_type = TYPE_MAIN_VARIANT (outer_type); + gcc_assert (DECL_P (base)); + + /* After inlining the code unification optimizations may invalidate + inline stacks. Also we need to give up on global variables after + IPA, because addresses of these may have been propagated to their + constructors. */ + if (DECL_STRUCT_FUNCTION (function)->after_inlining) + return true; + + /* Pure functions can not do any changes on the dynamic type; + that require writting to memory. */ + if (!auto_var_in_fn_p (base, function) + && flags_from_decl_or_type (function) & (ECF_PURE | ECF_CONST)) + return false; + + for (tree block = gimple_block (call); block && TREE_CODE (block) == BLOCK; + block = BLOCK_SUPERCONTEXT (block)) + if (BLOCK_ABSTRACT_ORIGIN (block) + && TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) == FUNCTION_DECL) + { + tree fn = BLOCK_ABSTRACT_ORIGIN (block); + + if (TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE + || (!DECL_CXX_CONSTRUCTOR_P (fn) + || !DECL_CXX_DESTRUCTOR_P (fn))) + { + /* Watch for clones where we constant propagated the first + argument (pointer to the instance). */ + fn = DECL_ABSTRACT_ORIGIN (fn); + if (!fn + || !is_global_var (base) + || TREE_CODE (TREE_TYPE (fn)) != METHOD_TYPE + || (!DECL_CXX_CONSTRUCTOR_P (fn) + || !DECL_CXX_DESTRUCTOR_P (fn))) + continue; + } + if (flags_from_decl_or_type (fn) & (ECF_PURE | ECF_CONST)) + continue; + + /* FIXME: this can go away once we have ODR types equivalency on + LTO level. */ + if (in_lto_p && !polymorphic_type_binfo_p (TYPE_BINFO (outer_type))) + return true; + tree type = TYPE_MAIN_VARIANT (method_class_type (TREE_TYPE (fn))); + if (types_same_for_odr (type, outer_type)) + return true; + } + + if (TREE_CODE (base) == VAR_DECL + && is_global_var (base)) + { + if (TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE + || (!DECL_CXX_CONSTRUCTOR_P (function) + || !DECL_CXX_DESTRUCTOR_P (function))) + { + if (!DECL_ABSTRACT_ORIGIN (function)) + return false; + /* Watch for clones where we constant propagated the first + argument (pointer to the instance). */ + function = DECL_ABSTRACT_ORIGIN (function); + if (!function + || TREE_CODE (TREE_TYPE (function)) != METHOD_TYPE + || (!DECL_CXX_CONSTRUCTOR_P (function) + || !DECL_CXX_DESTRUCTOR_P (function))) + return false; + } + /* FIXME: this can go away once we have ODR types equivalency on + LTO level. */ + if (in_lto_p && !polymorphic_type_binfo_p (TYPE_BINFO (outer_type))) + return true; + tree type = TYPE_MAIN_VARIANT (method_class_type (TREE_TYPE (function))); + if (types_same_for_odr (type, outer_type)) + return true; + } + return false; +} + /* Proudce polymorphic call context for call method of instance that is located within BASE (that is assumed to be a decl) at OFFSET. */ @@ -1490,6 +1583,8 @@ get_polymorphic_call_info_from_invariant (ipa_polymorphic_call_context *context, /* 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 */ tree @@ -1497,7 +1592,8 @@ get_polymorphic_call_info (tree fndecl, tree ref, tree *otr_type, HOST_WIDE_INT *otr_token, - ipa_polymorphic_call_context *context) + ipa_polymorphic_call_context *context, + gimple call) { tree base_pointer; *otr_type = obj_type_ref_class (ref); @@ -1561,6 +1657,12 @@ get_polymorphic_call_info (tree fndecl, } get_polymorphic_call_info_for_decl (context, base, context->offset + offset2); + if (context->maybe_in_construction && call) + context->maybe_in_construction + = decl_maybe_in_construction_p (base, + context->outer_type, + call, + current_function_decl); return NULL; } else |