[cfe-commits] r99015 - in /cfe/trunk: include/clang/Frontend/ASTUnit.h tools/CIndex/CIndex.cpp

Douglas Gregor dgregor at apple.com
Fri Mar 19 17:41:22 PDT 2010


Author: dgregor
Date: Fri Mar 19 19:41:21 2010
New Revision: 99015

URL: http://llvm.org/viewvc/llvm-project?rev=99015&view=rev
Log:
Optimize region-of-interest based cursor walks through the
preprocessed entities by grouping preprocessed entities by file
ID. This drastically improves performance of repeated
clang_getCursor() calls local tests, although it is a bit ugly.

Modified:
    cfe/trunk/include/clang/Frontend/ASTUnit.h
    cfe/trunk/tools/CIndex/CIndex.cpp

Modified: cfe/trunk/include/clang/Frontend/ASTUnit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/ASTUnit.h?rev=99015&r1=99014&r2=99015&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/ASTUnit.h (original)
+++ cfe/trunk/include/clang/Frontend/ASTUnit.h Fri Mar 19 19:41:21 2010
@@ -21,6 +21,7 @@
 #include "clang/Index/ASTLocation.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/System/Path.h"
+#include <map>
 #include <string>
 #include <vector>
 #include <cassert>
@@ -47,6 +48,11 @@
 /// \brief Utility class for loading a ASTContext from a PCH file.
 ///
 class ASTUnit {
+public:
+  typedef std::map<FileID, std::vector<PreprocessedEntity *> > 
+    PreprocessedEntitiesByFileMap;
+private:
+  
   FileManager FileMgr;
 
   SourceManager                     SourceMgr;
@@ -90,6 +96,15 @@
   /// destroyed.
   llvm::SmallVector<llvm::sys::Path, 4> TemporaryFiles;
 
+  /// \brief A mapping from file IDs to the set of preprocessed entities
+  /// stored in that file. 
+  ///
+  /// FIXME: This is just an optimization hack to avoid searching through
+  /// many preprocessed entities during cursor traversal in the CIndex library.
+  /// Ideally, we would just be able to perform a binary search within the
+  /// list of preprocessed entities.
+  PreprocessedEntitiesByFileMap PreprocessedEntitiesByFile;
+  
   /// \brief Simple hack to allow us to assert that ASTUnit is not being
   /// used concurrently, which is not supported.
   ///
@@ -163,6 +178,12 @@
     return TopLevelDecls;
   }
 
+  /// \brief Retrieve the mapping from File IDs to the preprocessed entities
+  /// within that file.
+  PreprocessedEntitiesByFileMap &getPreprocessedEntitiesByFile() {
+    return PreprocessedEntitiesByFile;
+  }
+  
   // Retrieve the diagnostics associated with this AST
   typedef const StoredDiagnostic * diag_iterator;
   diag_iterator diag_begin() const { return Diagnostics.begin(); }

Modified: cfe/trunk/tools/CIndex/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndex.cpp?rev=99015&r1=99014&r2=99015&view=diff
==============================================================================
--- cfe/trunk/tools/CIndex/CIndex.cpp (original)
+++ cfe/trunk/tools/CIndex/CIndex.cpp Fri Mar 19 19:41:21 2010
@@ -234,6 +234,10 @@
   }
 
   bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false);
+  
+  std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+    getPreprocessedEntities();
+
   bool VisitChildren(CXCursor Parent);
 
   // Declaration visitors
@@ -352,6 +356,48 @@
   return false;
 }
 
+std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+CursorVisitor::getPreprocessedEntities() {
+  PreprocessingRecord &PPRec
+    = *TU->getPreprocessor().getPreprocessingRecord();
+  
+  bool OnlyLocalDecls
+    = !TU->isMainFileAST() && TU->getOnlyLocalDecls();
+  
+  // There is no region of interest; we have to walk everything.
+  if (RegionOfInterest.isInvalid())
+    return std::make_pair(PPRec.begin(OnlyLocalDecls),
+                          PPRec.end(OnlyLocalDecls));
+
+  // Find the file in which the region of interest lands.
+  SourceManager &SM = TU->getSourceManager();
+  std::pair<FileID, unsigned> Begin
+    = SM.getDecomposedInstantiationLoc(RegionOfInterest.getBegin());
+  std::pair<FileID, unsigned> End
+    = SM.getDecomposedInstantiationLoc(RegionOfInterest.getEnd());
+  
+  // The region of interest spans files; we have to walk everything.
+  if (Begin.first != End.first)
+    return std::make_pair(PPRec.begin(OnlyLocalDecls),
+                          PPRec.end(OnlyLocalDecls));
+    
+  ASTUnit::PreprocessedEntitiesByFileMap &ByFileMap
+    = TU->getPreprocessedEntitiesByFile();
+  if (ByFileMap.empty()) {
+    // Build the mapping from files to sets of preprocessed entities.
+    for (PreprocessingRecord::iterator E = PPRec.begin(OnlyLocalDecls),
+                                    EEnd = PPRec.end(OnlyLocalDecls);
+         E != EEnd; ++E) {
+      std::pair<FileID, unsigned> P
+        = SM.getDecomposedInstantiationLoc((*E)->getSourceRange().getBegin());
+      ByFileMap[P.first].push_back(*E);
+    }
+  }
+
+  return std::make_pair(ByFileMap[Begin.first].begin(), 
+                        ByFileMap[Begin.first].end());
+}
+
 /// \brief Visit the children of the given cursor.
 ///
 /// \returns true if the visitation should be aborted, false if it
@@ -415,15 +461,12 @@
                        = CXXUnit->getPreprocessor().getPreprocessingRecord()) {
       // FIXME: Once we have the ability to deserialize a preprocessing record,
       // do so.
-      bool OnlyLocalDecls
-        = !CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls();
-      for (PreprocessingRecord::iterator 
-             E = PPRec->begin(OnlyLocalDecls), 
-             EEnd = PPRec->end(OnlyLocalDecls);
-           E != EEnd; ++E) {
+      PreprocessingRecord::iterator E, EEnd;
+      for (llvm::tie(E, EEnd) = getPreprocessedEntities(); E != EEnd; ++E) {
         if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
           if (Visit(MakeMacroInstantiationCursor(MI, CXXUnit)))
             return true;
+          
           continue;
         }
         





More information about the cfe-commits mailing list