re PR lto/64693 (PCH failed with --with-build-config=bootstrap-lto)
Fix PR ipa/64693 PR ipa/64693 * ipa-icf.c (symbol_compare_collection::symbol_compare_collection): New. (sem_item_optimizer::subdivide_classes_by_sensitive_refs): New function. (sem_item_optimizer::process_cong_reduction): Include division by sensitive references. * ipa-icf.h (struct symbol_compare_hashmap_traits): New class. * ipa-ref.c (ipa_ref::address_matters_p): New function. * ipa-ref.h (ipa_ref::address_matters_p): Likewise. * g++.dg/ipa/pr64146.C: Update expected results. * gcc.dg/ipa/ipa-icf-26.c: Update test. * gcc.dg/ipa/ipa-icf-33.c: Remove redundant line. * gcc.dg/ipa/ipa-icf-34.c: New test. Co-Authored-By: Jan Hubicka <hubicka@ucw.cz> From-SVN: r221031
This commit is contained in:
parent
ff5ed3f6de
commit
5ebd0e6155
@ -1,3 +1,15 @@
|
||||
2015-02-26 Martin Liska <mliska@suse.cz>
|
||||
Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
PR ipa/64693
|
||||
* ipa-icf.c (symbol_compare_collection::symbol_compare_collection): New.
|
||||
(sem_item_optimizer::subdivide_classes_by_sensitive_refs): New function.
|
||||
(sem_item_optimizer::process_cong_reduction): Include division by
|
||||
sensitive references.
|
||||
* ipa-icf.h (struct symbol_compare_hashmap_traits): New class.
|
||||
* ipa-ref.c (ipa_ref::address_matters_p): New function.
|
||||
* ipa-ref.h (ipa_ref::address_matters_p): Likewise.
|
||||
|
||||
2015-02-26 Georg-Johann Lay <avr@gjlay.de>
|
||||
|
||||
PR target/65192
|
||||
|
125
gcc/ipa-icf.c
125
gcc/ipa-icf.c
@ -126,6 +126,44 @@ along with GCC; see the file COPYING3. If not see
|
||||
using namespace ipa_icf_gimple;
|
||||
|
||||
namespace ipa_icf {
|
||||
|
||||
/* Constructor. */
|
||||
|
||||
symbol_compare_collection::symbol_compare_collection (symtab_node *node)
|
||||
{
|
||||
m_references.create (0);
|
||||
m_interposables.create (0);
|
||||
|
||||
ipa_ref *ref;
|
||||
|
||||
if (is_a <varpool_node *> (node) && DECL_VIRTUAL_P (node->decl))
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < node->num_references (); i++)
|
||||
{
|
||||
ref = node->iterate_reference (i, ref);
|
||||
if (ref->address_matters_p ())
|
||||
m_references.safe_push (ref->referred);
|
||||
|
||||
if (ref->referred->get_availability () <= AVAIL_INTERPOSABLE)
|
||||
{
|
||||
if (ref->use == IPA_REF_ADDR)
|
||||
m_references.safe_push (ref->referred);
|
||||
else
|
||||
m_interposables.safe_push (ref->referred);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_a <cgraph_node *> (node))
|
||||
{
|
||||
cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
|
||||
|
||||
for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
|
||||
if (e->callee->get_availability () <= AVAIL_INTERPOSABLE)
|
||||
m_interposables.safe_push (e->callee);
|
||||
}
|
||||
}
|
||||
|
||||
/* Constructor for key value pair, where _ITEM is key and _INDEX is a target. */
|
||||
|
||||
sem_usage_pair::sem_usage_pair (sem_item *_item, unsigned int _index):
|
||||
@ -1967,6 +2005,84 @@ sem_item_optimizer::subdivide_classes_by_equality (bool in_wpa)
|
||||
verify_classes ();
|
||||
}
|
||||
|
||||
/* Subdivide classes by address references that members of the class
|
||||
reference. Example can be a pair of functions that have an address
|
||||
taken from a function. If these addresses are different the class
|
||||
is split. */
|
||||
|
||||
unsigned
|
||||
sem_item_optimizer::subdivide_classes_by_sensitive_refs ()
|
||||
{
|
||||
unsigned newly_created_classes = 0;
|
||||
|
||||
for (hash_table <congruence_class_group_hash>::iterator it = m_classes.begin ();
|
||||
it != m_classes.end (); ++it)
|
||||
{
|
||||
unsigned int class_count = (*it)->classes.length ();
|
||||
auto_vec<congruence_class *> new_classes;
|
||||
|
||||
for (unsigned i = 0; i < class_count; i++)
|
||||
{
|
||||
congruence_class *c = (*it)->classes [i];
|
||||
|
||||
if (c->members.length() > 1)
|
||||
{
|
||||
hash_map <symbol_compare_collection *, vec <sem_item *>,
|
||||
symbol_compare_hashmap_traits> split_map;
|
||||
|
||||
for (unsigned j = 0; j < c->members.length (); j++)
|
||||
{
|
||||
sem_item *source_node = c->members[j];
|
||||
|
||||
symbol_compare_collection *collection = new symbol_compare_collection (source_node->node);
|
||||
|
||||
vec <sem_item *> *slot = &split_map.get_or_insert (collection);
|
||||
gcc_checking_assert (slot);
|
||||
|
||||
slot->safe_push (source_node);
|
||||
}
|
||||
|
||||
/* If the map contains more than one key, we have to split the map
|
||||
appropriately. */
|
||||
if (split_map.elements () != 1)
|
||||
{
|
||||
bool first_class = true;
|
||||
|
||||
hash_map <symbol_compare_collection *, vec <sem_item *>,
|
||||
symbol_compare_hashmap_traits>::iterator it2 = split_map.begin ();
|
||||
for (; it2 != split_map.end (); ++it2)
|
||||
{
|
||||
congruence_class *new_cls;
|
||||
new_cls = new congruence_class (class_id++);
|
||||
|
||||
for (unsigned k = 0; k < (*it2).second.length (); k++)
|
||||
add_item_to_class (new_cls, (*it2).second[k]);
|
||||
|
||||
worklist_push (new_cls);
|
||||
newly_created_classes++;
|
||||
|
||||
if (first_class)
|
||||
{
|
||||
(*it)->classes[i] = new_cls;
|
||||
first_class = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_classes.safe_push (new_cls);
|
||||
m_classes_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < new_classes.length (); i++)
|
||||
(*it)->classes.safe_push (new_classes[i]);
|
||||
}
|
||||
|
||||
return newly_created_classes;
|
||||
}
|
||||
|
||||
/* Verify congruence classes if checking is enabled. */
|
||||
|
||||
void
|
||||
@ -2256,8 +2372,17 @@ sem_item_optimizer::process_cong_reduction (void)
|
||||
fprintf (dump_file, "Congruence class reduction\n");
|
||||
|
||||
congruence_class *cls;
|
||||
|
||||
/* Process complete congruence reduction. */
|
||||
while ((cls = worklist_pop ()) != NULL)
|
||||
do_congruence_step (cls);
|
||||
|
||||
/* Subdivide newly created classes according to references. */
|
||||
unsigned new_classes = subdivide_classes_by_sensitive_refs ();
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Address reference subdivision created: %u "
|
||||
"new classes.\n", new_classes);
|
||||
}
|
||||
|
||||
/* Debug function prints all informations about congruence classes. */
|
||||
|
@ -63,6 +63,70 @@ enum sem_item_type
|
||||
VAR
|
||||
};
|
||||
|
||||
/* Class is container for address references for a symtab_node. */
|
||||
|
||||
class symbol_compare_collection
|
||||
{
|
||||
public:
|
||||
/* Constructor. */
|
||||
symbol_compare_collection (symtab_node *node);
|
||||
|
||||
/* Destructor. */
|
||||
~symbol_compare_collection ()
|
||||
{
|
||||
m_references.release ();
|
||||
m_interposables.release ();
|
||||
}
|
||||
|
||||
/* Vector of address references. */
|
||||
vec<symtab_node *> m_references;
|
||||
|
||||
/* Vector of interposable references. */
|
||||
vec<symtab_node *> m_interposables;
|
||||
};
|
||||
|
||||
/* Hash traits for symbol_compare_collection map. */
|
||||
|
||||
struct symbol_compare_hashmap_traits: default_hashmap_traits
|
||||
{
|
||||
static hashval_t
|
||||
hash (const symbol_compare_collection *v)
|
||||
{
|
||||
inchash::hash hstate;
|
||||
hstate.add_int (v->m_references.length ());
|
||||
|
||||
for (unsigned i = 0; i < v->m_references.length (); i++)
|
||||
hstate.add_ptr (v->m_references[i]->ultimate_alias_target ());
|
||||
|
||||
hstate.add_int (v->m_interposables.length ());
|
||||
|
||||
for (unsigned i = 0; i < v->m_interposables.length (); i++)
|
||||
hstate.add_ptr (v->m_interposables[i]->ultimate_alias_target ());
|
||||
|
||||
return hstate.end ();
|
||||
}
|
||||
|
||||
static bool
|
||||
equal_keys (const symbol_compare_collection *a,
|
||||
const symbol_compare_collection *b)
|
||||
{
|
||||
if (a->m_references.length () != b->m_references.length ())
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < a->m_references.length (); i++)
|
||||
if (a->m_references[i]->equal_address_to (b->m_references[i]) != 1)
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < a->m_interposables.length (); i++)
|
||||
if (!a->m_interposables[i]->semantically_equivalent_p
|
||||
(b->m_interposables[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* Semantic item usage pair. */
|
||||
class sem_usage_pair
|
||||
{
|
||||
@ -467,6 +531,13 @@ private:
|
||||
classes. If IN_WPA, fast equality function is invoked. */
|
||||
void subdivide_classes_by_equality (bool in_wpa = false);
|
||||
|
||||
/* Subdivide classes by address and interposable references
|
||||
that members of the class reference.
|
||||
Example can be a pair of functions that have an address
|
||||
taken from a function. If these addresses are different the class
|
||||
is split. */
|
||||
unsigned subdivide_classes_by_sensitive_refs();
|
||||
|
||||
/* Debug function prints all informations about congruence classes. */
|
||||
void dump_cong_classes (void);
|
||||
|
||||
|
@ -124,3 +124,23 @@ ipa_ref::referred_ref_list (void)
|
||||
{
|
||||
return &referred->ref_list;
|
||||
}
|
||||
|
||||
/* Return true if refernece may be used in address compare. */
|
||||
bool
|
||||
ipa_ref::address_matters_p ()
|
||||
{
|
||||
if (use != IPA_REF_ADDR)
|
||||
return false;
|
||||
/* Addresses taken from virtual tables are never compared. */
|
||||
if (is_a <varpool_node *> (referring)
|
||||
&& DECL_VIRTUAL_P (referring->decl))
|
||||
return false;
|
||||
/* Address of virtual tables and functions is never compared. */
|
||||
if (DECL_VIRTUAL_P (referred->decl))
|
||||
return false;
|
||||
/* Address of C++ cdtors is never compared. */
|
||||
if (is_a <cgraph_node *> (referred)
|
||||
&& (DECL_CXX_CONSTRUCTOR_P (referred->decl) || DECL_CXX_DESTRUCTOR_P (referred->decl)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -47,6 +47,9 @@ public:
|
||||
function. */
|
||||
bool cannot_lead_to_return ();
|
||||
|
||||
/* Return true if refernece may be used in address compare. */
|
||||
bool address_matters_p ();
|
||||
|
||||
/* Return reference list this reference is in. */
|
||||
struct ipa_ref_list * referring_ref_list (void);
|
||||
|
||||
|
@ -1,3 +1,11 @@
|
||||
2015-02-26 Martin Liska <mliska@suse.cz>
|
||||
Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
* g++.dg/ipa/pr64146.C: Update expected results.
|
||||
* gcc.dg/ipa/ipa-icf-26.c: Update test.
|
||||
* gcc.dg/ipa/ipa-icf-33.c: Remove redundant line.
|
||||
* gcc.dg/ipa/ipa-icf-34.c: New test.
|
||||
|
||||
2015-02-26 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* gcc.dg/vect/vect-pr61917.c: Rename to ...
|
||||
|
@ -34,6 +34,5 @@ int main (int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Declaration does not bind to currect definition." 2 "icf" } } */
|
||||
/* { dg-final { scan-ipa-dump "Equal symbols: 2" "icf" } } */
|
||||
/* { dg-final { scan-ipa-dump "Equal symbols: 1" "icf" } } */
|
||||
/* { dg-final { cleanup-ipa-dump "icf" } } */
|
||||
|
@ -38,7 +38,6 @@ int main()
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump "Semantic equality hit:bar->foo" "icf" } } */
|
||||
/* { dg-final { scan-ipa-dump "Semantic equality hit:remove->destroy" "icf" } } */
|
||||
/* { dg-final { scan-ipa-dump "Equal symbols: 2" "icf" } } */
|
||||
/* { dg-final { scan-ipa-dump "Equal symbols: 1" "icf" } } */
|
||||
/* { dg-final { cleanup-ipa-dump "icf" } } */
|
||||
|
@ -22,6 +22,5 @@ int main()
|
||||
return foo() - bar();
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump "Equal symbols: 1" "icf" } } */
|
||||
/* { dg-final { scan-ipa-dump "Equal symbols: 1" "icf" } } */
|
||||
/* { dg-final { cleanup-ipa-dump "icf" } } */
|
||||
|
Loading…
Reference in New Issue
Block a user