[llvm] [IR] Move the LLVMContext out of ReplaceableMetadataImpl. NFC (PR #222085)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 10:53:02 PDT 2026


https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/222085

No ReplaceableMetadataImpl method reads its LLVMContext reference, and
ValueAsMetadata reaches the context through the wrapped Value. Keep the
reference in a derived ReplaceableMetadataImplWithContext, used by the
two owners with no other route to it: MDNode's on-demand RAUW support
and DIArgList.

sizeof(ValueAsMetadata) 152 -> 144.


>From ca197e43d8cbfc49608956bbd13e646b1a87746d Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Tue, 8 Sep 2026 10:41:54 -0700
Subject: [PATCH] [IR] Move the LLVMContext out of ReplaceableMetadataImpl. NFC

No ReplaceableMetadataImpl method reads its LLVMContext reference, and
ValueAsMetadata reaches the context through the wrapped Value. Keep the
reference in a derived ReplaceableMetadataImplWithContext, used by the
two owners with no other route to it: MDNode's on-demand RAUW support
and DIArgList.

sizeof(ValueAsMetadata) 152 -> 144.
---
 llvm/include/llvm/IR/DebugInfoMetadata.h |  6 +--
 llvm/include/llvm/IR/Metadata.h          | 47 ++++++++++++++----------
 llvm/unittests/IR/MetadataTest.cpp       |  9 +++--
 3 files changed, 36 insertions(+), 26 deletions(-)

diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index e75dc8eb60b80..86c72213a5938 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -4977,7 +4977,7 @@ class DIMacroFile : public DIMacroNode {
 
 /// List of ValueAsMetadata, to be used as an argument to a dbg.value
 /// intrinsic.
-class DIArgList : public Metadata, ReplaceableMetadataImpl {
+class DIArgList : public Metadata, ReplaceableMetadataImplWithContext {
   friend class ReplaceableMetadataImpl;
   friend class LLVMContextImpl;
   using iterator = SmallVectorImpl<ValueAsMetadata *>::iterator;
@@ -4985,8 +4985,8 @@ class DIArgList : public Metadata, ReplaceableMetadataImpl {
   SmallVector<ValueAsMetadata *, 4> Args;
 
   DIArgList(LLVMContext &Context, ArrayRef<ValueAsMetadata *> Args)
-      : Metadata(DIArgListKind, Uniqued), ReplaceableMetadataImpl(Context),
-        Args(Args) {
+      : Metadata(DIArgListKind, Uniqued),
+        ReplaceableMetadataImplWithContext(Context), Args(Args) {
     track();
   }
   ~DIArgList() { untrack(); }
diff --git a/llvm/include/llvm/IR/Metadata.h b/llvm/include/llvm/IR/Metadata.h
index a53cb63ed59cf..7c4cc00396cfe 100644
--- a/llvm/include/llvm/IR/Metadata.h
+++ b/llvm/include/llvm/IR/Metadata.h
@@ -395,19 +395,15 @@ class ReplaceableMetadataImpl {
   using OwnerTy = MetadataTracking::OwnerTy;
 
 private:
-  LLVMContext &Context;
   uint64_t NextIndex = 0;
   SmallDenseMap<void *, std::pair<OwnerTy, uint64_t>, 4> UseMap;
 
-public:
-  ReplaceableMetadataImpl(LLVMContext &Context) : Context(Context) {}
-
+protected:
   ~ReplaceableMetadataImpl() {
     assert(UseMap.empty() && "Cannot destroy in-use replaceable metadata");
   }
 
-  LLVMContext &getContext() const { return Context; }
-
+public:
   /// Replace all uses of this with MD.
   ///
   /// Replace all uses of this with \c MD, which is allowed to be null.
@@ -448,6 +444,17 @@ class ReplaceableMetadataImpl {
   static bool isReplaceable(const Metadata &MD);
 };
 
+/// Replaceable metadata that remembers its \a LLVMContext, for owners with no
+/// other route to it. \a ValueAsMetadata goes through the wrapped \a Value.
+class ReplaceableMetadataImplWithContext : public ReplaceableMetadataImpl {
+  LLVMContext &Context;
+
+public:
+  ReplaceableMetadataImplWithContext(LLVMContext &Context) : Context(Context) {}
+
+  LLVMContext &getContext() const { return Context; }
+};
+
 /// Value wrapper in the Metadata hierarchy.
 ///
 /// This is a custom value handle that allows other metadata to refer to
@@ -468,8 +475,7 @@ class ValueAsMetadata : public Metadata, ReplaceableMetadataImpl {
   }
 
 protected:
-  ValueAsMetadata(unsigned ID, Value *V)
-      : Metadata(ID, Uniqued), ReplaceableMetadataImpl(V->getContext()), V(V) {
+  ValueAsMetadata(unsigned ID, Value *V) : Metadata(ID, Uniqued), V(V) {
     assert(V && "Expected valid value");
   }
 
@@ -964,14 +970,14 @@ template <> struct simplify_type<const MDOperand> {
 /// Pointer to the context, with optional RAUW support.
 ///
 /// Either a raw (non-null) pointer to the \a LLVMContext, or an owned pointer
-/// to \a ReplaceableMetadataImpl (which has a reference to \a LLVMContext).
+/// to \a ReplaceableMetadataImplWithContext.
 class ContextAndReplaceableUses {
-  PointerUnion<LLVMContext *, ReplaceableMetadataImpl *> Ptr;
+  PointerUnion<LLVMContext *, ReplaceableMetadataImplWithContext *> Ptr;
 
 public:
   ContextAndReplaceableUses(LLVMContext &Context) : Ptr(&Context) {}
   ContextAndReplaceableUses(
-      std::unique_ptr<ReplaceableMetadataImpl> ReplaceableUses)
+      std::unique_ptr<ReplaceableMetadataImplWithContext> ReplaceableUses)
       : Ptr(ReplaceableUses.release()) {
     assert(getReplaceableUses() && "Expected non-null replaceable uses");
   }
@@ -987,7 +993,7 @@ class ContextAndReplaceableUses {
 
   /// Whether this contains RAUW support.
   bool hasReplaceableUses() const {
-    return isa<ReplaceableMetadataImpl *>(Ptr);
+    return isa<ReplaceableMetadataImplWithContext *>(Ptr);
   }
 
   LLVMContext &getContext() const {
@@ -996,16 +1002,17 @@ class ContextAndReplaceableUses {
     return *cast<LLVMContext *>(Ptr);
   }
 
-  ReplaceableMetadataImpl *getReplaceableUses() const {
+  ReplaceableMetadataImplWithContext *getReplaceableUses() const {
     if (hasReplaceableUses())
-      return cast<ReplaceableMetadataImpl *>(Ptr);
+      return cast<ReplaceableMetadataImplWithContext *>(Ptr);
     return nullptr;
   }
 
   /// Ensure that this has RAUW support, and then return it.
-  ReplaceableMetadataImpl *getOrCreateReplaceableUses() {
+  ReplaceableMetadataImplWithContext *getOrCreateReplaceableUses() {
     if (!hasReplaceableUses())
-      makeReplaceable(std::make_unique<ReplaceableMetadataImpl>(getContext()));
+      makeReplaceable(
+          std::make_unique<ReplaceableMetadataImplWithContext>(getContext()));
     return getReplaceableUses();
   }
 
@@ -1013,8 +1020,8 @@ class ContextAndReplaceableUses {
   ///
   /// Make this replaceable, taking ownership of \c ReplaceableUses (which must
   /// not be null).
-  void
-  makeReplaceable(std::unique_ptr<ReplaceableMetadataImpl> ReplaceableUses) {
+  void makeReplaceable(
+      std::unique_ptr<ReplaceableMetadataImplWithContext> ReplaceableUses) {
     assert(ReplaceableUses && "Expected non-null replaceable uses");
     assert(&ReplaceableUses->getContext() == &getContext() &&
            "Expected same context");
@@ -1025,9 +1032,9 @@ class ContextAndReplaceableUses {
   /// Drop RAUW support.
   ///
   /// Cede ownership of RAUW support, returning it.
-  std::unique_ptr<ReplaceableMetadataImpl> takeReplaceableUses() {
+  std::unique_ptr<ReplaceableMetadataImplWithContext> takeReplaceableUses() {
     assert(hasReplaceableUses() && "Expected to own replaceable uses");
-    std::unique_ptr<ReplaceableMetadataImpl> ReplaceableUses(
+    std::unique_ptr<ReplaceableMetadataImplWithContext> ReplaceableUses(
         getReplaceableUses());
     Ptr = &ReplaceableUses->getContext();
     return ReplaceableUses;
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index 5f6feb5bd87bb..5faf354e76187 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -44,7 +44,8 @@ TEST(ContextAndReplaceableUsesTest, FromContext) {
 
 TEST(ContextAndReplaceableUsesTest, FromReplaceableUses) {
   LLVMContext Context;
-  ContextAndReplaceableUses CRU(std::make_unique<ReplaceableMetadataImpl>(Context));
+  ContextAndReplaceableUses CRU(
+      std::make_unique<ReplaceableMetadataImplWithContext>(Context));
   EXPECT_EQ(&Context, &CRU.getContext());
   EXPECT_TRUE(CRU.hasReplaceableUses());
   EXPECT_TRUE(CRU.getReplaceableUses());
@@ -53,7 +54,8 @@ TEST(ContextAndReplaceableUsesTest, FromReplaceableUses) {
 TEST(ContextAndReplaceableUsesTest, makeReplaceable) {
   LLVMContext Context;
   ContextAndReplaceableUses CRU(Context);
-  CRU.makeReplaceable(std::make_unique<ReplaceableMetadataImpl>(Context));
+  CRU.makeReplaceable(
+      std::make_unique<ReplaceableMetadataImplWithContext>(Context));
   EXPECT_EQ(&Context, &CRU.getContext());
   EXPECT_TRUE(CRU.hasReplaceableUses());
   EXPECT_TRUE(CRU.getReplaceableUses());
@@ -61,7 +63,8 @@ TEST(ContextAndReplaceableUsesTest, makeReplaceable) {
 
 TEST(ContextAndReplaceableUsesTest, takeReplaceableUses) {
   LLVMContext Context;
-  auto ReplaceableUses = std::make_unique<ReplaceableMetadataImpl>(Context);
+  auto ReplaceableUses =
+      std::make_unique<ReplaceableMetadataImplWithContext>(Context);
   auto *Ptr = ReplaceableUses.get();
   ContextAndReplaceableUses CRU(std::move(ReplaceableUses));
   ReplaceableUses = CRU.takeReplaceableUses();



More information about the llvm-commits mailing list