From fef609f15e09b4c42334a8ff8c2de29af502ff56 Mon Sep 17 00:00:00 2001 From: "Duncan P. N. Exon Smith" Date: Sun, 3 Apr 2016 21:23:52 +0000 Subject: [PATCH] IR: Lazily create ReplaceableMetadataImpl on MDNode RAUW support on MDNode usually requires an extra allocation for ReplaceableMetadataImpl. This is only strictly necessary if there are tracking references to the MDNode. Make the construction of ReplaceableMetadataImpl lazy, so that we don't get allocations if we don't need them. Since MDNode::isResolved now checks MDNode::isTemporary and MDNode::NumUnresolved instead of whether a ReplaceableMetadataImpl is allocated, the internal changes are intrusive (at various internal checkpoints, isResolved now has a different answer). However, there should be no real functionality change here; just slightly lazier allocation behaviour. The external semantics should be identical. llvm-svn: 265279 --- llvm/include/llvm/IR/Metadata.h | 35 +++++++++++++--- llvm/lib/IR/Metadata.cpp | 91 +++++++++++++++++++++++++++-------------- 2 files changed, 90 insertions(+), 36 deletions(-) diff --git a/llvm/include/llvm/IR/Metadata.h b/llvm/include/llvm/IR/Metadata.h index b2d643e..5d2bb1a 100644 --- a/llvm/include/llvm/IR/Metadata.h +++ b/llvm/include/llvm/IR/Metadata.h @@ -19,6 +19,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Constant.h" @@ -310,7 +311,19 @@ private: void dropRef(void *Ref); void moveRef(void *Ref, void *New, const Metadata &MD); - static ReplaceableMetadataImpl *get(Metadata &MD); + /// Lazily construct RAUW support on MD. + /// + /// If this is an unresolved MDNode, RAUW support will be created on-demand. + /// ValueAsMetadata always has RAUW support. + static ReplaceableMetadataImpl *getOrCreate(Metadata &MD); + + /// Get RAUW support on MD, if it exists. + static ReplaceableMetadataImpl *getIfExists(Metadata &MD); + + /// Check whether this node will support RAUW. + /// + /// Returns \c true unless getOrCreate() would return null. + static bool isReplaceable(const Metadata &MD); }; /// \brief Value wrapper in the Metadata hierarchy. @@ -760,6 +773,13 @@ public: return nullptr; } + /// Ensure that this has RAUW support, and then return it. + ReplaceableMetadataImpl *getOrCreateReplaceableUses() { + if (!hasReplaceableUses()) + makeReplaceable(llvm::make_unique(getContext())); + return getReplaceableUses(); + } + /// \brief Assign RAUW support to this. /// /// Make this replaceable, taking ownership of \c ReplaceableUses (which must @@ -885,7 +905,7 @@ public: /// As forward declarations are resolved, their containers should get /// resolved automatically. However, if this (or one of its operands) is /// involved in a cycle, \a resolveCycles() needs to be called explicitly. - bool isResolved() const { return !Context.hasReplaceableUses(); } + bool isResolved() const { return !isTemporary() && !NumUnresolved; } bool isUniqued() const { return Storage == Uniqued; } bool isDistinct() const { return Storage == Distinct; } @@ -896,8 +916,8 @@ public: /// \pre \a isTemporary() must be \c true. void replaceAllUsesWith(Metadata *MD) { assert(isTemporary() && "Expected temporary node"); - assert(!isResolved() && "Expected RAUW support"); - Context.getReplaceableUses()->replaceAllUsesWith(MD); + if (Context.hasReplaceableUses()) + Context.getReplaceableUses()->replaceAllUsesWith(MD); } /// \brief Resolve cycles. @@ -959,10 +979,15 @@ protected: private: void handleChangedOperand(void *Ref, Metadata *New); + /// Resolve a unique, unresolved node. void resolve(); + + /// Drop RAUW support, if any. + void dropReplaceableUses(); + void resolveAfterOperandChange(Metadata *Old, Metadata *New); void decrementUnresolvedOperandCount(); - unsigned countUnresolvedOperands(); + void countUnresolvedOperands(); /// \brief Mutate this to be "uniqued". /// diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp index b874308..fc134e4 100644 --- a/llvm/lib/IR/Metadata.cpp +++ b/llvm/lib/IR/Metadata.cpp @@ -124,7 +124,7 @@ bool MetadataTracking::track(void *Ref, Metadata &MD, OwnerTy Owner) { assert(Ref && "Expected live reference"); assert((Owner || *static_cast(Ref) == &MD) && "Reference without owner must be direct"); - if (auto *R = ReplaceableMetadataImpl::get(MD)) { + if (auto *R = ReplaceableMetadataImpl::getOrCreate(MD)) { R->addRef(Ref, Owner); return true; } @@ -133,7 +133,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::get(MD)) + if (auto *R = ReplaceableMetadataImpl::getIfExists(MD)) R->dropRef(Ref); } @@ -141,15 +141,17 @@ 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::get(MD)) { + if (auto *R = ReplaceableMetadataImpl::getIfExists(MD)) { R->moveRef(Ref, New, MD); return true; } + assert(!isReplaceable(MD) && + "Expected un-replaceable metadata, since we didn't move a reference"); return false; } bool MetadataTracking::isReplaceable(const Metadata &MD) { - return ReplaceableMetadataImpl::get(const_cast(MD)); + return ReplaceableMetadataImpl::isReplaceable(MD); } void ReplaceableMetadataImpl::addRef(void *Ref, OwnerTy Owner) { @@ -268,9 +270,21 @@ void ReplaceableMetadataImpl::resolveAllUses(bool ResolveUsers) { } } -ReplaceableMetadataImpl *ReplaceableMetadataImpl::get(Metadata &MD) { +ReplaceableMetadataImpl *ReplaceableMetadataImpl::getOrCreate(Metadata &MD) { if (auto *N = dyn_cast(&MD)) - return N->Context.getReplaceableUses(); + return N->isResolved() ? nullptr : N->Context.getOrCreateReplaceableUses(); + return dyn_cast(&MD); +} + +ReplaceableMetadataImpl *ReplaceableMetadataImpl::getIfExists(Metadata &MD) { + if (auto *N = dyn_cast(&MD)) + return N->isResolved() ? nullptr : N->Context.getReplaceableUses(); + return dyn_cast(&MD); +} + +bool ReplaceableMetadataImpl::isReplaceable(const Metadata &MD) { + if (auto *N = dyn_cast(&MD)) + return !N->isResolved(); return dyn_cast(&MD); } @@ -452,16 +466,12 @@ MDNode::MDNode(LLVMContext &Context, unsigned ID, StorageType Storage, for (Metadata *MD : Ops2) setOperand(Op++, MD); - if (isDistinct()) + if (!isUniqued()) return; - if (isUniqued()) - // Check whether any operands are unresolved, requiring re-uniquing. If - // not, don't support RAUW. - if (!countUnresolvedOperands()) - return; - - this->Context.makeReplaceable(make_unique(Context)); + // Count the unresolved operands. If there are any, RAUW support will be + // added lazily on first reference. + countUnresolvedOperands(); } TempMDNode MDNode::clone() const { @@ -481,10 +491,10 @@ static bool isOperandUnresolved(Metadata *Op) { return false; } -unsigned MDNode::countUnresolvedOperands() { +void MDNode::countUnresolvedOperands() { assert(NumUnresolved == 0 && "Expected unresolved ops to be uncounted"); + assert(isUniqued() && "Expected this to be uniqued"); NumUnresolved = std::count_if(op_begin(), op_end(), isOperandUnresolved); - return NumUnresolved; } void MDNode::makeUniqued() { @@ -497,8 +507,11 @@ void MDNode::makeUniqued() { // Make this 'uniqued'. Storage = Uniqued; - if (!countUnresolvedOperands()) - resolve(); + countUnresolvedOperands(); + if (!NumUnresolved) { + dropReplaceableUses(); + assert(isResolved() && "Expected this to be resolved"); + } assert(isUniqued() && "Expected this to be uniqued"); } @@ -507,9 +520,8 @@ void MDNode::makeDistinct() { assert(isTemporary() && "Expected this to be temporary"); assert(!isResolved() && "Expected this to be unresolved"); - // Pretend to be uniqued, resolve the node, and then store in distinct table. - Storage = Uniqued; - resolve(); + // Drop RAUW support and store as a distinct node. + dropReplaceableUses(); storeDistinctInContext(); assert(isDistinct() && "Expected this to be distinct"); @@ -520,16 +532,22 @@ void MDNode::resolve() { assert(isUniqued() && "Expected this to be uniqued"); assert(!isResolved() && "Expected this to be unresolved"); - // Move the map, so that this immediately looks resolved. - auto Uses = Context.takeReplaceableUses(); NumUnresolved = 0; + dropReplaceableUses(); + assert(isResolved() && "Expected this to be resolved"); +} + +void MDNode::dropReplaceableUses() { + assert(!NumUnresolved && "Unexpected unresolved operand"); - // Drop RAUW support. - Uses->resolveAllUses(); + // Drop any RAUW support. + if (Context.hasReplaceableUses()) + Context.takeReplaceableUses()->resolveAllUses(); } void MDNode::resolveAfterOperandChange(Metadata *Old, Metadata *New) { + assert(isUniqued() && "Expected this to be uniqued"); assert(NumUnresolved != 0 && "Expected unresolved operands"); // Check if an operand was resolved. @@ -542,9 +560,17 @@ void MDNode::resolveAfterOperandChange(Metadata *Old, Metadata *New) { } void MDNode::decrementUnresolvedOperandCount() { - if (!--NumUnresolved) - // Last unresolved operand has just been resolved. - resolve(); + assert(!isResolved() && "Expected this to be unresolved"); + if (isTemporary()) + return; + + assert(isUniqued() && "Expected this to be uniqued"); + if (--NumUnresolved) + return; + + // Last unresolved operand has just been resolved. + dropReplaceableUses(); + assert(isResolved() && "Expected this to become resolved"); } void MDNode::resolveCycles() { @@ -619,7 +645,7 @@ void MDTuple::recalculateHash() { void MDNode::dropAllReferences() { for (unsigned I = 0, E = NumOperands; I != E; ++I) setOperand(I, nullptr); - if (!isResolved()) { + if (Context.hasReplaceableUses()) { Context.getReplaceableUses()->resolveAllUses(/* ResolveUsers */ false); (void)Context.takeReplaceableUses(); } @@ -665,7 +691,8 @@ void MDNode::handleChangedOperand(void *Ref, Metadata *New) { // dropAllReferences(), but we still need the use-list). for (unsigned O = 0, E = getNumOperands(); O != E; ++O) setOperand(O, nullptr); - Context.getReplaceableUses()->replaceAllUsesWith(Uniqued); + if (Context.hasReplaceableUses()) + Context.getReplaceableUses()->replaceAllUsesWith(Uniqued); deleteAsSubclass(); return; } @@ -763,8 +790,10 @@ void MDNode::deleteTemporary(MDNode *N) { } void MDNode::storeDistinctInContext() { - assert(isResolved() && "Expected resolved nodes"); + assert(!Context.hasReplaceableUses() && "Unexpected replaceable uses"); + assert(!NumUnresolved && "Unexpected unresolved nodes"); Storage = Distinct; + assert(isResolved() && "Expected this to be resolved"); // Reset the hash. switch (getMetadataID()) { -- 2.7.4