Commit a37f58f5 by Martin Liska Committed by Martin Liska

Use func_checker::hash_operand for hashing of GIMPLE operands.

2019-11-14  Martin Liska  <mliska@suse.cz>

	* ipa-icf-gimple.h (func_checker::func_checker): Add
	default constructor.
	* ipa-icf.c (sem_function::init): Make operand_equal_p
	and hash_operand public.
	(sem_item::add_expr): Remove.
	(sem_item::add_type): Remove.
	(sem_function::hash_stmt): Use m_checker for hashing
	of GIMPLE statements.
	(sem_function::parse): Init with checker.
	(sem_variable::parse): Pass NULL as checker.
	(sem_item_optimizer::parse_funcs_and_vars):
	Pass checker to ::parse function.
	(sem_item_optimizer::parse_nonsingleton_classes): Likewise.
	(sem_variable::parse): New function.
	(sem_variable::get_hash): Only return computed hash value.
	(sem_variable::init): Initialize hash of a variable.
	* ipa-icf.h: Remove add_expr, add_type and add func_checker
	to couple of functions as a new argument.

From-SVN: r278207
parent 5d0152bf
2019-11-14 Martin Liska <mliska@suse.cz> 2019-11-14 Martin Liska <mliska@suse.cz>
* ipa-icf-gimple.h (func_checker::func_checker): Add
default constructor.
* ipa-icf.c (sem_function::init): Make operand_equal_p
and hash_operand public.
(sem_item::add_expr): Remove.
(sem_item::add_type): Remove.
(sem_function::hash_stmt): Use m_checker for hashing
of GIMPLE statements.
(sem_function::parse): Init with checker.
(sem_variable::parse): Pass NULL as checker.
(sem_item_optimizer::parse_funcs_and_vars):
Pass checker to ::parse function.
(sem_item_optimizer::parse_nonsingleton_classes): Likewise.
(sem_variable::parse): New function.
(sem_variable::get_hash): Only return computed hash value.
(sem_variable::init): Initialize hash of a variable.
* ipa-icf.h: Remove add_expr, add_type and add func_checker
to couple of functions as a new argument.
2019-11-14 Martin Liska <mliska@suse.cz>
* ipa-icf-gimple.c (func_checker::compare_gimple_call): Update * ipa-icf-gimple.c (func_checker::compare_gimple_call): Update
bail out reason. bail out reason.
(func_checker::compare_gimple_assign): Likewise. (func_checker::compare_gimple_assign): Likewise.
...@@ -121,6 +121,16 @@ public: ...@@ -121,6 +121,16 @@ public:
class func_checker : operand_compare class func_checker : operand_compare
{ {
public: public:
/* Default constructor. */
func_checker ():
m_source_func_decl (NULL_TREE), m_target_func_decl (NULL_TREE),
m_ignored_source_nodes (NULL), m_ignored_target_nodes (NULL),
m_ignore_labels (false)
{
m_source_ssa_names.create (0);
m_target_ssa_names.create (0);
}
/* Initialize internal structures for a given SOURCE_FUNC_DECL and /* Initialize internal structures for a given SOURCE_FUNC_DECL and
TARGET_FUNC_DECL. Strict polymorphic comparison is processed if TARGET_FUNC_DECL. Strict polymorphic comparison is processed if
an option COMPARE_POLYMORPHIC is true. For special cases, one can an option COMPARE_POLYMORPHIC is true. For special cases, one can
...@@ -254,6 +264,7 @@ private: ...@@ -254,6 +264,7 @@ private:
/* Flag if ignore labels in comparison. */ /* Flag if ignore labels in comparison. */
bool m_ignore_labels; bool m_ignore_labels;
public:
/* Return true if two operands are equal. The flags fields can be used /* Return true if two operands are equal. The flags fields can be used
to specify OEP flags described above. */ to specify OEP flags described above. */
virtual bool operand_equal_p (const_tree, const_tree, unsigned int flags); virtual bool operand_equal_p (const_tree, const_tree, unsigned int flags);
......
...@@ -1335,8 +1335,9 @@ sem_function::merge (sem_item *alias_item) ...@@ -1335,8 +1335,9 @@ sem_function::merge (sem_item *alias_item)
/* Semantic item initialization function. */ /* Semantic item initialization function. */
void void
sem_function::init (void) sem_function::init (ipa_icf_gimple::func_checker *checker)
{ {
m_checker = checker;
if (in_lto_p) if (in_lto_p)
get_node ()->get_untransformed_body (); get_node ()->get_untransformed_body ();
...@@ -1411,161 +1412,6 @@ sem_function::init (void) ...@@ -1411,161 +1412,6 @@ sem_function::init (void)
} }
} }
/* Accumulate to HSTATE a hash of expression EXP.
Identical to inchash::add_expr, but guaranteed to be stable across LTO
and DECL equality classes. */
void
sem_item::add_expr (const_tree exp, inchash::hash &hstate)
{
if (exp == NULL_TREE)
{
hstate.merge_hash (0);
return;
}
/* Handled component can be matched in a cureful way proving equivalence
even if they syntactically differ. Just skip them. */
STRIP_NOPS (exp);
while (handled_component_p (exp))
exp = TREE_OPERAND (exp, 0);
enum tree_code code = TREE_CODE (exp);
hstate.add_int (code);
switch (code)
{
/* Use inchash::add_expr for everything that is LTO stable. */
case VOID_CST:
case INTEGER_CST:
case REAL_CST:
case FIXED_CST:
case STRING_CST:
case COMPLEX_CST:
case VECTOR_CST:
inchash::add_expr (exp, hstate);
break;
case CONSTRUCTOR:
{
unsigned HOST_WIDE_INT idx;
tree value;
hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
if (value)
add_expr (value, hstate);
break;
}
case ADDR_EXPR:
case FDESC_EXPR:
add_expr (get_base_address (TREE_OPERAND (exp, 0)), hstate);
break;
case SSA_NAME:
case VAR_DECL:
case CONST_DECL:
case PARM_DECL:
hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
break;
case MEM_REF:
case POINTER_PLUS_EXPR:
case MINUS_EXPR:
case RANGE_EXPR:
add_expr (TREE_OPERAND (exp, 0), hstate);
add_expr (TREE_OPERAND (exp, 1), hstate);
break;
case PLUS_EXPR:
{
inchash::hash one, two;
add_expr (TREE_OPERAND (exp, 0), one);
add_expr (TREE_OPERAND (exp, 1), two);
hstate.add_commutative (one, two);
}
break;
CASE_CONVERT:
hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
return add_expr (TREE_OPERAND (exp, 0), hstate);
default:
break;
}
}
/* 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);
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))
{
/* Incomplete types must be skipped here. */
if (!COMPLETE_TYPE_P (type))
{
hstate.add_int (RECORD_TYPE);
return;
}
hashval_t *val = m_type_hash_cache.get (type);
if (!val)
{
inchash::hash hstate2;
unsigned nf;
tree f;
hashval_t hash;
hstate2.add_int (RECORD_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_hwi (hash);
m_type_hash_cache.put (type, hash);
}
else
hstate.add_hwi (*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
...@@ -1578,27 +1424,19 @@ sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate) ...@@ -1578,27 +1424,19 @@ sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate)
switch (code) switch (code)
{ {
case GIMPLE_SWITCH: case GIMPLE_SWITCH:
add_expr (gimple_switch_index (as_a <gswitch *> (stmt)), hstate); m_checker->hash_operand (gimple_switch_index (as_a <gswitch *> (stmt)),
hstate, 0);
break; break;
case GIMPLE_ASSIGN: case GIMPLE_ASSIGN:
hstate.add_int (gimple_assign_rhs_code (stmt)); 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; m_checker->hash_operand (gimple_assign_rhs1 (stmt), hstate, 0);
m_checker->hash_operand (gimple_assign_rhs2 (stmt), hstate, 0);
add_expr (gimple_assign_rhs1 (stmt), one);
add_type (TREE_TYPE (gimple_assign_rhs1 (stmt)), one);
add_expr (gimple_assign_rhs2 (stmt), two);
hstate.add_commutative (one, two);
if (commutative_ternary_tree_code (gimple_assign_rhs_code (stmt))) if (commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
{ m_checker->hash_operand (gimple_assign_rhs3 (stmt), hstate, 0);
add_expr (gimple_assign_rhs3 (stmt), hstate); m_checker->hash_operand (gimple_assign_lhs (stmt), hstate, 0);
add_type (TREE_TYPE (gimple_assign_rhs3 (stmt)), hstate);
}
add_expr (gimple_assign_lhs (stmt), hstate);
add_type (TREE_TYPE (gimple_assign_lhs (stmt)), two);
break;
} }
/* fall through */ /* fall through */
case GIMPLE_CALL: case GIMPLE_CALL:
...@@ -1608,11 +1446,7 @@ sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate) ...@@ -1608,11 +1446,7 @@ 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)
{ m_checker->hash_operand (gimple_op (stmt, i), hstate, 0);
add_expr (gimple_op (stmt, i), hstate);
if (gimple_op (stmt, i))
add_type (TREE_TYPE (gimple_op (stmt, i)), hstate);
}
/* Consider nocf_check attribute in hash as it affects code /* Consider nocf_check attribute in hash as it affects code
generation. */ generation. */
if (code == GIMPLE_CALL if (code == GIMPLE_CALL
...@@ -1648,7 +1482,8 @@ sem_function::compare_polymorphic_p (void) ...@@ -1648,7 +1482,8 @@ sem_function::compare_polymorphic_p (void)
semantic function item. */ semantic function item. */
sem_function * sem_function *
sem_function::parse (cgraph_node *node, bitmap_obstack *stack) sem_function::parse (cgraph_node *node, bitmap_obstack *stack,
func_checker *checker)
{ {
tree fndecl = node->decl; tree fndecl = node->decl;
function *func = DECL_STRUCT_FUNCTION (fndecl); function *func = DECL_STRUCT_FUNCTION (fndecl);
...@@ -1669,8 +1504,7 @@ sem_function::parse (cgraph_node *node, bitmap_obstack *stack) ...@@ -1669,8 +1504,7 @@ sem_function::parse (cgraph_node *node, bitmap_obstack *stack)
return NULL; return NULL;
sem_function *f = new sem_function (node, stack); sem_function *f = new sem_function (node, stack);
f->init (checker);
f->init ();
return f; return f;
} }
...@@ -2038,40 +1872,45 @@ sem_variable::equals (tree t1, tree t2) ...@@ -2038,40 +1872,45 @@ sem_variable::equals (tree t1, tree t2)
/* Parser function that visits a varpool NODE. */ /* Parser function that visits a varpool NODE. */
sem_variable * sem_variable *
sem_variable::parse (varpool_node *node, bitmap_obstack *stack) sem_variable::parse (varpool_node *node, bitmap_obstack *stack,
func_checker *checker)
{ {
if (TREE_THIS_VOLATILE (node->decl) || DECL_HARD_REGISTER (node->decl) if (TREE_THIS_VOLATILE (node->decl) || DECL_HARD_REGISTER (node->decl)
|| node->alias) || node->alias)
return NULL; return NULL;
sem_variable *v = new sem_variable (node, stack); sem_variable *v = new sem_variable (node, stack);
v->init (checker);
v->init ();
return v; return v;
} }
/* References independent hash function. */ /* Semantic variable initialization function. */
hashval_t void
sem_variable::get_hash (void) sem_variable::init (ipa_icf_gimple::func_checker *checker)
{ {
if (m_hash_set) decl = get_node ()->decl;
return m_hash;
/* All WPA streamed in symbols should have their hashes computed at compile /* All WPA streamed in symbols should have their hashes computed at compile
time. At this point, the constructor may not be in memory at all. time. At this point, the constructor may not be in memory at all.
DECL_INITIAL (decl) would be error_mark_node in that case. */ DECL_INITIAL (decl) would be error_mark_node in that case. */
gcc_assert (!node->lto_file_data); if (!m_hash_set)
tree ctor = DECL_INITIAL (decl); {
inchash::hash hstate; gcc_assert (!node->lto_file_data);
inchash::hash hstate;
hstate.add_int (456346417);
checker->hash_operand (DECL_INITIAL (decl), hstate, 0);
set_hash (hstate.end ());
}
}
hstate.add_int (456346417); /* References independent hash function. */
if (DECL_SIZE (decl) && tree_fits_shwi_p (DECL_SIZE (decl)))
hstate.add_hwi (tree_to_shwi (DECL_SIZE (decl)));
add_expr (ctor, hstate);
set_hash (hstate.end ());
hashval_t
sem_variable::get_hash (void)
{
gcc_checking_assert (m_hash_set);
return m_hash; return m_hash;
} }
...@@ -2590,10 +2429,13 @@ sem_item_optimizer::parse_funcs_and_vars (void) ...@@ -2590,10 +2429,13 @@ sem_item_optimizer::parse_funcs_and_vars (void)
{ {
cgraph_node *cnode; cgraph_node *cnode;
/* Create dummy func_checker for hashing purpose. */
func_checker checker;
if (flag_ipa_icf_functions) if (flag_ipa_icf_functions)
FOR_EACH_DEFINED_FUNCTION (cnode) FOR_EACH_DEFINED_FUNCTION (cnode)
{ {
sem_function *f = sem_function::parse (cnode, &m_bmstack); sem_function *f = sem_function::parse (cnode, &m_bmstack, &checker);
if (f) if (f)
{ {
m_items.safe_push (f); m_items.safe_push (f);
...@@ -2606,7 +2448,7 @@ sem_item_optimizer::parse_funcs_and_vars (void) ...@@ -2606,7 +2448,7 @@ sem_item_optimizer::parse_funcs_and_vars (void)
if (flag_ipa_icf_variables) if (flag_ipa_icf_variables)
FOR_EACH_DEFINED_VARIABLE (vnode) FOR_EACH_DEFINED_VARIABLE (vnode)
{ {
sem_variable *v = sem_variable::parse (vnode, &m_bmstack); sem_variable *v = sem_variable::parse (vnode, &m_bmstack, &checker);
if (v) if (v)
{ {
...@@ -2750,10 +2592,13 @@ sem_item_optimizer::parse_nonsingleton_classes (void) ...@@ -2750,10 +2592,13 @@ sem_item_optimizer::parse_nonsingleton_classes (void)
{ {
unsigned int counter = 0; unsigned int counter = 0;
/* Create dummy func_checker for hashing purpose. */
func_checker checker;
for (unsigned i = 0; i < m_items.length (); i++) for (unsigned i = 0; i < m_items.length (); i++)
if (m_items[i]->cls->members.length () > 1) if (m_items[i]->cls->members.length () > 1)
{ {
m_items[i]->init (); m_items[i]->init (&checker);
++counter; ++counter;
} }
......
...@@ -191,7 +191,7 @@ public: ...@@ -191,7 +191,7 @@ public:
DEBUG_FUNCTION void dump (void); DEBUG_FUNCTION void dump (void);
/* Semantic item initialization function. */ /* Semantic item initialization function. */
virtual void init (void) = 0; virtual void init (ipa_icf_gimple::func_checker *) = 0;
/* Add reference to a semantic TARGET. */ /* Add reference to a semantic TARGET. */
void add_reference (ref_map *map, sem_item *target); void add_reference (ref_map *map, sem_item *target);
...@@ -269,11 +269,6 @@ public: ...@@ -269,11 +269,6 @@ public:
protected: protected:
/* Cached, once calculated hash for the item. */ /* Cached, once calculated hash for the item. */
/* Accumulate to HSTATE a hash of expression EXP. */
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);
/* Compare properties of symbol that does not affect semantics of symbol /* Compare properties of symbol that does not affect semantics of symbol
itself but affects semantics of its references. itself but affects semantics of its references.
If ADDRESS is true, do extra checking needed for IPA_REF_ADDR. */ If ADDRESS is true, do extra checking needed for IPA_REF_ADDR. */
...@@ -322,7 +317,7 @@ public: ...@@ -322,7 +317,7 @@ public:
~sem_function (); ~sem_function ();
virtual void init (void); virtual void init (ipa_icf_gimple::func_checker *);
virtual bool equals_wpa (sem_item *item, virtual bool equals_wpa (sem_item *item,
hash_map <symtab_node *, sem_item *> &ignored_nodes); hash_map <symtab_node *, sem_item *> &ignored_nodes);
virtual hashval_t get_hash (void); virtual hashval_t get_hash (void);
...@@ -351,7 +346,8 @@ public: ...@@ -351,7 +346,8 @@ public:
/* For a given call graph NODE, the function constructs new /* For a given call graph NODE, the function constructs new
semantic function item. */ semantic function item. */
static sem_function *parse (cgraph_node *node, bitmap_obstack *stack); static sem_function *parse (cgraph_node *node, bitmap_obstack *stack,
ipa_icf_gimple::func_checker *checker);
/* Perform additional checks needed to match types of used function /* Perform additional checks needed to match types of used function
paramters. */ paramters. */
...@@ -423,10 +419,7 @@ public: ...@@ -423,10 +419,7 @@ public:
sem_variable (varpool_node *_node, bitmap_obstack *stack); sem_variable (varpool_node *_node, bitmap_obstack *stack);
/* Semantic variable initialization function. */ /* Semantic variable initialization function. */
inline virtual void init (void) virtual void init (ipa_icf_gimple::func_checker *);
{
decl = get_node ()->decl;
}
virtual hashval_t get_hash (void); virtual hashval_t get_hash (void);
virtual bool merge (sem_item *alias_item); virtual bool merge (sem_item *alias_item);
...@@ -445,7 +438,8 @@ public: ...@@ -445,7 +438,8 @@ public:
} }
/* Parser function that visits a varpool NODE. */ /* Parser function that visits a varpool NODE. */
static sem_variable *parse (varpool_node *node, bitmap_obstack *stack); static sem_variable *parse (varpool_node *node, bitmap_obstack *stack,
ipa_icf_gimple::func_checker *checker);
private: private:
/* Compares trees T1 and T2 for semantic equality. */ /* Compares trees T1 and T2 for semantic equality. */
......
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