Commit 060cfff4 by Jan Hubicka Committed by Jan Hubicka

ipa-icf.c (sem_function::equals_wpa): Match CXX_CONSTRUCTOR_P and CXX_DESTURCTOR_P.


	* ipa-icf.c (sem_function::equals_wpa): Match CXX_CONSTRUCTOR_P
	and CXX_DESTURCTOR_P. For consutrctors match ODR type of class they
	are building; for methods check ODR type of class they belong to if
	they may lead to a polymorphic call.
	(sem_function::compare_polymorphic_p): Be bit smarter about testing
	when function may lead to a polymorphic call.
	(sem_function::compare_type_list): Remove.
	(sem_variable::equals): Update use of compatible_types_p.
	(sem_variable::parse_tree_refs): Remove.
	(sem_item_optimizer::filter_removed_items): Do not filter out CXX
	cdtor.
	* ipa-icf-gimple.c (func_checker::compare_decl): Do polymorphic
	matching here.
	(func_checker::compatible_polymorphic_types_p): Break out from ...
	(unc_checker::compatible_types_p): ... here.
	* ipa-icf-gimple.h (func_checker::compatible_polymorphic_types_p):
	Declare.
	(unc_checker::compatible_types_p): Update.
	* ipa-icf.h (compare_type_list, parse_tree_refs, compare_sections):
	Remove.

From-SVN: r221406
parent d587bfd1
2015-03-12 Jan Hubicka <hubicka@ucw.cz>
* ipa-icf.c (sem_function::equals_wpa): Match CXX_CONSTRUCTOR_P
and CXX_DESTURCTOR_P. For consutrctors match ODR type of class they
are building; for methods check ODR type of class they belong to if
they may lead to a polymorphic call.
(sem_function::compare_polymorphic_p): Be bit smarter about testing
when function may lead to a polymorphic call.
(sem_function::compare_type_list): Remove.
(sem_variable::equals): Update use of compatible_types_p.
(sem_variable::parse_tree_refs): Remove.
(sem_item_optimizer::filter_removed_items): Do not filter out CXX
cdtor.
* ipa-icf-gimple.c (func_checker::compare_decl): Do polymorphic
matching here.
(func_checker::compatible_polymorphic_types_p): Break out from ...
(unc_checker::compatible_types_p): ... here.
* ipa-icf-gimple.h (func_checker::compatible_polymorphic_types_p):
Declare.
(unc_checker::compatible_types_p): Update.
* ipa-icf.h (compare_type_list, parse_tree_refs, compare_sections):
Remove.
2015-03-12 Kyrylo Tkachov <kyrylo.tkachov@arm.com> 2015-03-12 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
PR rtl-optimization/65235 PR rtl-optimization/65235
......
...@@ -200,8 +200,22 @@ func_checker::compare_decl (tree t1, tree t2) ...@@ -200,8 +200,22 @@ func_checker::compare_decl (tree t1, tree t2)
&& DECL_BY_REFERENCE (t1) != DECL_BY_REFERENCE (t2)) && DECL_BY_REFERENCE (t1) != DECL_BY_REFERENCE (t2))
return return_false_with_msg ("DECL_BY_REFERENCE flags are different"); return return_false_with_msg ("DECL_BY_REFERENCE flags are different");
if (!compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2), if (!compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2)))
m_compare_polymorphic)) return return_false ();
/* TODO: we are actually too strict here. We only need to compare if
T1 can be used in polymorphic call. */
if (TREE_ADDRESSABLE (t1)
&& m_compare_polymorphic
&& !compatible_polymorphic_types_p (TREE_TYPE (t1), TREE_TYPE (t2),
false))
return return_false ();
if ((t == VAR_DECL || t == PARM_DECL || t == RESULT_DECL)
&& DECL_BY_REFERENCE (t1)
&& m_compare_polymorphic
&& !compatible_polymorphic_types_p (TREE_TYPE (t1), TREE_TYPE (t2),
true))
return return_false (); return return_false ();
bool existed_p; bool existed_p;
...@@ -215,11 +229,41 @@ func_checker::compare_decl (tree t1, tree t2) ...@@ -215,11 +229,41 @@ func_checker::compare_decl (tree t1, tree t2)
return true; return true;
} }
/* Return true if T1 and T2 are same for purposes of ipa-polymorphic-call
analysis. COMPARE_PTR indicates if types of pointers needs to be
considered. */
bool
func_checker::compatible_polymorphic_types_p (tree t1, tree t2,
bool compare_ptr)
{
gcc_assert (TREE_CODE (t1) != FUNCTION_TYPE && TREE_CODE (t1) != METHOD_TYPE);
/* Pointer types generally give no information. */
if (POINTER_TYPE_P (t1))
{
if (!compare_ptr)
return true;
return func_checker::compatible_polymorphic_types_p (TREE_TYPE (t1),
TREE_TYPE (t2),
false);
}
/* If types contain a polymorphic types, match them. */
bool c1 = contains_polymorphic_type_p (t1);
bool c2 = contains_polymorphic_type_p (t2);
if (!c1 && !c2)
return true;
if (!c1 || !c2)
return return_false_with_msg ("one type is not polymorphic");
if (!types_must_be_same_for_odr (t1, t2))
return return_false_with_msg ("types are not same for ODR");
return true;
}
/* Return true if types are compatible from perspective of ICF. */ /* Return true if types are compatible from perspective of ICF. */
bool bool
func_checker::compatible_types_p (tree t1, tree t2, func_checker::compatible_types_p (tree t1, tree t2)
bool compare_polymorphic,
bool first_argument)
{ {
if (TREE_CODE (t1) != TREE_CODE (t2)) if (TREE_CODE (t1) != TREE_CODE (t2))
return return_false_with_msg ("different tree types"); return return_false_with_msg ("different tree types");
...@@ -233,23 +277,6 @@ func_checker::compatible_types_p (tree t1, tree t2, ...@@ -233,23 +277,6 @@ func_checker::compatible_types_p (tree t1, tree t2,
if (get_alias_set (t1) != get_alias_set (t2)) if (get_alias_set (t1) != get_alias_set (t2))
return return_false_with_msg ("alias sets are different"); return return_false_with_msg ("alias sets are different");
/* We call contains_polymorphic_type_p with this pointer type. */
if (first_argument && TREE_CODE (t1) == POINTER_TYPE)
{
t1 = TREE_TYPE (t1);
t2 = TREE_TYPE (t2);
}
if (compare_polymorphic)
if (contains_polymorphic_type_p (t1) || contains_polymorphic_type_p (t2))
{
if (!contains_polymorphic_type_p (t1) || !contains_polymorphic_type_p (t2))
return return_false_with_msg ("one type is not polymorphic");
if (!types_must_be_same_for_odr (t1, t2))
return return_false_with_msg ("types are not same for ODR");
}
return true; return true;
} }
......
...@@ -226,12 +226,16 @@ public: ...@@ -226,12 +226,16 @@ public:
/* Verifies that trees T1 and T2 do correspond. */ /* Verifies that trees T1 and T2 do correspond. */
bool compare_variable_decl (tree t1, tree t2); bool compare_variable_decl (tree t1, tree t2);
/* Return true if types are compatible for polymorphic call analysis.
COMPARE_PTR indicates if polymorphic type comparsion should be
done for pointers, too. */
static bool compatible_polymorphic_types_p (tree t1, tree t2,
bool compare_ptr);
/* Return true if types are compatible from perspective of ICF. /* Return true if types are compatible from perspective of ICF.
FIRST_ARGUMENT indicates if the comparison is called for FIRST_ARGUMENT indicates if the comparison is called for
first parameter of a function. */ first parameter of a function. */
static bool compatible_types_p (tree t1, tree t2, static bool compatible_types_p (tree t1, tree t2);
bool compare_polymorphic = true,
bool first_argument = false);
private: private:
......
...@@ -429,9 +429,29 @@ sem_function::equals_wpa (sem_item *item, ...@@ -429,9 +429,29 @@ sem_function::equals_wpa (sem_item *item,
if (DECL_NO_LIMIT_STACK (decl) != DECL_NO_LIMIT_STACK (item->decl)) if (DECL_NO_LIMIT_STACK (decl) != DECL_NO_LIMIT_STACK (item->decl))
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))
return return_false_with_msg ("DELC_CXX_CONSTRUCTOR mismatch");
if (DECL_CXX_DESTRUCTOR_P (decl) != DECL_CXX_DESTRUCTOR_P (item->decl))
return return_false_with_msg ("DELC_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");
/* Do not match polymorphic constructors of different types. They calls
type memory location for ipa-polymorphic-call and we do not want
it to get confused by wrong type. */
if (DECL_CXX_CONSTRUCTOR_P (decl)
&& TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
{
if (TREE_CODE (TREE_TYPE (item->decl)) != METHOD_TYPE)
return return_false_with_msg ("DECL_CXX_CONSTURCTOR type mismatch");
else if (!func_checker::compatible_polymorphic_types_p
(method_class_type (TREE_TYPE (decl)),
method_class_type (TREE_TYPE (item->decl)), false))
return return_false_with_msg ("ctor polymorphic type mismatch");
}
/* Checking function TARGET and OPTIMIZATION flags. */ /* Checking function TARGET and OPTIMIZATION flags. */
cl_target_option *tar1 = target_opts_for_fn (decl); cl_target_option *tar1 = target_opts_for_fn (decl);
cl_target_option *tar2 = target_opts_for_fn (item->decl); cl_target_option *tar2 = target_opts_for_fn (item->decl);
...@@ -473,13 +493,8 @@ sem_function::equals_wpa (sem_item *item, ...@@ -473,13 +493,8 @@ sem_function::equals_wpa (sem_item *item,
if (!arg_types[i] || !m_compared_func->arg_types[i]) if (!arg_types[i] || !m_compared_func->arg_types[i])
return return_false_with_msg ("NULL argument type"); return return_false_with_msg ("NULL argument type");
/* Polymorphic comparison is executed just for non-leaf functions. */
bool is_not_leaf = get_node ()->callees != NULL
|| get_node ()->indirect_calls != NULL;
if (!func_checker::compatible_types_p (arg_types[i], if (!func_checker::compatible_types_p (arg_types[i],
m_compared_func->arg_types[i], m_compared_func->arg_types[i]))
is_not_leaf, i == 0))
return return_false_with_msg ("argument type is different"); return return_false_with_msg ("argument type is different");
if (POINTER_TYPE_P (arg_types[i]) if (POINTER_TYPE_P (arg_types[i])
&& (TYPE_RESTRICT (arg_types[i]) && (TYPE_RESTRICT (arg_types[i])
...@@ -494,6 +509,24 @@ sem_function::equals_wpa (sem_item *item, ...@@ -494,6 +509,24 @@ sem_function::equals_wpa (sem_item *item,
TREE_TYPE (item->decl)) != 1) TREE_TYPE (item->decl)) != 1)
return return_false_with_msg ("different type attributes"); return return_false_with_msg ("different type attributes");
/* The type of THIS pointer type memory location for
ipa-polymorphic-call-analysis. */
if (opt_for_fn (decl, flag_devirtualize)
&& (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
|| TREE_CODE (TREE_TYPE (item->decl)) == METHOD_TYPE)
&& (!flag_ipa_cp
|| ipa_is_param_used (IPA_NODE_REF (dyn_cast <cgraph_node *>(node)),
0))
&& compare_polymorphic_p ())
{
if (TREE_CODE (TREE_TYPE (decl)) != TREE_CODE (TREE_TYPE (item->decl)))
return return_false_with_msg ("METHOD_TYPE and FUNCTION_TYPE mismatch");
if (!func_checker::compatible_polymorphic_types_p
(method_class_type (TREE_TYPE (decl)),
method_class_type (TREE_TYPE (item->decl)), false))
return return_false_with_msg ("THIS pointer ODR type mismatch");
}
ipa_ref *ref = NULL, *ref2 = NULL; ipa_ref *ref = NULL, *ref2 = NULL;
for (unsigned i = 0; node->iterate_reference (i, ref); i++) for (unsigned i = 0; node->iterate_reference (i, ref); i++)
{ {
...@@ -614,7 +647,6 @@ sem_function::equals_private (sem_item *item, ...@@ -614,7 +647,6 @@ sem_function::equals_private (sem_item *item,
if (decl1 != decl2) if (decl1 != decl2)
return return_false(); return return_false();
for (arg1 = DECL_ARGUMENTS (decl), for (arg1 = DECL_ARGUMENTS (decl),
arg2 = DECL_ARGUMENTS (m_compared_func->decl); arg2 = DECL_ARGUMENTS (m_compared_func->decl);
arg1; arg1 = DECL_CHAIN (arg1), arg2 = DECL_CHAIN (arg2)) arg1; arg1 = DECL_CHAIN (arg1), arg2 = DECL_CHAIN (arg2))
...@@ -1216,10 +1248,20 @@ sem_function::hash_stmt (gimple stmt, inchash::hash &hstate) ...@@ -1216,10 +1248,20 @@ sem_function::hash_stmt (gimple stmt, inchash::hash &hstate)
bool bool
sem_function::compare_polymorphic_p (void) sem_function::compare_polymorphic_p (void)
{ {
return get_node ()->callees != NULL struct cgraph_edge *e;
|| get_node ()->indirect_calls != NULL
|| m_compared_func->get_node ()->callees != NULL if (!opt_for_fn (decl, flag_devirtualize))
|| m_compared_func->get_node ()->indirect_calls != NULL; return false;
if (get_node ()->indirect_calls != NULL
|| m_compared_func->get_node ()->indirect_calls != NULL)
return true;
/* TODO: We can do simple propagation determining what calls may lead to
a polymorphic call. */
for (e = m_compared_func->get_node ()->callees; e; e = e->next_callee)
if (e->callee->definition
&& opt_for_fn (e->callee->decl, flag_devirtualize))
return true;
return false;
} }
/* For a given call graph NODE, the function constructs new /* For a given call graph NODE, the function constructs new
...@@ -1374,41 +1416,6 @@ sem_function::bb_dict_test (vec<int> *bb_dict, int source, int target) ...@@ -1374,41 +1416,6 @@ sem_function::bb_dict_test (vec<int> *bb_dict, int source, int target)
return (*bb_dict)[source] == target; 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. */ /* Semantic variable constructor that uses STACK as bitmap memory stack. */
...@@ -1586,8 +1593,7 @@ sem_variable::equals (tree t1, tree t2) ...@@ -1586,8 +1593,7 @@ sem_variable::equals (tree t1, tree t2)
tree y1 = TREE_OPERAND (t1, 1); tree y1 = TREE_OPERAND (t1, 1);
tree y2 = TREE_OPERAND (t2, 1); tree y2 = TREE_OPERAND (t2, 1);
if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2), if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2)))
true))
return return_false (); return return_false ();
/* Type of the offset on MEM_REF does not matter. */ /* Type of the offset on MEM_REF does not matter. */
...@@ -1696,8 +1702,7 @@ sem_variable::equals (tree t1, tree t2) ...@@ -1696,8 +1702,7 @@ sem_variable::equals (tree t1, tree t2)
CASE_CONVERT: CASE_CONVERT:
case VIEW_CONVERT_EXPR: case VIEW_CONVERT_EXPR:
if (!func_checker::compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2), if (!func_checker::compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2)))
true))
return return_false (); return return_false ();
return sem_variable::equals (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); return sem_variable::equals (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
case ERROR_MARK: case ERROR_MARK:
...@@ -1874,40 +1879,6 @@ sem_variable::dump_to_file (FILE *file) ...@@ -1874,40 +1879,6 @@ sem_variable::dump_to_file (FILE *file)
fprintf (file, "\n\n"); fprintf (file, "\n\n");
} }
/* Iterates though a constructor and identifies tree references
we are interested in semantic function equality. */
void
sem_variable::parse_tree_refs (tree t)
{
switch (TREE_CODE (t))
{
case CONSTRUCTOR:
{
unsigned length = vec_safe_length (CONSTRUCTOR_ELTS (t));
for (unsigned i = 0; i < length; i++)
parse_tree_refs(CONSTRUCTOR_ELT (t, i)->value);
break;
}
case NOP_EXPR:
case ADDR_EXPR:
{
tree op = TREE_OPERAND (t, 0);
parse_tree_refs (op);
break;
}
case FUNCTION_DECL:
{
tree_refs.safe_push (t);
break;
}
default:
break;
}
}
unsigned int sem_item_optimizer::class_id = 0; unsigned int sem_item_optimizer::class_id = 0;
sem_item_optimizer::sem_item_optimizer (): worklist (0), m_classes (0), sem_item_optimizer::sem_item_optimizer (): worklist (0), m_classes (0),
...@@ -2185,10 +2156,7 @@ sem_item_optimizer::filter_removed_items (void) ...@@ -2185,10 +2156,7 @@ sem_item_optimizer::filter_removed_items (void)
{ {
cgraph_node *cnode = static_cast <sem_function *>(item)->get_node (); cgraph_node *cnode = static_cast <sem_function *>(item)->get_node ();
bool no_body_function = in_lto_p && (cnode->alias || cnode->body_removed); if (in_lto_p && (cnode->alias || cnode->body_removed))
if (no_body_function || !opt_for_fn (item->decl, flag_ipa_icf_functions)
|| DECL_CXX_CONSTRUCTOR_P (item->decl)
|| DECL_CXX_DESTRUCTOR_P (item->decl))
remove_item (item); remove_item (item);
else else
filtered.safe_push (item); filtered.safe_push (item);
......
...@@ -353,11 +353,6 @@ private: ...@@ -353,11 +353,6 @@ private:
corresponds to TARGET. */ corresponds to TARGET. */
bool bb_dict_test (vec<int> *bb_dict, int source, int 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 /* If cgraph edges E1 and E2 are indirect calls, verify that
ICF flags are the same. */ ICF flags are the same. */
bool compare_edge_flags (cgraph_edge *e1, cgraph_edge *e2); bool compare_edge_flags (cgraph_edge *e1, cgraph_edge *e2);
...@@ -415,15 +410,8 @@ public: ...@@ -415,15 +410,8 @@ public:
static sem_variable *parse (varpool_node *node, bitmap_obstack *stack); static sem_variable *parse (varpool_node *node, bitmap_obstack *stack);
private: private:
/* Iterates though a constructor and identifies tree references
we are interested in semantic function equality. */
void parse_tree_refs (tree t);
/* Compares trees T1 and T2 for semantic equality. */ /* Compares trees T1 and T2 for semantic equality. */
static bool equals (tree t1, tree t2); static bool equals (tree t1, tree t2);
/* Compare that symbol sections are either NULL or have same name. */
bool compare_sections (sem_variable *alias);
}; // class sem_variable }; // class sem_variable
class sem_item_optimizer; class sem_item_optimizer;
......
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