[cfe-commits] r138225 - in /cfe/trunk: include/clang/Basic/SourceManager.h include/clang/Lex/PreprocessorLexer.h lib/Basic/SourceManager.cpp lib/Lex/PPLexerChange.cpp lib/Lex/PreprocessorLexer.cpp lib/Serialization/ASTReader.cpp lib/Serialization/ASTWriter.cpp

Argyrios Kyrtzidis akyrtzi at gmail.com
Sun Aug 21 16:33:04 PDT 2011


Author: akirtzidis
Date: Sun Aug 21 18:33:04 2011
New Revision: 138225

URL: http://llvm.org/viewvc/llvm-project?rev=138225&view=rev
Log:
Boost the efficiency of SourceManager::getMacroArgExpandedLocation.

Currently getMacroArgExpandedLocation is very inefficient and for the case
of a location pointing at the main file it will end up checking almost all of
the SLocEntries. Make it faster:

-Use a map of macro argument chunks to their expanded source location. The map
 is for a single source file, it's stored in the file's ContentCache and lazily
 computed, like the source lines cache.
-In SLocEntry's FileInfo add an 'unsigned NumCreatedFIDs' field that keeps track
 of the number of FileIDs (files and macros) that were created during preprocessing
 of that particular file SLocEntry. This is useful when computing the macro argument
 map in skipping included files while scanning for macro arg FileIDs that lexed from
 a specific source file. Due to padding, the new field does not increase the size
 of SLocEntry.

Modified:
    cfe/trunk/include/clang/Basic/SourceManager.h
    cfe/trunk/include/clang/Lex/PreprocessorLexer.h
    cfe/trunk/lib/Basic/SourceManager.cpp
    cfe/trunk/lib/Lex/PPLexerChange.cpp
    cfe/trunk/lib/Lex/PreprocessorLexer.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp

Modified: cfe/trunk/include/clang/Basic/SourceManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/SourceManager.h?rev=138225&r1=138224&r2=138225&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/SourceManager.h (original)
+++ cfe/trunk/include/clang/Basic/SourceManager.h Sun Aug 21 18:33:04 2011
@@ -23,6 +23,7 @@
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include <map>
 #include <vector>
 #include <cassert>
 
@@ -34,6 +35,8 @@
 class FileEntry;
 class LineTableInfo;
 class LangOptions;
+class ASTWriter;
+class ASTReader;
   
 /// SrcMgr - Public enums and private classes that are part of the
 /// SourceManager implementation.
@@ -85,6 +88,11 @@
     /// if SourceLineCache is non-null.
     unsigned NumLines;
 
+    /// \brief Lazily computed map of macro argument chunks to their expanded
+    /// source location.
+    typedef std::map<unsigned, SourceLocation> MacroArgsMap;
+    MacroArgsMap *MacroArgsCache;
+
     /// getBuffer - Returns the memory buffer for the associated content.
     ///
     /// \param Diag Object through which diagnostics will be emitted if the
@@ -142,11 +150,11 @@
     
     ContentCache(const FileEntry *Ent = 0)
       : Buffer(0, false), OrigEntry(Ent), ContentsEntry(Ent),
-        SourceLineCache(0), NumLines(0) {}
+        SourceLineCache(0), NumLines(0), MacroArgsCache(0) {}
 
     ContentCache(const FileEntry *Ent, const FileEntry *contentEnt)
       : Buffer(0, false), OrigEntry(Ent), ContentsEntry(contentEnt),
-        SourceLineCache(0), NumLines(0) {}
+        SourceLineCache(0), NumLines(0), MacroArgsCache(0) {}
 
     ~ContentCache();
 
@@ -154,12 +162,13 @@
     ///  a non-NULL Buffer or SourceLineCache.  Ownership of allocated memory
     ///  is not transferred, so this is a logical error.
     ContentCache(const ContentCache &RHS) 
-      : Buffer(0, false), SourceLineCache(0) 
+      : Buffer(0, false), SourceLineCache(0), MacroArgsCache(0)
     {
       OrigEntry = RHS.OrigEntry;
       ContentsEntry = RHS.ContentsEntry;
 
-      assert (RHS.Buffer.getPointer() == 0 && RHS.SourceLineCache == 0
+      assert (RHS.Buffer.getPointer() == 0 && RHS.SourceLineCache == 0 &&
+              RHS.MacroArgsCache == 0
               && "Passed ContentCache object cannot own a buffer.");
 
       NumLines = RHS.NumLines;
@@ -184,16 +193,26 @@
     /// This is an invalid SLOC for the main file (top of the #include chain).
     unsigned IncludeLoc;  // Really a SourceLocation
 
+    /// \brief Number of FileIDs (files and macros) that were created during
+    /// preprocessing of this #include, including this SLocEntry.
+    /// Zero means the preprocessor didn't provide such info for this SLocEntry.
+    unsigned NumCreatedFIDs;
+
     /// Data - This contains the ContentCache* and the bits indicating the
     /// characteristic of the file and whether it has #line info, all bitmangled
     /// together.
     uintptr_t Data;
+
+    friend class SourceManager;
+    friend class ASTWriter;
+    friend class ASTReader;
   public:
     /// get - Return a FileInfo object.
     static FileInfo get(SourceLocation IL, const ContentCache *Con,
                         CharacteristicKind FileCharacter) {
       FileInfo X;
       X.IncludeLoc = IL.getRawEncoding();
+      X.NumCreatedFIDs = 0;
       X.Data = (uintptr_t)Con;
       assert((X.Data & 7) == 0 &&"ContentCache pointer insufficiently aligned");
       assert((unsigned)FileCharacter < 4 && "invalid file character");
@@ -711,6 +730,28 @@
   /// \param Invalid If non-NULL, will be set true if an error occurred.
   StringRef getBufferData(FileID FID, bool *Invalid = 0) const;
 
+  /// \brief Get the number of FileIDs (files and macros) that were created
+  /// during preprocessing of \arg FID, including it.
+  unsigned getNumCreatedFIDsForFileID(FileID FID) const {
+    bool Invalid = false;
+    const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+    if (Invalid || !Entry.isFile())
+      return 0;
+
+    return Entry.getFile().NumCreatedFIDs;
+  }
+
+  /// \brief Set the number of FileIDs (files and macros) that were created
+  /// during preprocessing of \arg FID, including it.
+  void setNumCreatedFIDsForFileID(FileID FID, unsigned NumFIDs) const {
+    bool Invalid = false;
+    const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+    if (Invalid || !Entry.isFile())
+      return;
+
+    assert(Entry.getFile().NumCreatedFIDs == 0 && "Already set!");
+    const_cast<SrcMgr::FileInfo &>(Entry.getFile()).NumCreatedFIDs = NumFIDs;
+  }
 
   //===--------------------------------------------------------------------===//
   // SourceLocation manipulation methods.
@@ -743,6 +784,17 @@
     return SourceLocation::getFileLoc(FileOffset);
   }
 
+  /// \brief Returns the include location if \arg FID is a #include'd file
+  /// otherwise it returns an invalid location.
+  SourceLocation getIncludeLoc(FileID FID) const {
+    bool Invalid = false;
+    const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+    if (Invalid || !Entry.isFile())
+      return SourceLocation();
+    
+    return Entry.getFile().getIncludeLoc();
+  }
+
   /// getExpansionLoc - Given a SourceLocation object, return the expansion
   /// location referenced by the ID.
   SourceLocation getExpansionLoc(SourceLocation Loc) const {
@@ -1205,6 +1257,7 @@
   std::pair<FileID, unsigned>
   getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
                                    unsigned Offset) const;
+  void computeMacroArgsCache(SrcMgr::ContentCache *Content, FileID FID);
 };
 
 

Modified: cfe/trunk/include/clang/Lex/PreprocessorLexer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/PreprocessorLexer.h?rev=138225&r1=138224&r2=138225&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/PreprocessorLexer.h (original)
+++ cfe/trunk/include/clang/Lex/PreprocessorLexer.h Sun Aug 21 18:33:04 2011
@@ -30,6 +30,9 @@
   /// The SourceManager FileID corresponding to the file being lexed.
   const FileID FID;
 
+  /// \brief Number of SLocEntries before lexing the file.
+  unsigned InitialNumSLocEntries;
+
   //===--------------------------------------------------------------------===//
   // Context-specific lexing flags set by the preprocessor.
   //===--------------------------------------------------------------------===//
@@ -67,12 +70,10 @@
   void operator=(const PreprocessorLexer&); // DO NOT IMPLEMENT
   friend class Preprocessor;
 
-  PreprocessorLexer(Preprocessor *pp, FileID fid)
-    : PP(pp), FID(fid), ParsingPreprocessorDirective(false),
-      ParsingFilename(false), LexingRawMode(false) {}
+  PreprocessorLexer(Preprocessor *pp, FileID fid);
 
   PreprocessorLexer()
-    : PP(0),
+    : PP(0), InitialNumSLocEntries(0),
       ParsingPreprocessorDirective(false),
       ParsingFilename(false),
       LexingRawMode(false) {}
@@ -151,6 +152,11 @@
     return FID;
   }
 
+  /// \brief Number of SLocEntries before lexing the file.
+  unsigned getInitialNumSLocEntries() const {
+    return InitialNumSLocEntries;
+  }
+
   /// getFileEntry - Return the FileEntry corresponding to this FileID.  Like
   /// getFileID(), this only works for lexers with attached preprocessors.
   const FileEntry *getFileEntry() const;

Modified: cfe/trunk/lib/Basic/SourceManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/SourceManager.cpp?rev=138225&r1=138224&r2=138225&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/SourceManager.cpp (original)
+++ cfe/trunk/lib/Basic/SourceManager.cpp Sun Aug 21 18:33:04 2011
@@ -17,6 +17,7 @@
 #include "clang/Basic/FileManager.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/raw_ostream.h"
@@ -38,6 +39,7 @@
 ContentCache::~ContentCache() {
   if (shouldFreeBuffer())
     delete Buffer.getPointer();
+  delete MacroArgsCache;
 }
 
 /// getSizeBytesMapped - Returns the number of bytes actually mapped for this
@@ -1452,22 +1454,21 @@
   return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + Col - 1);
 }
 
-/// \brief If \arg Loc points inside a function macro argument, the returned
-/// location will be the macro location in which the argument was expanded.
-/// If a macro argument is used multiple times, the expanded location will
-/// be at the first expansion of the argument.
-/// e.g.
-///   MY_MACRO(foo);
-///             ^
-/// Passing a file location pointing at 'foo', will yield a macro location
-/// where 'foo' was expanded into.
-SourceLocation SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) {
-  if (Loc.isInvalid())
-    return Loc;
-  
-  FileID FID = getFileID(Loc);
-  if (FID.isInvalid())
-    return Loc;
+/// \brief Compute a map of macro argument chunks to their expanded source
+/// location. Chunks that are not part of a macro argument will map to an
+/// invalid source location. e.g. if a file contains one macro argument at
+/// offset 100 with length 10, this is how the map will be formed:
+///     0   -> SourceLocation()
+///     100 -> Expanded macro arg location
+///     110 -> SourceLocation()
+void SourceManager::computeMacroArgsCache(ContentCache *Content, FileID FID) {
+  assert(!Content->MacroArgsCache);
+  assert(!FID.isInvalid());
+
+  Content->MacroArgsCache = new ContentCache::MacroArgsMap();
+  ContentCache::MacroArgsMap &MacroArgsCache = *Content->MacroArgsCache;
+  // Initially no macro argument chunk is present.
+  MacroArgsCache.insert(std::make_pair(0, SourceLocation()));
 
   int ID = FID.ID;
   while (1) {
@@ -1475,41 +1476,99 @@
     // Stop if there are no more FileIDs to check.
     if (ID > 0) {
       if (unsigned(ID) >= local_sloc_entry_size())
-        return Loc;
+        return;
     } else if (ID == -1) {
-      return Loc;
+      return;
     }
 
     const SrcMgr::SLocEntry &Entry = getSLocEntryByID(ID);
     if (Entry.isFile()) {
-      if (Entry.getFile().getIncludeLoc().isValid() &&
-          !isBeforeInTranslationUnit(Entry.getFile().getIncludeLoc(), Loc))
-        return Loc;
+      SourceLocation IncludeLoc = Entry.getFile().getIncludeLoc();
+      if (IncludeLoc.isInvalid())
+        continue;
+      if (!isInFileID(IncludeLoc, FID))
+        return; // No more files/macros that may be "contained" in this file.
+
+      // Skip the files/macros of the #include'd file, we only care about macros
+      // that lexed macro arguments from our file.
+      if (Entry.getFile().NumCreatedFIDs)
+        ID += Entry.getFile().NumCreatedFIDs - 1/*because of next ++ID*/;
       continue;
     }
-  
-    if (isBeforeInTranslationUnit(Loc,
-                                  Entry.getExpansion().getExpansionLocStart()))
-      return Loc;
+
     if (!Entry.getExpansion().isMacroArgExpansion())
       continue;
+ 
+    SourceLocation SpellLoc =
+        getSpellingLoc(Entry.getExpansion().getSpellingLoc());
+    unsigned BeginOffs;
+    if (!isInFileID(SpellLoc, FID, &BeginOffs))
+      return; // No more files/macros that may be "contained" in this file.
+    unsigned EndOffs = BeginOffs + getFileIDSize(FileID::get(ID));
 
-    // This is a macro argument expansion. See if Loc points in the argument
-    // that was lexed.
+    // Add a new chunk for this macro argument. A previous macro argument chunk
+    // may have been lexed again, so e.g. if the map is
+    //     0   -> SourceLocation()
+    //     100 -> Expanded loc #1
+    //     110 -> SourceLocation()
+    // and we found a new macro FileID that lexed from offet 105 with length 3,
+    // the new map will be:
+    //     0   -> SourceLocation()
+    //     100 -> Expanded loc #1
+    //     105 -> Expanded loc #2
+    //     108 -> Expanded loc #1
+    //     110 -> SourceLocation()
+    //
+    // Since re-lexed macro chunks will always be the same size or less of
+    // previous chunks, we only need to find where the ending of the new macro
+    // chunk is mapped to and update the map with new begin/end mappings.
 
-    SourceLocation SpellLoc = Entry.getExpansion().getSpellingLoc();
-    unsigned BeginOffs = SpellLoc.getOffset();
-    unsigned EndOffs = BeginOffs + getFileIDSize(FileID::get(ID));
-    if (BeginOffs <= Loc.getOffset() && Loc.getOffset() < EndOffs) {
-      SourceLocation ExpandLoc = SourceLocation::getMacroLoc(Entry.getOffset());
-      // Replace current Loc with the expanded location and continue.
-      // The expanded argument may end up being passed to another function macro
-      // and relexed again.
-      Loc = ExpandLoc.getFileLocWithOffset(Loc.getOffset()-BeginOffs);
-    }
+    ContentCache::MacroArgsMap::iterator I= MacroArgsCache.upper_bound(EndOffs);
+    --I;
+    SourceLocation EndOffsMappedLoc = I->second;
+    MacroArgsCache[BeginOffs] = SourceLocation::getMacroLoc(Entry.getOffset());
+    MacroArgsCache[EndOffs] = EndOffsMappedLoc;
   }
 }
 
+/// \brief If \arg Loc points inside a function macro argument, the returned
+/// location will be the macro location in which the argument was expanded.
+/// If a macro argument is used multiple times, the expanded location will
+/// be at the first expansion of the argument.
+/// e.g.
+///   MY_MACRO(foo);
+///             ^
+/// Passing a file location pointing at 'foo', will yield a macro location
+/// where 'foo' was expanded into.
+SourceLocation SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) {
+  if (Loc.isInvalid() || !Loc.isFileID())
+    return Loc;
+
+  FileID FID;
+  unsigned Offset;
+  llvm::tie(FID, Offset) = getDecomposedLoc(Loc);
+  if (FID.isInvalid())
+    return Loc;
+
+  ContentCache *Content
+    = const_cast<ContentCache *>(getSLocEntry(FID).getFile().getContentCache());
+  if (!Content->MacroArgsCache)
+    computeMacroArgsCache(Content, FID);
+
+  assert(Content->MacroArgsCache);
+  assert(!Content->MacroArgsCache->empty());
+  ContentCache::MacroArgsMap::iterator
+      I = Content->MacroArgsCache->upper_bound(Offset);
+  --I;
+  
+  unsigned MacroArgBeginOffs = I->first;
+  SourceLocation MacroArgExpandedLoc = I->second;
+  if (MacroArgExpandedLoc.isValid())
+    return MacroArgExpandedLoc.getFileLocWithOffset(Offset - MacroArgBeginOffs);
+
+  return Loc;
+}
+
 /// Given a decomposed source location, move it up the include/expansion stack
 /// to the parent source location.  If this is possible, return the decomposed
 /// version of the parent in Loc and return false.  If Loc is the top-level
@@ -1617,14 +1676,17 @@
                << "B of Sloc address space used.\n";
   
   unsigned NumLineNumsComputed = 0;
+  unsigned NumMacroArgsComputed = 0;
   unsigned NumFileBytesMapped = 0;
   for (fileinfo_iterator I = fileinfo_begin(), E = fileinfo_end(); I != E; ++I){
     NumLineNumsComputed += I->second->SourceLineCache != 0;
+    NumMacroArgsComputed += I->second->MacroArgsCache != 0;
     NumFileBytesMapped  += I->second->getSizeBytesMapped();
   }
 
   llvm::errs() << NumFileBytesMapped << " bytes of files mapped, "
-               << NumLineNumsComputed << " files with line #'s computed.\n";
+               << NumLineNumsComputed << " files with line #'s computed, "
+               << NumMacroArgsComputed << " files with macro args computed.\n";
   llvm::errs() << "FileID scans: " << NumLinearScans << " linear, "
                << NumBinaryProbes << " binary.\n";
 }

Modified: cfe/trunk/lib/Lex/PPLexerChange.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPLexerChange.cpp?rev=138225&r1=138224&r2=138225&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPLexerChange.cpp (original)
+++ cfe/trunk/lib/Lex/PPLexerChange.cpp Sun Aug 21 18:33:04 2011
@@ -204,6 +204,16 @@
   // If this is a #include'd file, pop it off the include stack and continue
   // lexing the #includer file.
   if (!IncludeMacroStack.empty()) {
+    if (!isEndOfMacro && CurPPLexer &&
+        SourceMgr.getIncludeLoc(CurPPLexer->getFileID()).isValid()) {
+      // Notify SourceManager to record the number of FileIDs that were created
+      // during lexing of the #include'd file.
+      unsigned NumFIDs =
+          SourceMgr.local_sloc_entry_size() -
+          CurPPLexer->getInitialNumSLocEntries() + 1/*#include'd file*/;
+      SourceMgr.setNumCreatedFIDsForFileID(CurPPLexer->getFileID(), NumFIDs);
+    }
+
     // We're done with the #included file.
     RemoveTopOfLexerStack();
 

Modified: cfe/trunk/lib/Lex/PreprocessorLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PreprocessorLexer.cpp?rev=138225&r1=138224&r2=138225&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PreprocessorLexer.cpp (original)
+++ cfe/trunk/lib/Lex/PreprocessorLexer.cpp Sun Aug 21 18:33:04 2011
@@ -17,6 +17,14 @@
 #include "clang/Basic/SourceManager.h"
 using namespace clang;
 
+PreprocessorLexer::PreprocessorLexer(Preprocessor *pp, FileID fid)
+  : PP(pp), FID(fid), InitialNumSLocEntries(0),
+    ParsingPreprocessorDirective(false),
+    ParsingFilename(false), LexingRawMode(false) {
+  if (pp)
+    InitialNumSLocEntries = pp->getSourceManager().local_sloc_entry_size();
+}
+
 /// LexIncludeFilename - After the preprocessor has parsed a #include, lex and
 /// (potentially) macro expand the filename.
 void PreprocessorLexer::LexIncludeFilename(Token &FilenameTok) {

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=138225&r1=138224&r2=138225&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Sun Aug 21 18:33:04 2011
@@ -1320,9 +1320,11 @@
     FileID FID = SourceMgr.createFileID(File, IncludeLoc,
                                         (SrcMgr::CharacteristicKind)Record[2],
                                         ID, BaseOffset + Record[0]);
+    SrcMgr::FileInfo &FileInfo =
+          const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile());
+    FileInfo.NumCreatedFIDs = Record[6];
     if (Record[3])
-      const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile())
-        .setHasLineDirectives();
+      FileInfo.setHasLineDirectives();
     
     break;
   }

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=138225&r1=138224&r2=138225&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Sun Aug 21 18:33:04 2011
@@ -1243,6 +1243,7 @@
   // FileEntry fields.
   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs
   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
   return Stream.EmitAbbrev(Abbrev);
 }
@@ -1515,6 +1516,8 @@
         Record.push_back(Content->OrigEntry->getSize());
         Record.push_back(Content->OrigEntry->getModificationTime());
 
+        Record.push_back(File.NumCreatedFIDs);
+
         // Turn the file name into an absolute path, if it isn't already.
         const char *Filename = Content->OrigEntry->getName();
         llvm::SmallString<128> FilePath(Filename);





More information about the cfe-commits mailing list