Commit 69f6b1f4 by Jan Hubicka Committed by Martin Liska

IPA ICF: enhance hash value calculated in TU

	* ipa-icf-gimple.h (return_with_result): Add missing colon to dump.
	* ipa-icf.c (sem_function::get_hash): Hash new declaration properties.
	(sem_item::add_type): New function.
	(sem_function::hash_stmt): Add TREE_TYPE of gimple_op.
	(sem_function::compare_polymorphic_p): Do not consider indirect calls.
	(sem_item_optimizer::update_hash_by_addr_refs): Add ODR type to hash.
	(sem_function::equals_wpa): Fix typo.
	* ipa-icf.h (sem_item::add_type): New function.
	(symbol_compare_hashmap_traits): Replace hashing of pointer with symbol
	order.


Co-Authored-By: Martin Liska <mliska@suse.cz>

From-SVN: r221645
parent e93870c1
2015-03-24 Jan Hubicka <hubicka@ucw.cz>
Martin Liska <mliska@suse.cz>
* ipa-icf-gimple.h (return_with_result): Add missing colon to dump.
* ipa-icf.c (sem_function::get_hash): Hash new declaration properties.
(sem_item::add_type): New function.
(sem_function::hash_stmt): Add TREE_TYPE of gimple_op.
(sem_function::compare_polymorphic_p): Do not consider indirect calls.
(sem_item_optimizer::update_hash_by_addr_refs): Add ODR type to hash.
(sem_function::equals_wpa): Fix typo.
* ipa-icf.h (sem_item::add_type): New function.
(symbol_compare_hashmap_traits): Replace hashing of pointer with symbol
order.
2015-03-24 Jakub Jelinek <jakub@redhat.com> 2015-03-24 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/65533 PR tree-optimization/65533
......
...@@ -75,7 +75,7 @@ static inline bool ...@@ -75,7 +75,7 @@ static inline bool
return_with_result (bool result, const char *func, unsigned int line) return_with_result (bool result, const char *func, unsigned int line)
{ {
if (!result && dump_file && (dump_flags & TDF_DETAILS)) if (!result && dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " false returned (%s:%u)\n", func, line); fprintf (dump_file, " false returned: (%s:%u)\n", func, line);
return result; return result;
} }
......
...@@ -128,6 +128,11 @@ using namespace ipa_icf_gimple; ...@@ -128,6 +128,11 @@ using namespace ipa_icf_gimple;
namespace ipa_icf { namespace ipa_icf {
/* Initialization and computation of symtab node hash, there data
are propagated later on. */
static sem_item_optimizer *optimizer = NULL;
/* Constructor. */ /* Constructor. */
symbol_compare_collection::symbol_compare_collection (symtab_node *node) symbol_compare_collection::symbol_compare_collection (symtab_node *node)
...@@ -328,6 +333,21 @@ sem_function::get_hash (void) ...@@ -328,6 +333,21 @@ sem_function::get_hash (void)
for (unsigned i = 0; i < bb_sizes.length (); i++) for (unsigned i = 0; i < bb_sizes.length (); i++)
hstate.add_int (bb_sizes[i]); hstate.add_int (bb_sizes[i]);
/* Add common features of declaration itself. */
if (DECL_FUNCTION_SPECIFIC_TARGET (decl))
hstate.add_wide_int
(cl_target_option_hash
(TREE_TARGET_OPTION (DECL_FUNCTION_SPECIFIC_TARGET (decl))));
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));
hash = hstate.end (); hash = hstate.end ();
} }
...@@ -430,10 +450,10 @@ sem_function::equals_wpa (sem_item *item, ...@@ -430,10 +450,10 @@ sem_function::equals_wpa (sem_item *item,
return return_false_with_msg ("no stack limit attributes are different"); return return_false_with_msg ("no stack limit attributes are different");
if (DECL_CXX_CONSTRUCTOR_P (decl) != DECL_CXX_CONSTRUCTOR_P (item->decl)) if (DECL_CXX_CONSTRUCTOR_P (decl) != DECL_CXX_CONSTRUCTOR_P (item->decl))
return return_false_with_msg ("DELC_CXX_CONSTRUCTOR mismatch"); return return_false_with_msg ("DECL_CXX_CONSTRUCTOR mismatch");
if (DECL_CXX_DESTRUCTOR_P (decl) != DECL_CXX_DESTRUCTOR_P (item->decl)) if (DECL_CXX_DESTRUCTOR_P (decl) != DECL_CXX_DESTRUCTOR_P (item->decl))
return return_false_with_msg ("DELC_CXX_DESTRUCTOR mismatch"); return return_false_with_msg ("DECL_CXX_DESTRUCTOR mismatch");
if (flags_from_decl_or_type (decl) != flags_from_decl_or_type (item->decl)) if (flags_from_decl_or_type (decl) != flags_from_decl_or_type (item->decl))
return return_false_with_msg ("decl_or_type flags are different"); return return_false_with_msg ("decl_or_type flags are different");
...@@ -1283,6 +1303,80 @@ sem_item::add_expr (const_tree exp, inchash::hash &hstate) ...@@ -1283,6 +1303,80 @@ sem_item::add_expr (const_tree exp, inchash::hash &hstate)
} }
} }
/* Accumulate to HSTATE a hash of type t.
TYpes that may end up being compatible after LTO type merging needs to have
the same hash. */
void
sem_item::add_type (const_tree type, inchash::hash &hstate)
{
if (type == NULL_TREE)
{
hstate.merge_hash (0);
return;
}
type = TYPE_MAIN_VARIANT (type);
if (TYPE_CANONICAL (type))
type = TYPE_CANONICAL (type);
if (!AGGREGATE_TYPE_P (type))
hstate.add_int (TYPE_MODE (type));
if (TREE_CODE (type) == COMPLEX_TYPE)
{
hstate.add_int (COMPLEX_TYPE);
sem_item::add_type (TREE_TYPE (type), hstate);
}
else if (INTEGRAL_TYPE_P (type))
{
hstate.add_int (INTEGER_TYPE);
hstate.add_flag (TYPE_UNSIGNED (type));
hstate.add_int (TYPE_PRECISION (type));
}
else if (VECTOR_TYPE_P (type))
{
hstate.add_int (VECTOR_TYPE);
hstate.add_int (TYPE_PRECISION (type));
sem_item::add_type (TREE_TYPE (type), hstate);
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{
hstate.add_int (ARRAY_TYPE);
/* Do not hash size, so complete and incomplete types can match. */
sem_item::add_type (TREE_TYPE (type), hstate);
}
else if (RECORD_OR_UNION_TYPE_P (type))
{
hashval_t *val = optimizer->m_type_hash_cache.get (type);
if (!val)
{
inchash::hash hstate2;
unsigned nf;
tree f;
hashval_t hash;
hstate2.add_int (RECORD_TYPE);
gcc_assert (COMPLETE_TYPE_P (type));
for (f = TYPE_FIELDS (type), nf = 0; f; f = TREE_CHAIN (f))
if (TREE_CODE (f) == FIELD_DECL)
{
add_type (TREE_TYPE (f), hstate2);
nf++;
}
hstate2.add_int (nf);
hash = hstate2.end ();
hstate.add_wide_int (hash);
optimizer->m_type_hash_cache.put (type, hash);
}
else
hstate.add_wide_int (*val);
}
}
/* Improve accumulated hash for HSTATE based on a gimple statement STMT. */ /* Improve accumulated hash for HSTATE based on a gimple statement STMT. */
void void
...@@ -1294,16 +1388,27 @@ sem_function::hash_stmt (gimple stmt, inchash::hash &hstate) ...@@ -1294,16 +1388,27 @@ sem_function::hash_stmt (gimple stmt, inchash::hash &hstate)
switch (code) switch (code)
{ {
case GIMPLE_SWITCH:
add_expr (gimple_switch_index (as_a <gswitch *> (stmt)), hstate);
break;
case GIMPLE_ASSIGN: case GIMPLE_ASSIGN:
hstate.add_int (gimple_assign_rhs_code (stmt));
if (commutative_tree_code (gimple_assign_rhs_code (stmt)) if (commutative_tree_code (gimple_assign_rhs_code (stmt))
|| commutative_ternary_tree_code (gimple_assign_rhs_code (stmt))) || commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
{ {
inchash::hash one, two; inchash::hash one, two;
add_expr (gimple_assign_rhs1 (stmt), one); add_expr (gimple_assign_rhs1 (stmt), one);
add_type (TREE_TYPE (gimple_assign_rhs1 (stmt)), one);
add_expr (gimple_assign_rhs2 (stmt), two); add_expr (gimple_assign_rhs2 (stmt), two);
hstate.add_commutative (one, two); hstate.add_commutative (one, two);
if (commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
{
add_expr (gimple_assign_rhs3 (stmt), hstate);
add_type (TREE_TYPE (gimple_assign_rhs3 (stmt)), hstate);
}
add_expr (gimple_assign_lhs (stmt), hstate); add_expr (gimple_assign_lhs (stmt), hstate);
add_type (TREE_TYPE (gimple_assign_lhs (stmt)), two);
break; break;
} }
/* ... fall through ... */ /* ... fall through ... */
...@@ -1314,7 +1419,11 @@ sem_function::hash_stmt (gimple stmt, inchash::hash &hstate) ...@@ -1314,7 +1419,11 @@ sem_function::hash_stmt (gimple stmt, inchash::hash &hstate)
case GIMPLE_RETURN: case GIMPLE_RETURN:
/* All these statements are equivalent if their operands are. */ /* All these statements are equivalent if their operands are. */
for (unsigned i = 0; i < gimple_num_ops (stmt); ++i) for (unsigned i = 0; i < gimple_num_ops (stmt); ++i)
{
add_expr (gimple_op (stmt, i), hstate); add_expr (gimple_op (stmt, i), hstate);
if (gimple_op (stmt, i))
add_type (TREE_TYPE (gimple_op (stmt, i)), hstate);
}
default: default:
break; break;
} }
...@@ -1328,14 +1437,13 @@ sem_function::compare_polymorphic_p (void) ...@@ -1328,14 +1437,13 @@ sem_function::compare_polymorphic_p (void)
{ {
struct cgraph_edge *e; struct cgraph_edge *e;
if (!opt_for_fn (decl, flag_devirtualize)) if (!opt_for_fn (get_node ()->decl, flag_devirtualize))
return false; return false;
if (get_node ()->indirect_calls != NULL if (get_node ()->indirect_calls != NULL)
|| m_compared_func->get_node ()->indirect_calls != NULL)
return true; return true;
/* TODO: We can do simple propagation determining what calls may lead to /* TODO: We can do simple propagation determining what calls may lead to
a polymorphic call. */ a polymorphic call. */
for (e = m_compared_func->get_node ()->callees; e; e = e->next_callee) for (e = get_node ()->callees; e; e = e->next_callee)
if (e->callee->definition if (e->callee->definition
&& opt_for_fn (e->callee->decl, flag_devirtualize)) && opt_for_fn (e->callee->decl, flag_devirtualize))
return true; return true;
...@@ -2386,9 +2494,38 @@ sem_item_optimizer::add_item_to_class (congruence_class *cls, sem_item *item) ...@@ -2386,9 +2494,38 @@ sem_item_optimizer::add_item_to_class (congruence_class *cls, sem_item *item)
void void
sem_item_optimizer::update_hash_by_addr_refs () sem_item_optimizer::update_hash_by_addr_refs ()
{ {
/* First, append to hash sensitive references. */ /* First, append to hash sensitive references and class type if it need to
be matched for ODR. */
for (unsigned i = 0; i < m_items.length (); i++) for (unsigned i = 0; i < m_items.length (); i++)
{
m_items[i]->update_hash_by_addr_refs (m_symtab_node_map); m_items[i]->update_hash_by_addr_refs (m_symtab_node_map);
if (m_items[i]->type == FUNC)
{
if (TREE_CODE (TREE_TYPE (m_items[i]->decl)) == METHOD_TYPE
&& contains_polymorphic_type_p
(method_class_type (TREE_TYPE (m_items[i]->decl)))
&& (DECL_CXX_CONSTRUCTOR_P (m_items[i]->decl)
|| ((!flag_ipa_cp
|| ipa_is_param_used (
IPA_NODE_REF
(dyn_cast <cgraph_node *>(m_items[i]->node)), 0))
&& static_cast<sem_function *> (m_items[i])
->compare_polymorphic_p ())))
{
tree class_type
= method_class_type (TREE_TYPE (m_items[i]->decl));
inchash::hash hstate (m_items[i]->hash);
if (TYPE_NAME (class_type)
&& DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (class_type)))
hstate.add_wide_int
(IDENTIFIER_HASH_VALUE
(DECL_ASSEMBLER_NAME (TYPE_NAME (class_type))));
m_items[i]->hash = hstate.end ();
}
}
}
/* Once all symbols have enhanced hash value, we can append /* Once all symbols have enhanced hash value, we can append
hash values of symbols that are seen by IPA ICF and are hash values of symbols that are seen by IPA ICF and are
...@@ -3123,11 +3260,6 @@ congruence_class::is_class_used (void) ...@@ -3123,11 +3260,6 @@ congruence_class::is_class_used (void)
return false; return false;
} }
/* Initialization and computation of symtab node hash, there data
are propagated later on. */
static sem_item_optimizer *optimizer = NULL;
/* Generate pass summary for IPA ICF pass. */ /* Generate pass summary for IPA ICF pass. */
static void static void
......
...@@ -96,12 +96,12 @@ struct symbol_compare_hashmap_traits: default_hashmap_traits ...@@ -96,12 +96,12 @@ struct symbol_compare_hashmap_traits: default_hashmap_traits
hstate.add_int (v->m_references.length ()); hstate.add_int (v->m_references.length ());
for (unsigned i = 0; i < v->m_references.length (); i++) for (unsigned i = 0; i < v->m_references.length (); i++)
hstate.add_ptr (v->m_references[i]->ultimate_alias_target ()); hstate.add_int (v->m_references[i]->ultimate_alias_target ()->order);
hstate.add_int (v->m_interposables.length ()); hstate.add_int (v->m_interposables.length ());
for (unsigned i = 0; i < v->m_interposables.length (); i++) for (unsigned i = 0; i < v->m_interposables.length (); i++)
hstate.add_ptr (v->m_interposables[i]->ultimate_alias_target ()); hstate.add_int (v->m_interposables[i]->ultimate_alias_target ()->order);
return hstate.end (); return hstate.end ();
} }
...@@ -243,8 +243,10 @@ public: ...@@ -243,8 +243,10 @@ public:
protected: protected:
/* Cached, once calculated hash for the item. */ /* Cached, once calculated hash for the item. */
/* Accumulate to HSTATE a hash of constructor expression EXP. */ /* Accumulate to HSTATE a hash of expression EXP. */
static void add_expr (const_tree exp, inchash::hash &hstate); static void add_expr (const_tree exp, inchash::hash &hstate);
/* Accumulate to HSTATE a hash of type T. */
static void add_type (const_tree t, inchash::hash &hstate);
/* For a given symbol table nodes N1 and N2, we check that FUNCTION_DECLs /* 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 point to a same function. Comparison can be skipped if IGNORED_NODES
...@@ -505,6 +507,8 @@ public: ...@@ -505,6 +507,8 @@ public:
congruence_class_group *get_group_by_hash (hashval_t hash, congruence_class_group *get_group_by_hash (hashval_t hash,
sem_item_type type); sem_item_type type);
/* Because types can be arbitrarily large, avoid quadratic bottleneck. */
hash_map<const_tree, hashval_t> m_type_hash_cache;
private: private:
/* For each semantic item, append hash values of references. */ /* For each semantic item, append hash values of references. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment