/// \pre No operands (or operands' operands, etc.) have \a isTemporary().
void resolveCycles();
+ /// \brief Replace a temporary node with a permanent one.
+ ///
+ /// Try to create a uniqued version of \c N -- in place, if possible -- and
+ /// return it. If \c N cannot be uniqued, return a distinct node instead.
+ template <class T>
+ static typename std::enable_if<std::is_base_of<MDNode, T>::value, T *>::type
+ replaceWithPermanent(std::unique_ptr<T, TempMDNodeDeleter> N) {
+ return cast<T>(N.release()->replaceWithPermanentImpl());
+ }
+
/// \brief Replace a temporary node with a uniqued one.
///
/// Create a uniqued version of \c N -- in place, if possible -- and return
/// it. Takes ownership of the temporary node.
+ ///
+ /// \pre N does not self-reference.
template <class T>
static typename std::enable_if<std::is_base_of<MDNode, T>::value, T *>::type
replaceWithUniqued(std::unique_ptr<T, TempMDNodeDeleter> N) {
}
private:
+ MDNode *replaceWithPermanentImpl();
MDNode *replaceWithUniquedImpl();
MDNode *replaceWithDistinctImpl();
}
}
+static bool hasSelfReference(MDNode *N) {
+ for (Metadata *MD : N->operands())
+ if (MD == N)
+ return true;
+ return false;
+}
+
+MDNode *MDNode::replaceWithPermanentImpl() {
+ if (hasSelfReference(this))
+ return replaceWithDistinctImpl();
+ return replaceWithUniquedImpl();
+}
+
MDNode *MDNode::replaceWithUniquedImpl() {
// Try to uniquify in place.
MDNode *UniquedNode = uniquify();
+
if (UniquedNode == this) {
makeUniqued();
return this;
};
MDNode *MDNode::uniquify() {
+ assert(!hasSelfReference(this) && "Cannot uniquify a self-referencing node");
+
// Try to insert into uniquing store.
switch (getMetadataID()) {
default:
}
}
+TEST_F(MDNodeTest, replaceWithPermanent) {
+ Metadata *Ops[] = {nullptr};
+ auto Temp = MDTuple::getTemporary(Context, Ops);
+ auto *T = Temp.get();
+
+ // U is a normal, uniqued node that references T.
+ auto *U = MDTuple::get(Context, T);
+ EXPECT_TRUE(U->isUniqued());
+
+ // Make Temp self-referencing.
+ Temp->replaceOperandWith(0, T);
+
+ // Try to uniquify Temp. This should, despite the name in the API, give a
+ // 'distinct' node, since self-references aren't allowed to be uniqued.
+ //
+ // Since it's distinct, N should have the same address as when it was a
+ // temporary (i.e., be equal to T not U).
+ auto *N = MDNode::replaceWithPermanent(std::move(Temp));
+ EXPECT_EQ(N, T);
+ EXPECT_TRUE(N->isDistinct());
+
+ // U should be the canonical unique node with N as the argument.
+ EXPECT_EQ(U, MDTuple::get(Context, N));
+ EXPECT_TRUE(U->isUniqued());
+
+ // This temporary should collide with U when replaced, but it should still be
+ // uniqued.
+ EXPECT_EQ(U, MDNode::replaceWithPermanent(MDTuple::getTemporary(Context, N)));
+ EXPECT_TRUE(U->isUniqued());
+
+ // This temporary should become a new uniqued node.
+ auto Temp2 = MDTuple::getTemporary(Context, U);
+ auto *V = Temp2.get();
+ EXPECT_EQ(V, MDNode::replaceWithPermanent(std::move(Temp2)));
+ EXPECT_TRUE(V->isUniqued());
+ EXPECT_EQ(U, V->getOperand(0));
+}
+
TEST_F(MDNodeTest, deleteTemporaryWithTrackingRef) {
TrackingMDRef Ref;
EXPECT_EQ(nullptr, Ref.get());