[cfe-commits] r60956 - in /cfe/trunk: include/clang/Lex/PTHLexer.h include/clang/Lex/Preprocessor.h lib/Lex/PPDirectives.cpp lib/Lex/PTHLexer.cpp

Ted Kremenek kremenek at apple.com
Fri Dec 12 10:34:08 PST 2008


Author: kremenek
Date: Fri Dec 12 12:34:08 2008
New Revision: 60956

URL: http://llvm.org/viewvc/llvm-project?rev=60956&view=rev
Log:
Added PTH optimization to not process entire blocks of tokens that appear in skipped preprocessor blocks.  This improves PTH speed by 6%.  The code for this optimization itself is not very optimized, and will get cleaned up.

Modified:
    cfe/trunk/include/clang/Lex/PTHLexer.h
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/lib/Lex/PPDirectives.cpp
    cfe/trunk/lib/Lex/PTHLexer.cpp

Modified: cfe/trunk/include/clang/Lex/PTHLexer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/PTHLexer.h?rev=60956&r1=60955&r2=60956&view=diff

==============================================================================
--- cfe/trunk/include/clang/Lex/PTHLexer.h (original)
+++ cfe/trunk/include/clang/Lex/PTHLexer.h Fri Dec 12 12:34:08 2008
@@ -32,6 +32,15 @@
   /// LastHashTokPtr - Pointer into TokBuf of the last processed '#'
   ///  token that appears at the start of a line.
   const char* LastHashTokPtr;
+  
+  /// PPCond - Pointer to a side table in the PTH file that provides a
+  ///  a consise summary of the preproccessor conditional block structure.
+  ///  This is used to perform quick skipping of conditional blocks.
+  const char* PPCond;
+  
+  /// CurPPCondPtr - Pointer inside PPCond that refers to the next entry
+  ///  to process when doing quick skipping of preprocessor blocks.
+  const char* CurPPCondPtr;
 
   PTHLexer(const PTHLexer&);  // DO NOT IMPLEMENT
   void operator=(const PTHLexer&); // DO NOT IMPLEMENT
@@ -50,7 +59,7 @@
 
   /// Create a PTHLexer for the specified token stream.
   PTHLexer(Preprocessor& pp, SourceLocation fileloc, const char* D, 
-           PTHManager& PM);
+           const char* ppcond, PTHManager& PM);
   
   ~PTHLexer() {}
     
@@ -77,17 +86,11 @@
   /// getSourceLocation - Return a source location for the token in
   /// the current file.
   SourceLocation getSourceLocation() { return GetToken().getLocation(); }
-
-private:
-  
-  /// SkipToToken - Skip to the token at the specified offset in TokBuf.
-  void SkipToToken(unsigned offset) {
-    const char* NewPtr = TokBuf + offset;
-    assert(NewPtr > CurPtr && "SkipToToken should not go backwards!");
-    NeedsFetching = true;
-    CurPtr = NewPtr;
-  }
   
+  /// SkipBlock - Used by Preprocessor to skip the current conditional block.
+  bool SkipBlock();
+
+private:  
   /// AtLastToken - Returns true if the PTHLexer is at the last token.
   bool AtLastToken() { 
     Token T = GetToken();

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=60956&r1=60955&r2=60956&view=diff

==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Fri Dec 12 12:34:08 2008
@@ -560,6 +560,10 @@
   void SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
                                     bool FoundNonSkipPortion, bool FoundElse);
   
+  /// PTHSkipExcludedConditionalBlock - A fast PTH version of
+  ///  SkipExcludedConditionalBlock.
+  void PTHSkipExcludedConditionalBlock();
+  
   /// EvaluateDirectiveExpression - Evaluate an integer constant expression that
   /// may occur after a #if or #elif directive and return it as a bool.  If the
   /// expression is equivalent to "!defined(X)" return X in IfNDefMacro.

Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=60956&r1=60955&r2=60956&view=diff

==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Fri Dec 12 12:34:08 2008
@@ -122,6 +122,11 @@
   CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/false,
                                  FoundNonSkipPortion, FoundElse);
   
+  if (CurPTHLexer) {
+    PTHSkipExcludedConditionalBlock();
+    return;
+  }
+  
   // Enter raw mode to disable identifier lookup (and thus macro expansion),
   // disabling warnings, etc.
   CurPPLexer->LexingRawMode = true;
@@ -291,6 +296,79 @@
   CurPPLexer->LexingRawMode = false;
 }
 
+void Preprocessor::PTHSkipExcludedConditionalBlock() {
+  
+  while(1) {
+    assert(CurPTHLexer);
+    assert(CurPTHLexer->LexingRawMode == false);
+           
+    // Skip to the next '#else', '#elif', or #endif.
+    if (CurPTHLexer->SkipBlock()) {
+      // We have reached an #endif.  Both the '#' and 'endif' tokens
+      // have been consumed by the PTHLexer.  Just pop off the condition level.
+      PPConditionalInfo CondInfo;
+      bool InCond = CurPTHLexer->popConditionalLevel(CondInfo);
+      InCond = InCond;  // Silence warning in no-asserts mode.
+      assert(!InCond && "Can't be skipping if not in a conditional!");
+      break;
+    }
+      
+    // We have reached a '#else' or '#elif'.  Lex the next token to get
+    // the directive flavor.
+    Token Tok;
+    LexUnexpandedToken(Tok);
+                      
+    // We can actually look up the IdentifierInfo here since we aren't in
+    // raw mode.
+    tok::PPKeywordKind K = Tok.getIdentifierInfo()->getPPKeywordID();
+
+    if (K == tok::pp_else) {
+      // #else: Enter the else condition.  We aren't in a nested condition
+      //  since we skip those. We're always in the one matching the last
+      //  blocked we skipped.
+      PPConditionalInfo &CondInfo = CurPTHLexer->peekConditionalLevel();
+      // Note that we've seen a #else in this conditional.
+      CondInfo.FoundElse = true;
+      
+      // If the #if block wasn't entered then enter the #else block now.
+      if (!CondInfo.FoundNonSkip) {
+        CondInfo.FoundNonSkip = true;
+        break;
+      }
+      
+      // Otherwise skip this block.
+      continue;
+    }
+    
+    assert(K == tok::pp_elif);
+    PPConditionalInfo &CondInfo = CurPTHLexer->peekConditionalLevel();
+
+    // If this is a #elif with a #else before it, report the error.
+    if (CondInfo.FoundElse)
+      Diag(Tok, diag::pp_err_elif_after_else);
+    
+    // If this is in a skipping block or if we're already handled this #if
+    // block, don't bother parsing the condition.  We just skip this block.    
+    if (CondInfo.FoundNonSkip)
+      continue;
+
+    // Evaluate the condition of the #elif.
+    IdentifierInfo *IfNDefMacro = 0;
+    CurPTHLexer->ParsingPreprocessorDirective = true;
+    bool ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro);
+    CurPTHLexer->ParsingPreprocessorDirective = false;
+
+    // If this condition is true, enter it!
+    if (ShouldEnter) {
+      CondInfo.FoundNonSkip = true;
+      break;
+    }
+
+    // Otherwise, skip this block and go to the next one.
+    continue;
+  }
+}
+
 /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
 /// return null on failure.  isAngled indicates whether the file reference is
 /// for system #include's or not (i.e. using <> instead of "").

Modified: cfe/trunk/lib/Lex/PTHLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PTHLexer.cpp?rev=60956&r1=60955&r2=60956&view=diff

==============================================================================
--- cfe/trunk/lib/Lex/PTHLexer.cpp (original)
+++ cfe/trunk/lib/Lex/PTHLexer.cpp Fri Dec 12 12:34:08 2008
@@ -26,11 +26,12 @@
 
 using namespace clang;
 
+#define DISK_TOKEN_SIZE (2+3*4)
+
 PTHLexer::PTHLexer(Preprocessor& pp, SourceLocation fileloc, const char* D,
-                   PTHManager& PM)
+                   const char* ppcond, PTHManager& PM)
   : PreprocessorLexer(&pp, fileloc), TokBuf(D), CurPtr(D), LastHashTokPtr(0),
-    PTHMgr(PM),
-    NeedsFetching(true) {
+    PPCond(ppcond), CurPPCondPtr(ppcond), PTHMgr(PM), NeedsFetching(true) {
     // Make sure the EofToken is completely clean.
     EofToken.startToken();
   }
@@ -82,15 +83,16 @@
   AdvanceToken();
     
   if (Tok.is(tok::hash)) {    
-    if (Tok.isAtStartOfLine() && !LexingRawMode) {
-      LastHashTokPtr = CurPtr;
-      
-      PP->HandleDirective(Tok);
-
-      if (PP->isCurrentLexer(this))
-        goto LexNextToken;
-
-      return PP->Lex(Tok);
+    if (Tok.isAtStartOfLine()) {
+      LastHashTokPtr = CurPtr - DISK_TOKEN_SIZE;
+      if (!LexingRawMode) {
+        PP->HandleDirective(Tok);
+
+        if (PP->isCurrentLexer(this))
+          goto LexNextToken;
+        
+        return PP->Lex(Tok);
+      }
     }
   }
 
@@ -156,6 +158,82 @@
   return V;
 }
 
+/// SkipBlock - Used by Preprocessor to skip the current conditional block.
+bool PTHLexer::SkipBlock() {
+  assert(CurPPCondPtr && "No cached PP conditional information.");
+  assert(LastHashTokPtr && "No known '#' token.");
+  
+  const char* Next = 0;
+  uint32_t Offset; 
+  uint32_t TableIdx;
+  
+  do {
+    Offset = Read32(CurPPCondPtr);
+    TableIdx = Read32(CurPPCondPtr);
+    Next = TokBuf + Offset;
+  }
+  while (Next < LastHashTokPtr);  
+  assert(Next == LastHashTokPtr && "No PP-cond entry found for '#'");
+  assert(TableIdx && "No jumping from #endifs.");
+  
+  // Update our side-table iterator.
+  const char* NextPPCondPtr = PPCond + TableIdx*(sizeof(uint32_t)*2);
+  assert(NextPPCondPtr >= CurPPCondPtr);
+  CurPPCondPtr = NextPPCondPtr;
+  
+  // Read where we should jump to.
+  Next = TokBuf + Read32(NextPPCondPtr);
+  uint32_t NextIdx = Read32(NextPPCondPtr);
+  
+  // By construction NextIdx will be zero if this is a #endif.  This is useful
+  // to know to obviate lexing another token.
+  bool isEndif = NextIdx == 0;
+  NeedsFetching = true;
+  
+  // This case can occur when we see something like this:
+  //
+  //  #if ...
+  //   /* a comment or nothing */
+  //  #elif
+  //
+  // If we are skipping the first #if block it will be the case that CurPtr
+  // already points 'elif'.  Just return.
+  
+  if (CurPtr > Next) {
+    assert(CurPtr == Next + DISK_TOKEN_SIZE);
+    // Did we reach a #endif?  If so, go ahead and consume that token as well.
+    if (isEndif)
+      CurPtr += DISK_TOKEN_SIZE;
+    else
+      LastHashTokPtr = Next;
+    
+    return isEndif;
+  }
+
+  // Otherwise, we need to advance.  Update CurPtr to point to the '#' token.
+  CurPtr = Next;
+  
+  // Update the location of the last observed '#'.  This is useful if we
+  // are skipping multiple blocks.
+  LastHashTokPtr = CurPtr;
+  
+#ifndef DEBUG
+  // In a debug build we should verify that the token is really a '#' that
+  // appears at the start of the line.
+  Token Tok;
+  ReadToken(Tok);
+  assert(Tok.isAtStartOfLine() && Tok.is(tok::hash));
+#else
+  // In a full release build we can just skip the token entirely.
+  CurPtr += DISK_TOKEN_SIZE;
+#endif
+
+  // Did we reach a #endif?  If so, go ahead and consume that token as well.
+  if (isEndif) { CurPtr += DISK_TOKEN_SIZE; }
+
+  return isEndif;
+}
+
 //===----------------------------------------------------------------------===//
 // Token reconstruction from the PTH file.
 //===----------------------------------------------------------------------===//
@@ -179,7 +257,7 @@
   T.setLocation(SourceLocation::getFileLoc(FileID, Read32(CurPtr)));
   
   // Finally, read and set the length of the token.
-  T.setLength(Read32(CurPtr));
+  T.setLength(Read32(CurPtr));  
 }
 
 //===----------------------------------------------------------------------===//
@@ -364,6 +442,13 @@
   
   // Compute the offset of the token data within the buffer.
   const char* data = Buf->getBufferStart() + FileData.getTokenOffset();
+
+  // Get the location of pp-conditional table.
+  const char* ppcond = Buf->getBufferStart() + FileData.gettPPCondOffset();
+  uint32_t len = Read32(ppcond);  
+  if (len == 0) ppcond = 0;
+  
   assert(data < Buf->getBufferEnd());
-  return new PTHLexer(PP, SourceLocation::getFileLoc(FileID, 0), data, *this); 
+  return new PTHLexer(PP, SourceLocation::getFileLoc(FileID, 0), data, ppcond,
+                      *this); 
 }





More information about the cfe-commits mailing list