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>
* 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
bail out reason.
(func_checker::compare_gimple_assign): Likewise.
......@@ -121,6 +121,16 @@ public:
class func_checker : operand_compare
{
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
TARGET_FUNC_DECL. Strict polymorphic comparison is processed if
an option COMPARE_POLYMORPHIC is true. For special cases, one can
......@@ -254,6 +264,7 @@ private:
/* Flag if ignore labels in comparison. */
bool m_ignore_labels;
public:
/* Return true if two operands are equal. The flags fields can be used
to specify OEP flags described above. */
virtual bool operand_equal_p (const_tree, const_tree, unsigned int flags);
......
......@@ -1335,8 +1335,9 @@ sem_function::merge (sem_item *alias_item)
/* Semantic item initialization function. */
void
sem_function::init (void)
sem_function::init (ipa_icf_gimple::func_checker *checker)
{
m_checker = checker;
if (in_lto_p)
get_node ()->get_untransformed_body ();
......@@ -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. */
void
......@@ -1578,27 +1424,19 @@ sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate)
switch (code)
{
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;
case GIMPLE_ASSIGN:
hstate.add_int (gimple_assign_rhs_code (stmt));
if (commutative_tree_code (gimple_assign_rhs_code (stmt))
|| commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
{
inchash::hash one, two;
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);
m_checker->hash_operand (gimple_assign_rhs1 (stmt), hstate, 0);
m_checker->hash_operand (gimple_assign_rhs2 (stmt), hstate, 0);
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_type (TREE_TYPE (gimple_assign_lhs (stmt)), two);
break;
m_checker->hash_operand (gimple_assign_rhs3 (stmt), hstate, 0);
m_checker->hash_operand (gimple_assign_lhs (stmt), hstate, 0);
}
/* fall through */
case GIMPLE_CALL:
......@@ -1608,11 +1446,7 @@ sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate)
case GIMPLE_RETURN:
/* All these statements are equivalent if their operands are. */
for (unsigned i = 0; i < gimple_num_ops (stmt); ++i)
{
add_expr (gimple_op (stmt, i), hstate);
if (gimple_op (stmt, i))
add_type (TREE_TYPE (gimple_op (stmt, i)), hstate);
}
m_checker->hash_operand (gimple_op (stmt, i), hstate, 0);
/* Consider nocf_check attribute in hash as it affects code
generation. */
if (code == GIMPLE_CALL
......@@ -1648,7 +1482,8 @@ sem_function::compare_polymorphic_p (void)
semantic function item. */
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;
function *func = DECL_STRUCT_FUNCTION (fndecl);
......@@ -1669,8 +1504,7 @@ sem_function::parse (cgraph_node *node, bitmap_obstack *stack)
return NULL;
sem_function *f = new sem_function (node, stack);
f->init ();
f->init (checker);
return f;
}
......@@ -2038,40 +1872,45 @@ sem_variable::equals (tree t1, tree t2)
/* Parser function that visits a varpool NODE. */
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)
|| node->alias)
return NULL;
sem_variable *v = new sem_variable (node, stack);
v->init ();
v->init (checker);
return v;
}
/* References independent hash function. */
/* Semantic variable initialization function. */
hashval_t
sem_variable::get_hash (void)
void
sem_variable::init (ipa_icf_gimple::func_checker *checker)
{
if (m_hash_set)
return m_hash;
decl = get_node ()->decl;
/* 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.
DECL_INITIAL (decl) would be error_mark_node in that case. */
gcc_assert (!node->lto_file_data);
tree ctor = DECL_INITIAL (decl);
inchash::hash hstate;
if (!m_hash_set)
{
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);
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 ());
/* References independent hash function. */
hashval_t
sem_variable::get_hash (void)
{
gcc_checking_assert (m_hash_set);
return m_hash;
}
......@@ -2590,10 +2429,13 @@ sem_item_optimizer::parse_funcs_and_vars (void)
{
cgraph_node *cnode;
/* Create dummy func_checker for hashing purpose. */
func_checker checker;
if (flag_ipa_icf_functions)
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)
{
m_items.safe_push (f);
......@@ -2606,7 +2448,7 @@ sem_item_optimizer::parse_funcs_and_vars (void)
if (flag_ipa_icf_variables)
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)
{
......@@ -2750,10 +2592,13 @@ sem_item_optimizer::parse_nonsingleton_classes (void)
{
unsigned int counter = 0;
/* Create dummy func_checker for hashing purpose. */
func_checker checker;
for (unsigned i = 0; i < m_items.length (); i++)
if (m_items[i]->cls->members.length () > 1)
{
m_items[i]->init ();
m_items[i]->init (&checker);
++counter;
}
......
......@@ -191,7 +191,7 @@ public:
DEBUG_FUNCTION void dump (void);
/* Semantic item initialization function. */
virtual void init (void) = 0;
virtual void init (ipa_icf_gimple::func_checker *) = 0;
/* Add reference to a semantic TARGET. */
void add_reference (ref_map *map, sem_item *target);
......@@ -269,11 +269,6 @@ public:
protected:
/* 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
itself but affects semantics of its references.
If ADDRESS is true, do extra checking needed for IPA_REF_ADDR. */
......@@ -322,7 +317,7 @@ public:
~sem_function ();
virtual void init (void);
virtual void init (ipa_icf_gimple::func_checker *);
virtual bool equals_wpa (sem_item *item,
hash_map <symtab_node *, sem_item *> &ignored_nodes);
virtual hashval_t get_hash (void);
......@@ -351,7 +346,8 @@ public:
/* For a given call graph NODE, the function constructs new
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
paramters. */
......@@ -423,10 +419,7 @@ public:
sem_variable (varpool_node *_node, bitmap_obstack *stack);
/* Semantic variable initialization function. */
inline virtual void init (void)
{
decl = get_node ()->decl;
}
virtual void init (ipa_icf_gimple::func_checker *);
virtual hashval_t get_hash (void);
virtual bool merge (sem_item *alias_item);
......@@ -445,7 +438,8 @@ public:
}
/* 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:
/* 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