From 99734e76691de1011a4afc76e2aa183161a5aa1c Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 25 Apr 2009 23:30:02 +0000 Subject: [PATCH] Lazily load the controlling macros for all of the headers known in the PCH file. In the Cocoa-prefixed "Hello, World" benchmark, this takes us from reading 503 identifiers down to 37 and from 470 macros down to 4. It also results in an 8% performance improvement. llvm-svn: 70094 --- clang/include/clang/Basic/IdentifierTable.h | 15 ++++++++- clang/include/clang/Frontend/PCHReader.h | 9 +++++- clang/include/clang/Lex/HeaderSearch.h | 35 ++++++++++++++++++--- clang/lib/Basic/IdentifierTable.cpp | 2 ++ clang/lib/Frontend/PCHReader.cpp | 3 +- clang/lib/Lex/HeaderSearch.cpp | 26 +++++++++++---- 6 files changed, 77 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index 235c19081cda..083196a2c113 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -234,7 +234,20 @@ public: /// be found. virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd) = 0; }; - + +/// \brief An abstract class used to resolve numerical identifier +/// references (meaningful only to some external source) into +/// IdentifierInfo pointers. +class ExternalIdentifierLookup { +public: + virtual ~ExternalIdentifierLookup(); + + /// \brief Return the identifier associated with the given ID number. + /// + /// The ID 0 is associated with the NULL identifier. + virtual IdentifierInfo *GetIdentifier(unsigned ID) = 0; +}; + /// IdentifierTable - This table implements an efficient mapping from strings to /// IdentifierInfo nodes. It has no other purpose, but this is an /// extremely performance-critical piece of the code, as each occurrance of diff --git a/clang/include/clang/Frontend/PCHReader.h b/clang/include/clang/Frontend/PCHReader.h index 0c8520ceb44f..98e32fcf0e38 100644 --- a/clang/include/clang/Frontend/PCHReader.h +++ b/clang/include/clang/Frontend/PCHReader.h @@ -64,7 +64,10 @@ class SwitchCase; /// The PCH reader provides lazy de-serialization of declarations, as /// required when traversing the AST. Only those AST nodes that are /// actually required will be de-serialized. -class PCHReader : public ExternalSemaSource, public IdentifierInfoLookup { +class PCHReader + : public ExternalSemaSource, + public IdentifierInfoLookup, + public ExternalIdentifierLookup { public: enum PCHReadResult { Success, Failure, IgnorePCH }; @@ -371,6 +374,10 @@ public: return DecodeIdentifierInfo(Record[Idx++]); } + virtual IdentifierInfo *GetIdentifier(unsigned ID) { + return DecodeIdentifierInfo(ID); + } + Selector DecodeSelector(unsigned Idx); Selector GetSelector(const RecordData &Record, unsigned &Idx) { diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index fe7e7aef3bac..f21aab1b4015 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -19,6 +19,8 @@ #include namespace clang { + +class ExternalIdentifierLookup; class FileEntry; class FileManager; class IdentifierInfo; @@ -42,10 +44,27 @@ struct HeaderFileInfo { /// ControllingMacro - If this file has a #ifndef XXX (or equivalent) guard /// that protects the entire contents of the file, this is the identifier /// for the macro that controls whether or not it has any effect. + /// + /// Note: Most clients should use getControllingMacro() to access + /// the controlling macro of this header, since + /// getControllingMacro() is able to load a controlling macro from + /// external storage. const IdentifierInfo *ControllingMacro; - - HeaderFileInfo() : isImport(false), DirInfo(SrcMgr::C_User), - NumIncludes(0), ControllingMacro(0) {} + + /// \brief The ID number of the controlling macro. + /// + /// This ID number will be non-zero when there is a controlling + /// macro whose IdentifierInfo may not yet have been loaded from + /// external storage. + unsigned ControllingMacroID; + + HeaderFileInfo() + : isImport(false), DirInfo(SrcMgr::C_User), + NumIncludes(0), ControllingMacro(0), ControllingMacroID(0) {} + + /// \brief Retrieve the controlling macro for this header file, if + /// any. + const IdentifierInfo *getControllingMacro(ExternalIdentifierLookup *External); }; /// HeaderSearch - This class encapsulates the information needed to find the @@ -84,7 +103,11 @@ class HeaderSearch { /// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing /// headermaps. This vector owns the headermap. std::vector > HeaderMaps; - + + /// \brief Entity used to resolve the identifier IDs of controlling + /// macros into IdentifierInfo pointers, as needed. + ExternalIdentifierLookup *ExternalLookup; + // Various statistics we track for performance analysis. unsigned NumIncluded; unsigned NumMultiIncludeFileOptzn; @@ -115,6 +138,10 @@ public: FileInfo.clear(); } + void SetExternalLookup(ExternalIdentifierLookup *EIL) { + ExternalLookup = EIL; + } + /// LookupFile - Given a "foo" or reference, look up the indicated file, /// return null on failure. isAngled indicates whether the file reference is /// a <> reference. If successful, this returns 'UsedDir', the diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 344c4eb18dc1..8b74b20032a9 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -42,6 +42,8 @@ IdentifierInfo::IdentifierInfo() { IdentifierInfoLookup::~IdentifierInfoLookup() {} +ExternalIdentifierLookup::~ExternalIdentifierLookup() {} + IdentifierTable::IdentifierTable(const LangOptions &LangOpts, IdentifierInfoLookup* externalLookup) : HashTable(8192), // Start with space for 8K identifiers. diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index 40e5c0d60303..c351a24118ea 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/lib/Frontend/PCHReader.cpp @@ -1717,7 +1717,7 @@ bool PCHReader::ReadPreprocessorBlock() { HFI.isImport = Record[0]; HFI.DirInfo = Record[1]; HFI.NumIncludes = Record[2]; - HFI.ControllingMacro = DecodeIdentifierInfo(Record[3]); + HFI.ControllingMacroID = Record[3]; PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, NumHeaderInfos++); break; } @@ -1854,6 +1854,7 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) { } IdentifierOffsets = (const uint32_t *)BlobStart; IdentifiersLoaded.resize(Record[0]); + PP.getHeaderSearchInfo().SetExternalLookup(this); break; case pch::EXTERNAL_DEFINITIONS: diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index ddea8e52a021..129fa1ae35fa 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -20,10 +20,23 @@ #include using namespace clang; +const IdentifierInfo * +HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) { + if (ControllingMacro) + return ControllingMacro; + + if (!ControllingMacroID || !External) + return 0; + + ControllingMacro = External->GetIdentifier(ControllingMacroID); + return ControllingMacro; +} + HeaderSearch::HeaderSearch(FileManager &FM) : FileMgr(FM), FrameworkMap(64) { SystemDirIdx = 0; NoCurDirSearch = false; - + + ExternalLookup = 0; NumIncluded = 0; NumMultiIncludeFileOptzn = 0; NumFrameworkLookups = NumSubFrameworkLookups = 0; @@ -417,11 +430,12 @@ bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){ // Next, check to see if the file is wrapped with #ifndef guards. If so, and // if the macro that guards it is defined, we know the #include has no effect. - if (FileInfo.ControllingMacro && - FileInfo.ControllingMacro->hasMacroDefinition()) { - ++NumMultiIncludeFileOptzn; - return false; - } + if (const IdentifierInfo *ControllingMacro + = FileInfo.getControllingMacro(ExternalLookup)) + if (ControllingMacro->hasMacroDefinition()) { + ++NumMultiIncludeFileOptzn; + return false; + } // Increment the number of times this file has been included. ++FileInfo.NumIncludes;