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/PCHReader.cpp | |
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/PCHReader.cpp')
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 151 |
1 files changed, 108 insertions, 43 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"); } |