===================================================================
@@ -389,33 +389,79 @@ sem_function::equals_wpa (sem_item *item
m_compared_func = static_cast<sem_function *> (item);
- if (arg_types.length () != m_compared_func->arg_types.length ())
- return return_false_with_msg ("different number of arguments");
+ /* This is quite time ciritical, cheap checks first. */
- /* Checking types of arguments. */
- for (unsigned i = 0; i < arg_types.length (); i++)
- {
- /* This guard is here for function pointer with attributes (pr59927.c). */
- if (!arg_types[i] || !m_compared_func->arg_types[i])
- return return_false_with_msg ("NULL argument type");
+ if (node->num_references () != item->node->num_references ())
+ return return_false_with_msg ("different number of references");
- /* Polymorphic comparison is executed just for non-leaf functions. */
- bool is_not_leaf = get_node ()->callees != NULL
- || get_node ()->indirect_calls != NULL;
+ if (DECL_DISREGARD_INLINE_LIMITS (decl)
+ != DECL_DISREGARD_INLINE_LIMITS (item->decl))
+ return return_false_with_msg ("DECL_DISREGARD_INLINE_LIMITS are different");
- if (!func_checker::compatible_types_p (arg_types[i],
- m_compared_func->arg_types[i],
- is_not_leaf, i == 0))
- return return_false_with_msg ("argument type is 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 "
+ "attributes are different");
+
+ if (DECL_NO_LIMIT_STACK (decl) != DECL_NO_LIMIT_STACK (item->decl))
+ return return_false_with_msg ("no stack limit attributes are different");
+
+ /* Compare special function DECL attributes. */
+ if (DECL_FUNCTION_PERSONALITY (decl)
+ != DECL_FUNCTION_PERSONALITY (item->decl))
+ return return_false_with_msg ("function personalities are different");
+
+ 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");
/* Result type checking. */
if (!func_checker::compatible_types_p (result_type,
m_compared_func->result_type))
return return_false_with_msg ("result types are different");
- if (node->num_references () != item->node->num_references ())
- return return_false_with_msg ("different number of references");
+ /* Checking function TARGET and OPTIMIZATION flags. */
+ cl_target_option *tar1 = target_opts_for_fn (decl);
+ cl_target_option *tar2 = target_opts_for_fn (item->decl);
+
+ if (tar1 != tar2 && !cl_target_option_eq (tar1, tar2))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "target flags difference");
+ cl_target_option_print_diff (dump_file, 2, tar1, tar2);
+ }
+
+ return return_false_with_msg ("Target flags are different");
+ }
+
+ cl_optimization *opt1 = opts_for_fn (decl);
+ cl_optimization *opt2 = opts_for_fn (item->decl);
+
+ if (opt1 != opt2 && memcmp (opt1, opt2, sizeof(cl_optimization)))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "optimization flags difference");
+ cl_optimization_print_diff (dump_file, 2, opt1, opt2);
+ }
+
+ return return_false_with_msg ("optimization flags are different");
+ }
+
+ /* Checking function attributes.
+ This is quadratic in number of attributes */
+ if (!comp_attributes (DECL_ATTRIBUTES (decl),
+ DECL_ATTRIBUTES (item->decl)))
+ return return_false ();
+ if (comp_type_attributes (TREE_TYPE (decl),
+ TREE_TYPE (item->decl)) != 1)
+ return return_false ();
ipa_ref *ref = NULL, *ref2 = NULL;
for (unsigned i = 0; node->iterate_reference (i, ref); i++)
@@ -424,7 +470,8 @@ sem_function::equals_wpa (sem_item *item
if (!compare_cgraph_references (ignored_nodes, ref->referred,
ref2->referred,
- ref->address_matters_p ()))
+ ref->address_matters_p ()
+ || ref2->address_matters_p ()))
return false;
}
@@ -471,11 +518,57 @@ sem_function::equals (sem_item *item,
return eq;
}
+/* Return ture if A1 and A2 represent equivalent function attribute lists.
+ Based on comp_type_attributes. */
+
+bool
+sem_function::comp_attributes (const_tree a1, const_tree a2)
+{
+ const_tree a;
+ if (a1 == a2)
+ return true;
+ for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
+ {
+ const struct attribute_spec *as;
+ const_tree attr;
+
+ as = lookup_attribute_spec (get_attribute_name (a));
+ if (!as || as->affects_type_identity == false)
+ continue;
+
+ attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
+ if (!attr || !attribute_value_equal (a, attr))
+ break;
+ }
+ if (!a)
+ {
+ for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
+ {
+ const struct attribute_spec *as;
+
+ as = lookup_attribute_spec (get_attribute_name (a));
+ if (!as || as->affects_type_identity == false)
+ continue;
+
+ if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
+ break;
+ /* We don't need to compare trees again, as we did this
+ already in first loop. */
+ }
+ /* All types - affecting identity - are equal, so
+ there is no need to call target hook for comparison. */
+ if (!a)
+ return true;
+ }
+ return false;
+}
+
/* Processes function equality comparison. */
bool
sem_function::equals_private (sem_item *item,
- hash_map <symtab_node *, sem_item *> &ignored_nodes)
+ hash_map <symtab_node *, sem_item *>
+ &ignored_nodes ATTRIBUTE_UNUSED)
{
if (item->type != FUNC)
return false;
@@ -484,7 +577,6 @@ sem_function::equals_private (sem_item *
edge e1, e2;
edge_iterator ei1, ei2;
bool result = true;
- tree arg1, arg2;
m_compared_func = static_cast<sem_function *> (item);
@@ -495,93 +587,39 @@ sem_function::equals_private (sem_item *
|| cfg_checksum != m_compared_func->cfg_checksum)
return return_false ();
- if (!equals_wpa (item, ignored_nodes))
- return false;
+#ifdef ENABLE_CHECKING
+ gcc_assert (equals_wpa (item, ignored_nodes));
+#endif
- /* Checking function TARGET and OPTIMIZATION flags. */
- cl_target_option *tar1 = target_opts_for_fn (decl);
- cl_target_option *tar2 = target_opts_for_fn (m_compared_func->decl);
+ if (arg_types.length () != m_compared_func->arg_types.length ())
+ return return_false_with_msg ("different number of arguments");
- if (tar1 != NULL && tar2 != NULL)
+ /* Checking types of arguments. */
+ for (unsigned i = 0; i < arg_types.length (); i++)
{
- if (!cl_target_option_eq (tar1, tar2))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "target flags difference");
- cl_target_option_print_diff (dump_file, 2, tar1, tar2);
- }
-
- return return_false_with_msg ("Target flags are different");
- }
- }
- else if (tar1 != NULL || tar2 != NULL)
- return return_false_with_msg ("Target flags are different");
-
- cl_optimization *opt1 = opts_for_fn (decl);
- cl_optimization *opt2 = opts_for_fn (m_compared_func->decl);
+ /* This guard is here for function pointer with attributes (pr59927.c). */
+ if (!arg_types[i] || !m_compared_func->arg_types[i])
+ return return_false_with_msg ("NULL argument type");
- if (opt1 != NULL && opt2 != NULL)
- {
- if (memcmp (opt1, opt2, sizeof(cl_optimization)))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "optimization flags difference");
- cl_optimization_print_diff (dump_file, 2, opt1, opt2);
- }
+ /* Polymorphic comparison is executed just for non-leaf functions. */
+ bool is_not_leaf = get_node ()->callees != NULL
+ || get_node ()->indirect_calls != NULL;
- return return_false_with_msg ("optimization flags are different");
- }
+ if (!func_checker::compatible_types_p (arg_types[i],
+ m_compared_func->arg_types[i],
+ is_not_leaf,
+ i == 0
+ && TREE_CODE (TREE_TYPE (decl))
+ == METHOD_TYPE
+ && compare_polymorphic_p ()))
+ return return_false_with_msg ("argument type is different");
}
- else if (opt1 != NULL || opt2 != NULL)
- return return_false_with_msg ("optimization flags are different");
-
- /* Checking function arguments. */
- tree decl1 = DECL_ATTRIBUTES (decl);
- tree decl2 = DECL_ATTRIBUTES (m_compared_func->decl);
m_checker = new func_checker (decl, m_compared_func->decl,
compare_polymorphic_p (),
false,
&refs_set,
&m_compared_func->refs_set);
- while (decl1)
- {
- if (decl2 == NULL)
- return return_false ();
-
- if (get_attribute_name (decl1) != get_attribute_name (decl2))
- return return_false ();
-
- tree attr_value1 = TREE_VALUE (decl1);
- tree attr_value2 = TREE_VALUE (decl2);
-
- if (attr_value1 && attr_value2)
- {
- bool ret = m_checker->compare_operand (TREE_VALUE (attr_value1),
- TREE_VALUE (attr_value2));
- if (!ret)
- return return_false_with_msg ("attribute values are different");
- }
- else if (!attr_value1 && !attr_value2)
- {}
- else
- return return_false ();
-
- decl1 = TREE_CHAIN (decl1);
- decl2 = TREE_CHAIN (decl2);
- }
-
- if (decl1 != decl2)
- return return_false();
-
-
- for (arg1 = DECL_ARGUMENTS (decl),
- arg2 = DECL_ARGUMENTS (m_compared_func->decl);
- arg1; arg1 = DECL_CHAIN (arg1), arg2 = DECL_CHAIN (arg2))
- if (!m_checker->compare_decl (arg1, arg2))
- return return_false ();
/* Fill-up label dictionary. */
for (unsigned i = 0; i < bb_sorted.length (); ++i)
@@ -632,30 +670,6 @@ sem_function::equals_private (sem_item *
if (!compare_phi_node (bb_sorted[i]->bb, m_compared_func->bb_sorted[i]->bb))
return return_false_with_msg ("PHI node comparison returns false");
- /* Compare special function DECL attributes. */
- if (DECL_FUNCTION_PERSONALITY (decl) != 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 "
- "attributes are different");
-
- if (DECL_NO_LIMIT_STACK (decl) != DECL_NO_LIMIT_STACK (item->decl))
- return return_false_with_msg ("no stack limit attributes are different");
-
- 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 result;
}
@@ -716,7 +730,7 @@ redirect_all_callers (cgraph_node *n, cg
&& n->get_availability () > AVAIL_INTERPOSABLE))
{
nredirected += redirect_all_callers (n_alias, to);
- if (n_alias->can_remove_if_no_direct_calls_p ()
+ if (n_alias->can_remove_with_comdat_group_if_no_direct_calls_p ()
&& !n_alias->has_aliases_p ())
n_alias->remove ();
}
@@ -907,7 +921,7 @@ sem_function::merge (sem_item *alias_ite
return false;
}
if (!create_wrapper
- && !alias->can_remove_if_no_direct_calls_p ())
+ && !alias->can_remove_with_comdat_group_if_no_direct_calls_p ())
{
if (dump_file)
fprintf (dump_file, "Not unifying; can not make wrapper and "
@@ -933,7 +947,7 @@ sem_function::merge (sem_item *alias_ite
}
/* If all callers was redirected, do not produce wrapper. */
- if (alias->can_remove_if_no_direct_calls_p ()
+ if (alias->can_remove_with_comdat_group_if_no_direct_calls_p ()
&& !alias->has_aliases_p ())
{
create_wrapper = false;
@@ -1114,10 +1128,8 @@ sem_item::add_expr (const_tree exp, inch
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_wide_int (int_size_in_bytes (TREE_TYPE (exp)));
+ if (SSA_NAME_IS_DEFAULT_DEF (exp))
+ add_expr (SSA_NAME_VAR (exp), hstate);
break;
case MEM_REF:
case POINTER_PLUS_EXPR:
@@ -1142,6 +1154,66 @@ sem_item::add_expr (const_tree exp, inch
}
}
+/* 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);
+ sem_item::add_type (TREE_TYPE (type), hstate);
+ sem_item::add_expr (TYPE_SIZE (type), hstate);
+ hstate.add_int (POINTER_TYPE_P (type));
+ }
+ else if (RECORD_OR_UNION_TYPE_P (type))
+ {
+ unsigned nf;
+ tree f;
+ hstate.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), hstate);
+ nf++;
+ }
+
+ hstate.add_int (nf);
+ }
+}
+
/* Improve accumulated hash for HSTATE based on a gimple statement STMT. */
void
@@ -1153,14 +1225,20 @@ sem_function::hash_stmt (gimple stmt, in
switch (code)
{
+ case GIMPLE_SWITCH:
+ add_expr (gimple_switch_index (as_a <gswitch *> (stmt)), hstate);
+ 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);
+ add_type (TREE_TYPE (gimple_assign_rhs2 (stmt)), two);
hstate.add_commutative (one, two);
add_expr (gimple_assign_lhs (stmt), hstate);
break;
@@ -1173,7 +1251,11 @@ sem_function::hash_stmt (gimple stmt, in
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);
+ {
+ add_expr (gimple_op (stmt, i), hstate);
+ if (gimple_op (stmt, i))
+ add_type (TREE_TYPE (gimple_op (stmt, i)), hstate);
+ }
default:
break;
}
@@ -1343,41 +1425,6 @@ sem_function::bb_dict_test (vec<int> *bb
return (*bb_dict)[source] == target;
}
-/* Iterates all tree types in T1 and T2 and returns true if all types
- are compatible. If COMPARE_POLYMORPHIC is set to true,
- more strict comparison is executed. */
-
-bool
-sem_function::compare_type_list (tree t1, tree t2, bool compare_polymorphic)
-{
- tree tv1, tv2;
- tree_code tc1, tc2;
-
- if (!t1 && !t2)
- return true;
-
- while (t1 != NULL && t2 != NULL)
- {
- tv1 = TREE_VALUE (t1);
- tv2 = TREE_VALUE (t2);
-
- tc1 = TREE_CODE (tv1);
- tc2 = TREE_CODE (tv2);
-
- if (tc1 == NOP_EXPR && tc2 == NOP_EXPR)
- {}
- else if (tc1 == NOP_EXPR || tc2 == NOP_EXPR)
- return false;
- else if (!func_checker::compatible_types_p (tv1, tv2, compare_polymorphic))
- return false;
-
- t1 = TREE_CHAIN (t1);
- t2 = TREE_CHAIN (t2);
- }
-
- return !(t1 || t2);
-}
-
/* Semantic variable constructor that uses STACK as bitmap memory stack. */
@@ -1439,7 +1486,8 @@ sem_variable::equals_wpa (sem_item *item
if (!compare_cgraph_references (ignored_nodes,
ref->referred, ref2->referred,
- ref->address_matters_p ()))
+ ref->address_matters_p ()
+ || ref2->address_matters_p ()))
return false;
}
@@ -1452,7 +1500,8 @@ sem_variable::equals_wpa (sem_item *item
bool
sem_variable::equals (sem_item *item,
- hash_map <symtab_node *, sem_item *> &)
+ hash_map <symtab_node *, sem_item *> &ignored_nodes
+ ATTRIBUTE_UNUSED)
{
gcc_assert (item->type == VAR);
bool ret;
@@ -1462,6 +1511,9 @@ sem_variable::equals (sem_item *item,
if (DECL_INITIAL (item->decl) == error_mark_node && in_lto_p)
dyn_cast <varpool_node *>(item->node)->get_constructor ();
+#ifdef ENABLE_CHECKING
+ gcc_assert (equals_wpa (item, ignored_nodes));
+#endif
ret = sem_variable::equals (DECL_INITIAL (decl),
DECL_INITIAL (item->node->decl));
if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2384,8 +2436,9 @@ sem_item_optimizer::subdivide_classes_by
{
sem_item *item = c->members[j];
- bool equals = in_wpa ? first->equals_wpa (item,
- m_symtab_node_map) : first->equals (item, m_symtab_node_map);
+ bool equals = in_wpa
+ ? first->equals_wpa (item, m_symtab_node_map)
+ : first->equals (item, m_symtab_node_map);
if (equals)
new_vector.safe_push (item);
@@ -2396,8 +2449,9 @@ sem_item_optimizer::subdivide_classes_by
for (unsigned k = class_split_first; k < (*it)->classes.length (); k++)
{
sem_item *x = (*it)->classes[k]->members[0];
- bool equals = in_wpa ? x->equals_wpa (item,
- m_symtab_node_map) : x->equals (item, m_symtab_node_map);
+ bool equals = in_wpa
+ ? x->equals_wpa (item, m_symtab_node_map)
+ : x->equals (item, m_symtab_node_map);
if (equals)
{
@@ -2419,7 +2473,8 @@ sem_item_optimizer::subdivide_classes_by
}
}
- // we replace newly created new_vector for the class we've just splitted
+ /* we replace newly created new_vector for the class we've just
+ splitted. */
c->members.release ();
c->members.create (new_vector.length ());
===================================================================
@@ -242,8 +242,11 @@ protected:
/* Cached, once calculated hash for the item. */
hashval_t hash;
- /* Accumulate to HSTATE a hash of constructor expression EXP. */
+ /* Accumulate to HSTATE a hash of expression EXP (either constructor or
+ gimple operand). */
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
point to a same function. Comparison can be skipped if IGNORED_NODES
@@ -353,15 +356,12 @@ private:
corresponds to TARGET. */
bool bb_dict_test (vec<int> *bb_dict, int source, int target);
- /* Iterates all tree types in T1 and T2 and returns true if all types
- are compatible. If COMPARE_POLYMORPHIC is set to true,
- more strict comparison is executed. */
- bool compare_type_list (tree t1, tree t2, bool compare_polymorphic);
-
/* If cgraph edges E1 and E2 are indirect calls, verify that
ICF flags are the same. */
bool compare_edge_flags (cgraph_edge *e1, cgraph_edge *e2);
+ bool comp_attributes (const_tree list1, const_tree list2);
+
/* Processes function equality comparison. */
bool equals_private (sem_item *item,
hash_map <symtab_node *, sem_item *> &ignored_nodes);
===================================================================
@@ -4873,7 +4873,7 @@ simple_cst_list_equal (const_tree l1, co
attribute values are known to be equal; otherwise return false.
*/
-static bool
+bool
attribute_value_equal (const_tree attr1, const_tree attr2)
{
if (TREE_VALUE (attr1) == TREE_VALUE (attr2))
===================================================================
@@ -4366,6 +4366,7 @@ extern tree lhd_gcc_personality (void);
extern void assign_assembler_name_if_neeeded (tree);
extern void warn_deprecated_use (tree, tree);
extern void cache_integer_cst (tree);
+extern bool attribute_value_equal (const_tree, const_tree);
/* Compare and hash for any structure which begins with a canonical
pointer. Assumes all pointers are interchangeable, which is sort