/* 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 ();
}
}
-/* 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
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:
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
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);
return NULL;
sem_function *f = new sem_function (node, stack);
-
- f->init ();
+ f->init (checker);
return f;
}
/* 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;
}
{
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);
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)
{
{
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;
}
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);
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. */
~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);
/* 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. */
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);
}
/* 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. */