[cfe-commits] r109937 - in /cfe/trunk: include/clang/Basic/SourceManager.h include/clang/Frontend/ASTUnit.h lib/Basic/Diagnostic.cpp lib/Frontend/ASTUnit.cpp

Douglas Gregor dgregor at apple.com
Fri Jul 30 17:40:00 PDT 2010


Author: dgregor
Date: Fri Jul 30 19:40:00 2010
New Revision: 109937

URL: http://llvm.org/viewvc/llvm-project?rev=109937&view=rev
Log:
Implement dependency analysis for the precompiled preamble. If any of
the files in the precompiled preamble have changed since it was build,
force the preamble to be rebuilt.

Modified:
    cfe/trunk/include/clang/Basic/SourceManager.h
    cfe/trunk/include/clang/Frontend/ASTUnit.h
    cfe/trunk/lib/Basic/Diagnostic.cpp
    cfe/trunk/lib/Frontend/ASTUnit.cpp

Modified: cfe/trunk/include/clang/Basic/SourceManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/SourceManager.h?rev=109937&r1=109936&r2=109937&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/SourceManager.h (original)
+++ cfe/trunk/include/clang/Basic/SourceManager.h Fri Jul 30 19:40:00 2010
@@ -110,6 +110,12 @@
       Buffer.setPointer(B);
       Buffer.setInt(false);
     }
+    
+    /// \brief Get the underlying buffer, returning NULL if the buffer is not
+    /// yet available.
+    const llvm::MemoryBuffer *getRawBuffer() const {
+      return Buffer.getPointer();
+    }
 
     /// \brief Replace the existing buffer (which will be deleted)
     /// with the given buffer.

Modified: cfe/trunk/include/clang/Frontend/ASTUnit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/ASTUnit.h?rev=109937&r1=109936&r2=109937&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/ASTUnit.h (original)
+++ cfe/trunk/include/clang/Frontend/ASTUnit.h Fri Jul 30 19:40:00 2010
@@ -21,6 +21,7 @@
 #include "clang/Basic/FileManager.h"
 #include "clang/Index/ASTLocation.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/System/Path.h"
 #include "llvm/Support/Timer.h"
 #include <map>
@@ -28,6 +29,7 @@
 #include <vector>
 #include <cassert>
 #include <utility>
+#include <sys/types.h>
 
 namespace llvm {
   class MemoryBuffer;
@@ -135,14 +137,21 @@
   /// \brief The size of the source buffer that we've reserved for the main 
   /// file within the precompiled preamble.
   unsigned PreambleReservedSize;
-  
+
+  /// \brief Keeps track of the files that were used when computing the 
+  /// preamble, with both their buffer size and their modification time.
+  ///
+  /// If any of the files have changed from one compile to the next,
+  /// the preamble must be thrown away.
+  llvm::StringMap<std::pair<off_t, time_t> > FilesInPreamble;
+
   /// \brief When non-NULL, this is the buffer used to store the contents of
   /// the main file when it has been padded for use with the precompiled
   /// preamble.
   llvm::MemoryBuffer *SavedMainFileBuffer;
   
   /// \brief The group of timers associated with this translation unit.
-  llvm::OwningPtr<llvm::TimerGroup> TimerGroup;
+  llvm::OwningPtr<llvm::TimerGroup> TimerGroup;  
   
   /// \brief The timers we've created from the various parses, reparses, etc.
   /// involved in this translation unit.

Modified: cfe/trunk/lib/Basic/Diagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Diagnostic.cpp?rev=109937&r1=109936&r2=109937&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Diagnostic.cpp (original)
+++ cfe/trunk/lib/Basic/Diagnostic.cpp Fri Jul 30 19:40:00 2010
@@ -251,6 +251,23 @@
   ArgToStringFn = DummyArgToStringFn;
   ArgToStringCookie = 0;
 
+  AllExtensionsSilenced = 0;
+  IgnoreAllWarnings = false;
+  WarningsAsErrors = false;
+  ErrorsAsFatal = false;
+  SuppressSystemWarnings = false;
+  SuppressAllDiagnostics = false;
+  ShowOverloads = Ovl_All;
+  ExtBehavior = Ext_Ignore;
+
+  ErrorLimit = 0;
+  TemplateBacktraceLimit = 0;
+  CustomDiagInfo = 0;
+
+  // Set all mappings to 'unset'.
+  DiagMappingsStack.clear();
+  DiagMappingsStack.push_back(DiagMappings());
+
   Reset();
 }
 
@@ -315,31 +332,15 @@
 }
 
 void Diagnostic::Reset() {
-  AllExtensionsSilenced = 0;
-  IgnoreAllWarnings = false;
-  WarningsAsErrors = false;
-  ErrorsAsFatal = false;
-  SuppressSystemWarnings = false;
-  SuppressAllDiagnostics = false;
-  ShowOverloads = Ovl_All;
-  ExtBehavior = Ext_Ignore;
-  
   ErrorOccurred = false;
   FatalErrorOccurred = false;
-  ErrorLimit = 0;
-  TemplateBacktraceLimit = 0;
   
   NumWarnings = 0;
   NumErrors = 0;
   NumErrorsSuppressed = 0;
-  CustomDiagInfo = 0;
   CurDiagID = ~0U;
   LastDiagLevel = Ignored;
   DelayedDiagID = 0;
-
-  // Set all mappings to 'unset'.
-  DiagMappingsStack.clear();
-  DiagMappingsStack.push_back(DiagMappings());
 }
 
 /// getDescription - Given a diagnostic ID, return a description of the

Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=109937&r1=109936&r2=109937&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/ASTUnit.cpp (original)
+++ cfe/trunk/lib/Frontend/ASTUnit.cpp Fri Jul 30 19:40:00 2010
@@ -36,6 +36,7 @@
 #include "llvm/Support/Timer.h"
 #include <cstdlib>
 #include <cstdio>
+#include <sys/stat.h>
 using namespace clang;
 
 ASTUnit::ASTUnit(bool _MainFileIsAST)
@@ -626,14 +627,72 @@
                NewPreamble.second.first) == 0) {
       // The preamble has not changed. We may be able to re-use the precompiled
       // preamble.
-      // FIXME: Check that none of the files used by the preamble have changed.
           
+      // Check that none of the files used by the preamble have changed.
+      bool AnyFileChanged = false;
+          
+      // First, make a record of those files that have been overridden via
+      // remapping or unsaved_files.
+      llvm::StringMap<std::pair<off_t, time_t> > OverriddenFiles;
+      for (PreprocessorOptions::remapped_file_iterator
+                R = PreprocessorOpts.remapped_file_begin(),
+             REnd = PreprocessorOpts.remapped_file_end();
+           !AnyFileChanged && R != REnd;
+           ++R) {
+        struct stat StatBuf;
+        if (stat(R->second.c_str(), &StatBuf)) {
+          // If we can't stat the file we're remapping to, assume that something
+          // horrible happened.
+          AnyFileChanged = true;
+          break;
+        }
         
-      // Okay! Re-use the precompiled preamble.
-      return CreatePaddedMainFileBuffer(NewPreamble.first, 
-                                        CreatedPreambleBuffer,
-                                        PreambleReservedSize,
-                                        FrontendOpts.Inputs[0].second);
+        OverriddenFiles[R->first] = std::make_pair(StatBuf.st_size, 
+                                                   StatBuf.st_mtime);
+      }
+      for (PreprocessorOptions::remapped_file_buffer_iterator
+                R = PreprocessorOpts.remapped_file_buffer_begin(),
+             REnd = PreprocessorOpts.remapped_file_buffer_end();
+           !AnyFileChanged && R != REnd;
+           ++R) {
+        // FIXME: Should we actually compare the contents of file->buffer
+        // remappings?
+        OverriddenFiles[R->first] = std::make_pair(R->second->getBufferSize(), 
+                                                   0);
+      }
+       
+      // Check whether anything has changed.
+      for (llvm::StringMap<std::pair<off_t, time_t> >::iterator 
+             F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end();
+           !AnyFileChanged && F != FEnd; 
+           ++F) {
+        llvm::StringMap<std::pair<off_t, time_t> >::iterator Overridden
+          = OverriddenFiles.find(F->first());
+        if (Overridden != OverriddenFiles.end()) {
+          // This file was remapped; check whether the newly-mapped file 
+          // matches up with the previous mapping.
+          if (Overridden->second != F->second)
+            AnyFileChanged = true;
+          continue;
+        }
+        
+        // The file was not remapped; check whether it has changed on disk.
+        struct stat StatBuf;
+        if (stat(F->first(), &StatBuf)) {
+          // If we can't stat the file, assume that something horrible happened.
+          AnyFileChanged = true;
+        } else if (StatBuf.st_size != F->second.first || 
+                   StatBuf.st_mtime != F->second.second)
+          AnyFileChanged = true;
+      }
+          
+      if (!AnyFileChanged) {
+        // Okay! Re-use the precompiled preamble.
+        return CreatePaddedMainFileBuffer(NewPreamble.first, 
+                                          CreatedPreambleBuffer,
+                                          PreambleReservedSize,
+                                          FrontendOpts.Inputs[0].second);
+      }
     }
     
     // We can't reuse the previously-computed preamble. Build a new one.
@@ -768,14 +827,31 @@
       delete NewPreamble.first;
     if (PreambleTimer)
       PreambleTimer->stopTimer();
-    if (PreambleTimer)
-      PreambleTimer->stopTimer();
 
     return 0;
   }
   
   // Keep track of the preamble we precompiled.
   PreambleFile = FrontendOpts.OutputFile;
+  
+  // Keep track of all of the files that the source manager knows about,
+  // so we can verify whether they have changed or not.
+  FilesInPreamble.clear();
+  SourceManager &SourceMgr = Clang.getSourceManager();
+  const llvm::MemoryBuffer *MainFileBuffer
+    = SourceMgr.getBuffer(SourceMgr.getMainFileID());
+  for (SourceManager::fileinfo_iterator F = SourceMgr.fileinfo_begin(),
+                                     FEnd = SourceMgr.fileinfo_end();
+       F != FEnd;
+       ++F) {
+    const FileEntry *File = F->second->Entry;
+    if (!File || F->second->getRawBuffer() == MainFileBuffer)
+      continue;
+    
+    FilesInPreamble[File->getName()]
+      = std::make_pair(F->second->getSize(), File->getModificationTime());
+  }
+  
   if (PreambleTimer)
     PreambleTimer->stopTimer();
   
@@ -913,6 +989,13 @@
     Timers.push_back(ReparsingTimer);
   }
   
+  // Remap files.
+  // FIXME: Do we want to remove old mappings for these files?
+  Invocation->getPreprocessorOpts().clearRemappedFiles();
+  for (unsigned I = 0; I != NumRemappedFiles; ++I)
+    Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
+                                                      RemappedFiles[I].second);
+  
   // If we have a preamble file lying around, build or reuse the precompiled
   // preamble.
   llvm::MemoryBuffer *OverrideMainBuffer = 0;
@@ -922,12 +1005,6 @@
   // Clear out the diagnostics state.
   getDiagnostics().Reset();
   
-  // Remap files.
-  Invocation->getPreprocessorOpts().clearRemappedFiles();
-  for (unsigned I = 0; I != NumRemappedFiles; ++I)
-    Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
-                                                      RemappedFiles[I].second);
-
   // Parse the sources
   bool Result = Parse(OverrideMainBuffer);  
   if (ReparsingTimer)





More information about the cfe-commits mailing list