On Wed, Nov 20, 2019 at 07:46:13PM -0500, Jason Merrill wrote: > > If decl_tree_cache_map will be needed in more than one spot, I'll probably > > need to move it to some generic header. > > Most of them probably need it, for code that uses the relevant features. > Except debug_type_map, which probably needs to use TYPE_UID. > > Or we might make default_hash_traits<tree> use DECL_UID for decls and > TYPE_UID for types even if it doesn't do the more complex analysis of > tree_operand_hash.
Finding out what is a type and what is decl (and what to do with rest?) at runtime would be more costly than necessary. The following updated patch moves the decl_tree_cache_map to tree.h and adds there type_tree_cache_map too and uses it in all the tree_cache_map spots in the C++ FE. tree-hash-traits.h can't be included from tree.h, because operand_equal_p is declared elsewhere, so instead this patch moves some of the tree-hash-traits.h traits from that header to tree.h. I could move there just tree_decl_hash if moving the other two doesn't look right to you. Bootstrapped/regtested on x86_64-linux and i686-linux, additionally tested by compiling stdc++.h as PCH with -std=c++2a and using it. Ok for trunk? 2019-11-22 Jakub Jelinek <ja...@redhat.com> PR c++/92458 * tree-hash-traits.h (tree_decl_hash, tree_ssa_name_hash, tree_hash): Move to ... * tree.h (tree_decl_hash, tree_ssa_name_hash, tree_hash): ... here. (struct decl_tree_cache_traits, struct type_tree_cache_traits): New types. (decl_tree_cache_map, tree_tree_cache_map): New typedefs. * init.c (nsdmi_inst): Change type to decl_tree_cache_map * from tree_cache_map *. * constraint.cc (decl_constraints): Likewise. * decl.c (get_tuple_decomp_init): Likewise. * pt.c (defarg_inst, explicit_specifier_map): Likewise. (tsubst_default_argument, store_explicit_specifier): Use decl_tree_cache_map::create_ggc rather than tree_cache_map::create_ggc. * cp-objcp-common.c (debug_type_map): Change type to type_tree_cache_map * from tree_cache_map *. * g++.dg/pch/pr92458.C: New test. * g++.dg/pch/pr92458.Hs: New test. --- gcc/tree-hash-traits.h.jj 2019-01-01 12:37:16.902979134 +0100 +++ gcc/tree-hash-traits.h 2019-11-22 12:00:01.538725844 +0100 @@ -41,44 +41,4 @@ tree_operand_hash::equal (const value_ty return operand_equal_p (t1, t2, 0); } -/* Hasher for tree decls. Pointer equality is enough here, but the DECL_UID - is a better hash than the pointer value and gives a predictable traversal - order. */ -struct tree_decl_hash : ggc_ptr_hash <tree_node> -{ - static inline hashval_t hash (tree); -}; - -inline hashval_t -tree_decl_hash::hash (tree t) -{ - return DECL_UID (t); -} - -/* Hash for SSA_NAMEs in the same function. Pointer equality is enough - here, but the SSA_NAME_VERSION is a better hash than the pointer - value and gives a predictable traversal order. */ -struct tree_ssa_name_hash : ggc_ptr_hash <tree_node> -{ - static inline hashval_t hash (tree); -}; - -inline hashval_t -tree_ssa_name_hash::hash (tree t) -{ - return SSA_NAME_VERSION (t); -} - -/* Hasher for general trees, based on their TREE_HASH. */ -struct tree_hash : ggc_ptr_hash <tree_node> -{ - static hashval_t hash (tree); -}; - -inline hashval_t -tree_hash::hash (tree t) -{ - return TREE_HASH (t); -} - #endif --- gcc/tree.h.jj 2019-11-15 00:37:26.293070143 +0100 +++ gcc/tree.h 2019-11-22 12:00:17.479478830 +0100 @@ -5351,6 +5351,58 @@ struct tree_decl_map_cache_hasher : ggc_ #define tree_vec_map_hash tree_decl_map_hash #define tree_vec_map_marked_p tree_map_base_marked_p +/* Hasher for tree decls. Pointer equality is enough here, but the DECL_UID + is a better hash than the pointer value and gives a predictable traversal + order. Additionally it can be used across PCH save/restore. */ +struct tree_decl_hash : ggc_ptr_hash <tree_node> +{ + static inline hashval_t hash (tree); +}; + +inline hashval_t +tree_decl_hash::hash (tree t) +{ + return DECL_UID (t); +} + +/* Similarly for types. Uses TYPE_UID as hash function. */ +struct tree_type_hash : ggc_ptr_hash <tree_node> +{ + static inline hashval_t hash (tree); +}; + +inline hashval_t +tree_type_hash::hash (tree t) +{ + return TYPE_UID (t); +} + +/* Hash for SSA_NAMEs in the same function. Pointer equality is enough + here, but the SSA_NAME_VERSION is a better hash than the pointer + value and gives a predictable traversal order. */ +struct tree_ssa_name_hash : ggc_ptr_hash <tree_node> +{ + static inline hashval_t hash (tree); +}; + +inline hashval_t +tree_ssa_name_hash::hash (tree t) +{ + return SSA_NAME_VERSION (t); +} + +/* Hasher for general trees, based on their TREE_HASH. */ +struct tree_hash : ggc_ptr_hash <tree_node> +{ + static hashval_t hash (tree); +}; + +inline hashval_t +tree_hash::hash (tree t) +{ + return TREE_HASH (t); +} + /* A hash_map of two trees for use with GTY((cache)). Garbage collection for such a map will not mark keys, and will mark values if the key is already marked. */ @@ -5358,6 +5410,18 @@ struct tree_cache_traits : simple_cache_map_traits<default_hash_traits<tree>, tree> { }; typedef hash_map<tree,tree,tree_cache_traits> tree_cache_map; +/* Similarly, but use DECL_UID as hash function rather than pointer hashing. + This is for hash_maps from decls to trees that need to work across PCH. */ +struct decl_tree_cache_traits + : simple_cache_map_traits<tree_decl_hash, tree> { }; +typedef hash_map<tree,tree,decl_tree_cache_traits> decl_tree_cache_map; + +/* Similarly, but use TYPE_UID as hash function rather than pointer hashing. + This is for hash_maps from types to trees that need to work across PCH. */ +struct type_tree_cache_traits + : simple_cache_map_traits<tree_type_hash, tree> { }; +typedef hash_map<tree,tree,type_tree_cache_traits> type_tree_cache_map; + /* Initialize the abstract argument list iterator object ITER with the arguments from CALL_EXPR node EXP. */ static inline void --- gcc/cp/init.c.jj 2019-11-08 00:22:12.042424097 +0100 +++ gcc/cp/init.c 2019-11-22 11:50:11.285872353 +0100 @@ -548,7 +548,7 @@ perform_target_ctor (tree init) /* Return the non-static data initializer for FIELD_DECL MEMBER. */ -static GTY((cache)) tree_cache_map *nsdmi_inst; +static GTY((cache)) decl_tree_cache_map *nsdmi_inst; tree get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain) --- gcc/cp/constraint.cc.jj 2019-11-11 21:04:02.104306246 +0100 +++ gcc/cp/constraint.cc 2019-11-22 11:47:05.621749384 +0100 @@ -1113,7 +1113,7 @@ build_constraints (tree tr, tree dr) /* A mapping from declarations to constraint information. */ -static GTY ((cache)) tree_cache_map *decl_constraints; +static GTY ((cache)) decl_tree_cache_map *decl_constraints; /* Returns the template constraints of declaration T. If T is not constrained, return NULL_TREE. Note that T must be non-null. */ --- gcc/cp/decl.c.jj 2019-11-19 22:26:46.289293903 +0100 +++ gcc/cp/decl.c 2019-11-22 11:49:01.954946691 +0100 @@ -7998,7 +7998,7 @@ get_tuple_decomp_init (tree decl, unsign /* It's impossible to recover the decltype of a tuple decomposition variable based on the actual type of the variable, so store it in a hash table. */ -static GTY((cache)) tree_cache_map *decomp_type_table; +static GTY((cache)) decl_tree_cache_map *decomp_type_table; tree lookup_decomp_type (tree v) --- gcc/cp/pt.c.jj 2019-11-19 22:27:00.737077646 +0100 +++ gcc/cp/pt.c 2019-11-22 11:52:37.590605226 +0100 @@ -13272,7 +13272,7 @@ tsubst_aggr_type (tree t, } } -static GTY((cache)) tree_cache_map *defarg_inst; +static GTY((cache)) decl_tree_cache_map *defarg_inst; /* Substitute into the default argument ARG (a default argument for FN), which has the indicated TYPE. */ @@ -13346,7 +13346,7 @@ tsubst_default_argument (tree fn, int pa if (arg != error_mark_node && !cp_unevaluated_operand) { if (!defarg_inst) - defarg_inst = tree_cache_map::create_ggc (37); + defarg_inst = decl_tree_cache_map::create_ggc (37); defarg_inst->put (parm, arg); } @@ -13383,7 +13383,7 @@ tsubst_default_arguments (tree fn, tsubs } /* Hash table mapping a FUNCTION_DECL to its dependent explicit-specifier. */ -static GTY((cache)) tree_cache_map *explicit_specifier_map; +static GTY((cache)) decl_tree_cache_map *explicit_specifier_map; /* Store a pair to EXPLICIT_SPECIFIER_MAP. */ @@ -13391,7 +13391,7 @@ void store_explicit_specifier (tree v, tree t) { if (!explicit_specifier_map) - explicit_specifier_map = tree_cache_map::create_ggc (37); + explicit_specifier_map = decl_tree_cache_map::create_ggc (37); DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P (v) = true; explicit_specifier_map->put (v, t); } --- gcc/cp/cp-objcp-common.c.jj 2019-11-06 08:58:38.189471399 +0100 +++ gcc/cp/cp-objcp-common.c 2019-11-22 11:51:28.090682190 +0100 @@ -123,7 +123,7 @@ cxx_types_compatible_p (tree x, tree y) return same_type_ignoring_top_level_qualifiers_p (x, y); } -static GTY((cache)) tree_cache_map *debug_type_map; +static GTY((cache)) type_tree_cache_map *debug_type_map; /* Return a type to use in the debug info instead of TYPE, or NULL_TREE to keep TYPE. */ --- gcc/testsuite/g++.dg/pch/pr92458.C.jj 2019-11-22 11:46:31.465278668 +0100 +++ gcc/testsuite/g++.dg/pch/pr92458.C 2019-11-22 11:46:31.465278668 +0100 @@ -0,0 +1,5 @@ +// PR c++/92458 +// { dg-options "-std=c++2a" } + +#include "pr92458.H" +S<int> s; --- gcc/testsuite/g++.dg/pch/pr92458.Hs.jj 2019-11-22 11:46:31.466278653 +0100 +++ gcc/testsuite/g++.dg/pch/pr92458.Hs 2019-11-22 11:46:31.466278653 +0100 @@ -0,0 +1,7 @@ +// PR c++/92458 +// { dg-options "-std=c++2a" } + +template<typename T> concept C = sizeof(T) > 1; +template<typename T> struct S { }; +template<typename T> requires C<T> struct S<T> { }; +template<typename T> requires (!C<T>) struct S<T> { }; Jakub