[cfe-commits] r68732 - in /cfe/trunk: include/clang/AST/ include/clang/Frontend/ lib/AST/ lib/Frontend/ lib/Sema/ test/ test/PCH/ tools/clang-cc/

Douglas Gregor dgregor at apple.com
Thu Apr 9 15:27:45 PDT 2009


Author: dgregor
Date: Thu Apr  9 17:27:44 2009
New Revision: 68732

URL: http://llvm.org/viewvc/llvm-project?rev=68732&view=rev
Log:
Implementation of pre-compiled headers (PCH) based on lazy
de-serialization of abstract syntax trees.

PCH support serializes the contents of the abstract syntax tree (AST)
to a bitstream. When the PCH file is read, declarations are serialized
as-needed. For example, a declaration of a variable "x" will be
deserialized only when its VarDecl can be found by a client, e.g.,
based on name lookup for "x" or traversing the entire contents of the
owner of "x".

This commit provides the framework for serialization and (lazy)
deserialization, along with support for variable and typedef
declarations (along with several kinds of types). More
declarations/types, along with important auxiliary structures (source
manager, preprocessor, etc.), will follow.


Added:
    cfe/trunk/include/clang/AST/ExternalASTSource.h
    cfe/trunk/include/clang/Frontend/PCHBitCodes.h
    cfe/trunk/include/clang/Frontend/PCHReader.h
    cfe/trunk/include/clang/Frontend/PCHWriter.h
    cfe/trunk/lib/Frontend/PCHReader.cpp
    cfe/trunk/lib/Frontend/PCHWriter.cpp
    cfe/trunk/test/PCH/
    cfe/trunk/test/PCH/variables.c
    cfe/trunk/test/PCH/variables.h
    cfe/trunk/tools/clang-cc/GeneratePCH.cpp
Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/include/clang/AST/DeclContextInternals.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/DeclBase.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/test/TestRunner.sh
    cfe/trunk/tools/clang-cc/ASTConsumers.h
    cfe/trunk/tools/clang-cc/clang-cc.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=68732&r1=68731&r2=68732&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Thu Apr  9 17:27:44 2009
@@ -24,6 +24,7 @@
 #include "clang/Basic/SourceLocation.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/OwningPtr.h"
 #include "llvm/Bitcode/SerializationFwd.h"
 #include "llvm/Support/Allocator.h"
 #include <vector>
@@ -36,6 +37,7 @@
   class FileManager;
   class ASTRecordLayout;
   class Expr;
+  class ExternalASTSource;
   class IdentifierTable;
   class SelectorTable;
   class SourceManager;
@@ -146,6 +148,7 @@
   IdentifierTable &Idents;
   SelectorTable &Selectors;
   DeclarationNameTable DeclarationNames;
+  llvm::OwningPtr<ExternalASTSource> ExternalSource;
 
   SourceManager& getSourceManager() { return SourceMgr; }
   const SourceManager& getSourceManager() const { return SourceMgr; }
@@ -190,6 +193,17 @@
 
   ~ASTContext();
 
+  /// \brief Attach an external AST source to the AST context.
+  ///
+  /// The external AST source provides the ability to load parts of
+  /// the abstract syntax tree as needed from some external storage,
+  /// e.g., a precompiled header.
+  void setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source);
+
+  /// \brief Retrieve a pointer to the external AST source associated
+  /// with this AST context, if any.
+  ExternalASTSource *getExternalSource() const { return ExternalSource.get(); }
+
   void PrintStats() const;
   const std::vector<Type*>& getTypes() const { return Types; }
   

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=68732&r1=68731&r2=68732&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Thu Apr  9 17:27:44 2009
@@ -349,24 +349,36 @@
   /// DeclKind - This indicates which class this is.
   Decl::Kind DeclKind   :  8;
 
+  /// \brief Whether this declaration context also has some external
+  /// storage that contains additional declarations that are lexically
+  /// part of this context.
+  mutable bool ExternalLexicalStorage : 1;
+
+  /// \brief Whether this declaration context also has some external
+  /// storage that contains additional declarations that are visible
+  /// in this context.
+  mutable bool ExternalVisibleStorage : 1;
+
   /// \brief Pointer to the data structure used to lookup declarations
   /// within this context, which is a DenseMap<DeclarationName,
   /// StoredDeclsList>.
-  void* LookupPtr;
+  mutable void* LookupPtr;
 
   /// FirstDecl - The first declaration stored within this declaration
   /// context.
-  Decl *FirstDecl;
+  mutable Decl *FirstDecl;
 
   /// LastDecl - The last declaration stored within this declaration
   /// context. FIXME: We could probably cache this value somewhere
   /// outside of the DeclContext, to reduce the size of DeclContext by
   /// another pointer.
-  Decl *LastDecl;
+  mutable Decl *LastDecl;
 
 protected:
    DeclContext(Decl::Kind K) 
-     : DeclKind(K), LookupPtr(0), FirstDecl(0), LastDecl(0) { }
+     : DeclKind(K), ExternalLexicalStorage(false),
+       ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0), 
+       LastDecl(0) { }
 
   void DestroyDecls(ASTContext &C);
 
@@ -751,6 +763,26 @@
   /// \brief Retrieve the internal representation of the lookup structure.
   void* getLookupPtr() const { return LookupPtr; }
 
+  /// \brief Whether this DeclContext has external storage containing
+  /// additional declarations that are lexically in this context.
+  bool hasExternalLexicalStorage() const { return ExternalLexicalStorage; }
+
+  /// \brief State whether this DeclContext has external storage for
+  /// declarations lexically in this context.
+  void setHasExternalLexicalStorage(bool ES = true) { 
+    ExternalLexicalStorage = ES; 
+  }
+
+  /// \brief Whether this DeclContext has external storage containing
+  /// additional declarations that are visible in this context.
+  bool hasExternalVisibleStorage() const { return ExternalVisibleStorage; }
+
+  /// \brief State whether this DeclContext has external storage for
+  /// declarations visible in this context.
+  void setHasExternalVisibleStorage(bool ES = true) { 
+    ExternalVisibleStorage = ES; 
+  }
+
   static bool classof(const Decl *D);
   static bool classof(const DeclContext *D) { return true; }
 #define DECL_CONTEXT(Name) \
@@ -758,6 +790,9 @@
 #include "clang/AST/DeclNodes.def"
 
 private:
+  void LoadLexicalDeclsFromExternalStorage(ASTContext &Context) const;
+  void LoadVisibleDeclsFromExternalStorage(ASTContext &Context) const;
+
   void buildLookup(ASTContext &Context, DeclContext *DCtx);
   void makeDeclVisibleInContextImpl(ASTContext &Context, NamedDecl *D);
 

Modified: cfe/trunk/include/clang/AST/DeclContextInternals.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclContextInternals.h?rev=68732&r1=68731&r2=68732&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclContextInternals.h (original)
+++ cfe/trunk/include/clang/AST/DeclContextInternals.h Thu Apr  9 17:27:44 2009
@@ -19,54 +19,128 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/PointerUnion.h"
 #include "llvm/ADT/SmallVector.h"
-#include <functional>
+#include <algorithm>
 
 namespace clang {
 
 /// StoredDeclsList - This is an array of decls optimized a common case of only
 /// containing one entry.
 struct StoredDeclsList {
+  /// The kind of data encoded in this list.
+  enum DataKind {
+    /// \brief The data is a NamedDecl*.
+    DK_Decl = 0,
+    /// \brief The data is a declaration ID (an unsigned value),
+    /// shifted left by 2 bits.
+    DK_DeclID = 1,
+    /// \brief The data is a pointer to a vector (of type VectorTy)
+    /// that contains declarations.
+    DK_Decl_Vector = 2,
+    /// \brief The data is a pointer to a vector (of type VectorTy)
+    /// that contains declaration ID.
+    DK_ID_Vector = 3
+  };
+
   /// VectorTy - When in vector form, this is what the Data pointer points to.
-  typedef llvm::SmallVector<NamedDecl*, 4> VectorTy;
+  typedef llvm::SmallVector<uintptr_t, 4> VectorTy;
+
+  /// \brief The stored data, which will be either a declaration ID, a
+  /// pointer to a NamedDecl, or a pointer to a vector.
+  uintptr_t Data;
 
-  /// Data - Union of NamedDecl*/VectorTy*.
-  llvm::PointerUnion<NamedDecl*, VectorTy*> Data;
 public:
-  StoredDeclsList() {}
+  StoredDeclsList() : Data(0) {}
+
   StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) {
-    if (isVector())
-      Data = new VectorTy(*Data.get<VectorTy*>());
+    if (VectorTy *RHSVec = RHS.getAsVector()) {
+      VectorTy *New = new VectorTy(*RHSVec);
+      Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03);
+    }
   }
   
   ~StoredDeclsList() {
     // If this is a vector-form, free the vector.
-    if (isVector())
-      delete Data.get<VectorTy*>();
+    if (VectorTy *Vector = getAsVector())
+      delete Vector;
   }
   
   StoredDeclsList &operator=(const StoredDeclsList &RHS) {
-    if (isVector())
-      delete Data.get<VectorTy*>();
+    if (VectorTy *Vector = getAsVector())
+      delete Vector;
     Data = RHS.Data;
-    if (isVector())
-      Data = new VectorTy(*Data.get<VectorTy*>());
+    if (VectorTy *RHSVec = RHS.getAsVector()) {
+      VectorTy *New = new VectorTy(*RHSVec);
+      Data = reinterpret_cast<uintptr_t>(New) | (Data & 0x03);
+    }
     return *this;
   }
   
-  bool isVector() const { return Data.is<VectorTy*>(); }
-  bool isInline() const { return Data.is<NamedDecl*>(); }
-  bool isNull() const { return Data.isNull(); }
+  bool isNull() const { return (Data & ~0x03) == 0; }
   
+  NamedDecl *getAsDecl() const {
+    if ((Data & 0x03) != DK_Decl)
+      return 0;
+
+    return reinterpret_cast<NamedDecl *>(Data & ~0x03);
+  }
+
+  VectorTy *getAsVector() const {
+    if ((Data & 0x03) != DK_ID_Vector && (Data & 0x03) != DK_Decl_Vector)
+      return 0;
+
+    return reinterpret_cast<VectorTy *>(Data & ~0x03);
+  }
+
   void setOnlyValue(NamedDecl *ND) {
-    assert(isInline() && "Not inline");
-    Data = ND;
+    assert(!getAsVector() && "Not inline");
+    Data = reinterpret_cast<uintptr_t>(ND);
+  }
+
+  void setFromDeclIDs(const llvm::SmallVectorImpl<unsigned> &Vec) {
+    if (Vec.size() > 1) {
+      VectorTy *Vector = getAsVector();
+      if (!Vector) {
+        Vector = new VectorTy;
+        Data = reinterpret_cast<uintptr_t>(Vector) | DK_Decl_Vector;
+      }
+
+      Vector->resize(Vec.size());
+      std::copy(Vec.begin(), Vec.end(), Vector->begin());
+      return;
+    }
+
+    if (VectorTy *Vector = getAsVector())
+      delete Vector;
+
+    if (Vec.size() == 0)
+      Data = 0;
+    else
+      Data = (Vec[0] << 2) | DK_DeclID;
+  }
+
+  /// \brief Force the stored declarations list to contain actual
+  /// declarations.
+  ///
+  /// This routine will resolve any declaration IDs for declarations
+  /// that may not yet have been loaded from external storage.
+  void materializeDecls(ASTContext &Context);
+
+  bool hasDeclarationIDs() const {
+    DataKind DK = (DataKind)(Data & 0x03);
+    return DK == DK_DeclID || DK == DK_ID_Vector;
   }
 
   /// getLookupResult - Return an array of all the decls that this list
   /// represents.
   DeclContext::lookup_result getLookupResult(ASTContext &Context) {
-    // If we have a single inline unit, return it.
-    if (isInline()) {
+    if (isNull())
+      return DeclContext::lookup_result(0, 0);
+   
+    if (hasDeclarationIDs())
+      materializeDecls(Context);
+
+    // If we have a single NamedDecl, return it.
+    if (getAsDecl()) {
       assert(!isNull() && "Empty list isn't allowed");
       
       // Data is a raw pointer to a NamedDecl*, return it.
@@ -74,57 +148,67 @@
       return DeclContext::lookup_result((NamedDecl**)Ptr, (NamedDecl**)Ptr+1);
     }
     
+    assert(getAsVector() && "Must have a vector at this point");
+    VectorTy &Vector = *getAsVector();
+    
     // Otherwise, we have a range result.
-    VectorTy &V = *Data.get<VectorTy*>();
-    return DeclContext::lookup_result(&V[0], &V[0]+V.size());
+    return DeclContext::lookup_result((NamedDecl **)&Vector[0], 
+                                      (NamedDecl **)&Vector[0]+Vector.size());
   }
   
   /// HandleRedeclaration - If this is a redeclaration of an existing decl,
   /// replace the old one with D and return true.  Otherwise return false.
   bool HandleRedeclaration(ASTContext &Context, NamedDecl *D) {
+    if (hasDeclarationIDs())
+      materializeDecls(Context);
+
     // Most decls only have one entry in their list, special case it.
-    if (isInline()) {
-      if (!D->declarationReplaces(Data.get<NamedDecl*>()))
+    if (NamedDecl *OldD = getAsDecl()) {
+      if (!D->declarationReplaces(OldD))
         return false;
       setOnlyValue(D);
       return true;
     }
     
     // Determine if this declaration is actually a redeclaration.
-    VectorTy &Vec = *Data.get<VectorTy*>();
-    VectorTy::iterator RDI
-      = std::find_if(Vec.begin(), Vec.end(),
-                     std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces),
-                                  D));
-    if (RDI == Vec.end())
-      return false;
-    *RDI = D;
-    return true;
+    VectorTy &Vec = *getAsVector();
+    for (VectorTy::iterator OD = Vec.begin(), ODEnd = Vec.end();
+         OD != ODEnd; ++OD) {
+      NamedDecl *OldD = reinterpret_cast<NamedDecl *>(*OD);
+      if (D->declarationReplaces(OldD)) {
+        *OD = reinterpret_cast<uintptr_t>(D);
+        return true;
+      }
+    }
+
+    return false;
   }
   
   /// AddSubsequentDecl - This is called on the second and later decl when it is
   /// not a redeclaration to merge it into the appropriate place in our list.
   /// 
   void AddSubsequentDecl(NamedDecl *D) {
+    assert(!hasDeclarationIDs() && "Must materialize before adding decls");
+
     // If this is the second decl added to the list, convert this to vector
     // form.
-    if (isInline()) {
-      NamedDecl *OldD = Data.get<NamedDecl*>();
+    if (NamedDecl *OldD = getAsDecl()) {
       VectorTy *VT = new VectorTy();
-      VT->push_back(OldD);
-      Data = VT;
+      VT->push_back(reinterpret_cast<uintptr_t>(OldD));
+      Data = reinterpret_cast<uintptr_t>(VT) | DK_Decl_Vector;
     }
     
-    VectorTy &Vec = *Data.get<VectorTy*>();
+    VectorTy &Vec = *getAsVector();
     if (isa<UsingDirectiveDecl>(D) ||
         D->getIdentifierNamespace() == Decl::IDNS_Tag)
-      Vec.push_back(D);
-    else if (Vec.back()->getIdentifierNamespace() == Decl::IDNS_Tag) {
-      NamedDecl *TagD = Vec.back();
-      Vec.back() = D;
+      Vec.push_back(reinterpret_cast<uintptr_t>(D));
+    else if (reinterpret_cast<NamedDecl *>(Vec.back())
+               ->getIdentifierNamespace() == Decl::IDNS_Tag) {
+      uintptr_t TagD = Vec.back();
+      Vec.back() = reinterpret_cast<uintptr_t>(D);
       Vec.push_back(TagD);
     } else
-      Vec.push_back(D);
+      Vec.push_back(reinterpret_cast<uintptr_t>(D));
   }
 };
 

Added: cfe/trunk/include/clang/AST/ExternalASTSource.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExternalASTSource.h?rev=68732&view=auto

==============================================================================
--- cfe/trunk/include/clang/AST/ExternalASTSource.h (added)
+++ cfe/trunk/include/clang/AST/ExternalASTSource.h Thu Apr  9 17:27:44 2009
@@ -0,0 +1,94 @@
+//===--- ExternalASTSource.h - Abstract External AST Interface --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the ExternalASTSource interface, 
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
+#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
+
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+
+class Decl;
+class DeclContext;
+
+/// \brief The deserialized representation of a set of declarations
+/// with the same name that are visible in a given context.
+struct VisibleDeclaration {
+  /// \brief The name of the declarations.
+  DeclarationName Name;
+
+  /// \brief The ID numbers of all of the declarations with this name. 
+  ///
+  /// These declarations have not necessarily been de-serialized.
+  llvm::SmallVector<unsigned, 4> Declarations;
+};
+
+/// \brief Abstract interface for external sources of AST nodes.
+///
+/// External AST sources provide AST nodes constructed from some
+/// external source, such as a precompiled header. External AST
+/// sources can resolve types and declarations from abstract IDs into
+/// actual type and declaration nodes, and read parts of declaration
+/// contexts.
+class ExternalASTSource {
+public:
+  virtual ~ExternalASTSource();
+
+  /// \brief Resolve a type ID into a type, potentially building a new
+  /// type.
+  virtual QualType GetType(unsigned ID) = 0;
+
+  /// \brief Resolve a declaration ID into a declaration, potentially
+  /// building a new declaration.
+  virtual Decl *GetDecl(unsigned ID) = 0;
+
+  /// \brief Read all of the declarations lexically stored in a
+  /// declaration context.
+  ///
+  /// \param DC The declaration context whose declarations will be
+  /// read.
+  ///
+  /// \param Decls Vector that will contain the declarations loaded
+  /// from the external source. The caller is responsible for merging
+  /// these declarations with any declarations already stored in the
+  /// declaration context.
+  ///
+  /// \returns true if there was an error while reading the
+  /// declarations for this declaration context.
+  virtual bool ReadDeclsLexicallyInContext(DeclContext *DC,
+                                  llvm::SmallVectorImpl<unsigned> &Decls) = 0;
+
+  /// \brief Read all of the declarations visible from a declaration
+  /// context.
+  ///
+  /// \param DC The declaration context whose visible declarations
+  /// will be read.
+  ///
+  /// \param Decls A vector of visible declaration structures,
+  /// providing the mapping from each name visible in the declaration
+  /// context to the declaration IDs of declarations with that name.
+  ///
+  /// \returns true if there was an error while reading the
+  /// declarations for this declaration context.
+  virtual bool ReadDeclsVisibleInContext(DeclContext *DC,
+                       llvm::SmallVectorImpl<VisibleDeclaration> & Decls) = 0;
+
+  /// \brief Print any statistics that have been gathered regarding
+  /// the external AST source.
+  virtual void PrintStats();
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H

Added: cfe/trunk/include/clang/Frontend/PCHBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHBitCodes.h?rev=68732&view=auto

==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHBitCodes.h (added)
+++ cfe/trunk/include/clang/Frontend/PCHBitCodes.h Thu Apr  9 17:27:44 2009
@@ -0,0 +1,239 @@
+//===- PCHBitCodes.h - Enum values for the PCH bitcode format ---*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines Bitcode enum values for Clang precompiled header files.
+//
+// The enum values defined in this file should be considered permanent.  If
+// new features are added, they should have values added at the end of the
+// respective lists.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_FRONTEND_PCHBITCODES_H
+#define LLVM_CLANG_FRONTEND_PCHBITCODES_H
+
+#include "llvm/Bitcode/BitCodes.h"
+#include "llvm/Support/DataTypes.h"
+
+namespace clang {
+  namespace pch {
+    const int IDBits = 32;
+    typedef uint32_t ID;
+
+    /// \brief Describes the various kinds of blocks that occur within
+    /// a PCH file.
+    enum BlockIDs {
+      /// \brief The PCH block, which acts as a container around the
+      /// full PCH block.
+      PCH_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID,
+      
+      /// \brief The block containing the definitions of all of the
+      /// types used within the PCH file.
+      TYPES_BLOCK_ID,
+
+      /// \brief The block containing the offsets of all of the types
+      /// used within the PCH.
+      ///
+      /// The offsets in this block point into the block identified by
+      /// TYPES_BLOCK_ID, and are indexed by the type ID.
+      TYPE_OFFSETS_BLOCK_ID,
+
+      /// \brief The block containing the definitions of all of the
+      /// declarations stored in the PCH file.
+      DECLS_BLOCK_ID,
+
+      /// \brief The block containing the offsets of all of the
+      /// declarations stored within the PCH file.
+      ///
+      /// The offsets in this block point into the block identified by
+      /// DECLS_BLOCK_ID, and are indexed by the decaration ID.
+      DECL_OFFSETS_BLOCK_ID
+    };
+
+    /// \brief Predefined type IDs.
+    ///
+    /// These type IDs correspond to predefined types in the AST
+    /// context, such as built-in types (int) and special place-holder
+    /// types (the <overload> and <dependent> type markers). Such
+    /// types are never actually serialized, since they will be built
+    /// by the AST context when it is created.
+    enum PredefinedTypeIDs {
+      /// \brief The NULL type.
+      PREDEF_TYPE_NULL_ID       = 0,
+      /// \brief The void type.
+      PREDEF_TYPE_VOID_ID       = 1,
+      /// \brief The 'bool' or '_Bool' type.
+      PREDEF_TYPE_BOOL_ID       = 2,
+      /// \brief The 'char' type, when it is unsigned.
+      PREDEF_TYPE_CHAR_U_ID     = 3,
+      /// \brief The 'unsigned char' type.
+      PREDEF_TYPE_UCHAR_ID      = 4,
+      /// \brief The 'unsigned short' type.
+      PREDEF_TYPE_USHORT_ID     = 5,
+      /// \brief The 'unsigned int' type.
+      PREDEF_TYPE_UINT_ID       = 6,
+      /// \brief The 'unsigned long' type.
+      PREDEF_TYPE_ULONG_ID      = 7,
+      /// \brief The 'unsigned long long' type.
+      PREDEF_TYPE_ULONGLONG_ID  = 8,
+      /// \brief The 'char' type, when it is signed.
+      PREDEF_TYPE_CHAR_S_ID     = 9,
+      /// \brief The 'signed char' type.
+      PREDEF_TYPE_SCHAR_ID      = 10,
+      /// \brief The C++ 'wchar_t' type.
+      PREDEF_TYPE_WCHAR_ID      = 11,
+      /// \brief The (signed) 'short' type.
+      PREDEF_TYPE_SHORT_ID      = 12,
+      /// \brief The (signed) 'int' type.
+      PREDEF_TYPE_INT_ID        = 13,
+      /// \brief The (signed) 'long' type.
+      PREDEF_TYPE_LONG_ID       = 14,
+      /// \brief The (signed) 'long long' type.
+      PREDEF_TYPE_LONGLONG_ID   = 15,
+      /// \brief The 'float' type.
+      PREDEF_TYPE_FLOAT_ID      = 16,
+      /// \brief The 'double' type.
+      PREDEF_TYPE_DOUBLE_ID     = 17,
+      /// \brief The 'long double' type.
+      PREDEF_TYPE_LONGDOUBLE_ID = 18,
+      /// \brief The placeholder type for overloaded function sets.
+      PREDEF_TYPE_OVERLOAD_ID   = 19,
+      /// \brief The placeholder type for dependent types.
+      PREDEF_TYPE_DEPENDENT_ID  = 20
+    };
+
+    /// \brief The number of predefined type IDs that are reserved for
+    /// the PREDEF_TYPE_* constants.
+    ///
+    /// Type IDs for non-predefined types will start at
+    /// NUM_PREDEF_TYPE_IDs.
+    const unsigned NUM_PREDEF_TYPE_IDS = 100;
+
+    /// \brief Record codes for each kind of type.
+    ///
+    /// These constants describe the records that can occur within a
+    /// block identified by TYPES_BLOCK_ID in the PCH file. Each
+    /// constant describes a record for a specific type class in the
+    /// AST.
+    enum TypeCode {
+      /// \brief An ExtQualType record.
+      TYPE_EXT_QUAL                 = 1,
+      /// \brief A FixedWidthIntType record.
+      TYPE_FIXED_WIDTH_INT          = 2,
+      /// \brief A ComplexType record.
+      TYPE_COMPLEX                  = 3,
+      /// \brief A PointerType record.
+      TYPE_POINTER                  = 4,
+      /// \brief A BlockPointerType record.
+      TYPE_BLOCK_POINTER            = 5,
+      /// \brief An LValueReferenceType record.
+      TYPE_LVALUE_REFERENCE         = 6,
+      /// \brief An RValueReferenceType record.
+      TYPE_RVALUE_REFERENCE         = 7,
+      /// \brief A MemberPointerType record.
+      TYPE_MEMBER_POINTER           = 8,
+      /// \brief A ConstantArrayType record.
+      TYPE_CONSTANT_ARRAY           = 9,
+      /// \brief An IncompleteArrayType record.
+      TYPE_INCOMPLETE_ARRAY         = 10,
+      /// \brief A VariableArrayType record.
+      TYPE_VARIABLE_ARRAY           = 11,
+      /// \brief A VectorType record.
+      TYPE_VECTOR                   = 12,
+      /// \brief An ExtVectorType record.
+      TYPE_EXT_VECTOR               = 13,
+      /// \brief A FunctionNoProtoType record.
+      TYPE_FUNCTION_NO_PROTO        = 14,
+      /// \brief A FunctionProtoType record.
+      TYPE_FUNCTION_PROTO           = 15,
+      /// \brief A TypedefType record.
+      TYPE_TYPEDEF                  = 16,
+      /// \brief A TypeOfExprType record.
+      TYPE_TYPEOF_EXPR              = 17,
+      /// \brief A TypeOfType record.
+      TYPE_TYPEOF                   = 18,
+      /// \brief A RecordType record.
+      TYPE_RECORD                   = 19,
+      /// \brief An EnumType record.
+      TYPE_ENUM                     = 20,
+      /// \brief An ObjCInterfaceType record.
+      TYPE_OBJC_INTERFACE           = 21,
+      /// \brief An ObjCQualifiedInterfaceType record.
+      TYPE_OBJC_QUALIFIED_INTERFACE = 22,
+      /// \brief An ObjCQualifiedIdType record.
+      TYPE_OBJC_QUALIFIED_ID        = 23,
+      /// \brief An ObjCQualifiedClassType record.
+      TYPE_OBJC_QUALIFIED_CLASS     = 24
+    };
+
+    /// \brief Record code for the offsets of each type.
+    ///
+    /// The TYPE_OFFSET constant describes the record that occurs
+    /// within the block identified by TYPE_OFFSETS_BLOCK_ID within
+    /// the PCH file. The record itself is an array of offsets that
+    /// point into the types block (identified by TYPES_BLOCK_ID in
+    /// the PCH file). The index into the array is based on the ID of
+    /// a type. For a given type ID @c T, the lower three bits of @c T
+    /// are its qualifiers (const, volatile, restrict), as in the
+    /// QualType class. The upper bits, after being shifted and
+    /// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the
+    /// TYPE_OFFSET block to determine the offset of that type's
+    /// corresponding record within the TYPES_BLOCK_ID block.
+    enum TypeOffsetCode {
+      TYPE_OFFSET = 1
+    };
+
+    /// \brief Record codes for each kind of declaration.
+    ///
+    /// These constants describe the records that can occur within a
+    /// declarations block (identified by DECLS_BLOCK_ID). Each
+    /// constant describes a record for a specific declaration class
+    /// in the AST.
+    enum DeclCode {
+      /// \brief A TranslationUnitDecl record.
+      DECL_TRANSLATION_UNIT = 1,
+      /// \brief A TypedefDecl record.
+      DECL_TYPEDEF,
+      /// \brief A VarDecl record.
+      DECL_VAR,
+      /// \brief A record that stores the set of declarations that are
+      /// lexically stored within a given DeclContext.
+      ///
+      /// The record itself is an array of declaration IDs, in the
+      /// order in which those declarations were added to the
+      /// declaration context. This data is used when iterating over
+      /// the contents of a DeclContext, e.g., via
+      /// DeclContext::decls_begin()/DeclContext::decls_end().
+      DECL_CONTEXT_LEXICAL,
+      /// \brief A record that stores the set of declarations that are
+      /// visible from a given DeclContext.
+      ///
+      /// The record itself stores a set of mappings, each of which
+      /// associates a declaration name with one or more declaration
+      /// IDs. This data is used when performing qualified name lookup
+      /// into a DeclContext via DeclContext::lookup.
+      DECL_CONTEXT_VISIBLE
+    };
+
+    /// \brief Record code for the offsets of each decl.
+    ///
+    /// The DECL_OFFSET constant describes the record that occurs
+    /// within the block identifier by DECL_OFFSETS_BLOCK_ID within
+    /// the PCH file. The record itself is an array of offsets that
+    /// point into the declarations block (identified by
+    /// DECLS_BLOCK_ID). The declaration ID is an index into this
+    /// record, after subtracting one to account for the use of
+    /// declaration ID 0 for a NULL declaration pointer. Index 0 is
+    /// reserved for the translation unit declaration.
+    enum DeclOffsetCode {
+      DECL_OFFSET = 1
+    };
+  }
+} // end namespace clang
+
+#endif

Added: cfe/trunk/include/clang/Frontend/PCHReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHReader.h?rev=68732&view=auto

==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHReader.h (added)
+++ cfe/trunk/include/clang/Frontend/PCHReader.h Thu Apr  9 17:27:44 2009
@@ -0,0 +1,169 @@
+//===--- PCHReader.h - Precompiled Headers Reader ---------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the PCHReader class, which reads a precompiled header.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_FRONTEND_PCH_READER_H
+#define LLVM_CLANG_FRONTEND_PCH_READER_H
+
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/DataTypes.h"
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+  class MemoryBuffer;
+}
+
+namespace clang {
+
+class ASTContext;
+class Decl;
+class DeclContext;
+
+/// \brief Reads a precompiled head containing the contents of a
+/// translation unit.
+///
+/// The PCHReader class reads a bitstream (produced by the PCHWriter
+/// class) containing the serialized representation of a given
+/// abstract syntax tree and its supporting data structures. An
+/// instance of the PCHReader can be attached to an ASTContext object,
+/// which will provide access to the contents of the PCH file.
+///
+/// The PCH reader provides lazy de-serialization of declarations, as
+/// required when traversing the AST. Only those AST nodes that are
+/// actually required will be de-serialized.
+class PCHReader : public ExternalASTSource {
+  /// \brief The AST context into which we'll read the PCH file.
+  ASTContext &Context;
+
+  /// \brief The bitstream reader from which we'll read the PCH file.
+  llvm::BitstreamReader Stream;
+
+  /// \brief The memory buffer that stores the data associated with
+  /// this PCH file.
+  llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+
+  /// \brief Offset of each type within the bitstream, indexed by the
+  /// type ID, or the representation of a Type*.
+  llvm::SmallVector<uint64_t, 16> TypeOffsets;
+
+  /// \brief Whether the type with a given index has already been loaded.
+  /// 
+  /// When the bit at a given index I is true, then TypeOffsets[I] is
+  /// the already-loaded Type*. Otherwise, TypeOffsets[I] is the
+  /// location of the type's record in the PCH file.
+  ///
+  /// FIXME: We can probably eliminate this, e.g., by bitmangling the
+  /// values in TypeOffsets.
+  std::vector<bool> TypeAlreadyLoaded;
+
+  /// \brief Offset of each declaration within the bitstream, indexed
+  /// by the declaration ID.
+  llvm::SmallVector<uint64_t, 16> DeclOffsets;
+
+  /// \brief Whether the declaration with a given index has already
+  /// been loaded.
+  ///
+  /// When the bit at the given index I is true, then DeclOffsets[I]
+  /// is the already-loaded Decl*. Otherwise, DeclOffsets[I] is the
+  /// location of the declaration's record in the PCH file.
+  ///
+  /// FIXME: We can probably eliminate this, e.g., by bitmangling the
+  /// values in DeclOffsets.
+  std::vector<bool> DeclAlreadyLoaded;
+
+  typedef llvm::DenseMap<const DeclContext *, std::pair<uint64_t, uint64_t> >
+    DeclContextOffsetsMap;
+
+  /// \brief Offsets of the lexical and visible declarations for each
+  /// DeclContext.
+  DeclContextOffsetsMap DeclContextOffsets;
+
+  bool ReadPCHBlock();
+  bool ReadTypeOffsets();
+  bool ReadDeclOffsets();
+
+  QualType ReadTypeRecord(uint64_t Offset);
+  void LoadedDecl(unsigned Index, Decl *D);
+  Decl *ReadDeclRecord(uint64_t Offset, unsigned Index);
+
+  PCHReader(const PCHReader&); // do not implement
+  PCHReader &operator=(const PCHReader &); // do not implement
+
+public:
+  typedef llvm::SmallVector<uint64_t, 64> RecordData;
+
+  PCHReader(ASTContext &Context) : Context(Context), Buffer() { }
+  ~PCHReader();
+
+  bool ReadPCH(const std::string &FileName);
+
+  /// \brief Resolve a type ID into a type, potentially building a new
+  /// type.
+  virtual QualType GetType(unsigned ID);
+
+  /// \brief Resolve a declaration ID into a declaration, potentially
+  /// building a new declaration.
+  virtual Decl *GetDecl(unsigned ID);
+
+  /// \brief Read all of the declarations lexically stored in a
+  /// declaration context.
+  ///
+  /// \param DC The declaration context whose declarations will be
+  /// read.
+  ///
+  /// \param Decls Vector that will contain the declarations loaded
+  /// from the external source. The caller is responsible for merging
+  /// these declarations with any declarations already stored in the
+  /// declaration context.
+  ///
+  /// \returns true if there was an error while reading the
+  /// declarations for this declaration context.
+  virtual bool ReadDeclsLexicallyInContext(DeclContext *DC,
+                                      llvm::SmallVectorImpl<unsigned> &Decls);
+
+  /// \brief Read all of the declarations visible from a declaration
+  /// context.
+  ///
+  /// \param DC The declaration context whose visible declarations
+  /// will be read.
+  ///
+  /// \param Decls A vector of visible declaration structures,
+  /// providing the mapping from each name visible in the declaration
+  /// context to the declaration IDs of declarations with that name.
+  ///
+  /// \returns true if there was an error while reading the
+  /// declarations for this declaration context.
+  ///
+  /// FIXME: Using this intermediate data structure results in an
+  /// extraneous copying of the data. Could we pass in a reference to
+  /// the StoredDeclsMap instead?
+  virtual bool ReadDeclsVisibleInContext(DeclContext *DC,
+                       llvm::SmallVectorImpl<VisibleDeclaration> & Decls);
+
+  /// \brief Print some statistics about PCH usage.
+  virtual void PrintStats();
+
+  const IdentifierInfo *GetIdentifierInfo(const RecordData &Record, 
+                                          unsigned &Idx);
+  DeclarationName ReadDeclarationName(const RecordData &Record, unsigned &Idx);
+};
+
+} // end namespace clang
+
+#endif

Added: cfe/trunk/include/clang/Frontend/PCHWriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHWriter.h?rev=68732&view=auto

==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHWriter.h (added)
+++ cfe/trunk/include/clang/Frontend/PCHWriter.h Thu Apr  9 17:27:44 2009
@@ -0,0 +1,114 @@
+//===--- PCHWriter.h - Precompiled Headers Writer ---------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the PCHWriter class, which writes a precompiled
+//  header containing a serialized representation of a translation
+//  unit.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_FRONTEND_PCH_WRITER_H
+#define LLVM_CLANG_FRONTEND_PCH_WRITER_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/Frontend/PCHBitCodes.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include <queue>
+
+namespace llvm {
+  class APInt;
+  class BitstreamWriter;
+}
+
+namespace clang {
+
+class ASTContext;
+
+/// \brief Writes a precompiled header containing the contents of a
+/// translation unit.
+///
+/// The PCHWriter class produces a bitstream containing the serialized
+/// representation of a given abstract syntax tree and its supporting
+/// data structures. This bitstream can be de-serialized via an
+/// instance of the PCHReader class.
+class PCHWriter {
+  /// \brief The bitstream writer used to emit this precompiled header.
+  llvm::BitstreamWriter &S;
+
+  /// \brief Map that provides the ID numbers of each declaration within
+  /// the output stream.
+  ///
+  /// The ID numbers of declarations are consecutive (in order of
+  /// discovery) and start at 2. 1 is reserved for the translation
+  /// unit, while 0 is reserved for NULL.
+  llvm::DenseMap<const Decl *, pch::ID> DeclIDs;
+
+  /// \brief Offset of each declaration in the bitstream, indexed by
+  /// the declaration's ID.
+  llvm::SmallVector<uint64_t, 16> DeclOffsets;
+
+  /// \brief Queue containing the declarations that we still need to
+  /// emit.
+  std::queue<Decl *> DeclsToEmit;
+
+  /// \brief Map that provides the ID numbers of each type within the
+  /// output stream.
+  ///
+  /// The ID numbers of types are consecutive (in order of discovery)
+  /// and start at 1. 0 is reserved for NULL. When types are actually
+  /// stored in the stream, the ID number is shifted by 3 bits to
+  /// allow for the const/volatile/restrict qualifiers.
+  llvm::DenseMap<const Type *, pch::ID> TypeIDs;
+
+  /// \brief Offset of each type in the bitstream, indexed by
+  /// the type's ID.
+  llvm::SmallVector<uint64_t, 16> TypeOffsets;
+
+  /// \brief The type ID that will be assigned to the next new type.
+  unsigned NextTypeID;
+
+  void WriteType(const Type *T);
+  void WriteTypesBlock(ASTContext &Context);
+  uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
+  uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
+  void WriteDeclsBlock(ASTContext &Context);
+
+public:
+  typedef llvm::SmallVector<uint64_t, 64> RecordData;
+
+  /// \brief Create a new precompiled header writer that outputs to
+  /// the given bitstream.
+  PCHWriter(llvm::BitstreamWriter &S);
+  
+  /// \brief Write a precompiled header for the given AST context.
+  void WritePCH(ASTContext &Context);
+
+  /// \brief Emit a source location.
+  void AddSourceLocation(SourceLocation Loc, RecordData &Record);
+
+  /// \brief Emit an integral value.
+  void AddAPInt(const llvm::APInt &Value, RecordData &Record);
+
+  /// \brief Emit a reference to an identifier
+  void AddIdentifierRef(const IdentifierInfo *II, RecordData &Record);
+
+  /// \brief Emit a reference to a type.
+  void AddTypeRef(QualType T, RecordData &Record);
+
+  /// \brief Emit a reference to a declaration.
+  void AddDeclRef(const Decl *D, RecordData &Record);
+
+  /// \brief Emit a declaration name.
+  void AddDeclarationName(DeclarationName Name, RecordData &Record);
+};
+
+} // end namespace clang
+
+#endif

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=68732&r1=68731&r2=68732&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Thu Apr  9 17:27:44 2009
@@ -16,6 +16,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExternalASTSource.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
@@ -36,7 +37,8 @@
                        bool FreeMem, unsigned size_reserve) : 
   GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), 
   ObjCFastEnumerationStateTypeDecl(0), SourceMgr(SM), LangOpts(LOpts), 
-  FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels) {  
+  FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels),
+  ExternalSource(0) {  
   if (size_reserve > 0) Types.reserve(size_reserve);    
   InitBuiltinTypes();
   BuiltinInfo.InitializeBuiltins(idents, Target, LangOpts.NoBuiltin);
@@ -91,6 +93,11 @@
   TUDecl->Destroy(*this);
 }
 
+void 
+ASTContext::setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source) {
+  ExternalSource.reset(Source.take());
+}
+
 void ASTContext::PrintStats() const {
   fprintf(stderr, "*** AST Context Stats:\n");
   fprintf(stderr, "  %d types total.\n", (int)Types.size());
@@ -195,6 +202,11 @@
     NumTypeName*sizeof(TypedefType)+NumTagged*sizeof(TagType)+
     NumTypeOfTypes*sizeof(TypeOfType)+NumTypeOfExprTypes*sizeof(TypeOfExprType)+
     NumExtQual*sizeof(ExtQualType)));
+
+  if (ExternalSource.get()) {
+    fprintf(stderr, "\n");
+    ExternalSource->PrintStats();
+  }
 }
 
 
@@ -3359,3 +3371,7 @@
   
   return A;
 }
+
+ExternalASTSource::~ExternalASTSource() { }
+
+void ExternalASTSource::PrintStats() { }

Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=68732&r1=68731&r2=68732&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Thu Apr  9 17:27:44 2009
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExternalASTSource.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Type.h"
 #include "llvm/ADT/DenseMap.h"
@@ -439,11 +440,82 @@
   }
 }
 
+/// \brief Load the declarations within this lexical storage from an
+/// external source.
+void 
+DeclContext::LoadLexicalDeclsFromExternalStorage(ASTContext &Context) const {
+  ExternalASTSource *Source = Context.getExternalSource();
+  assert(hasExternalLexicalStorage() && Source && "No external storage?");
+
+  llvm::SmallVector<unsigned, 64> Decls;
+  if (Source->ReadDeclsLexicallyInContext(const_cast<DeclContext *>(this), 
+                                          Decls))
+    return;
+
+  // There is no longer any lexical storage in this context
+  ExternalLexicalStorage = false;
+
+  if (Decls.empty())
+    return;
+
+  // Resolve all of the declaration IDs into declarations, building up
+  // a chain of declarations via the Decl::NextDeclInContext field.
+  Decl *FirstNewDecl = 0;
+  Decl *PrevDecl = 0;
+  for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+    Decl *D = Source->GetDecl(Decls[I]);
+    if (PrevDecl)
+      PrevDecl->NextDeclInContext = D;
+    else
+      FirstNewDecl = D;
+
+    PrevDecl = D;
+  }
+
+  // Splice the newly-read declarations into the beginning of the list
+  // of declarations.
+  PrevDecl->NextDeclInContext = FirstDecl;
+  FirstDecl = FirstNewDecl;
+  if (!LastDecl)
+    LastDecl = PrevDecl;
+}
+
+void 
+DeclContext::LoadVisibleDeclsFromExternalStorage(ASTContext &Context) const {
+  DeclContext *This = const_cast<DeclContext *>(this);
+  ExternalASTSource *Source = Context.getExternalSource();
+  assert(hasExternalVisibleStorage() && Source && "No external storage?");
+
+  llvm::SmallVector<VisibleDeclaration, 64> Decls;
+  if (Source->ReadDeclsVisibleInContext(This, Decls))
+    return;
+
+  // There is no longer any visible storage in this context
+  ExternalVisibleStorage = false;
+
+  // Load the declaration IDs for all of the names visible in this
+  // context.
+  assert(!LookupPtr && "Have a lookup map before de-serialization?");
+  StoredDeclsMap *Map = new StoredDeclsMap;
+  LookupPtr = Map;
+  for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+    (*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations);
+  }
+}
+
 DeclContext::decl_iterator DeclContext::decls_begin(ASTContext &Context) const {
+  if (hasExternalLexicalStorage())
+    LoadLexicalDeclsFromExternalStorage(Context);
+
+  // FIXME: Check whether we need to load some declarations from
+  // external storage.
   return decl_iterator(FirstDecl); 
 }
 
 DeclContext::decl_iterator DeclContext::decls_end(ASTContext &Context) const {
+  if (hasExternalLexicalStorage())
+    LoadLexicalDeclsFromExternalStorage(Context);
+
   return decl_iterator(); 
 }
 
@@ -491,6 +563,9 @@
   if (PrimaryContext != this)
     return PrimaryContext->lookup(Context, Name);
 
+  if (hasExternalVisibleStorage())
+    LoadVisibleDeclsFromExternalStorage(Context);
+
   /// If there is no lookup data structure, build one now by walking
   /// all of the linked DeclContexts (in declaration order!) and
   /// inserting their values.
@@ -595,3 +670,40 @@
   return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first),
                              reinterpret_cast<udir_iterator>(Result.second));
 }
+
+void StoredDeclsList::materializeDecls(ASTContext &Context) {
+  if (isNull())
+    return;
+
+  switch ((DataKind)(Data & 0x03)) {
+  case DK_Decl:
+  case DK_Decl_Vector:
+    break;
+
+  case DK_DeclID: {
+    // Resolve this declaration ID to an actual declaration by
+    // querying the external AST source.
+    unsigned DeclID = Data >> 2;
+
+    ExternalASTSource *Source = Context.getExternalSource();
+    assert(Source && "No external AST source available!");
+
+    Data = reinterpret_cast<uintptr_t>(Source->GetDecl(DeclID));
+    break;
+  }
+
+  case DK_ID_Vector: {
+    // We have a vector of declaration IDs. Resolve all of them to
+    // actual declarations.
+    VectorTy &Vector = *getAsVector();
+    ExternalASTSource *Source = Context.getExternalSource();
+    assert(Source && "No external AST source available!");
+
+    for (unsigned I = 0, N = Vector.size(); I != N; ++I)
+      Vector[I] = reinterpret_cast<uintptr_t>(Source->GetDecl(Vector[I]));
+
+    Data = (Data & ~0x03) | DK_Decl_Vector;
+    break;
+  }
+  }
+}

Added: cfe/trunk/lib/Frontend/PCHReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReader.cpp?rev=68732&view=auto

==============================================================================
--- cfe/trunk/lib/Frontend/PCHReader.cpp (added)
+++ cfe/trunk/lib/Frontend/PCHReader.cpp Thu Apr  9 17:27:44 2009
@@ -0,0 +1,602 @@
+//===--- PCHReader.cpp - Precompiled Headers Reader -------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the PCHReader class, which reads a precompiled header.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Frontend/PCHReader.h"
+#include "clang/Frontend/PCHBitCodes.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Type.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <cstdio>
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Declaration deserialization
+//===----------------------------------------------------------------------===//
+namespace {
+  class VISIBILITY_HIDDEN PCHDeclReader {
+    PCHReader &Reader;
+    const PCHReader::RecordData &Record;
+    unsigned &Idx;
+
+  public:
+    PCHDeclReader(PCHReader &Reader, const PCHReader::RecordData &Record,
+                  unsigned &Idx)
+      : Reader(Reader), Record(Record), Idx(Idx) { }
+
+    void VisitDecl(Decl *D);
+    void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
+    void VisitNamedDecl(NamedDecl *ND);
+    void VisitTypeDecl(TypeDecl *TD);
+    void VisitTypedefDecl(TypedefDecl *TD);
+    void VisitValueDecl(ValueDecl *VD);
+    void VisitVarDecl(VarDecl *VD);
+
+    std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
+  };
+}
+
+void PCHDeclReader::VisitDecl(Decl *D) {
+  D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
+  D->setLexicalDeclContext(
+                     cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
+  D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+  D->setInvalidDecl(Record[Idx++]);
+  // FIXME: hasAttrs
+  D->setImplicit(Record[Idx++]);
+  D->setAccess((AccessSpecifier)Record[Idx++]);
+}
+
+void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
+  VisitDecl(TU);
+}
+
+void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) {
+  VisitDecl(ND);
+  ND->setDeclName(Reader.ReadDeclarationName(Record, Idx));  
+}
+
+void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) {
+  VisitNamedDecl(TD);
+  // FIXME: circular dependencies here?
+  TD->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr());
+}
+
+void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
+  VisitTypeDecl(TD);
+  TD->setUnderlyingType(Reader.GetType(Record[Idx++]));
+}
+
+void PCHDeclReader::VisitValueDecl(ValueDecl *VD) {
+  VisitNamedDecl(VD);
+  VD->setType(Reader.GetType(Record[Idx++]));
+}
+
+void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
+  VisitValueDecl(VD);
+  VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]);
+  VD->setThreadSpecified(Record[Idx++]);
+  VD->setCXXDirectInitializer(Record[Idx++]);
+  VD->setDeclaredInCondition(Record[Idx++]);
+  VD->setPreviousDeclaration(
+                         cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+  VD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+std::pair<uint64_t, uint64_t> 
+PCHDeclReader::VisitDeclContext(DeclContext *DC) {
+  uint64_t LexicalOffset = Record[Idx++];
+  uint64_t VisibleOffset = 0;
+  if (DC->getPrimaryContext() == DC)
+    VisibleOffset = Record[Idx++];
+  return std::make_pair(LexicalOffset, VisibleOffset);
+}
+
+// FIXME: use the diagnostics machinery
+static bool Error(const char *Str) {
+  std::fprintf(stderr, "%s\n", Str);
+  return true;
+}
+
+/// \brief Read the type-offsets block.
+bool PCHReader::ReadTypeOffsets() {
+  if (Stream.EnterSubBlock(pch::TYPE_OFFSETS_BLOCK_ID))
+    return Error("Malformed block record");
+
+  RecordData Record;
+  while (true) {
+    unsigned Code = Stream.ReadCode();
+    if (Code == llvm::bitc::END_BLOCK) {
+      if (Stream.ReadBlockEnd())
+        return Error("Error at end of TYPE_OFFSETS block");
+      return false;
+    }
+    
+    if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+      // No known subblocks, always skip them.
+      Stream.ReadSubBlockID();
+      if (Stream.SkipBlock())
+        return Error("Malformed block record");
+      continue;
+    }
+    
+    if (Code == llvm::bitc::DEFINE_ABBREV) {
+      Stream.ReadAbbrevRecord();
+      continue;
+    }
+    
+    // Read a record.
+    Record.clear();
+    switch (Stream.ReadRecord(Code, Record)) {
+    default:  // Default behavior: ignore.
+      break;
+    case pch::TYPE_OFFSET:
+      if (!TypeOffsets.empty())
+        return Error("Duplicate TYPE_OFFSETS block");
+      TypeOffsets.swap(Record);
+      TypeAlreadyLoaded.resize(TypeOffsets.size(), false);
+      break;
+    }
+  }
+}
+
+/// \brief Read the decl-offsets block.
+bool PCHReader::ReadDeclOffsets() {
+  if (Stream.EnterSubBlock(pch::DECL_OFFSETS_BLOCK_ID))
+    return Error("Malformed block record");
+
+  RecordData Record;
+  while (true) {
+    unsigned Code = Stream.ReadCode();
+    if (Code == llvm::bitc::END_BLOCK) {
+      if (Stream.ReadBlockEnd())
+        return Error("Error at end of DECL_OFFSETS block");
+      return false;
+    }
+    
+    if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+      // No known subblocks, always skip them.
+      Stream.ReadSubBlockID();
+      if (Stream.SkipBlock())
+        return Error("Malformed block record");
+      continue;
+    }
+    
+    if (Code == llvm::bitc::DEFINE_ABBREV) {
+      Stream.ReadAbbrevRecord();
+      continue;
+    }
+    
+    // Read a record.
+    Record.clear();
+    switch (Stream.ReadRecord(Code, Record)) {
+    default:  // Default behavior: ignore.
+      break;
+    case pch::DECL_OFFSET:
+      if (!DeclOffsets.empty())
+        return Error("Duplicate DECL_OFFSETS block");
+      DeclOffsets.swap(Record);
+      DeclAlreadyLoaded.resize(DeclOffsets.size(), false);
+      break;
+    }
+  }
+}
+
+bool PCHReader::ReadPCHBlock() {
+  if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID))
+    return Error("Malformed block record");
+
+  // Read all of the records and blocks for the PCH file.
+  while (!Stream.AtEndOfStream()) {
+    unsigned Code = Stream.ReadCode();
+    if (Code == llvm::bitc::END_BLOCK) {
+      if (Stream.ReadBlockEnd())
+        return Error("Error at end of module block");
+      return false;
+    }
+
+    if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+      switch (Stream.ReadSubBlockID()) {
+      case pch::DECLS_BLOCK_ID: // Skip decls block (lazily loaded)
+      case pch::TYPES_BLOCK_ID: // Skip types block (lazily loaded)
+      default:  // Skip unknown content.
+        if (Stream.SkipBlock())
+          return Error("Malformed block record");
+        break;
+
+
+      case pch::TYPE_OFFSETS_BLOCK_ID:
+        if (ReadTypeOffsets())
+          return Error("Malformed type-offsets block");
+        break;
+
+      case pch::DECL_OFFSETS_BLOCK_ID:
+        if (ReadDeclOffsets())
+          return Error("Malformed decl-offsets block");
+        break;
+      }
+    }
+  }
+
+  return Error("Premature end of bitstream");
+}
+
+PCHReader::~PCHReader() { }
+
+bool PCHReader::ReadPCH(const std::string &FileName) {
+  // Open the PCH file.
+  std::string ErrStr;
+  Buffer.reset(llvm::MemoryBuffer::getFile(FileName.c_str(), &ErrStr));
+  if (!Buffer)
+    return Error(ErrStr.c_str());
+
+  // Initialize the stream
+  Stream.init((const unsigned char *)Buffer->getBufferStart(), 
+              (const unsigned char *)Buffer->getBufferEnd());
+
+  // Sniff for the signature.
+  if (Stream.Read(8) != 'C' ||
+      Stream.Read(8) != 'P' ||
+      Stream.Read(8) != 'C' ||
+      Stream.Read(8) != 'H')
+    return Error("Not a PCH file");
+
+  // We expect a number of well-defined blocks, though we don't necessarily
+  // need to understand them all.
+  while (!Stream.AtEndOfStream()) {
+    unsigned Code = Stream.ReadCode();
+    
+    if (Code != llvm::bitc::ENTER_SUBBLOCK)
+      return Error("Invalid record at top-level");
+
+    unsigned BlockID = Stream.ReadSubBlockID();
+    
+    // We only know the PCH subblock ID.
+    switch (BlockID) {
+    case llvm::bitc::BLOCKINFO_BLOCK_ID:
+      if (Stream.ReadBlockInfoBlock())
+        return Error("Malformed BlockInfoBlock");
+      break;
+    case pch::PCH_BLOCK_ID:
+      if (ReadPCHBlock())
+        return true;
+      break;
+    default:
+      if (Stream.SkipBlock())
+        return Error("Malformed block record");
+      break;
+    }
+  }  
+
+  // Load the translation unit declaration
+  ReadDeclRecord(DeclOffsets[0], 0);
+
+  return false;
+}
+
+/// \brief Read and return the type at the given offset.
+///
+/// This routine actually reads the record corresponding to the type
+/// at the given offset in the bitstream. It is a helper routine for
+/// GetType, which deals with reading type IDs.
+QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
+  Stream.JumpToBit(Offset);
+  RecordData Record;
+  unsigned Code = Stream.ReadCode();
+  switch ((pch::TypeCode)Stream.ReadRecord(Code, Record)) {
+  case pch::TYPE_FIXED_WIDTH_INT: {
+    assert(Record.size() == 2 && "Incorrect encoding of fixed-width int type");
+    return Context.getFixedWidthIntType(Record[0], Record[1]);
+  }
+
+  case pch::TYPE_COMPLEX: {
+    assert(Record.size() == 1 && "Incorrect encoding of complex type");
+    QualType ElemType = GetType(Record[0]);
+    return Context.getComplexType(ElemType);
+  }
+
+  case pch::TYPE_POINTER: {
+    assert(Record.size() == 1 && "Incorrect encoding of pointer type");
+    QualType PointeeType = GetType(Record[0]);
+    return Context.getPointerType(PointeeType);
+  }
+
+  case pch::TYPE_BLOCK_POINTER: {
+    assert(Record.size() == 1 && "Incorrect encoding of block pointer type");
+    QualType PointeeType = GetType(Record[0]);
+    return Context.getBlockPointerType(PointeeType);
+  }
+
+  case pch::TYPE_LVALUE_REFERENCE: {
+    assert(Record.size() == 1 && "Incorrect encoding of lvalue reference type");
+    QualType PointeeType = GetType(Record[0]);
+    return Context.getLValueReferenceType(PointeeType);
+  }
+
+  case pch::TYPE_RVALUE_REFERENCE: {
+    assert(Record.size() == 1 && "Incorrect encoding of rvalue reference type");
+    QualType PointeeType = GetType(Record[0]);
+    return Context.getRValueReferenceType(PointeeType);
+  }
+
+  case pch::TYPE_MEMBER_POINTER: {
+    assert(Record.size() == 1 && "Incorrect encoding of member pointer type");
+    QualType PointeeType = GetType(Record[0]);
+    QualType ClassType = GetType(Record[1]);
+    return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr());
+  }
+
+    // FIXME: Several other kinds of types to deserialize here!
+  default:
+    assert("Unable to deserialize this type");
+    break;
+  }
+
+  // Suppress a GCC warning
+  return QualType();
+}
+
+/// \brief Note that we have loaded the declaration with the given
+/// Index.
+/// 
+/// This routine notes that this declaration has already been loaded,
+/// so that future GetDecl calls will return this declaration rather
+/// than trying to load a new declaration.
+inline void PCHReader::LoadedDecl(unsigned Index, Decl *D) {
+  assert(!DeclAlreadyLoaded[Index] && "Decl loaded twice?");
+  DeclAlreadyLoaded[Index] = true;
+  DeclOffsets[Index] = reinterpret_cast<uint64_t>(D);
+}
+
+/// \brief Read the declaration at the given offset from the PCH file.
+Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
+  Decl *D = 0;
+  Stream.JumpToBit(Offset);
+  RecordData Record;
+  unsigned Code = Stream.ReadCode();
+  unsigned Idx = 0;
+  PCHDeclReader Reader(*this, Record, Idx);
+  switch ((pch::DeclCode)Stream.ReadRecord(Code, Record)) {
+  case pch::DECL_TRANSLATION_UNIT:
+    assert(Index == 0 && "Translation unit must be at index 0");
+    Reader.VisitTranslationUnitDecl(Context.getTranslationUnitDecl());
+    D = Context.getTranslationUnitDecl();
+    LoadedDecl(Index, D);
+    break;
+
+  case pch::DECL_TYPEDEF: {
+    TypedefDecl *Typedef = TypedefDecl::Create(Context, 0, SourceLocation(),
+                                               0, QualType());
+    LoadedDecl(Index, Typedef);
+    Reader.VisitTypedefDecl(Typedef);
+    D = Typedef;
+    break;
+  }
+
+  case pch::DECL_VAR: {
+    VarDecl *Var = VarDecl::Create(Context, 0, SourceLocation(), 0, QualType(),
+                                   VarDecl::None, SourceLocation());
+    LoadedDecl(Index, Var);
+    Reader.VisitVarDecl(Var);
+    D = Var;
+    break;
+  }
+
+  default:
+    assert(false && "Cannot de-serialize this kind of declaration");
+    break;
+  }
+
+  // If this declaration is also a declaration context, get the
+  // offsets for its tables of lexical and visible declarations.
+  if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
+    std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC);
+    if (Offsets.first || Offsets.second) {
+      DC->setHasExternalLexicalStorage(Offsets.first != 0);
+      DC->setHasExternalVisibleStorage(Offsets.second != 0);
+      DeclContextOffsets[DC] = Offsets;
+    }
+  }
+  assert(Idx == Record.size());
+
+  return D;
+}
+
+QualType PCHReader::GetType(unsigned ID) {
+  unsigned Quals = ID & 0x07; 
+  unsigned Index = ID >> 3;
+
+  if (Index < pch::NUM_PREDEF_TYPE_IDS) {
+    QualType T;
+    switch ((pch::PredefinedTypeIDs)Index) {
+    case pch::PREDEF_TYPE_NULL_ID: return QualType();
+    case pch::PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break;
+    case pch::PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break;
+
+    case pch::PREDEF_TYPE_CHAR_U_ID:
+    case pch::PREDEF_TYPE_CHAR_S_ID:
+      // FIXME: Check that the signedness of CharTy is correct!
+      T = Context.CharTy;
+      break;
+
+    case pch::PREDEF_TYPE_UCHAR_ID:      T = Context.UnsignedCharTy;     break;
+    case pch::PREDEF_TYPE_USHORT_ID:     T = Context.UnsignedShortTy;    break;
+    case pch::PREDEF_TYPE_UINT_ID:       T = Context.UnsignedIntTy;      break;
+    case pch::PREDEF_TYPE_ULONG_ID:      T = Context.UnsignedLongTy;     break;
+    case pch::PREDEF_TYPE_ULONGLONG_ID:  T = Context.UnsignedLongLongTy; break;
+    case pch::PREDEF_TYPE_SCHAR_ID:      T = Context.SignedCharTy;       break;
+    case pch::PREDEF_TYPE_WCHAR_ID:      T = Context.WCharTy;            break;
+    case pch::PREDEF_TYPE_SHORT_ID:      T = Context.ShortTy;            break;
+    case pch::PREDEF_TYPE_INT_ID:        T = Context.IntTy;              break;
+    case pch::PREDEF_TYPE_LONG_ID:       T = Context.LongTy;             break;
+    case pch::PREDEF_TYPE_LONGLONG_ID:   T = Context.LongLongTy;         break;
+    case pch::PREDEF_TYPE_FLOAT_ID:      T = Context.FloatTy;            break;
+    case pch::PREDEF_TYPE_DOUBLE_ID:     T = Context.DoubleTy;           break;
+    case pch::PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy;       break;
+    case pch::PREDEF_TYPE_OVERLOAD_ID:   T = Context.OverloadTy;         break;
+    case pch::PREDEF_TYPE_DEPENDENT_ID:  T = Context.DependentTy;        break;
+    }
+
+    assert(!T.isNull() && "Unknown predefined type");
+    return T.getQualifiedType(Quals);
+  }
+
+  Index -= pch::NUM_PREDEF_TYPE_IDS;
+  if (!TypeAlreadyLoaded[Index]) {
+    // Load the type from the PCH file.
+    TypeOffsets[Index] = reinterpret_cast<uint64_t>(
+                             ReadTypeRecord(TypeOffsets[Index]).getTypePtr());
+    TypeAlreadyLoaded[Index] = true;
+  }
+    
+  return QualType(reinterpret_cast<Type *>(TypeOffsets[Index]), Quals);
+}
+
+Decl *PCHReader::GetDecl(unsigned ID) {
+  if (ID == 0)
+    return 0;
+
+  unsigned Index = ID - 1;
+  if (DeclAlreadyLoaded[Index])
+    return reinterpret_cast<Decl *>(DeclOffsets[Index]);
+
+  // Load the declaration from the PCH file.
+  return ReadDeclRecord(DeclOffsets[Index], Index);
+}
+
+bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC,
+                                     llvm::SmallVectorImpl<unsigned> &Decls) {
+  assert(DC->hasExternalLexicalStorage() && 
+         "DeclContext has no lexical decls in storage");
+  uint64_t Offset = DeclContextOffsets[DC].first;
+  assert(Offset && "DeclContext has no lexical decls in storage");
+
+  // Load the record containing all of the declarations lexically in
+  // this context.
+  Stream.JumpToBit(Offset);
+  RecordData Record;
+  unsigned Code = Stream.ReadCode();
+  unsigned RecCode = Stream.ReadRecord(Code, Record);
+  assert(RecCode == pch::DECL_CONTEXT_LEXICAL && "Expected lexical block");
+
+  // Load all of the declaration IDs
+  Decls.clear();
+  Decls.insert(Decls.end(), Record.begin(), Record.end());
+  return false;
+}
+
+bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC,
+                           llvm::SmallVectorImpl<VisibleDeclaration> & Decls) {
+  assert(DC->hasExternalVisibleStorage() && 
+         "DeclContext has no visible decls in storage");
+  uint64_t Offset = DeclContextOffsets[DC].second;
+  assert(Offset && "DeclContext has no visible decls in storage");
+
+  // Load the record containing all of the declarations visible in
+  // this context.
+  Stream.JumpToBit(Offset);
+  RecordData Record;
+  unsigned Code = Stream.ReadCode();
+  unsigned RecCode = Stream.ReadRecord(Code, Record);
+  assert(RecCode == pch::DECL_CONTEXT_VISIBLE && "Expected visible block");
+  if (Record.size() == 0)
+    return false;  
+
+  Decls.clear();
+
+  unsigned Idx = 0;
+  //  llvm::SmallVector<uintptr_t, 16> DeclIDs;
+  while (Idx < Record.size()) {
+    Decls.push_back(VisibleDeclaration());
+    Decls.back().Name = ReadDeclarationName(Record, Idx);
+
+    // FIXME: Don't actually read anything here!
+    unsigned Size = Record[Idx++];
+    llvm::SmallVector<unsigned, 4> & LoadedDecls
+      = Decls.back().Declarations;
+    LoadedDecls.reserve(Size);
+    for (unsigned I = 0; I < Size; ++I)
+      LoadedDecls.push_back(Record[Idx++]);
+  }
+
+  return false;
+}
+
+void PCHReader::PrintStats() {
+  std::fprintf(stderr, "*** PCH Statistics:\n");
+
+  unsigned NumTypesLoaded = std::count(TypeAlreadyLoaded.begin(),
+                                       TypeAlreadyLoaded.end(),
+                                       true);
+  unsigned NumDeclsLoaded = std::count(DeclAlreadyLoaded.begin(),
+                                       DeclAlreadyLoaded.end(),
+                                       true);
+  std::fprintf(stderr, "  %u/%u types read (%f%%)\n",
+               NumTypesLoaded, (unsigned)TypeAlreadyLoaded.size(),
+               ((float)NumTypesLoaded/(float)TypeAlreadyLoaded.size() * 100));
+  std::fprintf(stderr, "  %u/%u declarations read (%f%%)\n",
+               NumDeclsLoaded, (unsigned)DeclAlreadyLoaded.size(),
+               ((float)NumDeclsLoaded/(float)DeclAlreadyLoaded.size() * 100));
+  std::fprintf(stderr, "\n");
+}
+
+const IdentifierInfo *PCHReader::GetIdentifierInfo(const RecordData &Record, 
+                                                   unsigned &Idx) {
+  // FIXME: we need unique IDs for identifiers.
+  std::string Str;
+  unsigned Length = Record[Idx++];
+  Str.resize(Length);
+  for (unsigned I = 0; I != Length; ++I)
+    Str[I] = Record[Idx++];
+  return &Context.Idents.get(Str);
+}
+
+DeclarationName 
+PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
+  DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
+  switch (Kind) {
+  case DeclarationName::Identifier:
+    return DeclarationName(GetIdentifierInfo(Record, Idx));
+
+  case DeclarationName::ObjCZeroArgSelector:
+  case DeclarationName::ObjCOneArgSelector:
+  case DeclarationName::ObjCMultiArgSelector:
+    assert(false && "Unable to de-serialize Objective-C selectors");
+    break;
+
+  case DeclarationName::CXXConstructorName:
+    return Context.DeclarationNames.getCXXConstructorName(
+                                                      GetType(Record[Idx++]));
+
+  case DeclarationName::CXXDestructorName:
+    return Context.DeclarationNames.getCXXDestructorName(
+                                                      GetType(Record[Idx++]));
+
+  case DeclarationName::CXXConversionFunctionName:
+    return Context.DeclarationNames.getCXXConversionFunctionName(
+                                                      GetType(Record[Idx++]));
+
+  case DeclarationName::CXXOperatorName:
+    return Context.DeclarationNames.getCXXOperatorName(
+                                       (OverloadedOperatorKind)Record[Idx++]);
+
+  case DeclarationName::CXXUsingDirective:
+    return DeclarationName::getUsingDirectiveName();
+  }
+
+  // Required to silence GCC warning
+  return DeclarationName();
+}

Added: cfe/trunk/lib/Frontend/PCHWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriter.cpp?rev=68732&view=auto

==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriter.cpp (added)
+++ cfe/trunk/lib/Frontend/PCHWriter.cpp Thu Apr  9 17:27:44 2009
@@ -0,0 +1,636 @@
+//===--- PCHWriter.h - Precompiled Headers Writer ---------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the PCHWriter class, which writes a precompiled header.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHWriter.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclContextInternals.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Type.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Type serialization
+//===----------------------------------------------------------------------===//
+namespace {
+  class VISIBILITY_HIDDEN PCHTypeWriter {
+    PCHWriter &Writer;
+    PCHWriter::RecordData &Record;
+
+  public:
+    /// \brief Type code that corresponds to the record generated.
+    pch::TypeCode Code;
+
+    PCHTypeWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) 
+      : Writer(Writer), Record(Record) { }
+
+    void VisitArrayType(const ArrayType *T);
+    void VisitFunctionType(const FunctionType *T);
+    void VisitTagType(const TagType *T);
+
+#define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T);
+#define ABSTRACT_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+  };
+}
+
+void PCHTypeWriter::VisitExtQualType(const ExtQualType *T) {
+  Writer.AddTypeRef(QualType(T->getBaseType(), 0), Record);
+  Record.push_back(T->getObjCGCAttr()); // FIXME: use stable values
+  Record.push_back(T->getAddressSpace());
+  Code = pch::TYPE_EXT_QUAL;
+}
+
+void PCHTypeWriter::VisitBuiltinType(const BuiltinType *T) {
+  assert(false && "Built-in types are never serialized");
+}
+
+void PCHTypeWriter::VisitFixedWidthIntType(const FixedWidthIntType *T) {
+  Record.push_back(T->getWidth());
+  Record.push_back(T->isSigned());
+  Code = pch::TYPE_FIXED_WIDTH_INT;
+}
+
+void PCHTypeWriter::VisitComplexType(const ComplexType *T) {
+  Writer.AddTypeRef(T->getElementType(), Record);
+  Code = pch::TYPE_COMPLEX;
+}
+
+void PCHTypeWriter::VisitPointerType(const PointerType *T) {
+  Writer.AddTypeRef(T->getPointeeType(), Record);
+  Code = pch::TYPE_POINTER;
+}
+
+void PCHTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
+  Writer.AddTypeRef(T->getPointeeType(), Record);  
+  Code = pch::TYPE_BLOCK_POINTER;
+}
+
+void PCHTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) {
+  Writer.AddTypeRef(T->getPointeeType(), Record);
+  Code = pch::TYPE_LVALUE_REFERENCE;
+}
+
+void PCHTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) {
+  Writer.AddTypeRef(T->getPointeeType(), Record);
+  Code = pch::TYPE_RVALUE_REFERENCE;
+}
+
+void PCHTypeWriter::VisitMemberPointerType(const MemberPointerType *T) {
+  Writer.AddTypeRef(T->getPointeeType(), Record);  
+  Writer.AddTypeRef(QualType(T->getClass(), 0), Record);  
+  Code = pch::TYPE_MEMBER_POINTER;
+}
+
+void PCHTypeWriter::VisitArrayType(const ArrayType *T) {
+  Writer.AddTypeRef(T->getElementType(), Record);
+  Record.push_back(T->getSizeModifier()); // FIXME: stable values
+  Record.push_back(T->getIndexTypeQualifier()); // FIXME: stable values
+}
+
+void PCHTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) {
+  VisitArrayType(T);
+  Writer.AddAPInt(T->getSize(), Record);
+  Code = pch::TYPE_CONSTANT_ARRAY;
+}
+
+void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
+  VisitArrayType(T);
+  Code = pch::TYPE_INCOMPLETE_ARRAY;
+}
+
+void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) {
+  VisitArrayType(T);
+  // FIXME: Serialize array size expression.
+  assert(false && "Cannot serialize variable-length arrays");
+  Code = pch::TYPE_VARIABLE_ARRAY;
+}
+
+void PCHTypeWriter::VisitVectorType(const VectorType *T) {
+  Writer.AddTypeRef(T->getElementType(), Record);
+  Record.push_back(T->getNumElements());
+  Code = pch::TYPE_VECTOR;
+}
+
+void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) {
+  VisitVectorType(T);
+  Code = pch::TYPE_EXT_VECTOR;
+}
+
+void PCHTypeWriter::VisitFunctionType(const FunctionType *T) {
+  Writer.AddTypeRef(T->getResultType(), Record);
+}
+
+void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
+  VisitFunctionType(T);
+  Code = pch::TYPE_FUNCTION_NO_PROTO;
+}
+
+void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
+  VisitFunctionType(T);
+  Record.push_back(T->getNumArgs());
+  for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I)
+    Writer.AddTypeRef(T->getArgType(I), Record);
+  Record.push_back(T->isVariadic());
+  Record.push_back(T->getTypeQuals());
+  Code = pch::TYPE_FUNCTION_PROTO;
+}
+
+void PCHTypeWriter::VisitTypedefType(const TypedefType *T) {
+  Writer.AddDeclRef(T->getDecl(), Record);
+  Code = pch::TYPE_TYPEDEF;
+}
+
+void PCHTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) {
+  // FIXME: serialize the typeof expression
+  assert(false && "Cannot serialize typeof(expr)");
+  Code = pch::TYPE_TYPEOF_EXPR;
+}
+
+void PCHTypeWriter::VisitTypeOfType(const TypeOfType *T) {
+  Writer.AddTypeRef(T->getUnderlyingType(), Record);
+  Code = pch::TYPE_TYPEOF;
+}
+
+void PCHTypeWriter::VisitTagType(const TagType *T) {
+  Writer.AddDeclRef(T->getDecl(), Record);
+  assert(!T->isBeingDefined() && 
+         "Cannot serialize in the middle of a type definition");
+}
+
+void PCHTypeWriter::VisitRecordType(const RecordType *T) {
+  VisitTagType(T);
+  Code = pch::TYPE_RECORD;
+}
+
+void PCHTypeWriter::VisitEnumType(const EnumType *T) {
+  VisitTagType(T);
+  Code = pch::TYPE_ENUM;
+}
+
+void 
+PCHTypeWriter::VisitTemplateSpecializationType(
+                                       const TemplateSpecializationType *T) {
+  // FIXME: Serialize this type
+  assert(false && "Cannot serialize template specialization types");
+}
+
+void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) {
+  // FIXME: Serialize this type
+  assert(false && "Cannot serialize qualified name types");
+}
+
+void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
+  Writer.AddDeclRef(T->getDecl(), Record);
+  Code = pch::TYPE_OBJC_INTERFACE;
+}
+
+void 
+PCHTypeWriter::VisitObjCQualifiedInterfaceType(
+                                      const ObjCQualifiedInterfaceType *T) {
+  VisitObjCInterfaceType(T);
+  Record.push_back(T->getNumProtocols());
+  for (unsigned I = 0, N = T->getNumProtocols(); I != N; ++I)
+    Writer.AddDeclRef(T->getProtocol(I), Record);
+  Code = pch::TYPE_OBJC_QUALIFIED_INTERFACE;
+}
+
+void PCHTypeWriter::VisitObjCQualifiedIdType(const ObjCQualifiedIdType *T) {
+  Record.push_back(T->getNumProtocols());
+  for (unsigned I = 0, N = T->getNumProtocols(); I != N; ++I)
+    Writer.AddDeclRef(T->getProtocols(I), Record);
+  Code = pch::TYPE_OBJC_QUALIFIED_ID;
+}
+
+void 
+PCHTypeWriter::VisitObjCQualifiedClassType(const ObjCQualifiedClassType *T) {
+  Record.push_back(T->getNumProtocols());
+  for (unsigned I = 0, N = T->getNumProtocols(); I != N; ++I)
+    Writer.AddDeclRef(T->getProtocols(I), Record);
+  Code = pch::TYPE_OBJC_QUALIFIED_CLASS;
+}
+
+//===----------------------------------------------------------------------===//
+// Declaration serialization
+//===----------------------------------------------------------------------===//
+namespace {
+  class VISIBILITY_HIDDEN PCHDeclWriter
+    : public DeclVisitor<PCHDeclWriter, void> {
+
+    PCHWriter &Writer;
+    PCHWriter::RecordData &Record;
+
+  public:
+    pch::DeclCode Code;
+
+    PCHDeclWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) 
+      : Writer(Writer), Record(Record) { }
+
+    void VisitDecl(Decl *D);
+    void VisitTranslationUnitDecl(TranslationUnitDecl *D);
+    void VisitNamedDecl(NamedDecl *D);
+    void VisitTypeDecl(TypeDecl *D);
+    void VisitTypedefDecl(TypedefDecl *D);
+    void VisitValueDecl(ValueDecl *D);
+    void VisitVarDecl(VarDecl *D);
+
+    void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, 
+                          uint64_t VisibleOffset);
+  };
+}
+
+void PCHDeclWriter::VisitDecl(Decl *D) {
+  Writer.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()), Record);
+  Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record);
+  Writer.AddSourceLocation(D->getLocation(), Record);
+  Record.push_back(D->isInvalidDecl());
+  // FIXME: hasAttrs
+  Record.push_back(D->isImplicit());
+  Record.push_back(D->getAccess());
+}
+
+void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+  VisitDecl(D);
+  Code = pch::DECL_TRANSLATION_UNIT;
+}
+
+void PCHDeclWriter::VisitNamedDecl(NamedDecl *D) {
+  VisitDecl(D);
+  Writer.AddDeclarationName(D->getDeclName(), Record);
+}
+
+void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) {
+  VisitNamedDecl(D);
+  Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
+}
+
+void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
+  VisitTypeDecl(D);
+  Writer.AddTypeRef(D->getUnderlyingType(), Record);
+  Code = pch::DECL_TYPEDEF;
+}
+
+void PCHDeclWriter::VisitValueDecl(ValueDecl *D) {
+  VisitNamedDecl(D);
+  Writer.AddTypeRef(D->getType(), Record);
+}
+
+void PCHDeclWriter::VisitVarDecl(VarDecl *D) {
+  VisitValueDecl(D);
+  Record.push_back(D->getStorageClass());
+  Record.push_back(D->isThreadSpecified());
+  Record.push_back(D->hasCXXDirectInitializer());
+  Record.push_back(D->isDeclaredInCondition());
+  Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+  Writer.AddSourceLocation(D->getTypeSpecStartLoc(), Record);
+  // FIXME: emit initializer
+  Code = pch::DECL_VAR;
+}
+
+/// \brief Emit the DeclContext part of a declaration context decl.
+///
+/// \param LexicalOffset the offset at which the DECL_CONTEXT_LEXICAL
+/// block for this declaration context is stored. May be 0 to indicate
+/// that there are no declarations stored within this context.
+///
+/// \param VisibleOffset the offset at which the DECL_CONTEXT_VISIBLE
+/// block for this declaration context is stored. May be 0 to indicate
+/// that there are no declarations visible from this context. Note
+/// that this value will not be emitted for non-primary declaration
+/// contexts.
+void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, 
+                                     uint64_t VisibleOffset) {
+  Record.push_back(LexicalOffset);
+  if (DC->getPrimaryContext() == DC)
+    Record.push_back(VisibleOffset);
+}
+
+//===----------------------------------------------------------------------===//
+// PCHWriter Implementation
+//===----------------------------------------------------------------------===//
+
+/// \brief Write the representation of a type to the PCH stream.
+void PCHWriter::WriteType(const Type *T) {
+  pch::ID &ID = TypeIDs[T];
+  if (ID == 0) // we haven't seen this type before
+    ID = NextTypeID++;
+  
+  // Record the offset for this type.
+  if (TypeOffsets.size() == ID - pch::NUM_PREDEF_TYPE_IDS)
+    TypeOffsets.push_back(S.GetCurrentBitNo());
+  else if (TypeOffsets.size() < ID - pch::NUM_PREDEF_TYPE_IDS) {
+    TypeOffsets.resize(ID + 1 - pch::NUM_PREDEF_TYPE_IDS);
+    TypeOffsets[ID - pch::NUM_PREDEF_TYPE_IDS] = S.GetCurrentBitNo();
+  }
+
+  RecordData Record;
+  
+  // Emit the type's representation.
+  PCHTypeWriter W(*this, Record);
+  switch (T->getTypeClass()) {
+    // For all of the concrete, non-dependent types, call the
+    // appropriate visitor function.
+#define TYPE(Class, Base) \
+    case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break;
+#define ABSTRACT_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+
+    // For all of the dependent type nodes (which only occur in C++
+    // templates), produce an error.
+#define TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+    assert(false && "Cannot serialize dependent type nodes");
+    break;
+  }
+
+  // Emit the serialized record.
+  S.EmitRecord(W.Code, Record);
+}
+
+/// \brief Write a block containing all of the types.
+void PCHWriter::WriteTypesBlock(ASTContext &Context) {
+  // Enter the types block
+  S.EnterSubblock(pch::TYPES_BLOCK_ID, 2);
+
+  // Emit all of the types in the ASTContext
+  for (std::vector<Type*>::const_iterator T = Context.getTypes().begin(),
+                                       TEnd = Context.getTypes().end();
+       T != TEnd; ++T) {
+    // Builtin types are never serialized.
+    if (isa<BuiltinType>(*T))
+      continue;
+
+    WriteType(*T);
+  }
+
+  // Exit the types block
+  S.ExitBlock();
+
+  // Write the type offsets block
+  S.EnterSubblock(pch::TYPE_OFFSETS_BLOCK_ID, 2);
+  S.EmitRecord(pch::TYPE_OFFSET, TypeOffsets);
+  S.ExitBlock();
+}
+
+/// \brief Write the block containing all of the declaration IDs
+/// lexically declared within the given DeclContext.
+///
+/// \returns the offset of the DECL_CONTEXT_LEXICAL block within the
+/// bistream, or 0 if no block was written.
+uint64_t PCHWriter::WriteDeclContextLexicalBlock(ASTContext &Context, 
+                                                 DeclContext *DC) {
+  if (DC->decls_begin(Context) == DC->decls_end(Context))
+    return 0;
+
+  uint64_t Offset = S.GetCurrentBitNo();
+  RecordData Record;
+  for (DeclContext::decl_iterator D = DC->decls_begin(Context),
+                               DEnd = DC->decls_end(Context);
+       D != DEnd; ++D)
+    AddDeclRef(*D, Record);
+
+  S.EmitRecord(pch::DECL_CONTEXT_LEXICAL, Record);
+  return Offset;
+}
+
+/// \brief Write the block containing all of the declaration IDs
+/// visible from the given DeclContext.
+///
+/// \returns the offset of the DECL_CONTEXT_VISIBLE block within the
+/// bistream, or 0 if no block was written.
+uint64_t PCHWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
+                                                 DeclContext *DC) {
+  if (DC->getPrimaryContext() != DC)
+    return 0;
+
+  // Force the DeclContext to build a its name-lookup table.
+  DC->lookup(Context, DeclarationName());
+
+  // Serialize the contents of the mapping used for lookup. Note that,
+  // although we have two very different code paths, the serialized
+  // representation is the same for both cases: a declaration name,
+  // followed by a size, followed by references to the visible
+  // declarations that have that name.
+  uint64_t Offset = S.GetCurrentBitNo();
+  RecordData Record;
+  StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr());
+  for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
+       D != DEnd; ++D) {
+    AddDeclarationName(D->first, Record);
+    DeclContext::lookup_result Result = D->second.getLookupResult(Context);
+    Record.push_back(Result.second - Result.first);
+    for(; Result.first != Result.second; ++Result.first)
+      AddDeclRef(*Result.first, Record);
+  }
+
+  if (Record.size() == 0)
+    return 0;
+
+  S.EmitRecord(pch::DECL_CONTEXT_VISIBLE, Record);
+  return Offset;
+}
+
+/// \brief Write a block containing all of the declarations.
+void PCHWriter::WriteDeclsBlock(ASTContext &Context) {
+  // Enter the declarations block
+  S.EnterSubblock(pch::DECLS_BLOCK_ID, 2);
+
+  // Emit all of the declarations.
+  RecordData Record;
+  PCHDeclWriter W(*this, Record);
+  while (!DeclsToEmit.empty()) {
+    // Pull the next declaration off the queue
+    Decl *D = DeclsToEmit.front();
+    DeclsToEmit.pop();
+
+    // If this declaration is also a DeclContext, write blocks for the
+    // declarations that lexically stored inside its context and those
+    // declarations that are visible from its context. These blocks
+    // are written before the declaration itself so that we can put
+    // their offsets into the record for the declaration.
+    uint64_t LexicalOffset = 0;
+    uint64_t VisibleOffset = 0;
+    DeclContext *DC = dyn_cast<DeclContext>(D);
+    if (DC) {
+      LexicalOffset = WriteDeclContextLexicalBlock(Context, DC);
+      VisibleOffset = WriteDeclContextVisibleBlock(Context, DC);
+    }
+
+    // Determine the ID for this declaration
+    pch::ID ID = DeclIDs[D];
+    if (ID == 0)
+      ID = DeclIDs.size();
+
+    unsigned Index = ID - 1;
+
+    // Record the offset for this declaration
+    if (DeclOffsets.size() == Index)
+      DeclOffsets.push_back(S.GetCurrentBitNo());
+    else if (DeclOffsets.size() < Index) {
+      DeclOffsets.resize(Index+1);
+      DeclOffsets[Index] = S.GetCurrentBitNo();
+    }
+
+    // Build and emit a record for this declaration
+    Record.clear();
+    W.Code = (pch::DeclCode)0;
+    W.Visit(D);
+    if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset);
+    assert(W.Code && "Visitor did not set record code");
+    S.EmitRecord(W.Code, Record);
+  }
+
+  // Exit the declarations block
+  S.ExitBlock();
+
+  // Write the declaration offsets block
+  S.EnterSubblock(pch::DECL_OFFSETS_BLOCK_ID, 2);
+  S.EmitRecord(pch::DECL_OFFSET, DeclOffsets);
+  S.ExitBlock();
+}
+
+PCHWriter::PCHWriter(llvm::BitstreamWriter &S) 
+  : S(S), NextTypeID(pch::NUM_PREDEF_TYPE_IDS) { }
+
+void PCHWriter::WritePCH(ASTContext &Context) {
+  // Emit the file header.
+  S.Emit((unsigned)'C', 8);
+  S.Emit((unsigned)'P', 8);
+  S.Emit((unsigned)'C', 8);
+  S.Emit((unsigned)'H', 8);
+
+  // The translation unit is the first declaration we'll emit.
+  DeclIDs[Context.getTranslationUnitDecl()] = 1;
+  DeclsToEmit.push(Context.getTranslationUnitDecl());
+
+  // Write the remaining PCH contents.
+  S.EnterSubblock(pch::PCH_BLOCK_ID, 2);
+  WriteTypesBlock(Context);
+  WriteDeclsBlock(Context);
+  S.ExitBlock();
+}
+
+void PCHWriter::AddSourceLocation(SourceLocation Loc, RecordData &Record) {
+  Record.push_back(Loc.getRawEncoding());
+}
+
+void PCHWriter::AddAPInt(const llvm::APInt &Value, RecordData &Record) {
+  Record.push_back(Value.getBitWidth());
+  unsigned N = Value.getNumWords();
+  const uint64_t* Words = Value.getRawData();
+  for (unsigned I = 0; I != N; ++I)
+    Record.push_back(Words[I]);
+}
+
+void PCHWriter::AddIdentifierRef(const IdentifierInfo *II, RecordData &Record) {
+  // FIXME: Emit an identifier ID, not the actual string!
+  const char *Name = II->getName();
+  unsigned Len = strlen(Name);
+  Record.push_back(Len);
+  Record.insert(Record.end(), Name, Name + Len);
+}
+
+void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
+  if (T.isNull()) {
+    Record.push_back(pch::PREDEF_TYPE_NULL_ID);
+    return;
+  }
+
+  if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) {
+    pch::ID ID;
+    switch (BT->getKind()) {
+    case BuiltinType::Void:       ID = pch::PREDEF_TYPE_VOID_ID;       break;
+    case BuiltinType::Bool:       ID = pch::PREDEF_TYPE_BOOL_ID;       break;
+    case BuiltinType::Char_U:     ID = pch::PREDEF_TYPE_CHAR_U_ID;     break;
+    case BuiltinType::UChar:      ID = pch::PREDEF_TYPE_UCHAR_ID;      break;
+    case BuiltinType::UShort:     ID = pch::PREDEF_TYPE_USHORT_ID;     break;
+    case BuiltinType::UInt:       ID = pch::PREDEF_TYPE_UINT_ID;       break;
+    case BuiltinType::ULong:      ID = pch::PREDEF_TYPE_ULONG_ID;      break;
+    case BuiltinType::ULongLong:  ID = pch::PREDEF_TYPE_ULONGLONG_ID;  break;
+    case BuiltinType::Char_S:     ID = pch::PREDEF_TYPE_CHAR_S_ID;     break;
+    case BuiltinType::SChar:      ID = pch::PREDEF_TYPE_SCHAR_ID;      break;
+    case BuiltinType::WChar:      ID = pch::PREDEF_TYPE_WCHAR_ID;      break;
+    case BuiltinType::Short:      ID = pch::PREDEF_TYPE_SHORT_ID;      break;
+    case BuiltinType::Int:        ID = pch::PREDEF_TYPE_INT_ID;        break;
+    case BuiltinType::Long:       ID = pch::PREDEF_TYPE_LONG_ID;       break;
+    case BuiltinType::LongLong:   ID = pch::PREDEF_TYPE_LONGLONG_ID;   break;
+    case BuiltinType::Float:      ID = pch::PREDEF_TYPE_FLOAT_ID;      break;
+    case BuiltinType::Double:     ID = pch::PREDEF_TYPE_DOUBLE_ID;     break;
+    case BuiltinType::LongDouble: ID = pch::PREDEF_TYPE_LONGDOUBLE_ID; break;
+    case BuiltinType::Overload:   ID = pch::PREDEF_TYPE_OVERLOAD_ID;   break;
+    case BuiltinType::Dependent:  ID = pch::PREDEF_TYPE_DEPENDENT_ID;  break;
+    }
+
+    Record.push_back((ID << 3) | T.getCVRQualifiers());
+    return;
+  }
+
+  pch::ID &ID = TypeIDs[T.getTypePtr()];
+  if (ID == 0) // we haven't seen this type before
+    ID = NextTypeID++;
+
+  // Encode the type qualifiers in the type reference.
+  Record.push_back((ID << 3) | T.getCVRQualifiers());
+}
+
+void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) {
+  if (D == 0) {
+    Record.push_back(0);
+    return;
+  }
+
+  pch::ID &ID = DeclIDs[D];
+  if (ID == 0) { 
+    // We haven't seen this declaration before. Give it a new ID and
+    // enqueue it in the list of declarations to emit.
+    ID = DeclIDs.size();
+    DeclsToEmit.push(const_cast<Decl *>(D));
+  }
+
+  Record.push_back(ID);
+}
+
+void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) {
+  Record.push_back(Name.getNameKind());
+  switch (Name.getNameKind()) {
+  case DeclarationName::Identifier:
+    AddIdentifierRef(Name.getAsIdentifierInfo(), Record);
+    break;
+
+  case DeclarationName::ObjCZeroArgSelector:
+  case DeclarationName::ObjCOneArgSelector:
+  case DeclarationName::ObjCMultiArgSelector:
+    assert(false && "Serialization of Objective-C selectors unavailable");
+    break;
+
+  case DeclarationName::CXXConstructorName:
+  case DeclarationName::CXXDestructorName:
+  case DeclarationName::CXXConversionFunctionName:
+    AddTypeRef(Name.getCXXNameType(), Record);
+    break;
+
+  case DeclarationName::CXXOperatorName:
+    Record.push_back(Name.getCXXOverloadedOperator());
+    break;
+
+  case DeclarationName::CXXUsingDirective:
+    // No extra data to emit
+    break;
+  }
+}

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=68732&r1=68731&r2=68732&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Apr  9 17:27:44 2009
@@ -524,6 +524,12 @@
       return false;
   }
 
+  // __builtin_va_list gets redeclared in the built-in definitions
+  // buffer when using PCH. Don't complain about such redefinitions.
+  if (Context.getExternalSource() && 
+      strcmp(SourceMgr.getBufferName(New->getLocation()), "<built-in>") == 0)
+    return false;
+
   Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName();
   Diag(Old->getLocation(), diag::note_previous_definition);
   return true;

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=68732&r1=68731&r2=68732&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Thu Apr  9 17:27:44 2009
@@ -878,6 +878,17 @@
         // We have a single lookup result.
         return LookupResult::CreateLookupResult(Context, *I);
       }
+
+    /// If the context has an external AST source attached, look at
+    /// translation unit scope.
+    if (Context.getExternalSource()) {
+      DeclContext::lookup_iterator I, E;
+      for (llvm::tie(I, E) 
+             = Context.getTranslationUnitDecl()->lookup(Context, Name); 
+           I != E; ++I)
+        if (isAcceptableLookupResult(*I, NameKind, IDNS))
+          return LookupResult::CreateLookupResult(Context, I, E);
+    }
   } else {
     // Perform C++ unqualified name lookup.
     std::pair<bool, LookupResult> MaybeResult =

Added: cfe/trunk/test/PCH/variables.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/variables.c?rev=68732&view=auto

==============================================================================
--- cfe/trunk/test/PCH/variables.c (added)
+++ cfe/trunk/test/PCH/variables.c Thu Apr  9 17:27:44 2009
@@ -0,0 +1,6 @@
+// RUN: clang-cc -emit-pch -o %t %S/variables.h &&
+// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s 
+
+int *ip2 = &x;
+float *fp = &ip; // expected-warning{{incompatible pointer types}}
+

Added: cfe/trunk/test/PCH/variables.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/variables.h?rev=68732&view=auto

==============================================================================
--- cfe/trunk/test/PCH/variables.h (added)
+++ cfe/trunk/test/PCH/variables.h Thu Apr  9 17:27:44 2009
@@ -0,0 +1,5 @@
+// RUN: clang-cc -emit-pch -o variables.h.pch variables.h
+extern int x;
+extern float y;
+extern int *ip;
+float z;

Modified: cfe/trunk/test/TestRunner.sh
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/TestRunner.sh?rev=68732&r1=68731&r2=68732&view=diff

==============================================================================
--- cfe/trunk/test/TestRunner.sh (original)
+++ cfe/trunk/test/TestRunner.sh Thu Apr  9 17:27:44 2009
@@ -8,6 +8,7 @@
 #
 #     %s - Replaced with the input name of the program, or the program to
 #          execute, as appropriate.
+#     %S - Replaced with the directory where the input file resides
 #     %prcontext - prcontext.tcl script
 #     %t - temporary file name (derived from testcase name)
 #
@@ -15,6 +16,7 @@
 FILENAME=$1
 TESTNAME=$1
 SUBST=$1
+FILEDIR=`dirname $TESTNAME`
 
 OUTPUT=Output/$1.out
 
@@ -78,6 +80,7 @@
       -e "s| clang | $CLANG |g" \
       -e "s| clang-cc | $CLANGCC |g" \
       -e "s|%s|$SUBST|g" \
+      -e "s|%S|$FILEDIR|g" \
       -e "s|%prcontext|prcontext.tcl|g" \
       -e "s|%t|$TEMPOUTPUT|g" > $SCRIPT
 

Modified: cfe/trunk/tools/clang-cc/ASTConsumers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-cc/ASTConsumers.h?rev=68732&r1=68731&r2=68732&view=diff

==============================================================================
--- cfe/trunk/tools/clang-cc/ASTConsumers.h (original)
+++ cfe/trunk/tools/clang-cc/ASTConsumers.h Thu Apr  9 17:27:44 2009
@@ -68,6 +68,11 @@
                                  const std::string& EmitDir,
                                  Diagnostic &Diags);
   
+ASTConsumer *CreatePCHGenerator(Diagnostic &Diags,
+                                const LangOptions &Features,
+                                const std::string& InFile,
+                                const std::string& OutFile);
+
 ASTConsumer *CreateBlockRewriter(const std::string& InFile,
                                  const std::string& OutFile,
                                  Diagnostic &Diags,

Added: cfe/trunk/tools/clang-cc/GeneratePCH.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-cc/GeneratePCH.cpp?rev=68732&view=auto

==============================================================================
--- cfe/trunk/tools/clang-cc/GeneratePCH.cpp (added)
+++ cfe/trunk/tools/clang-cc/GeneratePCH.cpp Thu Apr  9 17:27:44 2009
@@ -0,0 +1,78 @@
+//===--- GeneratePCH.cpp - AST Consumer for PCH Generation ------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the CreatePCHGenerate function, which creates an
+//  ASTConsume that generates a PCH file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/PCHWriter.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/System/Path.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Streams.h"
+#include <string>
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+  class VISIBILITY_HIDDEN PCHGenerator : public ASTConsumer {
+    Diagnostic &Diags;
+    std::string OutFile;
+
+  public:
+    explicit PCHGenerator(Diagnostic &Diags, const std::string &OutFile)
+      : Diags(Diags), OutFile(OutFile) { }
+
+    virtual void HandleTranslationUnit(ASTContext &Ctx);
+  };
+}
+
+void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
+  if (Diags.hasErrorOccurred())
+    return;
+
+ // Write the PCH contents into a buffer
+  std::vector<unsigned char> Buffer;
+  BitstreamWriter Stream(Buffer);
+  PCHWriter Writer(Stream);
+
+  // Emit the PCH file
+  Writer.WritePCH(Ctx);
+
+  // Open up the PCH file.
+  std::string ErrMsg;
+  llvm::raw_fd_ostream Out(OutFile.c_str(), true, ErrMsg);
+  
+  if (!ErrMsg.empty()) {
+    llvm::errs() << "PCH error: " << ErrMsg << "\n";
+    return;
+  }
+
+  // Write the generated bitstream to "Out".
+  Out.write((char *)&Buffer.front(), Buffer.size());
+
+  // Make sure it hits disk now.
+  Out.flush();
+}
+
+namespace clang {
+
+ASTConsumer *CreatePCHGenerator(Diagnostic &Diags,
+                                const LangOptions &Features,
+                                const std::string& InFile,
+                                const std::string& OutFile) {
+  return new PCHGenerator(Diags, OutFile);
+}
+
+}

Modified: cfe/trunk/tools/clang-cc/clang-cc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-cc/clang-cc.cpp?rev=68732&r1=68731&r2=68732&view=diff

==============================================================================
--- cfe/trunk/tools/clang-cc/clang-cc.cpp (original)
+++ cfe/trunk/tools/clang-cc/clang-cc.cpp Thu Apr  9 17:27:44 2009
@@ -29,6 +29,7 @@
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/InitHeaderSearch.h"
 #include "clang/Frontend/PathDiagnosticClients.h"
+#include "clang/Frontend/PCHReader.h"
 #include "clang/Frontend/TextDiagnosticBuffer.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Analysis/PathDiagnostic.h"
@@ -194,6 +195,7 @@
   DumpRawTokens,                // Dump out raw tokens.
   RunAnalysis,                  // Run one or more source code analyses. 
   GeneratePTH,                  // Generate pre-tokenized header.
+  GeneratePCH,                  // Generate pre-compiled header.
   InheritanceView               // View C++ inheritance for a specified class.
 };
 
@@ -229,6 +231,8 @@
                         "Print DeclContexts and their Decls"),
              clEnumValN(GeneratePTH, "emit-pth",
                         "Generate pre-tokenized header file"),
+             clEnumValN(GeneratePCH, "emit-pch",
+                        "Generate pre-compiled header file"),
              clEnumValN(TestSerialization, "test-pickling",
                         "Run prototype serialization code"),
              clEnumValN(EmitAssembly, "S",
@@ -975,6 +979,10 @@
 ImplicitIncludePTH("include-pth", llvm::cl::value_desc("file"),
                    llvm::cl::desc("Include file before parsing"));
 
+static llvm::cl::opt<std::string>
+ImplicitIncludePCH("include-pch", llvm::cl::value_desc("file"),
+                   llvm::cl::desc("Include precompiled header file"));
+
 // Append a #define line to Buf for Macro.  Macro should be of the form XXX,
 // in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit
 // "#define XXX Y z W".  To get a #define with no value, use "XXX=".
@@ -1516,6 +1524,9 @@
     // FIXME: Allow user to tailor where the file is written.
     return CreateASTSerializer(InFile, OutputFile, Diag);
     
+  case GeneratePCH:
+    return CreatePCHGenerator(Diag, LangOpts, InFile, OutputFile);    
+
   case RewriteObjC:
     return CreateCodeRewriterTest(InFile, OutputFile, Diag, LangOpts);
 
@@ -1683,6 +1694,18 @@
                                       PP.getSelectorTable(),
                                       /* FreeMemory = */ !DisableFree));
     
+    if (!ImplicitIncludePCH.empty()) {
+      // The user has asked us to include a precompiled header. Load
+      // the precompiled header into the AST context.
+      llvm::OwningPtr<PCHReader> Reader(
+                                   new clang::PCHReader(*ContextOwner.get()));
+      if (Reader->ReadPCH(ImplicitIncludePCH))
+        return;
+
+      llvm::OwningPtr<ExternalASTSource> Source(Reader.take());
+      ContextOwner->setExternalSource(Source);
+    }
+
     ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats);
     
     if (FixItRewrite)





More information about the cfe-commits mailing list