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
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 2be3689..bba9cfb 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -170,6 +170,8 @@
/// 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 @@
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 9216029..b16d3bf 100644
--- a/include/clang/AST/Builtins.h
+++ b/include/clang/AST/Builtins.h
@@ -17,6 +17,7 @@
#include <cstring>
#include <string>
+#include "llvm/ADT/SmallVector.h"
namespace clang {
class TargetInfo;
@@ -60,6 +61,10 @@
/// 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<const char *> &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 2db253e..d721f10 100644
--- a/include/clang/Frontend/PCHWriter.h
+++ b/include/clang/Frontend/PCHWriter.h
@@ -171,6 +171,10 @@
/// \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 7d3c119..159110a 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -34,16 +34,17 @@
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 @@
TUDecl->Destroy(*this);
}
+void ASTContext::InitializeBuiltins(IdentifierTable &idents) {
+ BuiltinInfo.InitializeTargetBuiltins(Target);
+ BuiltinInfo.InitializeBuiltins(idents, LangOpts.NoBuiltin);
+}
+
void
ASTContext::setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source) {
ExternalSource.reset(Source.take());
diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp
index ece9eee..3e1b3dc 100644
--- a/lib/AST/Builtins.cpp
+++ b/lib/AST/Builtins.cpp
@@ -58,6 +58,24 @@
Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin);
}
+void
+Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &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 031b71f..976b98d 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -1110,10 +1110,21 @@
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 @@
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 f34323c..15ee236 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -1800,8 +1800,8 @@
II->hasMacroDefinition() &&
!PP.getMacroInfo(const_cast<IdentifierInfo *>(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 @@
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<const char *, 32> 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::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 4f2ab2b..3723313 100644
--- a/tools/clang-cc/clang-cc.cpp
+++ b/tools/clang-cc/clang-cc.cpp
@@ -1760,7 +1760,9 @@
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 @@
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;
}