From: Jan Hubicka Date: Thu, 23 Apr 2015 14:55:07 +0000 (+0200) Subject: ipa-icf.c (symbol_compare_collection::symbol_compare_collection): cleanup. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=977b01e34d85c3612fa87d47e17bed0e3ac18d0b;p=gcc.git ipa-icf.c (symbol_compare_collection::symbol_compare_collection): cleanup. * ipa-icf.c (symbol_compare_collection::symbol_compare_collection): cleanup. (sem_function::get_hash): Do not hash DECL_DISREGARD_INLINE_LIMITS, DECL_DECLARED_INLINE_P and DECL_IS_OPERATOR_NEW. (sem_item::compare_referenced_symbol_properties): New. (sem_item::hash_referenced_symbol_properties): New. (sem_item::compare_cgraph_references): Rename to ... (sem_item::compare_symbol_references): ... this one; use compare_referenced_symbol_properties. (sem_function::equals_wpa): Do not compare DECL_DISREGARD_INLINE_LIMITS, DECL_DECLARED_INLINE_P, DECL_IS_OPERATOR_NEW; compare pointer sizes. (sem_item::update_hash_by_addr_refs): Call hash_referenced_symbol_properties. (sem_item::update_hash_by_local_refs): Cleanup. (sem_function::merge): Do not mix up symbol properties. (sem_variable::equals_wpa): Use compare_symbol_references. * ipa-icf.h (sem_item::compare_referenced_symbol_properties): New. (sem_item::hash_referenced_symbol_properties): New. (sem_item::compare_symbol_references): New. (sem_item::compare_cgraph_references): Remove. From-SVN: r222372 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5c1e4c15eee..5be1e9c3d34 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2015-04-23 Jan Hubicka + + * ipa-icf.c (symbol_compare_collection::symbol_compare_collection): + cleanup. + (sem_function::get_hash): Do not hash DECL_DISREGARD_INLINE_LIMITS, + DECL_DECLARED_INLINE_P and DECL_IS_OPERATOR_NEW. + (sem_item::compare_referenced_symbol_properties): New. + (sem_item::hash_referenced_symbol_properties): New. + (sem_item::compare_cgraph_references): Rename to ... + (sem_item::compare_symbol_references): ... this one; use + compare_referenced_symbol_properties. + (sem_function::equals_wpa): Do not compare + DECL_DISREGARD_INLINE_LIMITS, DECL_DECLARED_INLINE_P, + DECL_IS_OPERATOR_NEW; compare pointer sizes. + (sem_item::update_hash_by_addr_refs): Call + hash_referenced_symbol_properties. + (sem_item::update_hash_by_local_refs): Cleanup. + (sem_function::merge): Do not mix up symbol properties. + (sem_variable::equals_wpa): Use compare_symbol_references. + * ipa-icf.h (sem_item::compare_referenced_symbol_properties): New. + (sem_item::hash_referenced_symbol_properties): New. + (sem_item::compare_symbol_references): New. + (sem_item::compare_cgraph_references): Remove. + 2015-04-23 Kwok Cheung Yeung PR target/26702 diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c index a72ac2ee482..64fa4fa82b1 100644 --- a/gcc/ipa-icf.c +++ b/gcc/ipa-icf.c @@ -145,9 +145,8 @@ symbol_compare_collection::symbol_compare_collection (symtab_node *node) if (is_a (node) && DECL_VIRTUAL_P (node->decl)) return; - for (unsigned i = 0; i < node->num_references (); i++) + for (unsigned i = 0; node->iterate_reference (i, ref); i++) { - ref = node->iterate_reference (i, ref); if (ref->address_matters_p ()) m_references.safe_push (ref->referred); @@ -342,9 +341,6 @@ sem_function::get_hash (void) if (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl)) (cl_optimization_hash (TREE_OPTIMIZATION (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl)))); - hstate.add_flag (DECL_DISREGARD_INLINE_LIMITS (decl)); - hstate.add_flag (DECL_DECLARED_INLINE_P (decl)); - hstate.add_flag (DECL_IS_OPERATOR_NEW (decl)); hstate.add_flag (DECL_CXX_CONSTRUCTOR_P (decl)); hstate.add_flag (DECL_CXX_DESTRUCTOR_P (decl)); @@ -354,12 +350,117 @@ sem_function::get_hash (void) return hash; } +/* Compare properties of symbols N1 and N2 that does not affect semantics of + symbol itself but affects semantics of its references from USED_BY (which + may be NULL if it is unknown). If comparsion is false, symbols + can still be merged but any symbols referring them can't. + + If ADDRESS is true, do extra checking needed for IPA_REF_ADDR. + + TODO: We can also split attributes to those that determine codegen of + a function body/variable constructor itself and those that are used when + referring to it. */ + +bool +sem_item::compare_referenced_symbol_properties (symtab_node *used_by, + symtab_node *n1, + symtab_node *n2, + bool address) +{ + if (is_a (n1)) + { + /* Inline properties matters: we do now want to merge uses of inline + function to uses of normal function because inline hint would be lost. + We however can merge inline function to noinline because the alias + will keep its DECL_DECLARED_INLINE flag. + + Also ignore inline flag when optimizing for size or when function + is known to not be inlinable. + + TODO: the optimize_size checks can also be assumed to be true if + unit has no !optimize_size functions. */ + + if ((!used_by || address || !is_a (used_by) + || !opt_for_fn (used_by->decl, optimize_size)) + && !opt_for_fn (n1->decl, optimize_size) + && n1->get_availability () > AVAIL_INTERPOSABLE + && (!DECL_UNINLINABLE (n1->decl) || !DECL_UNINLINABLE (n2->decl))) + { + if (DECL_DISREGARD_INLINE_LIMITS (n1->decl) + != DECL_DISREGARD_INLINE_LIMITS (n2->decl)) + return return_false_with_msg + ("DECL_DISREGARD_INLINE_LIMITS are different"); + + if (DECL_DECLARED_INLINE_P (n1->decl) + != DECL_DECLARED_INLINE_P (n2->decl)) + return return_false_with_msg ("inline attributes are different"); + } + + if (DECL_IS_OPERATOR_NEW (n1->decl) + != DECL_IS_OPERATOR_NEW (n2->decl)) + return return_false_with_msg ("operator new flags are different"); + } + + /* Merging two definitions with a reference to equivalent vtables, but + belonging to a different type may result in ipa-polymorphic-call analysis + giving a wrong answer about the dynamic type of instance. */ + if (is_a (n1)) + { + if ((DECL_VIRTUAL_P (n1->decl) || DECL_VIRTUAL_P (n2->decl)) + && (DECL_VIRTUAL_P (n1->decl) != DECL_VIRTUAL_P (n2->decl) + || !types_must_be_same_for_odr (DECL_CONTEXT (n1->decl), + DECL_CONTEXT (n2->decl))) + && (!used_by || !is_a (used_by) || address + || opt_for_fn (used_by->decl, flag_devirtualize))) + return return_false_with_msg + ("references to virtual tables can not be merged"); + } + + /* When matching virtual tables, be sure to also match information + relevant for polymorphic call analysis. */ + if (used_by && is_a (used_by) + && DECL_VIRTUAL_P (used_by->decl)) + { + if (DECL_VIRTUAL_P (n1->decl) != DECL_VIRTUAL_P (n2->decl)) + return return_false_with_msg ("virtual flag mismatch"); + if (DECL_VIRTUAL_P (n1->decl) && is_a (n1) + && (DECL_FINAL_P (n1->decl) != DECL_FINAL_P (n2->decl))) + return return_false_with_msg ("final flag mismatch"); + } + return true; +} + +/* Hash properties that are compared by compare_referenced_symbol_properties. */ + +void +sem_item::hash_referenced_symbol_properties (symtab_node *ref, + inchash::hash &hstate, + bool address) +{ + if (is_a (ref)) + { + if ((!type == FUNC || address || !opt_for_fn (decl, optimize_size)) + && !opt_for_fn (ref->decl, optimize_size) + && !DECL_UNINLINABLE (ref->decl)) + { + hstate.add_flag (DECL_DISREGARD_INLINE_LIMITS (ref->decl)); + hstate.add_flag (DECL_DECLARED_INLINE_P (ref->decl)); + } + hstate.add_flag (DECL_IS_OPERATOR_NEW (ref->decl)); + } + else if (is_a (ref)) + { + hstate.add_flag (DECL_VIRTUAL_P (ref->decl)); + } +} + + /* For a given symbol table nodes N1 and N2, we check that FUNCTION_DECLs point to a same function. Comparison can be skipped if IGNORED_NODES contains these nodes. ADDRESS indicate if address is taken. */ bool -sem_item::compare_cgraph_references ( +sem_item::compare_symbol_references ( hash_map &ignored_nodes, symtab_node *n1, symtab_node *n2, bool address) { @@ -372,17 +473,8 @@ sem_item::compare_cgraph_references ( if (is_a (n1) != is_a (n2)) return false; - /* Merging two definitions with a reference to equivalent vtables, but - belonging to a different type may result in ipa-polymorphic-call analysis - giving a wrong answer about the dynamic type of instance. */ - if (is_a (n1) - && (DECL_VIRTUAL_P (n1->decl) || DECL_VIRTUAL_P (n2->decl)) - && (DECL_VIRTUAL_P (n1->decl) != DECL_VIRTUAL_P (n2->decl) - || !types_must_be_same_for_odr (DECL_CONTEXT (n1->decl), - DECL_CONTEXT (n2->decl)))) - return return_false_with_msg - ("references to virtual tables can not be merged"); - + if (!compare_referenced_symbol_properties (node, n1, n2, address)) + return false; if (address && n1->equal_address_to (n2) == 1) return true; if (!address && n1->semantically_equivalent_p (n2)) @@ -435,16 +527,6 @@ sem_function::equals_wpa (sem_item *item, != DECL_FUNCTION_PERSONALITY (item->decl)) return return_false_with_msg ("function personalities are different"); - if (DECL_DISREGARD_INLINE_LIMITS (decl) - != DECL_DISREGARD_INLINE_LIMITS (item->decl)) - return return_false_with_msg ("DECL_DISREGARD_INLINE_LIMITS are different"); - - if (DECL_DECLARED_INLINE_P (decl) != DECL_DECLARED_INLINE_P (item->decl)) - return return_false_with_msg ("inline attributes are different"); - - if (DECL_IS_OPERATOR_NEW (decl) != DECL_IS_OPERATOR_NEW (item->decl)) - return return_false_with_msg ("operator new flags are different"); - if (DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) != DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (item->decl)) return return_false_with_msg ("intrument function entry exit " @@ -524,6 +606,12 @@ sem_function::equals_wpa (sem_item *item, && (TYPE_RESTRICT (arg_types[i]) != TYPE_RESTRICT (m_compared_func->arg_types[i]))) return return_false_with_msg ("argument restrict flag mismatch"); + /* nonnull_arg_p implies non-zero range to REFERENCE types. */ + if (POINTER_TYPE_P (arg_types[i]) + && TREE_CODE (arg_types[i]) + != TREE_CODE (m_compared_func->arg_types[i]) + && opt_for_fn (decl, flag_delete_null_pointer_checks)) + return return_false_with_msg ("pointer wrt reference mismatch"); } if (node->num_references () != item->node->num_references ()) @@ -557,7 +645,7 @@ sem_function::equals_wpa (sem_item *item, { item->node->iterate_reference (i, ref2); - if (!compare_cgraph_references (ignored_nodes, ref->referred, + if (!compare_symbol_references (ignored_nodes, ref->referred, ref2->referred, ref->address_matters_p ())) return false; @@ -568,7 +656,7 @@ sem_function::equals_wpa (sem_item *item, while (e1 && e2) { - if (!compare_cgraph_references (ignored_nodes, e1->callee, + if (!compare_symbol_references (ignored_nodes, e1->callee, e2->callee, false)) return false; @@ -585,7 +673,10 @@ sem_function::equals_wpa (sem_item *item, /* Update hash by address sensitive references. We iterate over all sensitive references (address_matters_p) and we hash ultime alias target of these nodes, which can improve a semantic item hash. - TODO: stronger SCC based hashing would be desirable here. */ + + Also hash in referenced symbols properties. This can be done at any time + (as the properties should not change), but it is convenient to do it here + while we walk the references anyway. */ void sem_item::update_hash_by_addr_refs (hash_map num_references (); i++) + + for (unsigned i = 0; node->iterate_reference (i, ref); i++) { - ref = node->iterate_reference (i, ref); + hash_referenced_symbol_properties (ref->referred, hstate, + ref->use == IPA_REF_ADDR); if (ref->address_matters_p () || !m_symtab_node_map.get (ref->referred)) hstate.add_int (ref->referred->ultimate_alias_target ()->order); } @@ -606,6 +699,7 @@ sem_item::update_hash_by_addr_refs (hash_map next_caller) { sem_item **result = m_symtab_node_map.get (e->callee); + hash_referenced_symbol_properties (e->callee, hstate, false); if (!result) hstate.add_int (e->callee->ultimate_alias_target ()->order); } @@ -615,17 +709,18 @@ sem_item::update_hash_by_addr_refs (hash_map &m_symtab_node_map) { + ipa_ref* ref; inchash::hash state (hash); - for (unsigned j = 0; j < node->num_references (); j++) + + for (unsigned j = 0; node->iterate_reference (j, ref); j++) { - ipa_ref *ref; - ref = node->iterate_reference (j, ref); sem_item **result = m_symtab_node_map.get (ref->referring); if (result) state.merge_hash ((*result)->hash); @@ -967,13 +1062,25 @@ sem_function::merge (sem_item *alias_item) { /* First see if we can produce wrapper. */ + /* Symbol properties that matter for references must be preserved. + TODO: We can produce wrapper, but we need to produce alias of ORIGINAL + with proper properties. */ + if (!sem_item::compare_referenced_symbol_properties (NULL, original, alias, + alias->address_taken)) + { + if (dump_file) + fprintf (dump_file, + "Wrapper cannot be created because referenced symbol " + "properties mismatch\n"); + } /* Do not turn function in one comdat group into wrapper to another comdat group. Other compiler producing the body of the another comdat group may make opossite decision and with unfortunate linker choices this may close a loop. */ - if (DECL_COMDAT_GROUP (original->decl) && DECL_COMDAT_GROUP (alias->decl) - && (DECL_COMDAT_GROUP (alias->decl) - != DECL_COMDAT_GROUP (original->decl))) + else if (DECL_COMDAT_GROUP (original->decl) + && DECL_COMDAT_GROUP (alias->decl) + && (DECL_COMDAT_GROUP (alias->decl) + != DECL_COMDAT_GROUP (original->decl))) { if (dump_file) fprintf (dump_file, @@ -1017,6 +1124,11 @@ sem_function::merge (sem_item *alias_item) = alias->get_availability () > AVAIL_INTERPOSABLE && original->get_availability () > AVAIL_INTERPOSABLE && !alias->instrumented_version; + /* TODO: We can redirect, but we need to produce alias of ORIGINAL + with proper properties. */ + if (!sem_item::compare_referenced_symbol_properties (NULL, original, alias, + alias->address_taken)) + redirect_callers = false; if (!redirect_callers && !create_wrapper) { @@ -1663,24 +1775,10 @@ sem_variable::equals_wpa (sem_item *item, { item->node->iterate_reference (i, ref2); - if (!compare_cgraph_references (ignored_nodes, + if (!compare_symbol_references (ignored_nodes, ref->referred, ref2->referred, ref->address_matters_p ())) return false; - - /* When matching virtual tables, be sure to also match information - relevant for polymorphic call analysis. */ - if (DECL_VIRTUAL_P (decl) || DECL_VIRTUAL_P (item->decl)) - { - if (DECL_VIRTUAL_P (ref->referred->decl) - != DECL_VIRTUAL_P (ref2->referred->decl)) - return return_false_with_msg ("virtual flag mismatch"); - if (DECL_VIRTUAL_P (ref->referred->decl) - && is_a (ref->referred) - && (DECL_FINAL_P (ref->referred->decl) - != DECL_FINAL_P (ref2->referred->decl))) - return return_false_with_msg ("final flag mismatch"); - } } return true; @@ -1688,8 +1786,6 @@ sem_variable::equals_wpa (sem_item *item, /* Returns true if the item equals to ITEM given as argument. */ -/* Returns true if the item equals to ITEM given as argument. */ - bool sem_variable::equals (sem_item *item, hash_map &) diff --git a/gcc/ipa-icf.h b/gcc/ipa-icf.h index b9d70b4537e..981952b3368 100644 --- a/gcc/ipa-icf.h +++ b/gcc/ipa-icf.h @@ -248,10 +248,23 @@ protected: /* Accumulate to HSTATE a hash of type T. */ static void add_type (const_tree t, inchash::hash &hstate); + /* Compare properties of symbol that does not affect semantics of symbol + itself but affects semantics of its references. + If ADDRESS is true, do extra checking needed for IPA_REF_ADDR. */ + static bool compare_referenced_symbol_properties (symtab_node *used_by, + symtab_node *n1, + symtab_node *n2, + bool address); + + /* Hash properties compared by compare_referenced_symbol_properties. */ + void hash_referenced_symbol_properties (symtab_node *ref, + inchash::hash &hstate, + bool address); + /* For a given symbol table nodes N1 and N2, we check that FUNCTION_DECLs point to a same function. Comparison can be skipped if IGNORED_NODES contains these nodes. ADDRESS indicate if address is taken. */ - bool compare_cgraph_references (hash_map + bool compare_symbol_references (hash_map &ignored_nodes, symtab_node *n1, symtab_node *n2, bool address);