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

Chris Lattner clattner at apple.com
Thu Apr 9 22:52:36 PDT 2009


> 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.

Awesome Doug! Thank you for splitting out the astcontext-everwhere  
part of the patch, it definitely makes it easier to review.

> +++ cfe/trunk/include/clang/AST/DeclContextInternals.h Thu Apr  9  
> 17:27:44 2009
>   /// VectorTy - When in vector form, this is what the Data pointer  
> points to.
> +  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;

Why the custom bitmangling?

> +  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)

Vec.empty() ?

> +++ cfe/trunk/include/clang/Frontend/PCHBitCodes.h Thu Apr  9  
> 17:27:44 2009
> @@ -0,0 +1,239 @@

>
> +#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;

IDBits is dead?

> +++ cfe/trunk/include/clang/Frontend/PCHWriter.h Thu Apr  9 17:27:44  
> 2009
>
> +  /// 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.

Please repeat or move this comment to the definition of the pch::ID  
typedef.

> +  /// \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.

Okay, maybe not.  Would it make sense to have two different typedefs  
for TypeID vs DeclID?  If that happened, you could have an appropriate  
comment for each.

> +++ cfe/trunk/lib/Frontend/PCHReader.cpp Thu Apr  9 17:27:44 2009

> +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++]);

This is a very cute idiom.  One potential problem to think about is  
that a malformed pch file could crash the reader by having a record  
with too-few fields: this would cause invalid indexes of Record to be  
used.
>
> +/// \brief Read the type-offsets block.
> +bool PCHReader::ReadTypeOffsets() {

Would it make sense to just make TYPE_OFFSETS be a record in the top- 
level block instead of a block that only contains one record type?   
Likewise with DECL_OFFSETS.  That would get rid of the boilerplate to  
read a block.

> +/// \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");

Instead of asserts, should these emit an error somehow and return  
something bogus?  Having an invalid PCH file crash the compiler is  
acceptable, but suboptimal.

> +    // FIXME: Several other kinds of types to deserialize here!
> +  default:
> +    assert("Unable to deserialize this type");

0 && "unable...

> +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

Interesting question: would it be better to unique attribute lists and  
output an attr ID # with each decl, or would it be better to emit a  
"has attr" bit and then emit a separate declid->attrlist datastructure  
independent of this?

> +/// \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);
> +  }

Why not just emit all types referred to by decls?  Is there a  
difference?

> +/// \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;

How about a new DC->decls_empty(Context) method?

> +++ 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;

Eww.  We should really just fix sema to not do this.  Can you add a  
verbose fixme explaining the issue and the fix we discussed?

Overall, this is great Doug!

-Chris



More information about the cfe-commits mailing list