[llvm] 914e15c - [IR] Move the LLVMContext out of ReplaceableMetadataImpl. NFC (#222085)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 13 11:19:46 PDT 2026
Author: Fangrui Song
Date: 2026-09-13T18:19:40Z
New Revision: 914e15cd29f78e01e15378cfccff97d42e6e9e82
URL: https://github.com/llvm/llvm-project/commit/914e15cd29f78e01e15378cfccff97d42e6e9e82
DIFF: https://github.com/llvm/llvm-project/commit/914e15cd29f78e01e15378cfccff97d42e6e9e82.diff
LOG: [IR] Move the LLVMContext out of ReplaceableMetadataImpl. NFC (#222085)
No ReplaceableMetadataImpl method reads its LLVMContext reference, and
ValueAsMetadata reaches the context through the wrapped Value. Keep the
reference in a derived ReplaceableUsesWithContext, used by the two
owners with no other route to it: MDNode's on-demand RAUW support and
DIArgList.
Rename the base to ReplaceableUses: it is the use map behind RAUW for
the metadata kinds that support it, not a pimpl, and the name matches
ContextAndReplaceableUses and getReplaceableUses().
Make the base destructor protected, since getOrCreate() hands out
ReplaceableUses pointers that must never be deleted. Delete copy
assignment explicitly; the LLVMContext reference suppresses it
implicitly.
sizeof(ValueAsMetadata) 152 -> 144.
Aided by Opus 5
Added:
Modified:
llvm/include/llvm/IR/DebugInfoMetadata.h
llvm/include/llvm/IR/Metadata.h
llvm/lib/IR/Constants.cpp
llvm/lib/IR/DebugInfoMetadata.cpp
llvm/lib/IR/Metadata.cpp
llvm/lib/Transforms/IPO/GlobalOpt.cpp
llvm/unittests/IR/MetadataTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index e75dc8eb60b80..3327471f461b6 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -4977,15 +4977,15 @@ class DIMacroFile : public DIMacroNode {
/// List of ValueAsMetadata, to be used as an argument to a dbg.value
/// intrinsic.
-class DIArgList : public Metadata, ReplaceableMetadataImpl {
- friend class ReplaceableMetadataImpl;
+class DIArgList : public Metadata, ReplaceableUsesWithContext {
+ friend class ReplaceableUses;
friend class LLVMContextImpl;
using iterator = SmallVectorImpl<ValueAsMetadata *>::iterator;
SmallVector<ValueAsMetadata *, 4> Args;
DIArgList(LLVMContext &Context, ArrayRef<ValueAsMetadata *> Args)
- : Metadata(DIArgListKind, Uniqued), ReplaceableMetadataImpl(Context),
+ : Metadata(DIArgListKind, Uniqued), ReplaceableUsesWithContext(Context),
Args(Args) {
track();
}
@@ -5009,7 +5009,7 @@ class DIArgList : public Metadata, ReplaceableMetadataImpl {
}
SmallVector<DbgVariableRecord *> getAllDbgVariableRecordUsers() {
- return ReplaceableMetadataImpl::getAllDbgVariableRecordUsers();
+ return ReplaceableUses::getAllDbgVariableRecordUsers();
}
LLVM_ABI void handleChangedOperand(void *Ref, Metadata *New);
diff --git a/llvm/include/llvm/IR/Metadata.h b/llvm/include/llvm/IR/Metadata.h
index a53cb63ed59cf..c677f9cc61769 100644
--- a/llvm/include/llvm/IR/Metadata.h
+++ b/llvm/include/llvm/IR/Metadata.h
@@ -62,7 +62,7 @@ const uint64_t NOMORE_ICP_MAGICNUM = -1;
///
/// This is a root class for typeless data in the IR.
class Metadata {
- friend class ReplaceableMetadataImpl;
+ friend class ReplaceableUses;
/// RTTI.
const unsigned char SubclassID;
@@ -182,7 +182,7 @@ inline raw_ostream &operator<<(raw_ostream &OS, const Metadata &MD) {
/// Notably, this is the only thing in either hierarchy that is allowed to
/// reference \a LocalAsMetadata.
class MetadataAsValue : public Value {
- friend class ReplaceableMetadataImpl;
+ friend class ReplaceableUses;
friend class LLVMContextImpl;
Metadata *MD;
@@ -231,7 +231,7 @@ class DebugValueUser {
public:
LLVM_ABI DbgVariableRecord *getUser();
LLVM_ABI const DbgVariableRecord *getUser() const;
- /// To be called by ReplaceableMetadataImpl::replaceAllUsesWith, where `Old`
+ /// To be called by ReplaceableUses::replaceAllUsesWith, where `Old`
/// is a pointer to one of the pointers in `DebugValues` (so should be type
/// Metadata**), and `NewDebugValue` is the new Metadata* that is replacing
/// *Old.
@@ -388,25 +388,23 @@ class MetadataTracking {
/// Most metadata cannot be RAUW'ed. This is a shared implementation of
/// use-lists and associated API for the three that support it (
/// \a ValueAsMetadata, \a TempMDNode, and \a DIArgList).
-class ReplaceableMetadataImpl {
+class ReplaceableUses {
friend class MetadataTracking;
public:
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) {}
-
- ~ReplaceableMetadataImpl() {
+protected:
+ ~ReplaceableUses() {
assert(UseMap.empty() && "Cannot destroy in-use replaceable metadata");
}
- LLVMContext &getContext() const { return Context; }
+public:
+ ReplaceableUses &operator=(const ReplaceableUses &) = delete;
/// Replace all uses of this with MD.
///
@@ -437,10 +435,10 @@ class ReplaceableMetadataImpl {
///
/// If this is an unresolved MDNode, RAUW support will be created on-demand.
/// ValueAsMetadata always has RAUW support.
- static ReplaceableMetadataImpl *getOrCreate(Metadata &MD);
+ static ReplaceableUses *getOrCreate(Metadata &MD);
/// Get RAUW support on MD, if it exists.
- static ReplaceableMetadataImpl *getIfExists(Metadata &MD);
+ static ReplaceableUses *getIfExists(Metadata &MD);
/// Check whether this node will support RAUW.
///
@@ -448,6 +446,18 @@ class ReplaceableMetadataImpl {
static bool isReplaceable(const Metadata &MD);
};
+/// Replaceable metadata that remembers its \a LLVMContext, for owners with no
+/// other route to it.
+class ReplaceableUsesWithContext : public ReplaceableUses {
+ LLVMContext &Context;
+
+public:
+ explicit ReplaceableUsesWithContext(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
@@ -456,20 +466,19 @@ class ReplaceableMetadataImpl {
/// Because of full uniquing support, each value is only wrapped by a single \a
/// ValueAsMetadata object, so the lookup maps are far more efficient than
/// those using ValueHandleBase.
-class ValueAsMetadata : public Metadata, ReplaceableMetadataImpl {
- friend class ReplaceableMetadataImpl;
+class ValueAsMetadata : public Metadata, ReplaceableUses {
+ friend class ReplaceableUses;
friend class LLVMContextImpl;
Value *V;
/// Drop users without RAUW (during teardown).
void dropUsers() {
- ReplaceableMetadataImpl::resolveAllUses(/* ResolveUsers */ false);
+ ReplaceableUses::resolveAllUses(/* ResolveUsers */ false);
}
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");
}
@@ -501,10 +510,10 @@ class ValueAsMetadata : public Metadata, ReplaceableMetadataImpl {
LLVMContext &getContext() const { return V->getContext(); }
SmallVector<Metadata *> getAllArgListUsers() {
- return ReplaceableMetadataImpl::getAllArgListUsers();
+ return ReplaceableUses::getAllArgListUsers();
}
SmallVector<DbgVariableRecord *> getAllDbgVariableRecordUsers() {
- return ReplaceableMetadataImpl::getAllDbgVariableRecordUsers();
+ return ReplaceableUses::getAllDbgVariableRecordUsers();
}
LLVM_ABI static void handleDeletion(Value *V);
@@ -517,7 +526,7 @@ class ValueAsMetadata : public Metadata, ReplaceableMetadataImpl {
/// \a Value gets RAUW'ed and the target already exists, this is used to
/// merge the two metadata nodes.
void replaceAllUsesWith(Metadata *MD) {
- ReplaceableMetadataImpl::replaceAllUsesWith(MD);
+ ReplaceableUses::replaceAllUsesWith(MD);
}
public:
@@ -964,14 +973,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 ReplaceableUsesWithContext.
class ContextAndReplaceableUses {
- PointerUnion<LLVMContext *, ReplaceableMetadataImpl *> Ptr;
+ PointerUnion<LLVMContext *, ReplaceableUsesWithContext *> Ptr;
public:
ContextAndReplaceableUses(LLVMContext &Context) : Ptr(&Context) {}
ContextAndReplaceableUses(
- std::unique_ptr<ReplaceableMetadataImpl> ReplaceableUses)
+ std::unique_ptr<ReplaceableUsesWithContext> ReplaceableUses)
: Ptr(ReplaceableUses.release()) {
assert(getReplaceableUses() && "Expected non-null replaceable uses");
}
@@ -987,7 +996,7 @@ class ContextAndReplaceableUses {
/// Whether this contains RAUW support.
bool hasReplaceableUses() const {
- return isa<ReplaceableMetadataImpl *>(Ptr);
+ return isa<ReplaceableUsesWithContext *>(Ptr);
}
LLVMContext &getContext() const {
@@ -996,16 +1005,17 @@ class ContextAndReplaceableUses {
return *cast<LLVMContext *>(Ptr);
}
- ReplaceableMetadataImpl *getReplaceableUses() const {
+ ReplaceableUsesWithContext *getReplaceableUses() const {
if (hasReplaceableUses())
- return cast<ReplaceableMetadataImpl *>(Ptr);
+ return cast<ReplaceableUsesWithContext *>(Ptr);
return nullptr;
}
/// Ensure that this has RAUW support, and then return it.
- ReplaceableMetadataImpl *getOrCreateReplaceableUses() {
+ ReplaceableUsesWithContext *getOrCreateReplaceableUses() {
if (!hasReplaceableUses())
- makeReplaceable(std::make_unique<ReplaceableMetadataImpl>(getContext()));
+ makeReplaceable(
+ std::make_unique<ReplaceableUsesWithContext>(getContext()));
return getReplaceableUses();
}
@@ -1014,7 +1024,7 @@ class ContextAndReplaceableUses {
/// Make this replaceable, taking ownership of \c ReplaceableUses (which must
/// not be null).
void
- makeReplaceable(std::unique_ptr<ReplaceableMetadataImpl> ReplaceableUses) {
+ makeReplaceable(std::unique_ptr<ReplaceableUsesWithContext> ReplaceableUses) {
assert(ReplaceableUses && "Expected non-null replaceable uses");
assert(&ReplaceableUses->getContext() == &getContext() &&
"Expected same context");
@@ -1025,9 +1035,9 @@ class ContextAndReplaceableUses {
/// Drop RAUW support.
///
/// Cede ownership of RAUW support, returning it.
- std::unique_ptr<ReplaceableMetadataImpl> takeReplaceableUses() {
+ std::unique_ptr<ReplaceableUsesWithContext> takeReplaceableUses() {
assert(hasReplaceableUses() && "Expected to own replaceable uses");
- std::unique_ptr<ReplaceableMetadataImpl> ReplaceableUses(
+ std::unique_ptr<ReplaceableUsesWithContext> ReplaceableUses(
getReplaceableUses());
Ptr = &ReplaceableUses->getContext();
return ReplaceableUses;
@@ -1067,7 +1077,7 @@ struct TempMDNodeDeleter {
///
/// Clients can add operands to resizable MDNodes using push_back().
class MDNode : public Metadata {
- friend class ReplaceableMetadataImpl;
+ friend class ReplaceableUses;
friend class LLVMContextImpl;
friend class DIAssignID;
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index 5b56a0008b1d1..def1ba1854371 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -760,7 +760,7 @@ static bool constantIsDead(const Constant *C, bool RemoveDeadUsers) {
if (RemoveDeadUsers) {
// If C is only used by metadata, it should not be preserved but should
// have its uses replaced.
- ReplaceableMetadataImpl::SalvageDebugInfo(*C);
+ ReplaceableUses::SalvageDebugInfo(*C);
const_cast<Constant *>(C)->destroyConstant();
}
diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index c25b8c6796bbc..7da33a7abc48a 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -2775,5 +2775,5 @@ void DIArgList::dropAllReferences(bool Untrack) {
if (Untrack)
untrack();
Args.clear();
- ReplaceableMetadataImpl::resolveAllUses(/* ResolveUsers */ false);
+ ReplaceableUses::resolveAllUses(/* ResolveUsers */ false);
}
diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp
index fe79bd08ffa52..fc03bf4a87eb1 100644
--- a/llvm/lib/IR/Metadata.cpp
+++ b/llvm/lib/IR/Metadata.cpp
@@ -211,7 +211,7 @@ bool MetadataTracking::track(void *Ref, Metadata &MD, OwnerTy Owner) {
assert(Ref && "Expected live reference");
assert((Owner || *static_cast<Metadata **>(Ref) == &MD) &&
"Reference without owner must be direct");
- if (auto *R = ReplaceableMetadataImpl::getOrCreate(MD)) {
+ if (auto *R = ReplaceableUses::getOrCreate(MD)) {
R->addRef(Ref, Owner);
return true;
}
@@ -226,7 +226,7 @@ bool MetadataTracking::track(void *Ref, Metadata &MD, OwnerTy Owner) {
void MetadataTracking::untrack(void *Ref, Metadata &MD) {
assert(Ref && "Expected live reference");
- if (auto *R = ReplaceableMetadataImpl::getIfExists(MD))
+ if (auto *R = ReplaceableUses::getIfExists(MD))
R->dropRef(Ref);
else if (auto *PH = dyn_cast<DistinctMDOperandPlaceholder>(&MD))
PH->Use = nullptr;
@@ -236,7 +236,7 @@ bool MetadataTracking::retrack(void *Ref, Metadata &MD, void *New) {
assert(Ref && "Expected live reference");
assert(New && "Expected live reference");
assert(Ref != New && "Expected change");
- if (auto *R = ReplaceableMetadataImpl::getIfExists(MD)) {
+ if (auto *R = ReplaceableUses::getIfExists(MD)) {
R->moveRef(Ref, New, MD);
return true;
}
@@ -248,10 +248,10 @@ bool MetadataTracking::retrack(void *Ref, Metadata &MD, void *New) {
}
bool MetadataTracking::isReplaceable(const Metadata &MD) {
- return ReplaceableMetadataImpl::isReplaceable(MD);
+ return ReplaceableUses::isReplaceable(MD);
}
-SmallVector<Metadata *> ReplaceableMetadataImpl::getAllArgListUsers() {
+SmallVector<Metadata *> ReplaceableUses::getAllArgListUsers() {
SmallVector<std::pair<OwnerTy, uint64_t> *> MDUsersWithID;
for (auto Pair : UseMap) {
OwnerTy Owner = Pair.second.first;
@@ -273,7 +273,7 @@ SmallVector<Metadata *> ReplaceableMetadataImpl::getAllArgListUsers() {
}
SmallVector<DbgVariableRecord *>
-ReplaceableMetadataImpl::getAllDbgVariableRecordUsers() {
+ReplaceableUses::getAllDbgVariableRecordUsers() {
SmallVector<std::pair<OwnerTy, uint64_t> *> DVRUsersWithID;
for (auto Pair : UseMap) {
OwnerTy Owner = Pair.second.first;
@@ -297,7 +297,7 @@ ReplaceableMetadataImpl::getAllDbgVariableRecordUsers() {
return DVRUsers;
}
-void ReplaceableMetadataImpl::addRef(void *Ref, OwnerTy Owner) {
+void ReplaceableUses::addRef(void *Ref, OwnerTy Owner) {
bool WasInserted =
UseMap.insert(std::make_pair(Ref, std::make_pair(Owner, NextIndex)))
.second;
@@ -308,14 +308,13 @@ void ReplaceableMetadataImpl::addRef(void *Ref, OwnerTy Owner) {
assert(NextIndex != 0 && "Unexpected overflow");
}
-void ReplaceableMetadataImpl::dropRef(void *Ref) {
+void ReplaceableUses::dropRef(void *Ref) {
bool WasErased = UseMap.erase(Ref);
(void)WasErased;
assert(WasErased && "Expected to drop a reference");
}
-void ReplaceableMetadataImpl::moveRef(void *Ref, void *New,
- const Metadata &MD) {
+void ReplaceableUses::moveRef(void *Ref, void *New, const Metadata &MD) {
auto I = UseMap.find(Ref);
assert(I != UseMap.end() && "Expected to move a reference");
auto OwnerAndIndex = I->second;
@@ -332,7 +331,7 @@ void ReplaceableMetadataImpl::moveRef(void *Ref, void *New,
"Reference without owner must be direct");
}
-void ReplaceableMetadataImpl::SalvageDebugInfo(const Constant &C) {
+void ReplaceableUses::SalvageDebugInfo(const Constant &C) {
if (!C.isUsedByMetadata()) {
return;
}
@@ -369,7 +368,7 @@ void ReplaceableMetadataImpl::SalvageDebugInfo(const Constant &C) {
}
}
-void ReplaceableMetadataImpl::replaceAllUsesWith(Metadata *MD) {
+void ReplaceableUses::replaceAllUsesWith(Metadata *MD) {
if (UseMap.empty())
return;
@@ -422,7 +421,7 @@ void ReplaceableMetadataImpl::replaceAllUsesWith(Metadata *MD) {
assert(UseMap.empty() && "Expected all uses to be replaced");
}
-void ReplaceableMetadataImpl::resolveAllUses(bool ResolveUsers) {
+void ReplaceableUses::resolveAllUses(bool ResolveUsers) {
if (UseMap.empty())
return;
@@ -458,7 +457,7 @@ void ReplaceableMetadataImpl::resolveAllUses(bool ResolveUsers) {
// Special handing of DIArgList is required in the RemoveDIs project, see
// commentry in DIArgList::handleChangedOperand for details. Hidden behind
// conditional compilation to avoid a compile time regression.
-ReplaceableMetadataImpl *ReplaceableMetadataImpl::getOrCreate(Metadata &MD) {
+ReplaceableUses *ReplaceableUses::getOrCreate(Metadata &MD) {
if (auto *N = dyn_cast<MDNode>(&MD)) {
return !N->isResolved() || N->isAlwaysReplaceable()
? N->Context.getOrCreateReplaceableUses()
@@ -469,7 +468,7 @@ ReplaceableMetadataImpl *ReplaceableMetadataImpl::getOrCreate(Metadata &MD) {
return dyn_cast<ValueAsMetadata>(&MD);
}
-ReplaceableMetadataImpl *ReplaceableMetadataImpl::getIfExists(Metadata &MD) {
+ReplaceableUses *ReplaceableUses::getIfExists(Metadata &MD) {
if (auto *N = dyn_cast<MDNode>(&MD)) {
return !N->isResolved() || N->isAlwaysReplaceable()
? N->Context.getReplaceableUses()
@@ -480,7 +479,7 @@ ReplaceableMetadataImpl *ReplaceableMetadataImpl::getIfExists(Metadata &MD) {
return dyn_cast<ValueAsMetadata>(&MD);
}
-bool ReplaceableMetadataImpl::isReplaceable(const Metadata &MD) {
+bool ReplaceableUses::isReplaceable(const Metadata &MD) {
if (auto *N = dyn_cast<MDNode>(&MD))
return !N->isResolved() || N->isAlwaysReplaceable();
return isa<ValueAsMetadata>(&MD) || isa<DIArgList>(&MD);
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index 9892c6796517c..2c1a5f0feaf1c 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -1348,7 +1348,7 @@ deleteIfDead(GlobalValue &GV,
if (DeleteFnCallback)
DeleteFnCallback(*F);
}
- ReplaceableMetadataImpl::SalvageDebugInfo(GV);
+ ReplaceableUses::SalvageDebugInfo(GV);
GV.eraseFromParent();
++NumDeleted;
return true;
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index 5f6feb5bd87bb..cb0096d8f4a2c 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<ReplaceableUsesWithContext>(Context));
EXPECT_EQ(&Context, &CRU.getContext());
EXPECT_TRUE(CRU.hasReplaceableUses());
EXPECT_TRUE(CRU.getReplaceableUses());
@@ -53,7 +54,7 @@ TEST(ContextAndReplaceableUsesTest, FromReplaceableUses) {
TEST(ContextAndReplaceableUsesTest, makeReplaceable) {
LLVMContext Context;
ContextAndReplaceableUses CRU(Context);
- CRU.makeReplaceable(std::make_unique<ReplaceableMetadataImpl>(Context));
+ CRU.makeReplaceable(std::make_unique<ReplaceableUsesWithContext>(Context));
EXPECT_EQ(&Context, &CRU.getContext());
EXPECT_TRUE(CRU.hasReplaceableUses());
EXPECT_TRUE(CRU.getReplaceableUses());
@@ -61,7 +62,7 @@ TEST(ContextAndReplaceableUsesTest, makeReplaceable) {
TEST(ContextAndReplaceableUsesTest, takeReplaceableUses) {
LLVMContext Context;
- auto ReplaceableUses = std::make_unique<ReplaceableMetadataImpl>(Context);
+ auto ReplaceableUses = std::make_unique<ReplaceableUsesWithContext>(Context);
auto *Ptr = ReplaceableUses.get();
ContextAndReplaceableUses CRU(std::move(ReplaceableUses));
ReplaceableUses = CRU.takeReplaceableUses();
More information about the llvm-commits
mailing list