https://github.com/joker-eph created https://github.com/llvm/llvm-project/pull/223042
Cache the corresponding Decl pointer after the first DeclContext conversion and route parent traversal and generic casts through the cache. Use relaxed atomic access so concurrent read-only AST traversal remains race-free. CTMark O0 (3 samples): 29.439800 s -> 29.303500 s (-0.463%). Impact on significant TUs in MLIR build time: - `mlir/lib/RegisterAllDialects.cpp`: 2.5437% fewer retired instructions. - `mlir/lib/Dialect/LLVMIR/IR/NVVMDialect.cpp`: 1.3250% fewer retired instructions. Assisted-by: Codex >From 2a109893ce3f5970a9c618b8845eb4d158b3c6e6 Mon Sep 17 00:00:00 2001 From: Mehdi Amini <[email protected]> Date: Thu, 10 Sep 2026 05:32:04 -0700 Subject: [PATCH] Cache DeclContext-to-Decl conversions Cache the corresponding Decl pointer after the first DeclContext conversion and route parent traversal and generic casts through the cache. Use relaxed atomic access so concurrent read-only AST traversal remains race-free. CTMark O0 (3 samples, CPU 6): 29.439800 s -> 29.303500 s (-0.463%). Impact on significant TUs in MLIR build time: - `mlir/lib/RegisterAllDialects.cpp`: 2.5437% fewer retired instructions. - `mlir/lib/Dialect/LLVMIR/IR/NVVMDialect.cpp`: 1.3250% fewer retired instructions. Assisted-by: Codex --- clang/include/clang/AST/DeclBase.h | 30 ++++++++++++++++++++++++------ clang/lib/AST/DeclBase.cpp | 9 ++++++++- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 9d233be282dbb..8d0fcd76dd5ca 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -33,6 +33,7 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/VersionTuple.h" #include <algorithm> +#include <atomic> #include <cassert> #include <cstddef> #include <iterator> @@ -1464,6 +1465,8 @@ enum class LinkageSpecLanguageIDs; /// BlockDecl /// CapturedDecl class DeclContext { + friend class Decl; + /// For makeDeclVisibleInContextImpl friend class ASTDeclReader; /// For checking the new bits in the Serialization part. @@ -2101,6 +2104,12 @@ class DeclContext { /// another pointer. mutable Decl *LastDecl = nullptr; + /// The corresponding declaration, cached after the first conversion. + /// This correspondence is immutable. Relaxed atomics allow concurrent + /// read-only AST traversals to populate the cache without synchronizing + /// mutations to the AST itself. + mutable std::atomic<Decl *> CachedDecl = nullptr; + /// Build up a chain of declarations. /// /// \returns the first/last pair of declarations. @@ -2122,10 +2131,19 @@ class DeclContext { const char *getDeclKindName() const; - /// getParent - Returns the containing DeclContext. - DeclContext *getParent() { - return cast<Decl>(this)->getDeclContext(); + /// Return the declaration containing this context. + Decl *getAsDecl() { + if (Decl *Cached = CachedDecl.load(std::memory_order_relaxed)) + return Cached; + return Decl::castFromDeclContext(this); } + + const Decl *getAsDecl() const { + return const_cast<DeclContext *>(this)->getAsDecl(); + } + + /// getParent - Returns the containing DeclContext. + DeclContext *getParent() { return getAsDecl()->getDeclContext(); } const DeclContext *getParent() const { return const_cast<DeclContext*>(this)->getParent(); } @@ -2140,7 +2158,7 @@ class DeclContext { /// // getLexicalParent() == translation unit /// DeclContext *getLexicalParent() { - return cast<Decl>(this)->getLexicalDeclContext(); + return getAsDecl()->getLexicalDeclContext(); } const DeclContext *getLexicalParent() const { return const_cast<DeclContext*>(this)->getLexicalParent(); @@ -2830,11 +2848,11 @@ template <class ToTy, bool IsKnownSubtype = ::std::is_base_of<DeclContext, ToTy>::value> struct cast_convert_decl_context { static const ToTy *doit(const DeclContext *Val) { - return static_cast<const ToTy*>(Decl::castFromDeclContext(Val)); + return static_cast<const ToTy *>(Val->getAsDecl()); } static ToTy *doit(DeclContext *Val) { - return static_cast<ToTy*>(Decl::castFromDeclContext(Val)); + return static_cast<ToTy *>(Val->getAsDecl()); } }; diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 70f61fa57a682..e0903a19a8c5a 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1080,16 +1080,23 @@ const AttrVec &Decl::getAttrs() const { } Decl *Decl::castFromDeclContext (const DeclContext *D) { + if (Decl *Cached = D->CachedDecl.load(std::memory_order_relaxed)) + return Cached; + Decl::Kind DK = D->getDeclKind(); + Decl *Result = nullptr; switch (DK) { #define DECL(NAME, BASE) #define DECL_CONTEXT(NAME) \ case Decl::NAME: \ - return static_cast<NAME##Decl *>(const_cast<DeclContext *>(D)); + Result = static_cast<NAME##Decl *>(const_cast<DeclContext *>(D)); \ + break; #include "clang/AST/DeclNodes.inc" default: llvm_unreachable("a decl that inherits DeclContext isn't handled"); } + D->CachedDecl.store(Result, std::memory_order_relaxed); + return Result; } DeclContext *Decl::castToDeclContext(const Decl *D) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
