IR: Separate out decrementUnresolvedOperandCount(), NFC
[oota-llvm.git] / lib / IR / Metadata.cpp
index bd3805842a58ec3151be9193a00ca1d8e0610fbf..f78e7d2534d9e3dabf68ea18b0c5d1af21557bc8 100644 (file)
@@ -228,9 +228,7 @@ void ReplaceableMetadataImpl::resolveAllUses(bool ResolveUsers) {
       continue;
     if (OwnerMD->isResolved())
       continue;
-    OwnerMD->decrementUnresolvedOperands();
-    if (!OwnerMD->hasUnresolvedOperands())
-      OwnerMD->resolve();
+    OwnerMD->decrementUnresolvedOperandCount();
   }
 }
 
@@ -418,12 +416,15 @@ GenericMDNode::GenericMDNode(LLVMContext &C, ArrayRef<Metadata *> Vals,
     return;
 
   // Check whether any operands are unresolved, requiring re-uniquing.
+  unsigned NumUnresolved = 0;
   for (const auto &Op : operands())
-    if (isOperandUnresolved(Op))
-      incrementUnresolvedOperands();
+    NumUnresolved += unsigned(isOperandUnresolved(Op));
 
-  if (hasUnresolvedOperands())
-    ReplaceableUses.reset(new ReplaceableMetadataImpl);
+  if (!NumUnresolved)
+    return;
+
+  ReplaceableUses.reset(new ReplaceableMetadataImpl);
+  SubclassData32 = NumUnresolved;
 }
 
 GenericMDNode::~GenericMDNode() {
@@ -447,6 +448,25 @@ void GenericMDNode::resolve() {
   Uses->resolveAllUses();
 }
 
+void GenericMDNode::resolveAfterOperandChange(Metadata *Old, Metadata *New) {
+  assert(SubclassData32 != 0 && "Expected unresolved operands");
+
+  // Check if the last unresolved operand has just been resolved; if so,
+  // resolve this as well.
+  if (isOperandUnresolved(Old)) {
+    if (!isOperandUnresolved(New))
+      decrementUnresolvedOperandCount();
+  } else {
+    // Operands shouldn't become unresolved.
+    assert(isOperandUnresolved(New) && "Operand just became unresolved");
+  }
+}
+
+void GenericMDNode::decrementUnresolvedOperandCount() {
+  if (!--SubclassData32)
+    resolve();
+}
+
 void GenericMDNode::resolveCycles() {
   if (isResolved())
     return;
@@ -466,6 +486,18 @@ void GenericMDNode::resolveCycles() {
   }
 }
 
+void GenericMDNode::recalculateHash() {
+  setHash(hash_combine_range(op_begin(), op_end()));
+#ifndef NDEBUG
+  {
+    SmallVector<Metadata *, 8> MDs(op_begin(), op_end());
+    unsigned RawHash = hash_combine_range(MDs.begin(), MDs.end());
+    assert(getHash() == RawHash &&
+           "Expected hash of MDOperand to equal hash of Metadata*");
+  }
+#endif
+}
+
 void MDNode::dropAllReferences() {
   for (unsigned I = 0, E = NumOperands; I != E; ++I)
     setOperand(I, nullptr);
@@ -504,14 +536,6 @@ void GenericMDNode::handleChangedOperand(void *Ref, Metadata *New) {
     setOperand(Op, New);
     return;
   }
-  if (InRAUW) {
-    // We just hit a recursion due to RAUW.  Set the operand and move on, since
-    // we're about to be deleted.
-    //
-    // FIXME: Can this cycle really happen?
-    setOperand(Op, New);
-    return;
-  }
 
   auto &Store = getContext().pImpl->MDNodeSet;
   Store.erase(this);
@@ -522,39 +546,20 @@ void GenericMDNode::handleChangedOperand(void *Ref, Metadata *New) {
   // Drop uniquing for self-reference cycles.
   if (New == this) {
     storeDistinctInContext();
-    setHash(0);
     if (!isResolved())
       resolve();
     return;
   }
 
-  // Re-calculate the hash.
-  setHash(hash_combine_range(op_begin(), op_end()));
-#ifndef NDEBUG
-  {
-    SmallVector<Metadata *, 8> MDs(op_begin(), op_end());
-    unsigned RawHash = hash_combine_range(MDs.begin(), MDs.end());
-    assert(getHash() == RawHash &&
-           "Expected hash of MDOperand to equal hash of Metadata*");
-  }
-#endif
-
   // Re-unique the node.
+  recalculateHash();
   GenericMDNodeInfo::KeyTy Key(this);
   auto I = Store.find_as(Key);
   if (I == Store.end()) {
     Store.insert(this);
 
-    if (!isResolved()) {
-      // Check if the last unresolved operand has just been resolved; if so,
-      // resolve this as well.
-      if (isOperandUnresolved(Old))
-        decrementUnresolvedOperands();
-      if (isOperandUnresolved(New))
-        incrementUnresolvedOperands();
-      if (!hasUnresolvedOperands())
-        resolve();
-    }
+    if (!isResolved())
+      resolveAfterOperandChange(Old, New);
 
     return;
   }
@@ -562,14 +567,17 @@ void GenericMDNode::handleChangedOperand(void *Ref, Metadata *New) {
   // Collision.
   if (!isResolved()) {
     // Still unresolved, so RAUW.
-    InRAUW = true;
+    //
+    // First, clear out all operands to prevent any recursion (similar to
+    // dropAllReferences(), but we still need the use-list).
+    for (unsigned O = 0, E = getNumOperands(); O != E; ++O)
+      setOperand(O, nullptr);
     ReplaceableUses->replaceAllUsesWith(*I);
     delete this;
     return;
   }
 
-  // Store in non-uniqued form if this node has already been resolved.
-  setHash(0);
+  // Store in non-uniqued form if RAUW isn't possible.
   storeDistinctInContext();
 }
 
@@ -616,18 +624,16 @@ void MDNode::storeDistinctInContext() {
   getContext().pImpl->NonUniquedMDNodes.insert(G);
 }
 
-// Replace value from this node's operand list.
 void MDNode::replaceOperandWith(unsigned I, Metadata *New) {
   if (getOperand(I) == New)
     return;
 
-  if (auto *N = dyn_cast<GenericMDNode>(this)) {
-    N->handleChangedOperand(mutable_begin() + I, New);
+  if (isDistinct()) {
+    setOperand(I, New);
     return;
   }
 
-  assert(isa<MDNodeFwdDecl>(this) && "Expected an MDNode");
-  setOperand(I, New);
+  cast<GenericMDNode>(this)->handleChangedOperand(mutable_begin() + I, New);
 }
 
 void MDNode::setOperand(unsigned I, Metadata *New) {