Fix PR ipa/64693
authormarxin <marxin@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 26 Feb 2015 20:21:38 +0000 (20:21 +0000)
committermarxin <marxin@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 26 Feb 2015 20:21:38 +0000 (20:21 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@221031 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/ipa-icf.c
gcc/ipa-icf.h
gcc/ipa-ref.c
gcc/ipa-ref.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ipa/pr64146.C
gcc/testsuite/gcc.dg/ipa/ipa-icf-26.c
gcc/testsuite/gcc.dg/ipa/ipa-icf-33.c

index 4049982..f303d0a 100644 (file)
@@ -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
index c564a92..1d6cbeb 100644 (file)
@@ -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.  */
index a55699b..9e76239 100644 (file)
@@ -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);
 
index 91c2f89..f9af352 100644 (file)
@@ -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;
+}
index aea7f4c..38df8c9 100644 (file)
@@ -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);
 
index 085792e..31bb268 100644 (file)
@@ -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 ...
index bdadfbe..c9a2590 100644 (file)
@@ -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" } } */
index 0c5a5a6..f48c040 100644 (file)
@@ -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" } } */
index d7e814d..7b6a8ae 100644 (file)
@@ -23,5 +23,4 @@ int main()
 }
 
 /* { dg-final { scan-ipa-dump "Equal symbols: 1" "icf"  } } */
-/* { dg-final { scan-ipa-dump "Equal symbols: 1" "icf"  } } */
 /* { dg-final { cleanup-ipa-dump "icf" } } */