https://gcc.gnu.org/g:5dad738c1dd1649a85d04a56f93d0ea229c9590f

commit r15-4050-g5dad738c1dd1649a85d04a56f93d0ea229c9590f
Author: Jason Merrill <ja...@redhat.com>
Date:   Thu Oct 3 16:29:20 2024 -0400

    c++: record template specialization hash
    
    A lot of compile time of template-heavy code is spent in re-hashing
    hashtable elements upon expansion.  The following records the hash in the
    hash element.  This speeds up C++20 compilation of stdc++.h by about 25% for
    about a 0.1% increase in memory usage.
    
    With the hash value in the entry, we don't need to pass it separately to the
    find functions.
    
    Adding default arguments to the spec and hash fields simplifies spec_entry
    initialization and avoids problems from hash starting with an indeterminate
    value.
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (spec_entry::hash): New member.
            * pt.cc (spec_hasher::hash): Set it and return it.
            (maybe_process_partial_specialization): Clear it when
            changing tmpl/args.
            (lookup_template_class): Likewise, don't pass hash to find.
            (retrieve_specialization): Set it, don't pass hash to find.
            (register_specialization): Don't pass hash to find.
            (reregister_specialization): Likewise.
            (match_mergeable_specialization): Likewise.
            (add_mergeable_specialization): Likewise.
    
    Co-authored-by: Richard Biener <rguent...@suse.de>

Diff:
---
 gcc/cp/cp-tree.h | 11 ++++++++---
 gcc/cp/pt.cc     | 35 +++++++++++++++--------------------
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c5d02567cb4b..dc153a97dc46 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5840,9 +5840,14 @@ public:
 /* Entry in the specialization hash table.  */
 struct GTY((for_user)) spec_entry
 {
-  tree tmpl;  /* The general template this is a specialization of.  */
-  tree args;  /* The args for this (maybe-partial) specialization.  */
-  tree spec;  /* The specialization itself.  */
+  /* The general template this is a specialization of.  */
+  tree tmpl;
+  /* The args for this (maybe-partial) specialization.  */
+  tree args;
+  /* The specialization itself.  */
+  tree spec = NULL_TREE;
+  /* The cached result of hash_tmpl_and_args (tmpl, args).  */
+  hashval_t hash = 0;
 };
 
 /* in class.cc */
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 4ceae1d38de1..03a1144765b2 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1161,6 +1161,7 @@ maybe_process_partial_specialization (tree type)
                  elt.tmpl = tmpl;
                  CLASSTYPE_TI_ARGS (inst)
                    = elt.args = INNERMOST_TEMPLATE_ARGS (elt.args);
+                 elt.hash = 0; /* Recalculate after changing tmpl/args.  */
 
                  spec_entry **slot
                    = type_specializations->find_slot (&elt, INSERT);
@@ -1282,7 +1283,7 @@ retrieve_specialization (tree tmpl, tree args, hashval_t 
hash)
   spec_entry elt;
   elt.tmpl = tmpl;
   elt.args = args;
-  elt.spec = NULL_TREE;
+  elt.hash = hash;
 
   spec_hash_table *specializations;
   if (DECL_CLASS_TEMPLATE_P (tmpl))
@@ -1290,9 +1291,7 @@ retrieve_specialization (tree tmpl, tree args, hashval_t 
hash)
   else
     specializations = decl_specializations;
 
-  if (hash == 0)
-    hash = spec_hasher::hash (&elt);
-  if (spec_entry *found = specializations->find_with_hash (&elt, hash))
+  if (spec_entry *found = specializations->find (&elt))
     return found->spec;
 
   return NULL_TREE;
@@ -1551,7 +1550,7 @@ register_specialization (tree spec, tree tmpl, tree args, 
bool is_friend,
   if (hash == 0)
     hash = spec_hasher::hash (&elt);
 
-  spec_entry **slot = decl_specializations->find_slot_with_hash (&elt, hash, 
INSERT);
+  spec_entry **slot = decl_specializations->find_slot (&elt, INSERT);
   if (*slot)
     fn = (*slot)->spec;
   else
@@ -1739,7 +1738,9 @@ spec_hasher::hash (tree tmpl, tree args)
 hashval_t
 spec_hasher::hash (spec_entry *e)
 {
-  return spec_hasher::hash (e->tmpl, e->args);
+  if (e->hash == 0)
+    e->hash = hash (e->tmpl, e->args);
+  return e->hash;
 }
 
 /* Recursively calculate a hash value for a template argument ARG, for use
@@ -1973,7 +1974,6 @@ reregister_specialization (tree spec, tree tinfo, tree 
new_spec)
 
   elt.tmpl = most_general_template (TI_TEMPLATE (tinfo));
   elt.args = TI_ARGS (tinfo);
-  elt.spec = NULL_TREE;
 
   entry = decl_specializations->find (&elt);
   if (entry != NULL)
@@ -10019,8 +10019,6 @@ lookup_template_class (tree d1, tree arglist, tree 
in_decl, tree context,
   tree t;
   spec_entry **slot;
   spec_entry *entry;
-  spec_entry elt;
-  hashval_t hash;
 
   if (identifier_p (d1))
     {
@@ -10236,11 +10234,10 @@ lookup_template_class (tree d1, tree arglist, tree 
in_decl, tree context,
        }
 
       /* If we already have this specialization, return it.  */
+      spec_entry elt;
       elt.tmpl = gen_tmpl;
       elt.args = arglist;
-      elt.spec = NULL_TREE;
-      hash = spec_hasher::hash (&elt);
-      entry = type_specializations->find_with_hash (&elt, hash);
+      entry = type_specializations->find (&elt);
 
       if (entry)
        return entry->spec;
@@ -10303,7 +10300,7 @@ lookup_template_class (tree d1, tree arglist, tree 
in_decl, tree context,
                    {
                      /* Completion could have caused us to register the desired
                         specialization already, so check the table again.  */
-                     entry = type_specializations->find_with_hash (&elt, hash);
+                     entry = type_specializations->find (&elt);
                      if (entry)
                        return entry->spec;
                    }
@@ -10524,7 +10521,7 @@ lookup_template_class (tree d1, tree arglist, tree 
in_decl, tree context,
                 use it for hash table lookup.  */
              elt.tmpl = found;
              elt.args = arglist = INNERMOST_TEMPLATE_ARGS (arglist);
-             hash = spec_hasher::hash (&elt);
+             elt.hash = 0; /* Recalculate after changing tmpl/args.  */
            }
        }
 
@@ -10532,7 +10529,7 @@ lookup_template_class (tree d1, tree arglist, tree 
in_decl, tree context,
       SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist));
 
       elt.spec = t;
-      slot = type_specializations->find_slot_with_hash (&elt, hash, INSERT);
+      slot = type_specializations->find_slot (&elt, INSERT);
       gcc_checking_assert (*slot == NULL);
       entry = ggc_alloc<spec_entry> ();
       *entry = elt;
@@ -31654,8 +31651,7 @@ match_mergeable_specialization (bool decl_p, spec_entry 
*elt)
 {
   hash_table<spec_hasher> *specializations
     = decl_p ? decl_specializations : type_specializations;
-  hashval_t hash = spec_hasher::hash (elt);
-  auto *slot = specializations->find_slot_with_hash (elt, hash, NO_INSERT);
+  auto *slot = specializations->find_slot (elt, NO_INSERT);
 
   if (slot)
     return (*slot)->spec;
@@ -31703,10 +31699,9 @@ void
 add_mergeable_specialization (bool decl_p, spec_entry *elt, tree decl,
                              unsigned flags)
 {
-  hashval_t hash = spec_hasher::hash (elt);
   if (decl_p)
     {
-      auto *slot = decl_specializations->find_slot_with_hash (elt, hash, 
INSERT);
+      auto *slot = decl_specializations->find_slot (elt, INSERT);
 
       gcc_checking_assert (!*slot);
       auto entry = ggc_alloc<spec_entry> ();
@@ -31715,7 +31710,7 @@ add_mergeable_specialization (bool decl_p, spec_entry 
*elt, tree decl,
     }
   else
     {
-      auto *slot = type_specializations->find_slot_with_hash (elt, hash, 
INSERT);
+      auto *slot = type_specializations->find_slot (elt, INSERT);
 
       /* We don't distinguish different constrained partial type
         specializations, so there could be duplicates.  Everything else

Reply via email to