mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
IR: Add MDNode::replaceWithPermanent()
Add new API for converting temporaries that may self-reference. Self-referencing nodes are not allowed to be uniqued, so sending them into `replaceWithUniqued()` is dangerous (and this commit adds assertions that prevent it). `replaceWithPermanent()` has similar semantics to `get()` followed by calls to `replaceOperandWith()`. In particular, if there's a self-reference, it returns a distinct node; otherwise, it returns a uniqued one. Like `replaceWithUniqued()` and `replaceWithDistinct()` (well, it calls out to them) it mutates the temporary node in place if possible, only calling `replaceAllUsesWith()` on a uniquing collision. llvm-svn: 228726
This commit is contained in:
parent
37700f757e
commit
73d123e7bc
@ -789,10 +789,22 @@ public:
|
||||
/// \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) {
|
||||
@ -810,6 +822,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
MDNode *replaceWithPermanentImpl();
|
||||
MDNode *replaceWithUniquedImpl();
|
||||
MDNode *replaceWithDistinctImpl();
|
||||
|
||||
|
@ -518,9 +518,23 @@ void MDNode::resolveCycles() {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@ -633,6 +647,8 @@ template <class NodeTy> struct MDNode::HasCachedHash {
|
||||
};
|
||||
|
||||
MDNode *MDNode::uniquify() {
|
||||
assert(!hasSelfReference(this) && "Cannot uniquify a self-referencing node");
|
||||
|
||||
// Try to insert into uniquing store.
|
||||
switch (getMetadataID()) {
|
||||
default:
|
||||
|
@ -518,6 +518,44 @@ TEST_F(MDNodeTest, replaceWithDistinct) {
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
|
Loading…
Reference in New Issue
Block a user