-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[NFC] [Serializer] Pack information in serializer #69287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-modules Author: Chuanqi Xu (ChuanqiXu9) ChangesPreviously, 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. After the patch, the time becomes to 4.374s and the size becomes to 27568 bytes. 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. Patch is 45.79 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/69287.diff 5 Files Affected:
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 7f076cc77ea82cb..cd9a830dbaaf426 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -4073,7 +4073,7 @@ class RecordDecl : public TagDecl {
/// returned from function calls. This takes into account the target-specific
/// and version-specific rules along with the rules determined by the
/// language.
- enum ArgPassingKind : unsigned {
+ enum ArgPassingKind : unsigned char {
/// The argument of this type can be passed directly in registers.
APK_CanPassInRegs,
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index d383e46e22e16f4..7a30529f1f73d74 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -211,7 +211,7 @@ class alignas(8) Decl {
/// 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,
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 3a3477c39efae25..62b2665c2211029 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -617,24 +617,27 @@ void ASTDeclReader::VisitDecl(Decl *D) {
Reader.getContext());
}
D->setLocation(ThisDeclLoc);
- D->InvalidDecl = Record.readInt();
- if (Record.readInt()) { // hasAttrs
+
+ uint64_t DeclBits = Record.readInt();
+ D->InvalidDecl = DeclBits & 0x1;
+ D->setImplicit(DeclBits & (1 << 2));
+ D->Used = (DeclBits >> 3) & 0x1;
+ IsDeclMarkedUsed |= D->Used;
+ D->setReferenced(DeclBits & (1 << 4));
+ D->setTopLevelDeclInObjCContainer(DeclBits & (1 << 5));
+ D->setAccess((AccessSpecifier)((DeclBits >> 6) & 0x3));
+ D->FromASTFile = true;
+ auto ModuleOwnership = (Decl::ModuleOwnershipKind)((DeclBits >> 8) & 0x7);
+ bool ModulePrivate =
+ (ModuleOwnership == Decl::ModuleOwnershipKind::ModulePrivate);
+
+ if (DeclBits & (0x1 << 1)) { // 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 +753,14 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) {
VisitTypeDecl(TD);
TD->IdentifierNamespace = Record.readInt();
- TD->setTagKind((TagDecl::TagKind)Record.readInt());
+
+ uint32_t TagDeclBits = Record.readInt();
+ TD->setTagKind((TagDecl::TagKind)(TagDeclBits & 0x7));
if (!isa<CXXRecordDecl>(TD))
- TD->setCompleteDefinition(Record.readInt());
- TD->setEmbeddedInDeclarator(Record.readInt());
- TD->setFreeStanding(Record.readInt());
- TD->setCompleteDefinitionRequired(Record.readInt());
+ TD->setCompleteDefinition(TagDeclBits & (0x1 << 3));
+ TD->setEmbeddedInDeclarator(TagDeclBits & (0x1 << 4));
+ TD->setFreeStanding(TagDeclBits & (0x1 << 5));
+ TD->setCompleteDefinitionRequired(TagDeclBits & (0x1 << 6));
TD->setBraceRange(readSourceRange());
switch (Record.readInt()) {
@@ -787,11 +792,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());
+
+ uint32_t EnumDeclBits = Record.readInt();
+ ED->setNumPositiveBits(EnumDeclBits & 0xff);
+ ED->setNumNegativeBits((EnumDeclBits >> 8) & 0xff);
+ ED->setScoped(EnumDeclBits & (1 << 16));
+ ED->setScopedUsingClassTag(EnumDeclBits & (1 << 17));
+ ED->setFixed(EnumDeclBits & (1 << 18));
ED->setHasODRHash(true);
ED->ODRHash = Record.readInt();
@@ -834,18 +841,20 @@ 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((RecordDecl::ArgPassingKind)Record.readInt());
+
+ uint32_t RecordDeclBits = Record.readInt();
+ RD->setHasFlexibleArrayMember(RecordDeclBits & 0x1);
+ RD->setAnonymousStructOrUnion(RecordDeclBits & (1 << 1));
+ RD->setHasObjectMember(RecordDeclBits & (1 << 2));
+ RD->setHasVolatileMember(RecordDeclBits & (1 << 3));
+ RD->setNonTrivialToPrimitiveDefaultInitialize(RecordDeclBits & (1 << 4));
+ RD->setNonTrivialToPrimitiveCopy(RecordDeclBits & (1 << 5));
+ RD->setNonTrivialToPrimitiveDestroy(RecordDeclBits & (1 << 6));
+ RD->setHasNonTrivialToPrimitiveDefaultInitializeCUnion(RecordDeclBits & (1 << 7));
+ RD->setHasNonTrivialToPrimitiveDestructCUnion(RecordDeclBits & (1 << 8));
+ RD->setHasNonTrivialToPrimitiveCopyCUnion(RecordDeclBits & (1 << 9));
+ RD->setParamDestroyedInCallee(RecordDeclBits & (1 << 10));
+ RD->setArgPassingRestrictions((RecordDecl::ArgPassingKind)((RecordDeclBits >> 11) & 0x3));
return Redecl;
}
@@ -1046,32 +1055,33 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
// FunctionDecl's body is handled last at ASTDeclReader::Visit,
// after everything else is read.
+ uint64_t FunctionDeclBits = Record.readInt();
- FD->setStorageClass(static_cast<StorageClass>(Record.readInt()));
- FD->setInlineSpecified(Record.readInt());
- FD->setImplicitlyInline(Record.readInt());
- FD->setVirtualAsWritten(Record.readInt());
+ FD->setStorageClass(static_cast<StorageClass>(FunctionDeclBits & 0x7));
+ FD->setInlineSpecified(FunctionDeclBits & (1 << 3));
+ FD->setImplicitlyInline(FunctionDeclBits & (1 << 4));
+ FD->setVirtualAsWritten(FunctionDeclBits & (1 << 5));
// 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 & (1 << 6);
+ FD->setHasInheritedPrototype(FunctionDeclBits & (1 << 7));
+ FD->setHasWrittenPrototype(FunctionDeclBits & (1 << 8));
+ FD->setDeletedAsWritten(FunctionDeclBits & (1 << 9));
+ FD->setTrivial(FunctionDeclBits & (1 << 10));
+ FD->setTrivialForCall(FunctionDeclBits & (1 << 11));
+ FD->setDefaulted(FunctionDeclBits & (1 << 12));
+ FD->setExplicitlyDefaulted(FunctionDeclBits & (1 << 13));
+ FD->setIneligibleOrNotSelected(FunctionDeclBits & (1 << 14));
+ FD->setHasImplicitReturnZero(FunctionDeclBits & (1 << 15));
+ FD->setConstexprKind(static_cast<ConstexprSpecKind>((FunctionDeclBits >> 16) & 0x3));
+ FD->setUsesSEHTry(FunctionDeclBits & (1 << 18));
+ FD->setHasSkippedBody(FunctionDeclBits & (1 << 19));
+ FD->setIsMultiVersion(FunctionDeclBits & (1 << 20));
+ FD->setLateTemplateParsed(FunctionDeclBits & (1 << 21));
+ FD->setFriendConstraintRefersToEnclosingTemplate(FunctionDeclBits & (1 << 22));
+ FD->setCachedLinkage(static_cast<Linkage>((FunctionDeclBits >> 23) & 0x7));
+
FD->EndRangeLoc = readSourceLocation();
FD->setDefaultLoc(readSourceLocation());
@@ -1574,26 +1584,27 @@ 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();
+ uint32_t RecordDeclBits = Record.readInt();
+ VD->VarDeclBits.SClass = (StorageClass)(RecordDeclBits & 0x7);
+ VD->VarDeclBits.TSCSpec = (RecordDeclBits >> 3) & 0x3;
+ VD->VarDeclBits.InitStyle = (RecordDeclBits >> 5) & 0x3;
+ VD->VarDeclBits.ARCPseudoStrong = (bool)(RecordDeclBits & (1 << 7));
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();
+ (bool)(RecordDeclBits & (1 << 8));
+ VD->NonParmVarDeclBits.ExceptionVar = (bool)(RecordDeclBits & (1 << 9));
+ VD->NonParmVarDeclBits.NRVOVariable = (bool)(RecordDeclBits & (1 << 10));
+ VD->NonParmVarDeclBits.CXXForRangeDecl = (bool)(RecordDeclBits & (1 << 11));
+ VD->NonParmVarDeclBits.ObjCForDecl = (bool)(RecordDeclBits & (1 << 12));
+ VD->NonParmVarDeclBits.IsInline = (bool)(RecordDeclBits & (1 << 13));
+ VD->NonParmVarDeclBits.IsInlineSpecified = (bool)(RecordDeclBits & (1 << 14));
+ VD->NonParmVarDeclBits.IsConstexpr = (bool)(RecordDeclBits & (1 << 15));
+ VD->NonParmVarDeclBits.IsInitCapture = (bool)(RecordDeclBits & (1 << 16));
+ VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope = (bool)(RecordDeclBits & (1 << 17));
+ VD->NonParmVarDeclBits.ImplicitParamKind = (RecordDeclBits >> 18) & 0x7;
+ VD->NonParmVarDeclBits.EscapingByref = (bool)(RecordDeclBits & (1 << 21));
+ HasDeducedType = (bool)(RecordDeclBits & (1 << 22));
}
// If this variable has a deduced type, defer reading that type until we are
@@ -1605,7 +1616,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VD->setType(Reader.GetType(DeferredTypeID));
DeferredTypeID = 0;
- auto VarLinkage = Linkage(Record.readInt());
+ auto VarLinkage = Linkage((RecordDeclBits >> 23) & 0x7);
VD->setCachedLinkage(VarLinkage);
// Reconstruct the one piece of the IdentifierNamespace that we need.
@@ -1613,18 +1624,18 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VD->getLexicalDeclContext()->isFunctionOrMethod())
VD->setLocalExternDecl();
+ if (RecordDeclBits & (1 << 26)) {
+ 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
};
@@ -1678,9 +1689,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();
+
+ uint32_t ParmVarDeclBits = Record.readInt();
+ unsigned isObjCMethodParam = ParmVarDeclBits & 0x1;
+ unsigned scopeDepth = (ParmVarDeclBits >> 1) & 0x7f;
+ unsigned scopeIndex = (ParmVarDeclBits >> 8) & 0xff;
unsigned declQualifier = Record.readInt();
if (isObjCMethodParam) {
assert(scopeDepth == 0);
@@ -1689,9 +1702,9 @@ 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 = (bool)(ParmVarDeclBits & (1 << 16));
+ PD->ParmVarDeclBits.HasInheritedDefaultArg = (bool)(ParmVarDeclBits & (1 << 17));
+ if ((bool)(ParmVarDeclBits & (1 << 18))) // hasUninstantiatedDefaultArg.
PD->setUninstantiatedDefaultArg(Record.readExpr());
PD->ExplicitObjectParameterIntroducerLoc = Record.readSourceLocation();
@@ -1790,8 +1803,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());
+
+ uint32_t NamespaceDeclBits = Record.readInt();
+ D->setInline(NamespaceDeclBits & 0x1);
+ D->setNested(NamespaceDeclBits & 0x2);
D->LocStart = readSourceLocation();
D->RBraceLoc = readSourceLocation();
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 8a2ea7c7624ceb8..96cdfec14257c98 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -325,16 +325,22 @@ void ASTDeclWriter::VisitDecl(Decl *D) {
Record.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()));
else
Record.push_back(0);
- Record.push_back(D->isInvalidDecl());
- Record.push_back(D->hasAttrs());
+
+ uint64_t DeclBits = 0;
+ DeclBits = D->isInvalidDecl();
+ DeclBits |= D->hasAttrs() << 1;
+ DeclBits |= D->isImplicit() << 2;
+ DeclBits |= D->isUsed(false) << 3;
+ DeclBits |= D->isReferenced() << 4;
+ DeclBits |= D->isTopLevelDeclInObjCContainer() << 5;
+ assert(D->getAccess() < 4);
+ DeclBits |= D->getAccess() << 6;
+ DeclBits |= (uint64_t)D->getModuleOwnershipKind() << 8;
+ Record.push_back(DeclBits);
+
if (D->hasAttrs())
Record.AddAttributes(D->getAttrs());
- Record.push_back(D->isImplicit());
- Record.push_back(D->isUsed(false));
- Record.push_back(D->isReferenced());
- Record.push_back(D->isTopLevelDeclInObjCContainer());
- Record.push_back(D->getAccess());
- Record.push_back((uint64_t)D->getModuleOwnershipKind());
+
Record.push_back(Writer.getSubmoduleID(D->getOwningModule()));
// If this declaration injected a name into a context different from its
@@ -438,12 +444,17 @@ void ASTDeclWriter::VisitTagDecl(TagDecl *D) {
VisitRedeclarable(D);
VisitTypeDecl(D);
Record.push_back(D->getIdentifierNamespace());
- Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
+
+ uint32_t TagDeclBits = 0;
+ assert(D->getTagKind() < 8);
+ TagDeclBits = D->getTagKind();
if (!isa<CXXRecordDecl>(D))
- Record.push_back(D->isCompleteDefinition());
- Record.push_back(D->isEmbeddedInDeclarator());
- Record.push_back(D->isFreeStanding());
- Record.push_back(D->isCompleteDefinitionRequired());
+ TagDeclBits |= D->isCompleteDefinition() << 3;
+ TagDeclBits |= D->isEmbeddedInDeclarator() << 4;
+ TagDeclBits |= D->isFreeStanding() << 5;
+ TagDeclBits |= D->isCompleteDefinitionRequired() << 6;
+ Record.push_back(TagDeclBits);
+
Record.AddSourceRange(D->getBraceRange());
if (D->hasExtInfo()) {
@@ -468,11 +479,17 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
if (!D->getIntegerTypeSourceInfo())
Record.AddTypeRef(D->getIntegerType());
Record.AddTypeRef(D->getPromotionType());
- Record.push_back(D->getNumPositiveBits());
- Record.push_back(D->getNumNegativeBits());
- Record.push_back(D->isScoped());
- Record.push_back(D->isScopedUsingClassTag());
- Record.push_back(D->isFixed());
+
+ uint32_t EnumDeclBits = 0;
+ assert(D->getNumPositiveBits() < (2 << 8));
+ EnumDeclBits = D->getNumPositiveBits();
+ assert(D->getNumNegativeBits() < (2 << 8));
+ EnumDeclBits |= D->getNumNegativeBits() << 8;
+ EnumDeclBits |= D->isScoped() << 16;
+ EnumDeclBits |= D->isScopedUsingClassTag() << 17;
+ EnumDeclBits |= D->isFixed() << 18;
+ Record.push_back(EnumDeclBits);
+
Record.push_back(D->getODRHash());
if (MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo()) {
@@ -511,18 +528,23 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
"RecordDeclBits");
VisitTagDecl(D);
- Record.push_back(D->hasFlexibleArrayMember());
- Record.push_back(D->isAnonymousStructOrUnion());
- Record.push_back(D->hasObjectMember());
- Record.push_back(D->hasVolatileMember());
- Record.push_back(D->isNonTrivialToPrimitiveDefaultInitialize());
- Record.push_back(D->isNonTrivialToPrimitiveCopy());
- Record.push_back(D->isNonTrivialToPrimitiveDestroy());
- Record.push_back(D->hasNonTrivialToPrimitiveDefaultInitializeCUnion());
- Record.push_back(D->hasNonTrivialToPrimitiveDestructCUnion());
- Record.push_back(D->hasNonTrivialToPrimitiveCopyCUnion());
- Record.push_back(D->isParamDestroyedInCallee());
- Record.push_back(D->getArgPassingRestrictions());
+
+ uint32_t RecordDeclBits = 0;
+ RecordDeclBits = D->hasFlexibleArrayMember();
+ RecordDeclBits |= D->isAnonymousStructOrUnion() << 1;
+ RecordDeclBits |= D->hasObjectMember() << 2;
+ RecordDeclBits |= D->hasVolatileMember() << 3;
+ RecordDeclBits |= D->isNonTrivialToPrimitiveDefaultInitialize() << 4;
+ RecordDeclBits |= D->isNonTrivialToPrimitiveCopy() << 5;
+ RecordDeclBits |= D->isNonTrivialToPrimitiveDestroy() << 6;
+ RecordDeclBits |= D->hasNonTrivialToPrimitiveDefaultInitializeCUnion() << 7;
+ RecordDeclBits |= D->hasNonTrivialToPrimitiveDestructCUnion() << 8;
+ RecordDeclBits |= D->hasNonTrivialToPrimitiveCopyCUnion() << 9;
+ RecordDeclBits |= D->isParamDestroyedInCallee() << 10;
+ assert(D->getArgPassingRestrictions() < 4);
+ RecordDeclBits |= D->getArgPassingRestrictions() << 11;
+ Record.push_back(RecordDeclBits);
+
// Only compute this for C/Objective-C, in C++ this is computed as part
// of CXXRecordDecl.
if (!isa<CXXRecordDecl>(D))
@@ -662,28 +684,34 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
// FunctionDecl's body is handled last at ASTWriterDecl::Visit,
// after everything else is written.
- Record.push_back(
- static_cast<int>(D->getStorageClass())); // FIXME: stable encoding
- Record.push_back(D->isInlineSpecified());
- Record.push_back(D->isInlined());
- Record.pus...
[truncated]
|
d6a724d
to
326bc3a
Compare
You can test this locally with the following command:git-clang-format --diff 03110ddeb2c21d1b500e7f6f6e70134e269738bc c841e9cbd9510c401def4d10df6da408ae496180 -- clang/include/clang/AST/DeclBase.h clang/include/clang/Serialization/ASTReader.h clang/include/clang/Serialization/ASTWriter.h clang/lib/Serialization/ASTReaderDecl.cpp clang/lib/Serialization/ASTWriter.cpp clang/lib/Serialization/ASTWriterDecl.cpp View the diff from clang-format here.diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index a63911cb4adf..7934b349ec56 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1954,7 +1954,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
BitsUnpacker CXXRecordDeclBits = Record.readInt();
#define FIELD(Name, Width, Merge) \
- if (!CXXRecordDeclBits.canGetNextNBits(Width)) \
+ if (!CXXRecordDeclBits.canGetNextNBits(Width)) \
CXXRecordDeclBits.updateValue(Record.readInt()); \
Data.Name = CXXRecordDeclBits.getNextBits(Width);
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index b4438e4cf6a0..a1de204f9adf 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -536,7 +536,8 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
RecordDeclBits.addBit(D->hasNonTrivialToPrimitiveDestructCUnion());
RecordDeclBits.addBit(D->hasNonTrivialToPrimitiveCopyCUnion());
RecordDeclBits.addBit(D->isParamDestroyedInCallee());
- RecordDeclBits.addBits(llvm::to_underlying(D->getArgPassingRestrictions()), 2);
+ RecordDeclBits.addBits(llvm::to_underlying(D->getArgPassingRestrictions()),
+ 2);
Record.push_back(RecordDeclBits);
// Only compute this for C/Objective-C, in C++ this is computed as part
@@ -1090,7 +1091,8 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
VarDeclBits.addBit(HasDeducedType);
}
- VarDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()), /*BitWidth=*/3);
+ VarDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()),
+ /*BitWidth=*/3);
bool ModulesCodegen = false;
if (Writer.WritingModule && D->getStorageDuration() == SD_Static &&
@@ -2216,13 +2218,13 @@ void ASTWriter::WriteDeclAbbrevs() {
BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
12)); // Packed Var Decl bits: SClass, TSCSpec, InitStyle,
// isARCPseudoStrong, Linkage, ModulesCodegen
- Abv->Add(BitCodeAbbrevOp(0)); // VarKind (local enum)
+ Abv->Add(BitCodeAbbrevOp(0)); // VarKind (local enum)
// ParmVarDecl
Abv->Add(BitCodeAbbrevOp(
BitCodeAbbrevOp::Fixed,
19)); // Packed Parm Var Decl bits: IsObjCMethodParameter, ScopeDepth,
// ScopeIndex, KNRPromoted, HasInheritedDefaultArg
- Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier
+ Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier
Abv->Add(BitCodeAbbrevOp(0)); // HasUninstantiatedDefaultArg
// Type Source Info
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
326bc3a
to
5a1f32f
Compare
@zygoloid @vgvassilev ping~ Personally I feel like the change itself should be safe. (The test for modules is really sensitive about the changes in Serializer) |
uint64_t DeclBits = Record.readInt(); | ||
D->InvalidDecl = DeclBits & 0x1; | ||
D->setImplicit(DeclBits & (1 << 2)); | ||
D->Used = (DeclBits >> 3) & 0x1; | ||
IsDeclMarkedUsed |= D->Used; | ||
D->setReferenced(DeclBits & (1 << 4)); | ||
D->setTopLevelDeclInObjCContainer(DeclBits & (1 << 5)); | ||
D->setAccess((AccessSpecifier)((DeclBits >> 6) & 0x3)); | ||
D->FromASTFile = true; | ||
auto ModuleOwnership = (Decl::ModuleOwnershipKind)((DeclBits >> 8) & 0x7); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to improve the API avoiding these magic constants? I suspect this would be difficult to read and maintain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I had in mind is to introduce a BitPacker, but it can't avoid magic constants completely. e.g, we have to know that the width of AccessSpecifier
should be 2 and the width of ModuleOwnershipKind
should be 3.
Then we can refactor the above section to:
BitPacker Bits = Record.readInt();
D->InvalidDecl = Bits.getNextBit();
D->setImplicit(Bits.getNextBit());
D->Used = Bits.getNextBit();
IsDeclMarkedUsed |= D->Used;
D->setReferenced(Bits.getNextBit());
D->setTopLevelDeclInObjCContainer(Bits.getNextBit());
D->setAccess((AccessSpecifier)Bits.getNextBit</*width = */2>()); // Still we can't avoid the magic constants completely.
D->FromASTFile = true;
auto ModuleOwnership = (Decl::ModuleOwnershipKind)Bits.getNextBit</*width = */3>());
Would you be happy about the above form?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks more readable to me. In the case of ModuleOwnershipKind
can we use the bit size either with sizeof
or via NextInContextAndBits
? If we use sizeof
this could look like:
auto ModuleOwnership = Bits.getNextBit<Decl::ModuleOwnershipKind>());
but we will likely read/write 8 bits instead of 3 in this case...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes... and I feel the magic numbers for some types (e.g., AccessSpecifier
and ModuleOwnershipKind
) might not be so scaring. Since the devs can see AccessSpecifier
and ModuleOwnershipKind
here then they can get the size quickly. Also even if now we have to look at both ASTWriterDecl.cpp and ASTReaderDecl.cpp to change anything. I mean, it is already tightly bounded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
e99fc1a
to
ae4ee48
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks pretty good modulo the comments.
@zygoloid ping.
Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer | ||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier | ||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModuleOwnershipKind | ||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 11)); // Decl Bits |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These sections became a little harder to read. Perhaps we could keep the comments and this way the reader could probably do the math why this is 11 bits for example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // ModuleOwnershipKind | ||
Abv->Add(BitCodeAbbrevOp( | ||
BitCodeAbbrevOp::Fixed, | ||
11)); // Packed DeclBits: isInvalidDecl, HasAttrs, isImplicit, isUsed, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks odd at the first sight. But it is formatted by clang-format. And it looks not bad after looking into it.
I'd like to land this in the next week if no objection come in. Since this may be safe. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you!
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.
e43e89b
to
c841e9c
Compare
Thanks for reviewing : ) |
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.