ValueMapper: Resolve cycles on the new nodes

Fix a major bug from r265456.  Although it's now much rarer, ValueMapper
sometimes has to duplicate cycles.  The
might-transitively-reference-a-temporary counts don't decrement on their
own when there are cycles, and you need to call MDNode::resolveCycles to
fix it.

r265456 was checking the input nodes to see if they were unresolved.
This is useless; they should never be unresolved.  Instead we should
check the output nodes and resolve cycles on them.

llvm-svn: 266258
This commit is contained in:
Duncan P. N. Exon Smith 2016-04-13 22:54:01 +00:00
parent 3ef4e4a98c
commit 11f60fd65a
2 changed files with 46 additions and 2 deletions

View File

@ -587,6 +587,7 @@ void MDNodeMapper::mapDistinctNodes() {
void MDNodeMapper::mapUniquedNodes() {
// Construct uniqued nodes, building forward references as necessary.
SmallVector<MDNode *, 16> CyclicNodes;
for (auto *N : POT) {
if (N->isDistinct())
continue;
@ -601,11 +602,12 @@ void MDNodeMapper::mapUniquedNodes() {
TempMDNode ClonedN = D.Placeholder ? std::move(D.Placeholder) : N->clone();
remapOperands(D, *ClonedN);
M.mapToMetadata(N, MDNode::replaceWithUniqued(std::move(ClonedN)));
CyclicNodes.push_back(MDNode::replaceWithUniqued(std::move(ClonedN)));
M.mapToMetadata(N, CyclicNodes.back());
}
// Resolve cycles.
for (auto *N : POT)
for (auto *N : CyclicNodes)
if (!N->isResolved())
N->resolveCycles();
}

View File

@ -9,6 +9,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
@ -63,6 +64,47 @@ TEST(ValueMapperTest, MapMetadataCycle) {
}
}
TEST(ValueMapperTest, MapMetadataDuplicatedCycle) {
LLVMContext Context;
auto *PtrTy = Type::getInt8Ty(Context)->getPointerTo();
std::unique_ptr<GlobalVariable> G0 = llvm::make_unique<GlobalVariable>(
PtrTy, false, GlobalValue::ExternalLinkage, nullptr, "G0");
std::unique_ptr<GlobalVariable> G1 = llvm::make_unique<GlobalVariable>(
PtrTy, false, GlobalValue::ExternalLinkage, nullptr, "G1");
// Create a cycle that references G0.
MDNode *N0; // !0 = !{!1}
MDNode *N1; // !1 = !{!0, i8* @G0}
{
auto T0 = MDTuple::getTemporary(Context, nullptr);
Metadata *Ops1[] = {T0.get(), ConstantAsMetadata::get(G0.get())};
N1 = MDTuple::get(Context, Ops1);
T0->replaceOperandWith(0, N1);
N0 = MDNode::replaceWithUniqued(std::move(T0));
}
// Resolve N0 and N1.
ASSERT_FALSE(N0->isResolved());
ASSERT_FALSE(N1->isResolved());
N0->resolveCycles();
ASSERT_TRUE(N0->isResolved());
ASSERT_TRUE(N1->isResolved());
// Seed the value map to map G0 to G1 and map the nodes. The output should
// have new nodes that reference G1 (instead of G0).
ValueToValueMapTy VM;
VM[G0.get()] = G1.get();
MDNode *MappedN0 = MapMetadata(N0, VM);
MDNode *MappedN1 = MapMetadata(N1, VM);
EXPECT_NE(N0, MappedN0);
EXPECT_NE(N1, MappedN1);
EXPECT_EQ(ConstantAsMetadata::get(G1.get()), MappedN1->getOperand(1));
// Check that the output nodes are resolved.
EXPECT_TRUE(MappedN0->isResolved());
EXPECT_TRUE(MappedN1->isResolved());
}
TEST(ValueMapperTest, MapMetadataUnresolved) {
LLVMContext Context;
TempMDTuple T = MDTuple::getTemporary(Context, None);