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.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68732 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index deeb763..7da1bf0 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -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() { }
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 763998e..be34942 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -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;
+  }
+  }
+}
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
new file mode 100644
index 0000000..d366cdd
--- /dev/null
+++ b/lib/Frontend/PCHReader.cpp
@@ -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();
+}
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
new file mode 100644
index 0000000..39936b3
--- /dev/null
+++ b/lib/Frontend/PCHWriter.cpp
@@ -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;
+  }
+}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 474c1e4..b024d36 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -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;
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 0b11d9c..cd82507 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -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 =