]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: record template specialization hash
authorJason Merrill <jason@redhat.com>
Thu, 3 Oct 2024 20:29:20 +0000 (16:29 -0400)
committerJason Merrill <jason@redhat.com>
Fri, 4 Oct 2024 01:43:21 +0000 (21:43 -0400)
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 <rguenther@suse.de>
gcc/cp/cp-tree.h
gcc/cp/pt.cc

index c5d02567cb4b07b3423416e4d47a1af1c0b8265b..dc153a97dc46171c9f9922f20dab20668e2f954c 100644 (file)
@@ -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 */
index 4ceae1d38de1be7fb9ffcf017400b4a4091ce83d..03a1144765b22d38f3f9098b0edce9f4b1e860c8 100644 (file)
@@ -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