Unverified Commit 48be81e1 authored by Chuanqi Xu's avatar Chuanqi Xu Committed by GitHub
Browse files

[NFC] [Serializer] Pack information in serializer (#69287)

Previously, the boolean values will occupy spaces that can contain
integers. It wastes the spaces especially if the boolean values are
serialized consecutively. The patch tries to pack such consecutive
boolean values (and enum values) so that we can save more spaces and so
the times.

Before the patch, we need 4.478s (in my machine) to build the std module
(https://libcxx.llvm.org/Modules.html) with 28712 bytes for size of the
BMI. After the patch, the time becomes to 4.374s and the size becomes to
27388 bytes for the size of the BMI.

This is intended to be a NFC patch.

This patch doesn't optimize all such cases. We can do it later after we
have consensus on this.
parent 03110dde
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -211,7 +211,7 @@ public:
  /// The kind of ownership a declaration has, for visibility purposes.
  /// This enumeration is designed such that higher values represent higher
  /// levels of name hiding.
  enum class ModuleOwnershipKind : unsigned {
  enum class ModuleOwnershipKind : unsigned char {
    /// This declaration is not owned by a module.
    Unowned,

+47 −0
Original line number Diff line number Diff line
@@ -2407,6 +2407,53 @@ public:
  bool isProcessingUpdateRecords() { return ProcessingUpdateRecords; }
};

/// A simple helper class to unpack an integer to bits and consuming
/// the bits in order.
class BitsUnpacker {
  constexpr static uint32_t BitsIndexUpbound = 32;

public:
  BitsUnpacker(uint32_t V) { updateValue(V); }
  BitsUnpacker(const BitsUnpacker &) = delete;
  BitsUnpacker(BitsUnpacker &&) = delete;
  BitsUnpacker operator=(const BitsUnpacker &) = delete;
  BitsUnpacker operator=(BitsUnpacker &&) = delete;
  ~BitsUnpacker() {
#ifndef NDEBUG
    while (isValid())
      assert(!getNextBit() && "There are unprocessed bits!");
#endif
  }

  void updateValue(uint32_t V) {
    Value = V;
    CurrentBitsIndex = 0;
  }

  bool getNextBit() {
    assert(isValid());
    return Value & (1 << CurrentBitsIndex++);
  }

  uint32_t getNextBits(uint32_t Width) {
    assert(isValid());
    assert(Width < BitsIndexUpbound);
    uint32_t Ret = (Value >> CurrentBitsIndex) & ((1 << Width) - 1);
    CurrentBitsIndex += Width;
    return Ret;
  }

  bool canGetNextNBits(uint32_t Width) const {
    return CurrentBitsIndex + Width < BitsIndexUpbound;
  }

private:
  bool isValid() const { return CurrentBitsIndex < BitsIndexUpbound; }

  uint32_t Value;
  uint32_t CurrentBitsIndex = ~0;
};

} // namespace clang

#endif // LLVM_CLANG_SERIALIZATION_ASTREADER_H
+53 −0
Original line number Diff line number Diff line
@@ -830,6 +830,59 @@ public:
  bool hasEmittedPCH() const { return Buffer->IsComplete; }
};

/// A simple helper class to pack several bits in order into (a) 32 bit
/// integer(s).
class BitsPacker {
  constexpr static uint32_t BitIndexUpbound = 32u;

public:
  BitsPacker() = default;
  BitsPacker(const BitsPacker &) = delete;
  BitsPacker(BitsPacker &&) = delete;
  BitsPacker operator=(const BitsPacker &) = delete;
  BitsPacker operator=(BitsPacker &&) = delete;
  ~BitsPacker() {
    assert(!hasUnconsumedValues() && "There are unprocessed bits!");
  }

  void addBit(bool Value) { addBits(Value, 1); }
  void addBits(uint32_t Value, uint32_t BitsWidth) {
    assert(BitsWidth < BitIndexUpbound);
    assert((Value < (1u << BitsWidth)) && "Passing narrower bit width!");

    if (CurrentBitIndex + BitsWidth >= BitIndexUpbound) {
      Values.push_back(0);
      CurrentBitIndex = 0;
    }

    assert(CurrentBitIndex < BitIndexUpbound);
    Values.back() |= Value << CurrentBitIndex;
    CurrentBitIndex += BitsWidth;
  }

  bool hasUnconsumedValues() const {
    return ConsumingValueIndex < Values.size();
  }
  uint32_t getNextValue() {
    assert(hasUnconsumedValues());
    return Values[ConsumingValueIndex++];
  }

  // We can convert the packer to an uint32_t if there is only one values.
  operator uint32_t() {
    assert(Values.size() == 1);
    return getNextValue();
  }

private:
  SmallVector<uint64_t, 4> Values;
  uint16_t ConsumingValueIndex = 0;
  // Initialize CurrentBitIndex with an invalid value
  // to make it easier to update Values. See the implementation
  // of `addBits` to see the details.
  uint16_t CurrentBitIndex = BitIndexUpbound;
};

} // namespace clang

#endif // LLVM_CLANG_SERIALIZATION_ASTWRITER_H
+133 −97
Original line number Diff line number Diff line
@@ -617,24 +617,29 @@ void ASTDeclReader::VisitDecl(Decl *D) {
                           Reader.getContext());
  }
  D->setLocation(ThisDeclLoc);
  D->InvalidDecl = Record.readInt();
  if (Record.readInt()) { // hasAttrs

  BitsUnpacker DeclBits(Record.readInt());
  D->InvalidDecl = DeclBits.getNextBit();
  bool HasAttrs = DeclBits.getNextBit();
  D->setImplicit(DeclBits.getNextBit());
  D->Used = DeclBits.getNextBit();
  IsDeclMarkedUsed |= D->Used;
  D->setReferenced(DeclBits.getNextBit());
  D->setTopLevelDeclInObjCContainer(DeclBits.getNextBit());
  D->setAccess((AccessSpecifier)DeclBits.getNextBits(/*Width=*/2));
  D->FromASTFile = true;
  auto ModuleOwnership =
      (Decl::ModuleOwnershipKind)DeclBits.getNextBits(/*Width=*/3);
  bool ModulePrivate =
      (ModuleOwnership == Decl::ModuleOwnershipKind::ModulePrivate);

  if (HasAttrs) {
    AttrVec Attrs;
    Record.readAttributes(Attrs);
    // Avoid calling setAttrs() directly because it uses Decl::getASTContext()
    // internally which is unsafe during derialization.
    D->setAttrsImpl(Attrs, Reader.getContext());
  }
  D->setImplicit(Record.readInt());
  D->Used = Record.readInt();
  IsDeclMarkedUsed |= D->Used;
  D->setReferenced(Record.readInt());
  D->setTopLevelDeclInObjCContainer(Record.readInt());
  D->setAccess((AccessSpecifier)Record.readInt());
  D->FromASTFile = true;
  auto ModuleOwnership = (Decl::ModuleOwnershipKind)Record.readInt();
  bool ModulePrivate =
      (ModuleOwnership == Decl::ModuleOwnershipKind::ModulePrivate);

  // Determine whether this declaration is part of a (sub)module. If so, it
  // may not yet be visible.
@@ -750,12 +755,13 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) {
  VisitTypeDecl(TD);

  TD->IdentifierNamespace = Record.readInt();
  TD->setTagKind((TagDecl::TagKind)Record.readInt());
  if (!isa<CXXRecordDecl>(TD))
    TD->setCompleteDefinition(Record.readInt());
  TD->setEmbeddedInDeclarator(Record.readInt());
  TD->setFreeStanding(Record.readInt());
  TD->setCompleteDefinitionRequired(Record.readInt());

  BitsUnpacker TagDeclBits(Record.readInt());
  TD->setTagKind((TagDecl::TagKind)TagDeclBits.getNextBits(/*Width=*/3));
  TD->setCompleteDefinition(TagDeclBits.getNextBit());
  TD->setEmbeddedInDeclarator(TagDeclBits.getNextBit());
  TD->setFreeStanding(TagDeclBits.getNextBit());
  TD->setCompleteDefinitionRequired(TagDeclBits.getNextBit());
  TD->setBraceRange(readSourceRange());

  switch (Record.readInt()) {
@@ -787,11 +793,13 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
  else
    ED->setIntegerType(Record.readType());
  ED->setPromotionType(Record.readType());
  ED->setNumPositiveBits(Record.readInt());
  ED->setNumNegativeBits(Record.readInt());
  ED->setScoped(Record.readInt());
  ED->setScopedUsingClassTag(Record.readInt());
  ED->setFixed(Record.readInt());

  BitsUnpacker EnumDeclBits(Record.readInt());
  ED->setNumPositiveBits(EnumDeclBits.getNextBits(/*Width=*/8));
  ED->setNumNegativeBits(EnumDeclBits.getNextBits(/*Width=*/8));
  ED->setScoped(EnumDeclBits.getNextBit());
  ED->setScopedUsingClassTag(EnumDeclBits.getNextBit());
  ED->setFixed(EnumDeclBits.getNextBit());

  ED->setHasODRHash(true);
  ED->ODRHash = Record.readInt();
@@ -834,18 +842,22 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
ASTDeclReader::RedeclarableResult
ASTDeclReader::VisitRecordDeclImpl(RecordDecl *RD) {
  RedeclarableResult Redecl = VisitTagDecl(RD);
  RD->setHasFlexibleArrayMember(Record.readInt());
  RD->setAnonymousStructOrUnion(Record.readInt());
  RD->setHasObjectMember(Record.readInt());
  RD->setHasVolatileMember(Record.readInt());
  RD->setNonTrivialToPrimitiveDefaultInitialize(Record.readInt());
  RD->setNonTrivialToPrimitiveCopy(Record.readInt());
  RD->setNonTrivialToPrimitiveDestroy(Record.readInt());
  RD->setHasNonTrivialToPrimitiveDefaultInitializeCUnion(Record.readInt());
  RD->setHasNonTrivialToPrimitiveDestructCUnion(Record.readInt());
  RD->setHasNonTrivialToPrimitiveCopyCUnion(Record.readInt());
  RD->setParamDestroyedInCallee(Record.readInt());
  RD->setArgPassingRestrictions((RecordArgPassingKind)Record.readInt());

  BitsUnpacker RecordDeclBits(Record.readInt());
  RD->setHasFlexibleArrayMember(RecordDeclBits.getNextBit());
  RD->setAnonymousStructOrUnion(RecordDeclBits.getNextBit());
  RD->setHasObjectMember(RecordDeclBits.getNextBit());
  RD->setHasVolatileMember(RecordDeclBits.getNextBit());
  RD->setNonTrivialToPrimitiveDefaultInitialize(RecordDeclBits.getNextBit());
  RD->setNonTrivialToPrimitiveCopy(RecordDeclBits.getNextBit());
  RD->setNonTrivialToPrimitiveDestroy(RecordDeclBits.getNextBit());
  RD->setHasNonTrivialToPrimitiveDefaultInitializeCUnion(
      RecordDeclBits.getNextBit());
  RD->setHasNonTrivialToPrimitiveDestructCUnion(RecordDeclBits.getNextBit());
  RD->setHasNonTrivialToPrimitiveCopyCUnion(RecordDeclBits.getNextBit());
  RD->setParamDestroyedInCallee(RecordDeclBits.getNextBit());
  RD->setArgPassingRestrictions(
      (RecordArgPassingKind)RecordDeclBits.getNextBits(/*Width=*/2));
  return Redecl;
}

@@ -1046,32 +1058,35 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {

  // FunctionDecl's body is handled last at ASTDeclReader::Visit,
  // after everything else is read.
  BitsUnpacker FunctionDeclBits(Record.readInt());

  FD->setStorageClass(static_cast<StorageClass>(Record.readInt()));
  FD->setInlineSpecified(Record.readInt());
  FD->setImplicitlyInline(Record.readInt());
  FD->setVirtualAsWritten(Record.readInt());
  FD->setStorageClass((StorageClass)FunctionDeclBits.getNextBits(/*Width=*/3));
  FD->setInlineSpecified(FunctionDeclBits.getNextBit());
  FD->setImplicitlyInline(FunctionDeclBits.getNextBit());
  FD->setVirtualAsWritten(FunctionDeclBits.getNextBit());
  // We defer calling `FunctionDecl::setPure()` here as for methods of
  // `CXXTemplateSpecializationDecl`s, we may not have connected up the
  // definition (which is required for `setPure`).
  const bool Pure = Record.readInt();
  FD->setHasInheritedPrototype(Record.readInt());
  FD->setHasWrittenPrototype(Record.readInt());
  FD->setDeletedAsWritten(Record.readInt());
  FD->setTrivial(Record.readInt());
  FD->setTrivialForCall(Record.readInt());
  FD->setDefaulted(Record.readInt());
  FD->setExplicitlyDefaulted(Record.readInt());
  FD->setIneligibleOrNotSelected(Record.readInt());
  FD->setHasImplicitReturnZero(Record.readInt());
  FD->setConstexprKind(static_cast<ConstexprSpecKind>(Record.readInt()));
  FD->setUsesSEHTry(Record.readInt());
  FD->setHasSkippedBody(Record.readInt());
  FD->setIsMultiVersion(Record.readInt());
  FD->setLateTemplateParsed(Record.readInt());
  FD->setFriendConstraintRefersToEnclosingTemplate(Record.readInt());

  FD->setCachedLinkage(static_cast<Linkage>(Record.readInt()));
  const bool Pure = FunctionDeclBits.getNextBit();
  FD->setHasInheritedPrototype(FunctionDeclBits.getNextBit());
  FD->setHasWrittenPrototype(FunctionDeclBits.getNextBit());
  FD->setDeletedAsWritten(FunctionDeclBits.getNextBit());
  FD->setTrivial(FunctionDeclBits.getNextBit());
  FD->setTrivialForCall(FunctionDeclBits.getNextBit());
  FD->setDefaulted(FunctionDeclBits.getNextBit());
  FD->setExplicitlyDefaulted(FunctionDeclBits.getNextBit());
  FD->setIneligibleOrNotSelected(FunctionDeclBits.getNextBit());
  FD->setHasImplicitReturnZero(FunctionDeclBits.getNextBit());
  FD->setConstexprKind(
      (ConstexprSpecKind)FunctionDeclBits.getNextBits(/*Width=*/2));
  FD->setUsesSEHTry(FunctionDeclBits.getNextBit());
  FD->setHasSkippedBody(FunctionDeclBits.getNextBit());
  FD->setIsMultiVersion(FunctionDeclBits.getNextBit());
  FD->setLateTemplateParsed(FunctionDeclBits.getNextBit());
  FD->setFriendConstraintRefersToEnclosingTemplate(
      FunctionDeclBits.getNextBit());
  FD->setCachedLinkage((Linkage)FunctionDeclBits.getNextBits(/*Width=*/3));

  FD->EndRangeLoc = readSourceLocation();
  FD->setDefaultLoc(readSourceLocation());

@@ -1575,26 +1590,29 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
  RedeclarableResult Redecl = VisitRedeclarable(VD);
  VisitDeclaratorDecl(VD);

  VD->VarDeclBits.SClass = (StorageClass)Record.readInt();
  VD->VarDeclBits.TSCSpec = Record.readInt();
  VD->VarDeclBits.InitStyle = Record.readInt();
  VD->VarDeclBits.ARCPseudoStrong = Record.readInt();
  BitsUnpacker VarDeclBits(Record.readInt());
  VD->VarDeclBits.SClass = (StorageClass)VarDeclBits.getNextBits(/*Width=*/3);
  VD->VarDeclBits.TSCSpec = VarDeclBits.getNextBits(/*Width=*/2);
  VD->VarDeclBits.InitStyle = VarDeclBits.getNextBits(/*Width=*/2);
  VD->VarDeclBits.ARCPseudoStrong = VarDeclBits.getNextBit();
  bool HasDeducedType = false;
  if (!isa<ParmVarDecl>(VD)) {
    VD->NonParmVarDeclBits.IsThisDeclarationADemotedDefinition =
        Record.readInt();
    VD->NonParmVarDeclBits.ExceptionVar = Record.readInt();
    VD->NonParmVarDeclBits.NRVOVariable = Record.readInt();
    VD->NonParmVarDeclBits.CXXForRangeDecl = Record.readInt();
    VD->NonParmVarDeclBits.ObjCForDecl = Record.readInt();
    VD->NonParmVarDeclBits.IsInline = Record.readInt();
    VD->NonParmVarDeclBits.IsInlineSpecified = Record.readInt();
    VD->NonParmVarDeclBits.IsConstexpr = Record.readInt();
    VD->NonParmVarDeclBits.IsInitCapture = Record.readInt();
    VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope = Record.readInt();
    VD->NonParmVarDeclBits.ImplicitParamKind = Record.readInt();
    VD->NonParmVarDeclBits.EscapingByref = Record.readInt();
    HasDeducedType = Record.readInt();
        VarDeclBits.getNextBit();
    VD->NonParmVarDeclBits.ExceptionVar = VarDeclBits.getNextBit();
    VD->NonParmVarDeclBits.NRVOVariable = VarDeclBits.getNextBit();
    VD->NonParmVarDeclBits.CXXForRangeDecl = VarDeclBits.getNextBit();
    VD->NonParmVarDeclBits.ObjCForDecl = VarDeclBits.getNextBit();
    VD->NonParmVarDeclBits.IsInline = VarDeclBits.getNextBit();
    VD->NonParmVarDeclBits.IsInlineSpecified = VarDeclBits.getNextBit();
    VD->NonParmVarDeclBits.IsConstexpr = VarDeclBits.getNextBit();
    VD->NonParmVarDeclBits.IsInitCapture = VarDeclBits.getNextBit();
    VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope =
        VarDeclBits.getNextBit();
    VD->NonParmVarDeclBits.ImplicitParamKind =
        VarDeclBits.getNextBits(/*Width*/ 3);
    VD->NonParmVarDeclBits.EscapingByref = VarDeclBits.getNextBit();
    HasDeducedType = VarDeclBits.getNextBit();
  }

  // If this variable has a deduced type, defer reading that type until we are
@@ -1606,7 +1624,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
    VD->setType(Reader.GetType(DeferredTypeID));
  DeferredTypeID = 0;

  auto VarLinkage = static_cast<Linkage>(Record.readInt());
  auto VarLinkage = Linkage(VarDeclBits.getNextBits(/*Width=*/3));
  VD->setCachedLinkage(VarLinkage);

  // Reconstruct the one piece of the IdentifierNamespace that we need.
@@ -1614,18 +1632,18 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
      VD->getLexicalDeclContext()->isFunctionOrMethod())
    VD->setLocalExternDecl();

  if (VarDeclBits.getNextBit()) {
    Reader.DefinitionSource[VD] =
        Loc.F->Kind == ModuleKind::MK_MainFile ||
        Reader.getContext().getLangOpts().BuildingPCHWithObjectFile;
  }

  if (VD->hasAttr<BlocksAttr>()) {
    Expr *CopyExpr = Record.readExpr();
    if (CopyExpr)
      Reader.getContext().setBlockVarCopyInit(VD, CopyExpr, Record.readInt());
  }

  if (Record.readInt()) {
    Reader.DefinitionSource[VD] =
        Loc.F->Kind == ModuleKind::MK_MainFile ||
        Reader.getContext().getLangOpts().BuildingPCHWithObjectFile;
  }

  enum VarKind {
    VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization
  };
@@ -1679,9 +1697,11 @@ void ASTDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {

void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
  VisitVarDecl(PD);
  unsigned isObjCMethodParam = Record.readInt();
  unsigned scopeDepth = Record.readInt();
  unsigned scopeIndex = Record.readInt();

  BitsUnpacker ParmVarDeclBits(Record.readInt());
  unsigned isObjCMethodParam = ParmVarDeclBits.getNextBit();
  unsigned scopeDepth = ParmVarDeclBits.getNextBits(/*Width=*/7);
  unsigned scopeIndex = ParmVarDeclBits.getNextBits(/*Width=*/8);
  unsigned declQualifier = Record.readInt();
  if (isObjCMethodParam) {
    assert(scopeDepth == 0);
@@ -1690,9 +1710,10 @@ void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
  } else {
    PD->setScopeInfo(scopeDepth, scopeIndex);
  }
  PD->ParmVarDeclBits.IsKNRPromoted = Record.readInt();
  PD->ParmVarDeclBits.HasInheritedDefaultArg = Record.readInt();
  if (Record.readInt()) // hasUninstantiatedDefaultArg.
  PD->ParmVarDeclBits.IsKNRPromoted = ParmVarDeclBits.getNextBit();

  PD->ParmVarDeclBits.HasInheritedDefaultArg = ParmVarDeclBits.getNextBit();
  if (ParmVarDeclBits.getNextBit()) // hasUninstantiatedDefaultArg.
    PD->setUninstantiatedDefaultArg(Record.readExpr());
  PD->ExplicitObjectParameterIntroducerLoc = Record.readSourceLocation();

@@ -1791,8 +1812,10 @@ void ASTDeclReader::VisitLabelDecl(LabelDecl *D) {
void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
  RedeclarableResult Redecl = VisitRedeclarable(D);
  VisitNamedDecl(D);
  D->setInline(Record.readInt());
  D->setNested(Record.readInt());

  BitsUnpacker NamespaceDeclBits(Record.readInt());
  D->setInline(NamespaceDeclBits.getNextBit());
  D->setNested(NamespaceDeclBits.getNextBit());
  D->LocStart = readSourceLocation();
  D->RBraceLoc = readSourceLocation();

@@ -1927,8 +1950,16 @@ void ASTDeclReader::VisitUnresolvedUsingIfExistsDecl(
void ASTDeclReader::ReadCXXDefinitionData(
    struct CXXRecordDecl::DefinitionData &Data, const CXXRecordDecl *D,
    Decl *LambdaContext, unsigned IndexInLambdaContext) {
#define FIELD(Name, Width, Merge) Data.Name = Record.readInt();

  BitsUnpacker CXXRecordDeclBits = Record.readInt();

#define FIELD(Name, Width, Merge)                                              \
  if (!CXXRecordDeclBits.canGetNextNBits(Width))                         \
    CXXRecordDeclBits.updateValue(Record.readInt());                           \
  Data.Name = CXXRecordDeclBits.getNextBits(Width);

#include "clang/AST/CXXRecordDeclDefinitionBits.def"
#undef FIELD

  // Note: the caller has deserialized the IsLambda bit already.
  Data.ODRHash = Record.readInt();
@@ -1963,12 +1994,15 @@ void ASTDeclReader::ReadCXXDefinitionData(
    using Capture = LambdaCapture;

    auto &Lambda = static_cast<CXXRecordDecl::LambdaDefinitionData &>(Data);
    Lambda.DependencyKind = Record.readInt();
    Lambda.IsGenericLambda = Record.readInt();
    Lambda.CaptureDefault = Record.readInt();
    Lambda.NumCaptures = Record.readInt();

    BitsUnpacker LambdaBits(Record.readInt());
    Lambda.DependencyKind = LambdaBits.getNextBits(/*Width=*/2);
    Lambda.IsGenericLambda = LambdaBits.getNextBit();
    Lambda.CaptureDefault = LambdaBits.getNextBits(/*Width=*/2);
    Lambda.NumCaptures = LambdaBits.getNextBits(/*Width=*/15);
    Lambda.HasKnownInternalLinkage = LambdaBits.getNextBit();

    Lambda.NumExplicitCaptures = Record.readInt();
    Lambda.HasKnownInternalLinkage = Record.readInt();
    Lambda.ManglingNumber = Record.readInt();
    if (unsigned DeviceManglingNumber = Record.readInt())
      Reader.getContext().DeviceLambdaManglingNumbers[D] = DeviceManglingNumber;
@@ -1983,8 +2017,10 @@ void ASTDeclReader::ReadCXXDefinitionData(
    Lambda.MethodTyInfo = readTypeSourceInfo();
    for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
      SourceLocation Loc = readSourceLocation();
      bool IsImplicit = Record.readInt();
      auto Kind = static_cast<LambdaCaptureKind>(Record.readInt());
      BitsUnpacker CaptureBits(Record.readInt());
      bool IsImplicit = CaptureBits.getNextBit();
      auto Kind =
          static_cast<LambdaCaptureKind>(CaptureBits.getNextBits(/*Width=*/3));
      switch (Kind) {
      case LCK_StarThis:
      case LCK_This:
+22 −10
Original line number Diff line number Diff line
@@ -5996,11 +5996,17 @@ void ASTRecordWriter::AddCXXCtorInitializers(

void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
  auto &Data = D->data();

  Record->push_back(Data.IsLambda);

  #define FIELD(Name, Width, Merge) \
  Record->push_back(Data.Name);
  BitsPacker DefinitionBits;

#define FIELD(Name, Width, Merge) DefinitionBits.addBits(Data.Name, Width);
#include "clang/AST/CXXRecordDeclDefinitionBits.def"
#undef FIELD

  while (DefinitionBits.hasUnconsumedValues())
    Record->push_back(DefinitionBits.getNextValue());

  // getODRHash will compute the ODRHash if it has not been previously computed.
  Record->push_back(D->getODRHash());
@@ -6032,12 +6038,16 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
    AddDeclRef(D->getFirstFriend());
  } else {
    auto &Lambda = D->getLambdaData();
    Record->push_back(Lambda.DependencyKind);
    Record->push_back(Lambda.IsGenericLambda);
    Record->push_back(Lambda.CaptureDefault);
    Record->push_back(Lambda.NumCaptures);

    BitsPacker LambdaBits;
    LambdaBits.addBits(Lambda.DependencyKind, /*Width=*/2);
    LambdaBits.addBit(Lambda.IsGenericLambda);
    LambdaBits.addBits(Lambda.CaptureDefault, /*Width=*/2);
    LambdaBits.addBits(Lambda.NumCaptures, /*Width=*/15);
    LambdaBits.addBit(Lambda.HasKnownInternalLinkage);
    Record->push_back(LambdaBits.getNextValue());

    Record->push_back(Lambda.NumExplicitCaptures);
    Record->push_back(Lambda.HasKnownInternalLinkage);
    Record->push_back(Lambda.ManglingNumber);
    Record->push_back(D->getDeviceLambdaManglingNumber());
    // The lambda context declaration and index within the context are provided
@@ -6046,8 +6056,10 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
    for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
      const LambdaCapture &Capture = Lambda.Captures.front()[I];
      AddSourceLocation(Capture.getLocation());
      Record->push_back(Capture.isImplicit());
      Record->push_back(Capture.getCaptureKind());
      BitsPacker CaptureBits;
      CaptureBits.addBit(Capture.isImplicit());
      CaptureBits.addBits(Capture.getCaptureKind(), /*Width=*/3);
      Record->push_back(CaptureBits);
      switch (Capture.getCaptureKind()) {
      case LCK_StarThis:
      case LCK_This:
Loading