diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-04-21 23:56:24 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-04-21 23:56:24 +0000 |
commit | 37e2684abfe38207fdb90620da062bb18c23f29a (patch) | |
tree | e6133b2dba7f58acdc97c3cecb98b19a091fbc08 /lib/Frontend | |
parent | 868210e64ee979670424fd160b85744b8281b310 (diff) |
Lazy deserialization of macro definitions for precompiled headers.
This optimization improves performance on the Carbon-prefixed "Hello,
World!" example by 57%. For reference, we're now about 2.25x faster
than GCC PCH. We're also pulling in far less of the PCH file:
*** 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@69755 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Frontend')
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 151 | ||||
-rw-r--r-- | lib/Frontend/PCHWriter.cpp | 33 |
2 files changed, 131 insertions, 53 deletions
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 00075c88b6..6a6cd64120 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -36,6 +36,23 @@ using namespace clang; +namespace { + /// \brief Helper class that saves the current stream position and + /// then restores it when destroyed. + struct VISIBILITY_HIDDEN SavedStreamPosition { + explicit SavedStreamPosition(llvm::BitstreamReader &Stream) + : Stream(Stream), Offset(Stream.GetCurrentBitNo()) { } + + ~SavedStreamPosition() { + Stream.JumpToBit(Offset); + } + + private: + llvm::BitstreamReader &Stream; + uint64_t Offset; + }; +} + //===----------------------------------------------------------------------===// // Declaration deserialization //===----------------------------------------------------------------------===// @@ -1053,6 +1070,8 @@ public: using namespace clang::io; uint32_t Bits = ReadUnalignedLE32(d); // FIXME: use these? (void)Bits; + bool hasMacroDefinition = (Bits >> 3) & 0x01; + pch::IdentID ID = ReadUnalignedLE32(d); DataLen -= 8; @@ -1064,8 +1083,13 @@ public: k.first, k.first + k.second); Reader.SetIdentifierInfo(ID, II); - // FIXME: If this identifier is a macro, deserialize the macro - // definition now. + // If this identifier is a macro, deserialize the macro + // definition. + if (hasMacroDefinition) { + uint32_t Offset = ReadUnalignedLE64(d); + Reader.ReadMacroRecord(Offset); + DataLen -= 8; + } // Read all of the declarations visible at global scope with this // name. @@ -1323,27 +1347,28 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { } } -bool PCHReader::ReadPreprocessorBlock() { - if (Stream.EnterSubBlock(pch::PREPROCESSOR_BLOCK_ID)) - return Error("Malformed preprocessor block record"); - +void PCHReader::ReadMacroRecord(uint64_t Offset) { + // Keep track of where we are in the stream, then jump back there + // after reading this macro. + SavedStreamPosition SavedPosition(Stream); + + Stream.JumpToBit(Offset); RecordData Record; llvm::SmallVector<IdentifierInfo*, 16> MacroArgs; - MacroInfo *LastMacro = 0; - + MacroInfo *Macro = 0; while (true) { unsigned Code = Stream.ReadCode(); switch (Code) { case llvm::bitc::END_BLOCK: - if (Stream.ReadBlockEnd()) - return Error("Error at end of preprocessor block"); - return false; - + return; + case llvm::bitc::ENTER_SUBBLOCK: // No known subblocks, always skip them. Stream.ReadSubBlockID(); - if (Stream.SkipBlock()) - return Error("Malformed block record"); + if (Stream.SkipBlock()) { + Error("Malformed block record"); + return; + } continue; case llvm::bitc::DEFINE_ABBREV: @@ -1351,24 +1376,29 @@ bool PCHReader::ReadPreprocessorBlock() { continue; default: break; } - + // Read a record. Record.clear(); pch::PreprocessorRecordTypes RecType = (pch::PreprocessorRecordTypes)Stream.ReadRecord(Code, Record); switch (RecType) { - default: // Default behavior: ignore unknown records. - break; case pch::PP_COUNTER_VALUE: - if (!Record.empty()) - PP.setCounterValue(Record[0]); + // Skip this record. break; case pch::PP_MACRO_OBJECT_LIKE: case pch::PP_MACRO_FUNCTION_LIKE: { + // If we already have a macro, that means that we've hit the end + // of the definition of the macro we were looking for. We're + // done. + if (Macro) + return; + IdentifierInfo *II = DecodeIdentifierInfo(Record[0]); - if (II == 0) - return Error("Macro must have a name"); + if (II == 0) { + Error("Macro must have a name"); + return; + } SourceLocation Loc = SourceLocation::getFromRawEncoding(Record[1]); bool isUsed = Record[2]; @@ -1397,14 +1427,15 @@ bool PCHReader::ReadPreprocessorBlock() { // Remember that we saw this macro last so that we add the tokens that // form its body to it. - LastMacro = MI; + Macro = MI; + ++NumMacrosRead; break; } case pch::PP_TOKEN: { - // If we see a TOKEN before a PP_MACRO_*, then the file is eroneous, just - // pretend we didn't see this. - if (LastMacro == 0) break; + // If we see a TOKEN before a PP_MACRO_*, then the file is + // erroneous, just pretend we didn't see this. + if (Macro == 0) break; Token Tok; Tok.startToken(); @@ -1414,13 +1445,60 @@ bool PCHReader::ReadPreprocessorBlock() { Tok.setIdentifierInfo(II); Tok.setKind((tok::TokenKind)Record[3]); Tok.setFlag((Token::TokenFlags)Record[4]); - LastMacro->AddTokenToBody(Tok); + Macro->AddTokenToBody(Tok); break; } } } } +bool PCHReader::ReadPreprocessorBlock() { + if (Stream.EnterSubBlock(pch::PREPROCESSOR_BLOCK_ID)) + return Error("Malformed preprocessor block record"); + + RecordData Record; + while (true) { + unsigned Code = Stream.ReadCode(); + switch (Code) { + case llvm::bitc::END_BLOCK: + if (Stream.ReadBlockEnd()) + return Error("Error at end of preprocessor block"); + return false; + + case llvm::bitc::ENTER_SUBBLOCK: + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block record"); + continue; + + case llvm::bitc::DEFINE_ABBREV: + Stream.ReadAbbrevRecord(); + continue; + default: break; + } + + // Read a record. + Record.clear(); + pch::PreprocessorRecordTypes RecType = + (pch::PreprocessorRecordTypes)Stream.ReadRecord(Code, Record); + switch (RecType) { + default: // Default behavior: ignore unknown records. + break; + case pch::PP_COUNTER_VALUE: + if (!Record.empty()) + PP.setCounterValue(Record[0]); + break; + + case pch::PP_MACRO_OBJECT_LIKE: + case pch::PP_MACRO_FUNCTION_LIKE: + case pch::PP_TOKEN: + // Once we've hit a macro definition or a token, we're done. + return false; + } + } +} + PCHReader::PCHReadResult PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) { if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) { @@ -1573,6 +1651,7 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) { case pch::STATISTICS: TotalNumStatements = Record[0]; + TotalNumMacros = Record[1]; break; } @@ -1582,23 +1661,6 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) { return Failure; } -namespace { - /// \brief Helper class that saves the current stream position and - /// then restores it when destroyed. - struct VISIBILITY_HIDDEN SavedStreamPosition { - explicit SavedStreamPosition(llvm::BitstreamReader &Stream) - : Stream(Stream), Offset(Stream.GetCurrentBitNo()) { } - - ~SavedStreamPosition() { - Stream.JumpToBit(Offset); - } - - private: - llvm::BitstreamReader &Stream; - uint64_t Offset; - }; -} - PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { // Set the PCH file name. this->FileName = FileName; @@ -2364,6 +2426,9 @@ void PCHReader::PrintStats() { std::fprintf(stderr, " %u/%u statements read (%f%%)\n", NumStatementsRead, TotalNumStatements, ((float)NumStatementsRead/TotalNumStatements * 100)); + std::fprintf(stderr, " %u/%u macros read (%f%%)\n", + NumMacrosRead, TotalNumMacros, + ((float)NumMacrosRead/TotalNumMacros * 100)); std::fprintf(stderr, "\n"); } diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 1167250624..bdcd359314 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -1439,8 +1439,6 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { // Loop over all the macro definitions that are live at the end of the file, // emitting each to the PP section. - // FIXME: Eventually we want to emit an index so that we can lazily load - // macros. for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); I != E; ++I) { // FIXME: This emits macros in hash table order, we should do it in a stable @@ -1452,7 +1450,9 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { if (MI->isBuiltinMacro()) continue; + // FIXME: Remove this identifier reference? AddIdentifierRef(I->first, Record); + MacroOffsets[I->first] = Stream.GetCurrentBitNo(); Record.push_back(MI->getDefinitionLoc().getRawEncoding()); Record.push_back(MI->isUsed()); @@ -1494,7 +1494,7 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { Stream.EmitRecord(pch::PP_TOKEN, Record); Record.clear(); } - + ++NumMacros; } Stream.ExitBlock(); @@ -1715,6 +1715,7 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) { namespace { class VISIBILITY_HIDDEN PCHIdentifierTableTrait { PCHWriter &Writer; + Preprocessor &PP; public: typedef const IdentifierInfo* key_type; @@ -1723,19 +1724,23 @@ public: typedef pch::IdentID data_type; typedef data_type data_type_ref; - PCHIdentifierTableTrait(PCHWriter &Writer) : Writer(Writer) { } + PCHIdentifierTableTrait(PCHWriter &Writer, Preprocessor &PP) + : Writer(Writer), PP(PP) { } static unsigned ComputeHash(const IdentifierInfo* II) { return clang::BernsteinHash(II->getName()); } - static std::pair<unsigned,unsigned> + std::pair<unsigned,unsigned> EmitKeyDataLength(llvm::raw_ostream& Out, const IdentifierInfo* II, pch::IdentID ID) { unsigned KeyLen = strlen(II->getName()) + 1; clang::io::Emit16(Out, KeyLen); unsigned DataLen = 4 + 4; // 4 bytes for token ID, builtin, flags // 4 bytes for the persistent ID + if (II->hasMacroDefinition() && + !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro()) + DataLen += 8; for (IdentifierResolver::iterator D = IdentifierResolver::begin(II), DEnd = IdentifierResolver::end(); D != DEnd; ++D) @@ -1755,15 +1760,21 @@ public: void EmitData(llvm::raw_ostream& Out, const IdentifierInfo* II, pch::IdentID ID, unsigned) { uint32_t Bits = 0; + bool hasMacroDefinition = + 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) | II->hasMacroDefinition(); + Bits = (Bits << 10) | hasMacroDefinition; Bits = (Bits << 1) | II->isExtensionToken(); Bits = (Bits << 1) | II->isPoisoned(); Bits = (Bits << 1) | II->isCPlusPlusOperatorKeyword(); clang::io::Emit32(Out, Bits); clang::io::Emit32(Out, ID); + if (hasMacroDefinition) + clang::io::Emit64(Out, Writer.getMacroOffset(II)); + // Emit the declaration IDs in reverse order, because the // IdentifierResolver provides the declarations as they would be // visible (e.g., the function "stat" would come before the struct @@ -1785,7 +1796,7 @@ public: /// The identifier table consists of a blob containing string data /// (the actual identifiers themselves) and a separate "offsets" index /// that maps identifier IDs to locations within the blob. -void PCHWriter::WriteIdentifierTable() { +void PCHWriter::WriteIdentifierTable(Preprocessor &PP) { using namespace llvm; // Create and write out the blob that contains the identifier @@ -1806,7 +1817,7 @@ void PCHWriter::WriteIdentifierTable() { llvm::SmallVector<char, 4096> IdentifierTable; uint32_t BucketOffset; { - PCHIdentifierTableTrait Trait(*this); + PCHIdentifierTableTrait Trait(*this, PP); llvm::raw_svector_ostream Out(IdentifierTable); BucketOffset = Generator.Emit(Out, Trait); } @@ -1964,7 +1975,8 @@ void PCHWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) { } PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream) - : Stream(Stream), NextTypeID(pch::NUM_PREDEF_TYPE_IDS), NumStatements(0) { } + : Stream(Stream), NextTypeID(pch::NUM_PREDEF_TYPE_IDS), + NumStatements(0), NumMacros(0) { } void PCHWriter::WritePCH(Sema &SemaRef) { ASTContext &Context = SemaRef.Context; @@ -1989,7 +2001,7 @@ void PCHWriter::WritePCH(Sema &SemaRef) { WritePreprocessor(PP); WriteTypesBlock(Context); WriteDeclsBlock(Context); - WriteIdentifierTable(); + WriteIdentifierTable(PP); Stream.EmitRecord(pch::TYPE_OFFSET, TypeOffsets); Stream.EmitRecord(pch::DECL_OFFSET, DeclOffsets); @@ -2004,6 +2016,7 @@ void PCHWriter::WritePCH(Sema &SemaRef) { // Some simple statistics Record.clear(); Record.push_back(NumStatements); + Record.push_back(NumMacros); Stream.EmitRecord(pch::STATISTICS, Record); Stream.ExitBlock(); } |