[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
Sun Apr 14 00:10:15 PDT 2024


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

>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 1/3] [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() ||

>From c17265390361c20230ce8ca22667e77068e3b2cb Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 8 Apr 2024 14:27:48 +0200
Subject: [PATCH 2/3] Address comments

---
 clang/include/clang/AST/DeclBase.h | 3 +++
 clang/lib/AST/DeclBase.cpp         | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 172bd581b527c8..9a3f8c41de387e 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -268,6 +268,9 @@ class alignas(8) Decl {
   ///   }
   ///   void A::f(); // SemanticDC == namespace 'A'
   ///                // LexicalDC == global namespace
+
+  // Compress the InvalidDecl and HasAttrs bits into DeclCtx to keep Decl below
+  // 32 bytes in size
   llvm::PointerIntPair<
       llvm::PointerIntPair<llvm::PointerUnion<DeclContext *, MultipleDC *>, 1,
                            bool>,
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 91e04f7a8a91be..c06b41d6b29f89 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -52,6 +52,8 @@
 
 using namespace clang;
 
+static_assert(sizeof(Decl) <= 32, "Decl grew beyond 32 bytes!");
+
 //===----------------------------------------------------------------------===//
 //  Statistics
 //===----------------------------------------------------------------------===//

>From 4c9ecd68ea7c2f550fd5168f07998fccd1cf3d42 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Fri, 12 Apr 2024 12:22:57 +0200
Subject: [PATCH 3/3] Fix formatting

---
 clang/include/clang/AST/DeclBase.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 9a3f8c41de387e..1fedba95d8ea3c 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -533,7 +533,9 @@ class alignas(8) Decl {
     return AccessSpecifier(Access);
   }
 
-  bool hasAttrs() const { return DeclCtxWithInvalidDeclAndHasAttrs.getPointer().getInt(); }
+  bool hasAttrs() const {
+    return DeclCtxWithInvalidDeclAndHasAttrs.getPointer().getInt();
+  }
 
   void setAttrs(const AttrVec& Attrs) {
     return setAttrsImpl(Attrs, getASTContext());
@@ -562,7 +564,8 @@ 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); });



More information about the cfe-commits mailing list