From 5dad738c1dd1649a85d04a56f93d0ea229c9590f Mon Sep 17 00:00:00 2001 From: Jason Merrill <jason@redhat.com> Date: Thu, 3 Oct 2024 16:29:20 -0400 Subject: [PATCH] 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 <rguenther@suse.de> --- 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 -- GitLab