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
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 00075c8..6a6cd64 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 @@
     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 @@
                                                  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,14 +1347,116 @@
   }
 }
 
+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 *Macro = 0;
+  while (true) {
+    unsigned Code = Stream.ReadCode();
+    switch (Code) {
+    case llvm::bitc::END_BLOCK:
+      return;
+
+    case llvm::bitc::ENTER_SUBBLOCK:
+      // No known subblocks, always skip them.
+      Stream.ReadSubBlockID();
+      if (Stream.SkipBlock()) {
+        Error("Malformed block record");
+        return;
+      }
+      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) {
+    case pch::PP_COUNTER_VALUE:
+      // 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) {
+        Error("Macro must have a name");
+        return;
+      }
+      SourceLocation Loc = SourceLocation::getFromRawEncoding(Record[1]);
+      bool isUsed = Record[2];
+      
+      MacroInfo *MI = PP.AllocateMacroInfo(Loc);
+      MI->setIsUsed(isUsed);
+      
+      if (RecType == pch::PP_MACRO_FUNCTION_LIKE) {
+        // Decode function-like macro info.
+        bool isC99VarArgs = Record[3];
+        bool isGNUVarArgs = Record[4];
+        MacroArgs.clear();
+        unsigned NumArgs = Record[5];
+        for (unsigned i = 0; i != NumArgs; ++i)
+          MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i]));
+
+        // Install function-like macro info.
+        MI->setIsFunctionLike();
+        if (isC99VarArgs) MI->setIsC99Varargs();
+        if (isGNUVarArgs) MI->setIsGNUVarargs();
+        MI->setArgumentList(&MacroArgs[0], MacroArgs.size(),
+                            PP.getPreprocessorAllocator());
+      }
+
+      // Finally, install the macro.
+      PP.setMacroInfo(II, MI);
+
+      // Remember that we saw this macro last so that we add the tokens that
+      // form its body to it.
+      Macro = MI;
+      ++NumMacrosRead;
+      break;
+    }
+        
+    case pch::PP_TOKEN: {
+      // 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();
+      Tok.setLocation(SourceLocation::getFromRawEncoding(Record[0]));
+      Tok.setLength(Record[1]);
+      if (IdentifierInfo *II = DecodeIdentifierInfo(Record[2]))
+        Tok.setIdentifierInfo(II);
+      Tok.setKind((tok::TokenKind)Record[3]);
+      Tok.setFlag((Token::TokenFlags)Record[4]);
+      Macro->AddTokenToBody(Tok);
+      break;
+    }
+    }
+  }
+}
+
 bool PCHReader::ReadPreprocessorBlock() {
   if (Stream.EnterSubBlock(pch::PREPROCESSOR_BLOCK_ID))
     return Error("Malformed preprocessor block record");
   
   RecordData Record;
-  llvm::SmallVector<IdentifierInfo*, 16> MacroArgs;
-  MacroInfo *LastMacro = 0;
-  
   while (true) {
     unsigned Code = Stream.ReadCode();
     switch (Code) {
@@ -1365,58 +1491,10 @@
       break;
 
     case pch::PP_MACRO_OBJECT_LIKE:
-    case pch::PP_MACRO_FUNCTION_LIKE: {
-      IdentifierInfo *II = DecodeIdentifierInfo(Record[0]);
-      if (II == 0)
-        return Error("Macro must have a name");
-      SourceLocation Loc = SourceLocation::getFromRawEncoding(Record[1]);
-      bool isUsed = Record[2];
-      
-      MacroInfo *MI = PP.AllocateMacroInfo(Loc);
-      MI->setIsUsed(isUsed);
-      
-      if (RecType == pch::PP_MACRO_FUNCTION_LIKE) {
-        // Decode function-like macro info.
-        bool isC99VarArgs = Record[3];
-        bool isGNUVarArgs = Record[4];
-        MacroArgs.clear();
-        unsigned NumArgs = Record[5];
-        for (unsigned i = 0; i != NumArgs; ++i)
-          MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i]));
-
-        // Install function-like macro info.
-        MI->setIsFunctionLike();
-        if (isC99VarArgs) MI->setIsC99Varargs();
-        if (isGNUVarArgs) MI->setIsGNUVarargs();
-        MI->setArgumentList(&MacroArgs[0], MacroArgs.size(),
-                            PP.getPreprocessorAllocator());
-      }
-
-      // Finally, install the macro.
-      PP.setMacroInfo(II, MI);
-
-      // Remember that we saw this macro last so that we add the tokens that
-      // form its body to it.
-      LastMacro = MI;
-      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;
-      
-      Token Tok;
-      Tok.startToken();
-      Tok.setLocation(SourceLocation::getFromRawEncoding(Record[0]));
-      Tok.setLength(Record[1]);
-      if (IdentifierInfo *II = DecodeIdentifierInfo(Record[2]))
-        Tok.setIdentifierInfo(II);
-      Tok.setKind((tok::TokenKind)Record[3]);
-      Tok.setFlag((Token::TokenFlags)Record[4]);
-      LastMacro->AddTokenToBody(Tok);
-      break;
-    }
+    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;
     }
   }
 }
@@ -1573,6 +1651,7 @@
 
     case pch::STATISTICS:
       TotalNumStatements = Record[0];
+      TotalNumMacros = Record[1];
       break;
 
     }
@@ -1582,23 +1661,6 @@
   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 @@
   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");
 }