[clang] [Clang] Cache DeclContext-to-Decl conversions (NFC) (PR #223042)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 11 13:02:34 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Mehdi Amini (joker-eph)
<details>
<summary>Changes</summary>
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
---
Full diff: https://github.com/llvm/llvm-project/pull/223042.diff
2 Files Affected:
- (modified) clang/include/clang/AST/DeclBase.h (+24-6)
- (modified) clang/lib/AST/DeclBase.cpp (+8-1)
``````````diff
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) {
``````````
</details>
https://github.com/llvm/llvm-project/pull/223042
More information about the cfe-commits
mailing list