#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"
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.
return nullptr;
}
+ /// Ensure that this has RAUW support, and then return it.
+ ReplaceableMetadataImpl *getOrCreateReplaceableUses() {
+ if (!hasReplaceableUses())
+ makeReplaceable(llvm::make_unique<ReplaceableMetadataImpl>(getContext()));
+ return getReplaceableUses();
+ }
+
/// \brief Assign RAUW support to this.
///
/// Make this replaceable, taking ownership of \c ReplaceableUses (which must
/// 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; }
/// \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.
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".
///
assert(Ref && "Expected live reference");
assert((Owner || *static_cast<Metadata **>(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;
}
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);
}
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<Metadata &>(MD));
+ return ReplaceableMetadataImpl::isReplaceable(MD);
}
void ReplaceableMetadataImpl::addRef(void *Ref, OwnerTy Owner) {
}
}
-ReplaceableMetadataImpl *ReplaceableMetadataImpl::get(Metadata &MD) {
+ReplaceableMetadataImpl *ReplaceableMetadataImpl::getOrCreate(Metadata &MD) {
if (auto *N = dyn_cast<MDNode>(&MD))
- return N->Context.getReplaceableUses();
+ return N->isResolved() ? nullptr : N->Context.getOrCreateReplaceableUses();
+ return dyn_cast<ValueAsMetadata>(&MD);
+}
+
+ReplaceableMetadataImpl *ReplaceableMetadataImpl::getIfExists(Metadata &MD) {
+ if (auto *N = dyn_cast<MDNode>(&MD))
+ return N->isResolved() ? nullptr : N->Context.getReplaceableUses();
+ return dyn_cast<ValueAsMetadata>(&MD);
+}
+
+bool ReplaceableMetadataImpl::isReplaceable(const Metadata &MD) {
+ if (auto *N = dyn_cast<MDNode>(&MD))
+ return !N->isResolved();
return dyn_cast<ValueAsMetadata>(&MD);
}
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<ReplaceableMetadataImpl>(Context));
+ // Count the unresolved operands. If there are any, RAUW support will be
+ // added lazily on first reference.
+ countUnresolvedOperands();
}
TempMDNode MDNode::clone() const {
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() {
// 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");
}
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");
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.
}
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() {
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();
}
// 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;
}
}
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()) {