IPA ICF: rewrite references into a hash_map.
authorMartin Liska <mliska@suse.cz>
Tue, 4 Jun 2019 07:52:51 +0000 (09:52 +0200)
committerMartin Liska <marxin@gcc.gnu.org>
Tue, 4 Jun 2019 07:52:51 +0000 (07:52 +0000)
2019-06-04  Martin Liska  <mliska@suse.cz>

* ipa-icf.h (struct sem_usage_pair_hash): New.
(sem_usage_pair_hash::hash): Likewise.
(sem_usage_pair_hash::equal): Likewise.
(struct sem_usage_hash): Likewise.
* ipa-icf.c (sem_item::sem_item): Initialize
referenced_by_count.
(sem_item::add_reference): Register a reference
in ref_map and not in target->usages.
(sem_item::setup): Remove initialization of
dead vectors.
(sem_item::~sem_item): Remove usage of dead vectors.
(sem_item::dump): Remove dump of references.
(sem_item_optimizer::sem_item_optimizer): Initialize
m_references.
(sem_item_optimizer::read_section): Remove useless
dump.
(sem_item_optimizer::parse_funcs_and_vars): Likewise here.
(sem_item_optimizer::build_graph): Pass m_references
to ::add_reference.
(sem_item_optimizer::verify_classes): Remove usage of dead
vectors.
(sem_item_optimizer::traverse_congruence_split): Return true
when a class is split.
(sem_item_optimizer::do_congruence_step_for_index): Use
hash_map for look up of (sem_item *, index). That brings
significant speed up.
(sem_item_optimizer::do_congruence_step): Return true
when a split is done.
(congruence_class::is_class_used): Use referenced_by_count.
2019-06-04  Martin Liska  <mliska@suse.cz>

* c-c++-common/goacc/acc-icf.c: Change scanned pattern.
* gfortran.dg/goacc/pr78027.f90: Likewise.

From-SVN: r271900

gcc/ChangeLog
gcc/ipa-icf.c
gcc/ipa-icf.h
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/goacc/acc-icf.c
gcc/testsuite/gfortran.dg/goacc/pr78027.f90

index 37aab79..8fbeb6e 100644 (file)
@@ -1,3 +1,35 @@
+2019-06-04  Martin Liska  <mliska@suse.cz>
+
+       * ipa-icf.h (struct sem_usage_pair_hash): New.
+       (sem_usage_pair_hash::hash): Likewise.
+       (sem_usage_pair_hash::equal): Likewise.
+       (struct sem_usage_hash): Likewise.
+       * ipa-icf.c (sem_item::sem_item): Initialize
+       referenced_by_count.
+       (sem_item::add_reference): Register a reference
+       in ref_map and not in target->usages.
+       (sem_item::setup): Remove initialization of
+       dead vectors.
+       (sem_item::~sem_item): Remove usage of dead vectors.
+       (sem_item::dump): Remove dump of references.
+       (sem_item_optimizer::sem_item_optimizer): Initialize
+       m_references.
+       (sem_item_optimizer::read_section): Remove useless
+       dump.
+       (sem_item_optimizer::parse_funcs_and_vars): Likewise here.
+       (sem_item_optimizer::build_graph): Pass m_references
+       to ::add_reference.
+       (sem_item_optimizer::verify_classes): Remove usage of dead
+       vectors.
+       (sem_item_optimizer::traverse_congruence_split): Return true
+       when a class is split.
+       (sem_item_optimizer::do_congruence_step_for_index): Use
+       hash_map for look up of (sem_item *, index). That brings
+       significant speed up.
+       (sem_item_optimizer::do_congruence_step): Return true
+       when a split is done.
+       (congruence_class::is_class_used): Use referenced_by_count.
+
 2019-06-04  Alan Modra  <amodra@gmail.com>
 
        PR target/90689
index 0741814..9f1e2c8 100644 (file)
@@ -138,14 +138,15 @@ sem_usage_pair::sem_usage_pair (sem_item *_item, unsigned int _index)
 }
 
 sem_item::sem_item (sem_item_type _type, bitmap_obstack *stack)
-: type (_type), m_hash (-1), m_hash_set (false)
+: type (_type), referenced_by_count (0), m_hash (-1), m_hash_set (false)
 {
   setup (stack);
 }
 
 sem_item::sem_item (sem_item_type _type, symtab_node *_node,
                    bitmap_obstack *stack)
-: type (_type), node (_node), m_hash (-1), m_hash_set (false)
+: type (_type), node (_node), referenced_by_count (0), m_hash (-1),
+  m_hash_set (false)
 {
   decl = node->decl;
   setup (stack);
@@ -154,13 +155,18 @@ sem_item::sem_item (sem_item_type _type, symtab_node *_node,
 /* Add reference to a semantic TARGET.  */
 
 void
-sem_item::add_reference (sem_item *target)
+sem_item::add_reference (ref_map *refs,
+                        sem_item *target)
 {
-  refs.safe_push (target);
-  unsigned index = refs.length ();
-  target->usages.safe_push (new sem_usage_pair(this, index));
+  unsigned index = reference_count++;
+  bool existed;
+
+  vec<sem_item *> &v
+    = refs->get_or_insert (new sem_usage_pair (target, index), &existed);
+  v.safe_push (this);
   bitmap_set_bit (target->usage_index_bitmap, index);
   refs_set.add (target->node);
+  ++target->referenced_by_count;
 }
 
 /* Initialize internal data structures. Bitmap STACK is used for
@@ -171,20 +177,14 @@ sem_item::setup (bitmap_obstack *stack)
 {
   gcc_checking_assert (node);
 
-  refs.create (0);
+  reference_count = 0;
   tree_refs.create (0);
-  usages.create (0);
   usage_index_bitmap = BITMAP_ALLOC (stack);
 }
 
 sem_item::~sem_item ()
 {
-  for (unsigned i = 0; i < usages.length (); i++)
-    delete usages[i];
-
-  refs.release ();
   tree_refs.release ();
-  usages.release ();
 
   BITMAP_FREE (usage_index_bitmap);
 }
@@ -199,13 +199,6 @@ sem_item::dump (void)
       fprintf (dump_file, "[%s] %s (tree:%p)\n", type == FUNC ? "func" : "var",
               node->dump_name (), (void *) node->decl);
       fprintf (dump_file, "  hash: %u\n", get_hash ());
-      fprintf (dump_file, "  references: ");
-
-      for (unsigned i = 0; i < refs.length (); i++)
-       fprintf (dump_file, "%s%s ", refs[i]->node->name (),
-                i < refs.length() - 1 ? "," : "");
-
-      fprintf (dump_file, "\n");
     }
 }
 
@@ -2230,7 +2223,7 @@ unsigned int sem_item_optimizer::class_id = 0;
 
 sem_item_optimizer::sem_item_optimizer ()
 : worklist (0), m_classes (0), m_classes_count (0), m_cgraph_node_hooks (NULL),
-  m_varpool_node_hooks (NULL), m_merged_variables ()
+  m_varpool_node_hooks (NULL), m_merged_variables (), m_references ()
 {
   m_items.create (0);
   bitmap_obstack_initialize (&m_bmstack);
@@ -2341,13 +2334,8 @@ sem_item_optimizer::read_section (lto_file_decl_data *file_data,
       node = lto_symtab_encoder_deref (encoder, index);
 
       hashval_t hash = streamer_read_uhwi (&ib_main);
-
       gcc_assert (node->definition);
 
-      if (dump_file)
-       fprintf (dump_file, "Symbol added: %s (tree: %p)\n",
-                node->dump_asm_name (), (void *) node->decl);
-
       if (is_a<cgraph_node *> (node))
        {
          cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
@@ -2611,15 +2599,7 @@ sem_item_optimizer::parse_funcs_and_vars (void)
        {
          m_items.safe_push (f);
          m_symtab_node_map.put (cnode, f);
-
-         if (dump_file)
-           fprintf (dump_file, "Parsed function:%s\n", f->node->asm_name ());
-
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           f->dump_to_file (dump_file);
        }
-      else if (dump_file)
-       fprintf (dump_file, "Not parsed function:%s\n", cnode->asm_name ());
     }
 
   varpool_node *vnode;
@@ -2745,7 +2725,7 @@ sem_item_optimizer::build_graph (void)
              sem_item **slot = m_symtab_node_map.get
                (e->callee->ultimate_alias_target ());
              if (slot)
-               item->add_reference (*slot);
+               item->add_reference (&m_references, *slot);
 
              e = e->next_callee;
            }
@@ -2757,7 +2737,7 @@ sem_item_optimizer::build_graph (void)
          sem_item **slot = m_symtab_node_map.get
            (ref->referred->ultimate_alias_target ());
          if (slot)
-           item->add_reference (*slot);
+           item->add_reference (&m_references, *slot);
        }
     }
 }
@@ -2987,13 +2967,6 @@ sem_item_optimizer::verify_classes (void)
 
              gcc_assert (item);
              gcc_assert (item->cls == cls);
-
-             for (unsigned k = 0; k < item->usages.length (); k++)
-               {
-                 sem_usage_pair *usage = item->usages[k];
-                 gcc_assert (usage->item->index_in_class
-                             < usage->item->cls->members.length ());
-               }
            }
        }
     }
@@ -3106,10 +3079,11 @@ sem_item_optimizer::traverse_congruence_split (congruence_class * const &cls,
       /* Release class if not presented in work list.  */
       if (!in_worklist)
        delete cls;
-    }
 
+      return true;
+    }
 
-  return true;
+  return false;
 }
 
 /* Compare function for sorting pairs in do_congruence_step_f.  */
@@ -3131,7 +3105,7 @@ sem_item_optimizer::sort_congruence_split (const void *a_, const void *b_)
 /* Tests if a class CLS used as INDEXth splits any congruence classes.
    Bitmap stack BMSTACK is used for bitmap allocation.  */
 
-void
+bool
 sem_item_optimizer::do_congruence_step_for_index (congruence_class *cls,
                                                  unsigned int index)
 {
@@ -3140,31 +3114,32 @@ sem_item_optimizer::do_congruence_step_for_index (congruence_class *cls,
   for (unsigned int i = 0; i < cls->members.length (); i++)
     {
       sem_item *item = cls->members[i];
+      sem_usage_pair needle (item, index);
+      vec<sem_item *> *callers = m_references.get (&needle);
+      if (callers == NULL)
+       continue;
 
-      /* Iterate all usages that have INDEX as usage of the item.  */
-      for (unsigned int j = 0; j < item->usages.length (); j++)
+      for (unsigned int j = 0; j < callers->length (); j++)
        {
-         sem_usage_pair *usage = item->usages[j];
-
-         if (usage->index != index)
+         sem_item *caller = (*callers)[j];
+         if (caller->cls->members.length () < 2)
            continue;
-
-         bitmap *slot = split_map.get (usage->item->cls);
+         bitmap *slot = split_map.get (caller->cls);
          bitmap b;
 
          if(!slot)
            {
              b = BITMAP_ALLOC (&m_bmstack);
-             split_map.put (usage->item->cls, b);
+             split_map.put (caller->cls, b);
            }
          else
            b = *slot;
 
-         gcc_checking_assert (usage->item->cls);
-         gcc_checking_assert (usage->item->index_in_class
-                              < usage->item->cls->members.length ());
+         gcc_checking_assert (caller->cls);
+         gcc_checking_assert (caller->index_in_class
+                              < caller->cls->members.length ());
 
-         bitmap_set_bit (b, usage->item->index_in_class);
+         bitmap_set_bit (b, caller->index_in_class);
        }
     }
 
@@ -3180,12 +3155,16 @@ sem_item_optimizer::do_congruence_step_for_index (congruence_class *cls,
   pair.cls = cls;
 
   splitter_class_removed = false;
+  bool r = false;
   for (unsigned i = 0; i < to_split.length (); ++i)
-    traverse_congruence_split (to_split[i].first, to_split[i].second, &pair);
+    r |= traverse_congruence_split (to_split[i].first, to_split[i].second,
+                                   &pair);
 
   /* Bitmap clean-up.  */
   split_map.traverse <traverse_split_pair *,
                      sem_item_optimizer::release_split_map> (NULL);
+
+  return r;
 }
 
 /* Every usage of a congruence class CLS is a candidate that can split the
@@ -3206,9 +3185,8 @@ sem_item_optimizer::do_congruence_step (congruence_class *cls)
   EXECUTE_IF_SET_IN_BITMAP (usage, 0, i, bi)
   {
     if (dump_file && (dump_flags & TDF_DETAILS))
-      fprintf (dump_file, "  processing congruence step for class: %u, "
-              "index: %u\n", cls->id, i);
-
+      fprintf (dump_file, "  processing congruence step for class: %u "
+              "(%u items), index: %u\n", cls->id, cls->members.length (), i);
     do_congruence_step_for_index (cls, i);
 
     if (splitter_class_removed)
@@ -3648,7 +3626,7 @@ bool
 congruence_class::is_class_used (void)
 {
   for (unsigned int i = 0; i < members.length (); i++)
-    if (members[i]->usages.length ())
+    if (members[i]->referenced_by_count)
       return true;
 
   return false;
index 27d588c..ede4c94 100644 (file)
@@ -126,7 +126,6 @@ struct symbol_compare_hash : nofree_ptr_hash <symbol_compare_collection>
   }
 };
 
-
 /* Semantic item usage pair.  */
 class sem_usage_pair
 {
@@ -141,6 +140,32 @@ public:
   unsigned int index;
 };
 
+struct sem_usage_pair_hash : pointer_hash <sem_usage_pair>
+{
+  static inline hashval_t hash (sem_usage_pair *);
+  static inline bool equal (sem_usage_pair *, sem_usage_pair *);
+};
+
+inline hashval_t
+sem_usage_pair_hash::hash (sem_usage_pair *pair)
+{
+  inchash::hash hstate;
+
+  hstate.add_ptr (pair->item);
+  hstate.add_int (pair->index);
+
+  return hstate.end ();
+}
+
+inline bool
+sem_usage_pair_hash::equal (sem_usage_pair *p1, sem_usage_pair *p2)
+{
+  return p1->item == p2->item && p1->index == p2->index;
+}
+
+struct sem_usage_hash : sem_usage_pair_hash, typed_delete_remove <sem_usage_pair> {};
+typedef hash_map<sem_usage_hash, auto_vec<sem_item *> > ref_map;
+
 typedef std::pair<symtab_node *, symtab_node *> symtab_pair;
 
 /* Semantic item is a base class that encapsulates all shared functionality
@@ -168,7 +193,7 @@ public:
   virtual void init (void) = 0;
 
   /* Add reference to a semantic TARGET.  */
-  void add_reference (sem_item *target);
+  void add_reference (ref_map *map, sem_item *target);
 
   /* Fast equality function based on knowledge known in WPA.  */
   virtual bool equals_wpa (sem_item *item,
@@ -216,8 +241,9 @@ public:
   /* Declaration tree node.  */
   tree decl;
 
-  /* Semantic references used that generate congruence groups.  */
-  vec <sem_item *> refs;
+  /* Number of references to a semantic symbols (function calls,
+     variable references).  */
+  unsigned reference_count;
 
   /* Pointer to a congruence class the item belongs to.  */
   congruence_class *cls;
@@ -225,9 +251,6 @@ public:
   /* Index of the item in a class belonging to.  */
   unsigned int index_in_class;
 
-  /* List of semantic items where the instance is used.  */
-  vec <sem_usage_pair *> usages;
-
   /* A bitmap with indices of all classes referencing this item.  */
   bitmap usage_index_bitmap;
 
@@ -239,6 +262,9 @@ public:
 
   /* Temporary hash used where hash values of references are added.  */
   hashval_t global_hash;
+
+  /* Number of references to this symbol.  */
+  unsigned referenced_by_count;
 protected:
   /* Cached, once calculated hash for the item.  */
 
@@ -581,7 +607,7 @@ private:
 
   /* Tests if a class CLS used as INDEXth splits any congruence classes.
      Bitmap stack BMSTACK is used for bitmap allocation.  */
-  void do_congruence_step_for_index (congruence_class *cls, unsigned int index);
+  bool do_congruence_step_for_index (congruence_class *cls, unsigned int index);
 
   /* Makes pairing between a congruence class CLS and semantic ITEM.  */
   static void add_item_to_class (congruence_class *cls, sem_item *item);
@@ -644,6 +670,9 @@ private:
   /* Vector of merged variables.  Needed for fixup of points-to-analysis
      info.  */
   vec <symtab_pair> m_merged_variables;
+
+  /* Hash map will all references.  */
+  ref_map m_references;
 }; // class sem_item_optimizer
 
 } // ipa_icf namespace
index 3f7ddfd..94dad4b 100644 (file)
@@ -1,3 +1,8 @@
+2019-06-04  Martin Liska  <mliska@suse.cz>
+
+       * c-c++-common/goacc/acc-icf.c: Change scanned pattern.
+       * gfortran.dg/goacc/pr78027.f90: Likewise.
+
 2019-06-03  Segher Boessenkool  <segher@kernel.crashing.org>
 
        * gcc.target/powerpc/mmfpgpr.c: Delete.
index ecfe3f2..53d5dcf 100644 (file)
@@ -44,6 +44,4 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-ipa-dump-times "Not parsed function:" 4 "icf" } }  */
-/* { dg-final { scan-ipa-dump "Parsed function:main" "icf" } }  */
-
+/* { dg-final { scan-ipa-dump-times "With total: 1 items" 5 "icf" } }  */
index a1e51fa..52e5662 100644 (file)
@@ -19,6 +19,4 @@ real function f()
    !$acc end parallel
  end
  
-! { dg-final { scan-ipa-dump "Not parsed function:f_._omp_fn.1" "icf" } }
-! { dg-final { scan-ipa-dump "Not parsed function:f_._omp_fn.0" "icf" } }
-! { dg-final { scan-ipa-dump "Not parsed function:f_" "icf" } }
+! { dg-final { scan-ipa-dump-times "With total: 0 items" 5 "icf" } }