From 2deaea37a637dd01221d0cced343702a39d8132c Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 22 Apr 2009 18:49:13 +0000 Subject: [PATCH] Lazy loading of builtins for precompiled headers. PCH files now contain complete information about builtins, including any declarations that have been synthesized as part of building the PCH file. When using a PCH file, we do not initialize builtins at all; when needed, they'll be found in the PCH file. This optimization translations into a 9% speedup for "Hello, World!" with Carbon.h as a prefix header and roughly a 5% speedup for 403.gcc with its prefix header. We're also reading less of the PCH file for "Hello, World!": *** PCH Statistics: 286/20693 types read (1.382110%) 1630/59230 declarations read (2.751984%) 764/44914 identifiers read (1.701029%) 1/32954 statements read (0.003035%) 5/6187 macros read (0.080815%) down from *** PCH Statistics: 411/20693 types read (1.986179%) 2553/59230 declarations read (4.310316%) 1093/44646 identifiers read (2.448148%) 1/32954 statements read (0.003035%) 21/6187 macros read (0.339421%) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69815 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 14 +++++++++++++- include/clang/AST/Builtins.h | 5 +++++ include/clang/Frontend/PCHWriter.h | 4 ++++ lib/AST/ASTContext.cpp | 12 +++++++++--- lib/AST/Builtins.cpp | 18 +++++++++++++++++ lib/Frontend/PCHReader.cpp | 31 +++++++++++++++++++++++++++--- lib/Frontend/PCHWriter.cpp | 28 +++++++++++++++++++-------- tools/clang-cc/clang-cc.cpp | 9 ++++++++- 8 files changed, 105 insertions(+), 16 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 2be3689bc0..bba9cfb400 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -170,6 +170,8 @@ public: /// This is intentionally not serialized. It is populated by the /// ASTContext ctor, and there are no external pointers/references to /// internal variables of BuiltinInfo. + // FIXME: PCH does serialize this information, so that we don't have to + // construct it again when the PCH is loaded. Builtin::Context BuiltinInfo; // Builtin Types. @@ -188,10 +190,20 @@ public: ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, - bool FreeMemory = true, unsigned size_reserve=0); + bool FreeMemory = true, unsigned size_reserve=0, + bool InitializeBuiltins = true); ~ASTContext(); + /// \brief Initialize builtins. + /// + /// Typically, this routine will be called automatically by the + /// constructor. However, in certain cases (e.g., when there is a + /// PCH file to be loaded), the constructor does not perform + /// initialization for builtins. This routine can be called to + /// perform the initialization. + void InitializeBuiltins(IdentifierTable &idents); + /// \brief Attach an external AST source to the AST context. /// /// The external AST source provides the ability to load parts of diff --git a/include/clang/AST/Builtins.h b/include/clang/AST/Builtins.h index 9216029860..b16d3bf341 100644 --- a/include/clang/AST/Builtins.h +++ b/include/clang/AST/Builtins.h @@ -17,6 +17,7 @@ #include #include +#include "llvm/ADT/SmallVector.h" namespace clang { class TargetInfo; @@ -60,6 +61,10 @@ public: /// appropriate builtin ID # and mark any non-portable builtin identifiers as /// such. void InitializeBuiltins(IdentifierTable &Table, bool NoBuiltins = false); + + /// \brief Popular the vector with the names of all of the builtins. + void GetBuiltinNames(llvm::SmallVectorImpl &Names, + bool NoBuiltins); /// Builtin::GetName - Return the identifier name for the specified builtin, /// e.g. "__builtin_abs". diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index 2db253e7dd..d721f1077f 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -171,6 +171,10 @@ public: /// \brief Emit a reference to an identifier void AddIdentifierRef(const IdentifierInfo *II, RecordData &Record); + /// \brief Get the unique number used to refer to the given + /// identifier. + pch::IdentID getIdentifierRef(const IdentifierInfo *II); + /// \brief Retrieve the offset of the macro definition for the given /// identifier. /// diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 7d3c119d57..159110a080 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -34,16 +34,17 @@ enum FloatingRank { ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, - bool FreeMem, unsigned size_reserve) : + bool FreeMem, unsigned size_reserve, + bool InitializeBuiltins) : GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0), SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels), ExternalSource(0) { if (size_reserve > 0) Types.reserve(size_reserve); InitBuiltinTypes(); - BuiltinInfo.InitializeTargetBuiltins(Target); - BuiltinInfo.InitializeBuiltins(idents, LangOpts.NoBuiltin); TUDecl = TranslationUnitDecl::Create(*this); + if (InitializeBuiltins) + this->InitializeBuiltins(idents); } ASTContext::~ASTContext() { @@ -94,6 +95,11 @@ ASTContext::~ASTContext() { TUDecl->Destroy(*this); } +void ASTContext::InitializeBuiltins(IdentifierTable &idents) { + BuiltinInfo.InitializeTargetBuiltins(Target); + BuiltinInfo.InitializeBuiltins(idents, LangOpts.NoBuiltin); +} + void ASTContext::setExternalSource(llvm::OwningPtr &Source) { ExternalSource.reset(Source.take()); diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index ece9eeed76..3e1b3dc2a1 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -58,6 +58,24 @@ void Builtin::Context::InitializeBuiltins(IdentifierTable &Table, Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin); } +void +Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl &Names, + bool NoBuiltins) { + // Final all target-independent names + for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) + if (!BuiltinInfo[i].Suppressed && + (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))) + Names.push_back(BuiltinInfo[i].Name); + + // Find target-specific names. + for (unsigned i = 0, e = NumTSRecords; i != e; ++i) + if (!TSRecords[i].Suppressed && + (!NoBuiltins || + (TSRecords[i].Attributes && + !strchr(TSRecords[i].Attributes, 'f')))) + Names.push_back(TSRecords[i].Name); +} + bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg) { diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 031b71fbac..976b98dd11 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1110,10 +1110,21 @@ public: unsigned DataLen) { using namespace clang::io; uint32_t Bits = ReadUnalignedLE32(d); // FIXME: use these? - (void)Bits; - bool hasMacroDefinition = (Bits >> 3) & 0x01; - + bool CPlusPlusOperatorKeyword = Bits & 0x01; + Bits >>= 1; + bool Poisoned = Bits & 0x01; + Bits >>= 1; + bool ExtensionToken = Bits & 0x01; + Bits >>= 1; + bool hasMacroDefinition = Bits & 0x01; + Bits >>= 1; + unsigned ObjCOrBuiltinID = Bits & 0x3FF; + Bits >>= 10; + unsigned TokenID = Bits & 0xFF; + Bits >>= 8; + pch::IdentID ID = ReadUnalignedLE32(d); + assert(Bits == 0 && "Extra bits in the identifier?"); DataLen -= 8; // Build the IdentifierInfo itself and link the identifier ID with @@ -1124,6 +1135,20 @@ public: k.first, k.first + k.second); Reader.SetIdentifierInfo(ID, II); + // Set or check the various bits in the IdentifierInfo structure. + // FIXME: Load token IDs lazily, too? + assert((unsigned)II->getTokenID() == TokenID && + "Incorrect token ID loaded"); + (void)TokenID; + II->setObjCOrBuiltinID(ObjCOrBuiltinID); + assert(II->isExtensionToken() == ExtensionToken && + "Incorrect extension token flag"); + (void)ExtensionToken; + II->setIsPoisoned(Poisoned); + assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword && + "Incorrect C++ operator keyword flag"); + (void)CPlusPlusOperatorKeyword; + // If this identifier is a macro, deserialize the macro // definition. if (hasMacroDefinition) { diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index f34323c160..15ee2369dd 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -1800,8 +1800,8 @@ public: II->hasMacroDefinition() && !PP.getMacroInfo(const_cast(II))->isBuiltinMacro(); Bits = Bits | (uint32_t)II->getTokenID(); - Bits = (Bits << 8) | (uint32_t)II->getObjCOrBuiltinID(); - Bits = (Bits << 10) | hasMacroDefinition; + Bits = (Bits << 10) | (uint32_t)II->getObjCOrBuiltinID(); + Bits = (Bits << 1) | hasMacroDefinition; Bits = (Bits << 1) | II->isExtensionToken(); Bits = (Bits << 1) | II->isPoisoned(); Bits = (Bits << 1) | II->isCPlusPlusOperatorKeyword(); @@ -2028,6 +2028,17 @@ void PCHWriter::WritePCH(Sema &SemaRef) { DeclIDs[Context.getTranslationUnitDecl()] = 1; DeclsToEmit.push(Context.getTranslationUnitDecl()); + // Make sure that we emit IdentifierInfos (and any attached + // declarations) for builtins. + { + IdentifierTable &Table = PP.getIdentifierTable(); + llvm::SmallVector BuiltinNames; + Context.BuiltinInfo.GetBuiltinNames(BuiltinNames, + Context.getLangOptions().NoBuiltin); + for (unsigned I = 0, N = BuiltinNames.size(); I != N; ++I) + getIdentifierRef(&Table.get(BuiltinNames[I])); + } + // Write the remaining PCH contents. RecordData Record; Stream.EnterSubblock(pch::PCH_BLOCK_ID, 3); @@ -2079,16 +2090,17 @@ void PCHWriter::AddAPFloat(const llvm::APFloat &Value, RecordData &Record) { } void PCHWriter::AddIdentifierRef(const IdentifierInfo *II, RecordData &Record) { - if (II == 0) { - Record.push_back(0); - return; - } + Record.push_back(getIdentifierRef(II)); +} + +pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) { + if (II == 0) + return 0; pch::IdentID &ID = IdentifierIDs[II]; if (ID == 0) ID = IdentifierIDs.size(); - - Record.push_back(ID); + return ID; } void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp index 4f2ab2b746..37233134da 100644 --- a/tools/clang-cc/clang-cc.cpp +++ b/tools/clang-cc/clang-cc.cpp @@ -1760,7 +1760,9 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF, PP.getTargetInfo(), PP.getIdentifierTable(), PP.getSelectorTable(), - /* FreeMemory = */ !DisableFree)); + /* FreeMemory = */ !DisableFree, + /* size_reserve = */0, + /* InitializeBuiltins = */ImplicitIncludePCH.empty())); if (!ImplicitIncludePCH.empty()) { // The user has asked us to include a precompiled header. Load @@ -1788,6 +1790,11 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF, case PCHReader::IgnorePCH: // No suitable PCH file could be found. Just ignore the // -include-pch option entirely. + + // We delayed the initialization of builtins in the hope of + // loading the PCH file. Since the PCH file could not be + // loaded, initialize builtins now. + ContextOwner->InitializeBuiltins(PP.getIdentifierTable()); break; } -- 2.40.0