From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 4A6313858439 for ; Sun, 21 Aug 2022 19:40:31 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4A6313858439 Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-283-oX-yu4q-NVKhwNA-C6Fuxg-1; Sun, 21 Aug 2022 15:40:29 -0400 X-MC-Unique: oX-yu4q-NVKhwNA-C6Fuxg-1 Received: by mail-wr1-f72.google.com with SMTP id t12-20020adfa2cc000000b00224f577fad1so1312883wra.4 for ; Sun, 21 Aug 2022 12:40:29 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:content-transfer-encoding:references :in-reply-to:date:cc:to:from:subject:message-id:x-gm-message-state :from:to:cc; bh=UtQ8P/qH05Yx4SVG5xeFm0VjJ5WH1b9anqjLIx5S6vE=; b=JjVb5g9pnOqSGlzJRj+ckDSXh6pG3GSE6hWkdW/h9BVDGXmlVbp7Ma7i7zExV1xZhq 9pff5JeIdnaPeigorQRQFtFp+X1yWR/lK493uHE53mWw68iaZyDx1XeqwTmqvJ8s8sjU QiwMu9IpbzaVC0aKzeJXaLbFErH5cqnyEf2C7GRQck2vrTsO/Y8/GYXNuXAlGXzGmxzP HferL0+gGwEI3x1W+twZ+cJbbVFDMn53+YWe3fLVX5xT51/gdD0D1+gCap6lKirCEWQf paradlDbnUvcyxkGrP/lOBEmVkSv6CDfP2xDknoJ4bZrKo0sxg2cKrxj6QhBo6h8MX2P brxw== X-Gm-Message-State: ACgBeo038CFuPCFxcoR1m2aTObXu0uZiRqrxiqhday84zfPr4sO/QvuL pgf/bQlMlTxg3OpQPr0FlUO+UWBAamvMJp4Kp6TToqJjexmnLTwrkjgPur7qwGQoeJkR7JC/f9D pq+Q/ZhsnVdPipyzXpA== X-Received: by 2002:a05:600c:3551:b0:3a5:dcf3:1001 with SMTP id i17-20020a05600c355100b003a5dcf31001mr13304330wmq.58.1661110828450; Sun, 21 Aug 2022 12:40:28 -0700 (PDT) X-Google-Smtp-Source: AA6agR5hHIx6wRgLw1qqBrgfTTe4sWYbDSbhg9SvgvRXxYWVffF1E+T42Vb5IW7BMzfwT4roLGu4jA== X-Received: by 2002:a05:600c:3551:b0:3a5:dcf3:1001 with SMTP id i17-20020a05600c355100b003a5dcf31001mr13304314wmq.58.1661110828161; Sun, 21 Aug 2022 12:40:28 -0700 (PDT) Received: from t14s.localdomain ([148.252.35.5]) by smtp.gmail.com with ESMTPSA id x2-20020adfffc2000000b0021e5bec14basm9548273wrs.5.2022.08.21.12.40.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 21 Aug 2022 12:40:27 -0700 (PDT) Message-ID: Subject: Re: Ping [PATCH V2] libcpp: Optimize #pragma once with a hash table [PR58770] From: David Malcolm To: Paul Hollinsky , gcc-patches@gcc.gnu.org Cc: Jason Merrill , Per Bothner , Nathan Sidwell , Tom Tromey Date: Sun, 21 Aug 2022 20:40:26 +0100 In-Reply-To: <20220819202734.wvourvrje3x5vfla@perseverance.local> References: <20220706230321.48041-1-paulhollinsky@gmail.com> <20220801051839.1454-1-paulhollinsky@gmail.com> <20220819202734.wvourvrje3x5vfla@perseverance.local> User-Agent: Evolution 3.44.4 (3.44.4-1.fc36) MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-11.3 required=5.0 tests=BAYES_00, BODY_8BITS, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 21 Aug 2022 19:40:33 -0000 On Fri, 2022-08-19 at 13:27 -0700, Paul Hollinsky wrote: > Hi all, >=20 > Would love some feedback on this patch! >=20 > Thanks, > Paul Hi Paul. Sorry for not getting back to you before. I'm listed as a libcpp maintainer, but this happens to be a part of libcpp I've not looked at (I'm mostly just familiar with location_t management).=20 FWIW, the patch seems sane to me, though I have one concern: does it work with precompiled headers? (given that PCH is implemented by taking a snapshot of the gc heap and reconstructing it on load, it thus tends to be an annoying source of bugs when trying the kind of cleanup this patch is doing). Sorry to not look be able to look at things in more detail (I'm travelling) Hope this is constructive Dave >=20 > On Mon, Aug 01, 2022 at 05:18:40AM +0000, Paul Hollinsky wrote: > > Rather than traversing the all_files linked list for every include, > > this factors out the quick idempotency checks (modification time > > and size) to be the keys in a hash table so we can find matching > > files quickly. > >=20 > > The hash table value type is a linked list, in case more than one > > file matches the quick check. > >=20 > > The table is only built if a once-only file is seen, so include > > guard performance is not affected. > >=20 > > My laptop would previously complete Ricardo's benchmark from the > > PR in ~1.1s using #pragma once, and ~0.35s using include guards. > >=20 > > After this change, both benchmarks now complete in ~0.35s. I did > > have to randomize the modification dates on the benchmark headers > > so the files did not all end up in the same hash table list, but > > that would likely not come up outside of the contrived benchmark. > >=20 > > I bootstrapped and ran the testsuite on x86_64 Darwin, as well as > > ppc64le and aarch64 Linux. > >=20 > > libcpp/ChangeLog: > >=20 > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0PR preprocessor/58770 > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* internal.h: Add hash = table for #pragma once > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0* files.cc: Optimize #p= ragma once with the hash table > >=20 > > Signed-off-by: Paul Hollinsky > > --- > > =C2=A0libcpp/files.cc=C2=A0=C2=A0 | 116 > > +++++++++++++++++++++++++++++++++++++++++++--- > > =C2=A0libcpp/internal.h |=C2=A0=C2=A0 3 ++ > > =C2=A02 files changed, 112 insertions(+), 7 deletions(-) > >=20 > > diff --git a/libcpp/files.cc b/libcpp/files.cc > > index 24208f7b0f8..d4ffd77578e 100644 > > --- a/libcpp/files.cc > > +++ b/libcpp/files.cc > > @@ -167,6 +167,33 @@ struct file_hash_entry_pool > > =C2=A0=C2=A0 struct cpp_file_hash_entry pool[FILE_HASH_POOL_SIZE]; > > =C2=A0}; > > =C2=A0 > > +/* A set of attributes designed to quickly identify obviously > > different files > > +=C2=A0=C2=A0 in a hashtable.=C2=A0 Just in case there are collisions, = we still > > maintain a > > +=C2=A0=C2=A0 list.=C2=A0 These sub-lists can then be checked for #prag= ma once > > rather than > > +=C2=A0=C2=A0 interating through all_files.=C2=A0 */ > > +struct file_quick_idempotency_attrs > > +{ > > +=C2=A0 file_quick_idempotency_attrs(const _cpp_file *f) > > +=C2=A0=C2=A0=C2=A0 : mtime(f->st.st_mtime), size(f->st.st_size) {} > > + > > +=C2=A0 time_t mtime; > > +=C2=A0 off_t size; > > + > > +=C2=A0 static hashval_t hash (/* _cpp_file* */ const void *p); > > +}; > > + > > +/* Sub-list of very similar files kept in a hashtable to check for > > #pragma > > +=C2=A0=C2=A0 once.=C2=A0 */ > > +struct file_sublist > > +{ > > +=C2=A0 _cpp_file *f; > > +=C2=A0 file_sublist *next; > > + > > +=C2=A0 static int eq (/* _cpp_file* */ const void *p, > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 /* file_sublist* */ const void *q); > > +=C2=A0 static void del (/* file_sublist* */ void *p); > > +}; > > + > > =C2=A0static bool open_file (_cpp_file *file); > > =C2=A0static bool pch_open_file (cpp_reader *pfile, _cpp_file *file, > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 bool *invalid_pch); > > @@ -849,17 +876,17 @@ has_unique_contents (cpp_reader *pfile, > > _cpp_file *file, bool import, > > =C2=A0=C2=A0 if (!pfile->seen_once_only) > > =C2=A0=C2=A0=C2=A0=C2=A0 return true; > > =C2=A0 > > -=C2=A0 /* We may have read the file under a different name.=C2=A0 Look > > -=C2=A0=C2=A0=C2=A0=C2=A0 for likely candidates and compare file conten= ts to be sure.=C2=A0 > > */ > > -=C2=A0 for (_cpp_file *f =3D pfile->all_files; f; f =3D f->next_file) > > +=C2=A0 /* We may have read the file under a different name.=C2=A0 We'v= e kept > > +=C2=A0=C2=A0=C2=A0=C2=A0 similar looking files in this lists under thi= s hash table, so > > +=C2=A0=C2=A0=C2=A0=C2=A0 check those more thoroughly.=C2=A0 */ > > +=C2=A0 void* ent =3D htab_find(pfile->pragma_once_files, file); > > +=C2=A0 for (file_sublist *e =3D static_cast (ent); e; = e =3D > > e->next) > > =C2=A0=C2=A0=C2=A0=C2=A0 { > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 _cpp_file *f =3D e->f; > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (f =3D=3D file) > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0continue; /* It'sa me!= =C2=A0 */ > > =C2=A0 > > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if ((import || f->once_only) > > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 && f->err_no =3D=3D 0 > > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 && f->st.st_mtime =3D= =3D file->st.st_mtime > > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 && f->st.st_size =3D= =3D file->st.st_size) > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if ((import || f->once_only) && f->err_= no =3D=3D 0) > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 _cpp_file *ref_f= ile; > > =C2=A0 > > @@ -895,6 +922,38 @@ has_unique_contents (cpp_reader *pfile, > > _cpp_file *file, bool import, > > =C2=A0=C2=A0 return true; > > =C2=A0} > > =C2=A0 > > +/* Add the given file to the #pragma once table so it can be > > +=C2=A0=C2=A0 quickly identified and excluded the next time it's seen.= =C2=A0 */ > > +static void > > +update_pragma_once_table (cpp_reader *pfile, _cpp_file *file) > > +{ > > +=C2=A0 void **slot =3D htab_find_slot (pfile->pragma_once_files, file, > > INSERT); > > +=C2=A0 if (slot) > > +=C2=A0=C2=A0=C2=A0 { > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (!*slot) > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0*slot =3D xcalloc (1, sizeof= (file_sublist)); > > + > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 file_sublist *e =3D static_cast (*slot); > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 while (e->f) > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (!e->next) > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 { > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 void *new_sublist =3D xcalloc(1, sizeof > > (file_sublist)); > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 e->next =3D static_cast (new_sublist); > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 e =3D e->next; > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > > + > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 e->f =3D file; > > +=C2=A0=C2=A0=C2=A0 } > > +=C2=A0 else > > +=C2=A0=C2=A0=C2=A0 { > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 cpp_error (pfile, CPP_DL_ERROR, > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 "Unable to create #pragma once table space for > > %s", > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 _cpp_get_file_name (file)); > > +=C2=A0=C2=A0=C2=A0 } > > +} > > + > > =C2=A0/* Place the file referenced by FILE into a new buffer on the > > buffer > > =C2=A0=C2=A0=C2=A0 stack if possible.=C2=A0 Returns true if a buffer is= stacked.=C2=A0 Use > > LOC > > =C2=A0=C2=A0=C2=A0 for any diagnostics.=C2=A0 */ > > @@ -950,6 +1009,9 @@ _cpp_stack_file (cpp_reader *pfile, _cpp_file > > *file, include_type type, > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (!has_unique_contents (pfile, f= ile, type =3D=3D IT_IMPORT, > > loc)) > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0return false; > > =C2=A0 > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (pfile->seen_once_only && file->once= _only) > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0update_pragma_once_table (pf= ile, file); > > + > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (pfile->buffer && file->dir) > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0sysp =3D MAX (pfile->bu= ffer->sysp, file->dir->sysp); > > =C2=A0 > > @@ -1434,6 +1496,41 @@ nonexistent_file_hash_eq (const void *p, > > const void *q) > > =C2=A0=C2=A0 return filename_cmp ((const char *) p, (const char *) q) = =3D=3D 0; > > =C2=A0} > > =C2=A0 > > +/* Hasher for the #pragma once hash table.=C2=A0 */ > > +hashval_t > > +file_quick_idempotency_attrs::hash (const void *p) > > +{ > > +=C2=A0 const _cpp_file *f =3D static_cast (p); > > +=C2=A0 file_quick_idempotency_attrs kh (f); > > +=C2=A0 return iterative_hash_object (kh, 0); > > +} > > + > > +/* Equality checker for the #pragma once hash table.=C2=A0 */ > > +int > > +file_sublist::eq (const void *p, const void *q) > > +{ > > +=C2=A0 /* Just check if the file q would be in the list p. Every > > +=C2=A0=C2=A0=C2=A0=C2=A0 file in the list should have these attributes= the same, > > +=C2=A0=C2=A0=C2=A0=C2=A0 so we don't need to traverse.=C2=A0 */ > > +=C2=A0 const file_sublist *e =3D static_cast (p)= ; > > +=C2=A0 const _cpp_file *f =3D static_cast (q); > > +=C2=A0 return f->st.st_mtime =3D=3D e->f->st.st_mtime > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 && f->st.st_size =3D=3D e->= f->st.st_size; > > +} > > + > > +/* Cleanup for a file sub-list. Does not free the _cpp_file > > +=C2=A0=C2=A0 structures within.=C2=A0 */ > > +void > > +file_sublist::del (void *p) > > +{ > > +=C2=A0 file_sublist *e =3D static_cast (p); > > +=C2=A0 if (e->next) > > +=C2=A0=C2=A0=C2=A0 { > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 file_sublist::del (e->next); > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 free (e->next); > > +=C2=A0=C2=A0=C2=A0 } > > +} > > + > > =C2=A0/* Initialize everything in this source file.=C2=A0 */ > > =C2=A0void > > =C2=A0_cpp_init_files (cpp_reader *pfile) > > @@ -1442,6 +1539,10 @@ _cpp_init_files (cpp_reader *pfile) > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0NULL, xcalloc, free); > > =C2=A0=C2=A0 pfile->dir_hash =3D htab_create_alloc (127, file_hash_hash= , > > file_hash_eq, > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0NULL, xcalloc, free); > > +=C2=A0 pfile->pragma_once_files =3D htab_create_alloc (127, > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0file_quick_idempotency_attr > > s::hash, > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0file_sublist::eq, > > file_sublist::del, > > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0xcalloc, free); > > =C2=A0=C2=A0 allocate_file_hash_entries (pfile); > > =C2=A0=C2=A0 pfile->nonexistent_file_hash =3D htab_create_alloc (127, > > htab_hash_string, > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 > > nonexistent_file_hash_eq, > > @@ -1456,6 +1557,7 @@ _cpp_cleanup_files (cpp_reader *pfile) > > =C2=A0{ > > =C2=A0=C2=A0 htab_delete (pfile->file_hash); > > =C2=A0=C2=A0 htab_delete (pfile->dir_hash); > > +=C2=A0 htab_delete (pfile->pragma_once_files); > > =C2=A0=C2=A0 htab_delete (pfile->nonexistent_file_hash); > > =C2=A0=C2=A0 obstack_free (&pfile->nonexistent_file_ob, 0); > > =C2=A0=C2=A0 free_file_hash_entries (pfile); > > diff --git a/libcpp/internal.h b/libcpp/internal.h > > index badfd1b40da..9c3c46df335 100644 > > --- a/libcpp/internal.h > > +++ b/libcpp/internal.h > > @@ -485,6 +485,9 @@ struct cpp_reader > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 been used.=C2=A0 */ > > =C2=A0=C2=A0 bool seen_once_only; > > =C2=A0 > > +=C2=A0 /* Optimization for #pragma once.=C2=A0 */ > > +=C2=A0 struct htab *pragma_once_files; > > + > > =C2=A0=C2=A0 /* Multiple include optimization.=C2=A0 */ > > =C2=A0=C2=A0 const cpp_hashnode *mi_cmacro; > > =C2=A0=C2=A0 const cpp_hashnode *mi_ind_cmacro; > > --=20 > > 2.34.1 > >=20 >=20