Skip to content

Commit

Permalink
[NFC] [Serialization] Improve AST serialization by reordering packed
Browse files Browse the repository at this point in the history
bits and extract big bits from packed bits

Previously I tried to improve the size of .pcm files by introducing
packed bits. And I find we can improve it further by reordering the
bits.

The secret comes from the VBR format. We can find the formal definition
of VBR format in the doc of LLVM. The VBR format will be pretty
efficicent for small numbers.

For example, if we need to pack 8 bits into a value and the stored value
is 0xf0, the actual stored value will be 0b000111'110000, which takes 12
bits actually. However, if we changed the order to be 0x0f, then we
can store it as 0b001111, which takes 6 bits only now.

So we can improve the size by placing bits with lower probability to be
1 in the higher bits and extract bit bigs from the packed bits to make
it possible to be optimized by VBR.

After this patch, the size of std module becomes to 27.7MB from 28.1MB.
  • Loading branch information
ChuanqiXu9 committed Dec 21, 2023
1 parent 0df3200 commit 2203a4e
Show file tree
Hide file tree
Showing 4 changed files with 280 additions and 236 deletions.
50 changes: 26 additions & 24 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,18 @@ void ASTDeclReader::Visit(Decl *D) {

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

if (D->isTemplateParameter() || D->isTemplateParameterPack() ||
isa<ParmVarDecl, ObjCTypeParamDecl>(D)) {
Expand Down Expand Up @@ -623,20 +634,6 @@ void ASTDeclReader::VisitDecl(Decl *D) {
}
D->setLocation(ThisDeclLoc);

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);
Expand All @@ -647,8 +644,9 @@ void ASTDeclReader::VisitDecl(Decl *D) {

// Determine whether this declaration is part of a (sub)module. If so, it
// may not yet be visible.
bool ModulePrivate =
(ModuleOwnership == Decl::ModuleOwnershipKind::ModulePrivate);
if (unsigned SubmoduleID = readSubmoduleID()) {

switch (ModuleOwnership) {
case Decl::ModuleOwnershipKind::Visible:
ModuleOwnership = Decl::ModuleOwnershipKind::VisibleWhenImported;
Expand Down Expand Up @@ -1065,9 +1063,11 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
// after everything else is read.
BitsUnpacker FunctionDeclBits(Record.readInt());

FD->setCachedLinkage((Linkage)FunctionDeclBits.getNextBits(/*Width=*/3));
FD->setStorageClass((StorageClass)FunctionDeclBits.getNextBits(/*Width=*/3));
FD->setInlineSpecified(FunctionDeclBits.getNextBit());
FD->setImplicitlyInline(FunctionDeclBits.getNextBit());
FD->setHasSkippedBody(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
Expand All @@ -1081,16 +1081,14 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
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->setHasImplicitReturnZero(FunctionDeclBits.getNextBit());
FD->setIsMultiVersion(FunctionDeclBits.getNextBit());
FD->setLateTemplateParsed(FunctionDeclBits.getNextBit());
FD->setFriendConstraintRefersToEnclosingTemplate(
FunctionDeclBits.getNextBit());
FD->setCachedLinkage((Linkage)FunctionDeclBits.getNextBits(/*Width=*/3));
FD->setUsesSEHTry(FunctionDeclBits.getNextBit());

FD->EndRangeLoc = readSourceLocation();
if (FD->isExplicitlyDefaulted())
Expand Down Expand Up @@ -1597,6 +1595,8 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VisitDeclaratorDecl(VD);

BitsUnpacker VarDeclBits(Record.readInt());
auto VarLinkage = Linkage(VarDeclBits.getNextBits(/*Width=*/3));
bool DefGeneratedInModule = VarDeclBits.getNextBit();
VD->VarDeclBits.SClass = (StorageClass)VarDeclBits.getNextBits(/*Width=*/3);
VD->VarDeclBits.TSCSpec = VarDeclBits.getNextBits(/*Width=*/2);
VD->VarDeclBits.InitStyle = VarDeclBits.getNextBits(/*Width=*/2);
Expand All @@ -1608,17 +1608,20 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
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();
VD->NonParmVarDeclBits.ImplicitParamKind =
VarDeclBits.getNextBits(/*Width*/ 3);

VD->NonParmVarDeclBits.ObjCForDecl = VarDeclBits.getNextBit();
}

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

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

// Reconstruct the one piece of the IdentifierNamespace that we need.
if (VD->getStorageClass() == SC_Extern && VarLinkage != Linkage::None &&
VD->getLexicalDeclContext()->isFunctionOrMethod())
VD->setLocalExternDecl();

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

0 comments on commit 2203a4e

Please sign in to comment.