[clang] [Clang] Reduce the size of Decl and classes derived from it (PR #87361)

Nikolas Klauser via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 2 09:01:25 PDT 2024


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/87361

Class                             | Old size (in bytes) | New size (in bytes)
----------------------------------|---------------------|--------------------
Decl                              | 40                  | 32
AccessSpecDecl                    | 40                  | 40
BlockDecl                         | 128                 | 120
CapturedDecl                      | 88                  | 80
EmptyDecl                         | 40                  | 32
ExportDecl                        | 80                  | 72
ExternCContextDecl                | 72                  | 64
FileScopeAsmDecl                  | 56                  | 48
FriendDecl                        | 64                  | 56
FriendTemplateDecl                | 64                  | 64
ImplicitConceptSpecializationDecl | 40                  | 40
ImportDecl                        | 56                  | 48
LifetimeExtendedTemporaryDecl     | 72                  | 64
LinkageSpecDecl                   | 80                  | 72
NamedDecl                         | 48                  | 40
ObjCPropertyImplDecl              | 96                  | 88
PragmaCommentDecl                 | 40                  | 40
PragmaDetectMismatchDecl          | 48                  | 40
RequiresExprBodyDecl              | 72                  | 64
StaticAssertDecl                  | 64                  | 56
TopLevelStmtDecl                  | 88                  | 80
TranslationUnitDecl               | 104                 | 96
BaseUsingDecl                     | 56                  | 48
UsingDecl                         | 88                  | 80
UsingEnumDecl                     | 72                  | 64
HLSLBufferDecl                    | 96                  | 88
LabelDecl                         | 80                  | 72
NamespaceAliasDecl                | 96                  | 88
NamespaceDecl                     | 112                 | 104
ObjCCompatibleAliasDecl           | 56                  | 48
ObjCContainerDecl                 | 88                  | 80
ObjCMethodDecl                    | 136                 | 128
ObjCPropertyDecl                  | 128                 | 120
TemplateDecl                      | 64                  | 56
BuiltinTemplateDecl               | 72                  | 64
TypeDecl                          | 64                  | 56
UnresolvedUsingIfExistsDecl       | 48                  | 40
UsingDirectiveDecl                | 88                  | 80
UsingPackDecl                     | 64                  | 56
UsingShadowDecl                   | 80                  | 72
ValueDecl                         | 56                  | 48

When parsing libc++'s `<string>` header the used memory is reduced from 42.8MB to 42.5MB.



>From b8a626116b0719c1acf75e9e7300df8e2bf82f99 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 2 Apr 2024 18:00:05 +0200
Subject: [PATCH] [Clang] Reduce the size of Decl and classes derived from it

---
 clang/include/clang/AST/DeclBase.h        | 66 ++++++++++++++---------
 clang/lib/AST/DeclBase.cpp                | 29 ++++++----
 clang/lib/Serialization/ASTReaderDecl.cpp |  2 +-
 3 files changed, 62 insertions(+), 35 deletions(-)

diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 47ed6d0d1db0df..172bd581b527c8 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -268,17 +268,34 @@ class alignas(8) Decl {
   ///   }
   ///   void A::f(); // SemanticDC == namespace 'A'
   ///                // LexicalDC == global namespace
-  llvm::PointerUnion<DeclContext*, MultipleDC*> DeclCtx;
+  llvm::PointerIntPair<
+      llvm::PointerIntPair<llvm::PointerUnion<DeclContext *, MultipleDC *>, 1,
+                           bool>,
+      1, bool>
+      DeclCtxWithInvalidDeclAndHasAttrs;
 
-  bool isInSemaDC() const { return DeclCtx.is<DeclContext*>(); }
-  bool isOutOfSemaDC() const { return DeclCtx.is<MultipleDC*>(); }
+  bool isInSemaDC() const {
+    return DeclCtxWithInvalidDeclAndHasAttrs.getPointer()
+        .getPointer()
+        .is<DeclContext *>();
+  }
+
+  bool isOutOfSemaDC() const {
+    return DeclCtxWithInvalidDeclAndHasAttrs.getPointer()
+        .getPointer()
+        .is<MultipleDC *>();
+  }
 
   MultipleDC *getMultipleDC() const {
-    return DeclCtx.get<MultipleDC*>();
+    return DeclCtxWithInvalidDeclAndHasAttrs.getPointer()
+        .getPointer()
+        .get<MultipleDC *>();
   }
 
   DeclContext *getSemanticDC() const {
-    return DeclCtx.get<DeclContext*>();
+    return DeclCtxWithInvalidDeclAndHasAttrs.getPointer()
+        .getPointer()
+        .get<DeclContext *>();
   }
 
   /// Loc - The location of this decl.
@@ -288,14 +305,6 @@ class alignas(8) Decl {
   LLVM_PREFERRED_TYPE(Kind)
   unsigned DeclKind : 7;
 
-  /// InvalidDecl - This indicates a semantic error occurred.
-  LLVM_PREFERRED_TYPE(bool)
-  unsigned InvalidDecl :  1;
-
-  /// HasAttrs - This indicates whether the decl has attributes or not.
-  LLVM_PREFERRED_TYPE(bool)
-  unsigned HasAttrs : 1;
-
   /// Implicit - Whether this declaration was implicitly generated by
   /// the implementation rather than explicitly written by the user.
   LLVM_PREFERRED_TYPE(bool)
@@ -393,21 +402,22 @@ class alignas(8) Decl {
 protected:
   Decl(Kind DK, DeclContext *DC, SourceLocation L)
       : NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)),
-        DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(false), HasAttrs(false),
-        Implicit(false), Used(false), Referenced(false),
+        DeclCtxWithInvalidDeclAndHasAttrs({DC, false}, false), Loc(L),
+        DeclKind(DK), Implicit(false), Used(false), Referenced(false),
         TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
         IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
         CacheValidAndLinkage(llvm::to_underlying(Linkage::Invalid)) {
-    if (StatisticsEnabled) add(DK);
+    if (StatisticsEnabled)
+      add(DK);
   }
 
   Decl(Kind DK, EmptyShell Empty)
-      : DeclKind(DK), InvalidDecl(false), HasAttrs(false), Implicit(false),
-        Used(false), Referenced(false), TopLevelDeclInObjCContainer(false),
-        Access(AS_none), FromASTFile(0),
+      : DeclKind(DK), Implicit(false), Used(false), Referenced(false),
+        TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
         IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
         CacheValidAndLinkage(llvm::to_underlying(Linkage::Invalid)) {
-    if (StatisticsEnabled) add(DK);
+    if (StatisticsEnabled)
+      add(DK);
   }
 
   virtual ~Decl();
@@ -520,7 +530,7 @@ class alignas(8) Decl {
     return AccessSpecifier(Access);
   }
 
-  bool hasAttrs() const { return HasAttrs; }
+  bool hasAttrs() const { return DeclCtxWithInvalidDeclAndHasAttrs.getPointer().getInt(); }
 
   void setAttrs(const AttrVec& Attrs) {
     return setAttrsImpl(Attrs, getASTContext());
@@ -549,13 +559,16 @@ class alignas(8) Decl {
   }
 
   template <typename... Ts> void dropAttrs() {
-    if (!HasAttrs) return;
+    if (!hasAttrs()) return;
 
     AttrVec &Vec = getAttrs();
     llvm::erase_if(Vec, [](Attr *A) { return isa<Ts...>(A); });
 
-    if (Vec.empty())
-      HasAttrs = false;
+    if (Vec.empty()) {
+      auto InnerPtr = DeclCtxWithInvalidDeclAndHasAttrs.getPointer();
+      InnerPtr.setInt(false);
+      DeclCtxWithInvalidDeclAndHasAttrs.setPointer(InnerPtr);
+    }
   }
 
   template <typename T> void dropAttr() { dropAttrs<T>(); }
@@ -590,7 +603,10 @@ class alignas(8) Decl {
   /// setInvalidDecl - Indicates the Decl had a semantic error. This
   /// allows for graceful error recovery.
   void setInvalidDecl(bool Invalid = true);
-  bool isInvalidDecl() const { return (bool) InvalidDecl; }
+
+  bool isInvalidDecl() const {
+    return DeclCtxWithInvalidDeclAndHasAttrs.getInt();
+  }
 
   /// isImplicit - Indicates whether the declaration was implicitly
   /// generated by the implementation. If false, this declaration
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 04bbc49ab2f319..91e04f7a8a91be 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -130,7 +130,7 @@ const char *Decl::getDeclKindName() const {
 }
 
 void Decl::setInvalidDecl(bool Invalid) {
-  InvalidDecl = Invalid;
+  DeclCtxWithInvalidDeclAndHasAttrs.setInt(Invalid);
   assert(!isa<TagDecl>(this) || !cast<TagDecl>(this)->isCompleteDefinition());
   if (!Invalid) {
     return;
@@ -334,7 +334,9 @@ void PrettyStackTraceDecl::print(raw_ostream &OS) const {
 Decl::~Decl() = default;
 
 void Decl::setDeclContext(DeclContext *DC) {
-  DeclCtx = DC;
+  auto InnerPtr = DeclCtxWithInvalidDeclAndHasAttrs.getPointer();
+  InnerPtr.setPointer(DC);
+  DeclCtxWithInvalidDeclAndHasAttrs.setPointer(InnerPtr);
 }
 
 void Decl::setLexicalDeclContext(DeclContext *DC) {
@@ -364,12 +366,16 @@ void Decl::setLexicalDeclContext(DeclContext *DC) {
 void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
                                ASTContext &Ctx) {
   if (SemaDC == LexicalDC) {
-    DeclCtx = SemaDC;
+    auto InnerPtr = DeclCtxWithInvalidDeclAndHasAttrs.getPointer();
+    InnerPtr.setPointer(SemaDC);
+    DeclCtxWithInvalidDeclAndHasAttrs.setPointer(InnerPtr);
   } else {
     auto *MDC = new (Ctx) Decl::MultipleDC();
     MDC->SemanticDC = SemaDC;
     MDC->LexicalDC = LexicalDC;
-    DeclCtx = MDC;
+    auto InnerPtr = DeclCtxWithInvalidDeclAndHasAttrs.getPointer();
+    InnerPtr.setPointer(MDC);
+    DeclCtxWithInvalidDeclAndHasAttrs.setPointer(InnerPtr);
   }
 }
 
@@ -956,19 +962,24 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
 }
 
 void Decl::setAttrsImpl(const AttrVec &attrs, ASTContext &Ctx) {
-  assert(!HasAttrs && "Decl already contains attrs.");
+  assert(!hasAttrs() && "Decl already contains attrs.");
 
   AttrVec &AttrBlank = Ctx.getDeclAttrs(this);
   assert(AttrBlank.empty() && "HasAttrs was wrong?");
 
   AttrBlank = attrs;
-  HasAttrs = true;
+  auto InnerPtr = DeclCtxWithInvalidDeclAndHasAttrs.getPointer();
+  InnerPtr.setInt(true);
+  DeclCtxWithInvalidDeclAndHasAttrs.setPointer(InnerPtr);
 }
 
 void Decl::dropAttrs() {
-  if (!HasAttrs) return;
+  if (!hasAttrs())
+    return;
 
-  HasAttrs = false;
+  auto InnerPtr = DeclCtxWithInvalidDeclAndHasAttrs.getPointer();
+  InnerPtr.setInt(false);
+  DeclCtxWithInvalidDeclAndHasAttrs.setPointer(InnerPtr);
   getASTContext().eraseDeclAttrs(this);
 }
 
@@ -996,7 +1007,7 @@ void Decl::addAttr(Attr *A) {
 }
 
 const AttrVec &Decl::getAttrs() const {
-  assert(HasAttrs && "No attrs to get!");
+  assert(hasAttrs() && "No attrs to get!");
   return getASTContext().getDeclAttrs(this);
 }
 
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index a22f760408c634..2e186109327fb2 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -594,7 +594,7 @@ void ASTDeclReader::VisitDecl(Decl *D) {
   bool HasStandaloneLexicalDC = DeclBits.getNextBit();
   bool HasAttrs = DeclBits.getNextBit();
   D->setTopLevelDeclInObjCContainer(DeclBits.getNextBit());
-  D->InvalidDecl = DeclBits.getNextBit();
+  D->DeclCtxWithInvalidDeclAndHasAttrs.setInt(DeclBits.getNextBit());
   D->FromASTFile = true;
 
   if (D->isTemplateParameter() || D->isTemplateParameterPack() ||



More information about the cfe-commits mailing list