On Mon, 10 Aug 2026, Patrick Palka wrote:

> 
> On Mon, 10 Aug 2026, Jason Merrill wrote:
> 
> > On 8/7/26 9:55 AM, Richard Biener wrote:
> > > From: Bernhard M. Wiedemann <[email protected]>
> > > 
> > > typename_htab is written to a precompiled header.  A hash table is
> > > streamed out slot array and all: gt_pch_nx() relocates the pointers
> > > inside the entries but leaves every entry in the slot it happened to
> > > occupy.  typename_hasher hashed on the addresses of the scope and the
> > > fullname, so the slots were chosen from addresses that ASLR randomises
> > > in the process writing the header, and they no longer correspond to the
> > > hash of anything once the header has been read back at a different
> > > address.
> > > 
> > > Lookups then find a restored TYPENAME_TYPE only when it happens to lie
> > > on the probe sequence of the slot the new hash points at, so most miss
> > > and build a duplicate, and which ones miss depends on the layout the
> > > writing process had.  That makes a compile using a PCH differ from the
> > > same compile without one, and differ from itself between runs: the
> > > duplicates consume DECL_UIDs, every later DECL_UID shifts, and
> > > var-tracking hashes on DECL_UID, so .debug_loclists comes out different.
> > > 
> > > Hash on TYPE_UID/DECL_UID and IDENTIFIER_HASH_VALUE instead, which the
> > > header preserves.  The name replaces the fullname in the hash because a
> > > TEMPLATE_ID_EXPR fullname has no address-independent hash of its own;
> > > both are compared by equal() either way.
> > 
> > We could handle TEMPLATE_ID_EXPR by using iterative_hash_template_arg 
> > instead
> > of iterative_hash_object?
> > 
> > But I suppose it's unlikely that we'd need a bunch of typenames that differ
> > only in template args, so OK either way.
> 
> IIRC the PR65328 compile-time-hog testcase had a lot of TEMPLATE_ID_EXPR
> typenames, and indeed this patch as-is significantly regresses compile
> time of the PR65328#c6 testcase since it effectively undoes part of
> r13-1047-g343d83c7a89d0c.  So I think we need to go with using
> iterative_hash_template_arg instead (with comparing_specializations
> set so that we produce distinct hashes for nested TYPENAME_TYPE).
> 
> > 
> > > Compiling qgstopologicalmesh.cpp of qgis 4.2.1, 4757 lookups in the
> > > table:
> > > 
> > >    no PCH                 3046 misses, 3046 entries
> > >    PCH, before            483-484 misses, 3135-3136 entries, varies per 
> > > run
> > >    PCH, after             394 misses, 3046 entries
> > > 
> > > and the object file now matches the one built without a PCH, byte for
> > > byte, from any of eight independently generated headers.
> > > 
> > > Bootstrapped and tested on x86_64-unknown-linux-gnu.
> > > 
> > > OK?
> > > 
> > > Thanks,
> > > Richard.
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >   PR pch/124811
> > >   * decl.cc (typename_hasher::hash): Hash the UIDs of the context
> > >   and the name rather than their addresses.
> > > 
> > > Assisted-by: Claude
> > > ---
> > >   gcc/cp/decl.cc | 20 +++++++++++++-------
> > >   1 file changed, 13 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > > index b5d9ed05874..c66f59fef79 100644
> > > --- a/gcc/cp/decl.cc
> > > +++ b/gcc/cp/decl.cc
> > > @@ -4920,27 +4920,33 @@ struct typename_hasher : ggc_ptr_hash<tree_node>
> > >   {
> > >     typedef typename_info *compare_type;
> > >   -  /* Hash a TYPENAME_TYPE.  */
> > > +  /* Hash a TYPENAME_TYPE.  This table goes into a precompiled header,
> > > which
> > > +     moves everything it contains to a different address; entries keep 
> > > the
> > > +     slot they were put in, so hashing on the addresses of CONTEXT and 
> > > NAME
> > > +     would leave them unfindable once the header has been read back.  
> > > Hash
> > > on
> > > +     the UIDs instead, which the header preserves.  */
> 
> Since this is a common problem with GC'd hash tables and PCH and not
> specific to this hash table, I don't think this comment is necessary
> here FWIW.  It'd be better suited in a more central piece of
> documentation such as in the gccint manual, if it's not already
> documented there.

ISTR seeing such comment in other places, so yes it's redundant.

Can you take the patch from here?  I'd have to second-guess
which tree is the TEMPLATE_ID_EXPR while it's probably obvious to
you.

The PR identifies two other GC'd and PCH streamed hash tables that
hash pointers (but any incremental improvement is good!), which
are cp/tree.cc:list_hash_table and cp/constraint.cc:atom_cache

Thanks,
Richard.

> > >       static hashval_t
> > > -  hash (tree context, tree fullname)
> > > +  hash (tree context, tree name)
> > >     {
> > >       hashval_t hash = 0;
> > > -    hash = iterative_hash_object (context, hash);
> > > -    hash = iterative_hash_object (fullname, hash);
> > > -    return hash;
> > > +    if (context)
> > > +      hash = iterative_hash_hashval_t (TYPE_P (context) ? TYPE_UID
> > > (context)
> > > +                                : DECL_P (context) ? DECL_UID (context)
> > > +                                : 0, hash);
> > > +    return iterative_hash_hashval_t (IDENTIFIER_HASH_VALUE (name), hash);
> > >     }
> > >       static hashval_t
> > >     hash (const typename_info *ti)
> > >     {
> > > -    return typename_hasher::hash (ti->scope, ti->template_id);
> > > +    return typename_hasher::hash (ti->scope, ti->name);
> > >     }
> > >       static hashval_t
> > >     hash (tree t)
> > >     {
> > > -    return typename_hasher::hash (TYPE_CONTEXT (t), 
> > > TYPENAME_TYPE_FULLNAME
> > > (t));
> > > +    return typename_hasher::hash (TYPE_CONTEXT (t), TYPE_IDENTIFIER (t));
> > >     }
> > >       /* Compare two TYPENAME_TYPEs.  */
> > 
> > 
> 
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)

Reply via email to