Index: lib/IR/Metadata.cpp =================================================================== --- lib/IR/Metadata.cpp +++ lib/IR/Metadata.cpp @@ -675,8 +675,8 @@ Metadata *Old = getOperand(Op); setOperand(Op, New); - // Drop uniquing for self-reference cycles. - if (New == this) { + // Drop uniquing for self-reference cycles and deleted constants. + if (New == this || (!New && Old && isa(Old))) { if (!isResolved()) resolve(); storeDistinctInContext(); Index: test/Linker/Inputs/metadata-with-global-value-operand.ll =================================================================== --- /dev/null +++ test/Linker/Inputs/metadata-with-global-value-operand.ll @@ -0,0 +1,3 @@ +!named.null = !{!0} + +!0 = !{null} Index: test/Linker/metadata-with-global-value-operand.ll =================================================================== --- /dev/null +++ test/Linker/metadata-with-global-value-operand.ll @@ -0,0 +1,14 @@ +; RUN: llvm-link -S -o - %s %S/Inputs/metadata-with-global-value-operand.ll | FileCheck %s +; This test confirms that the !{null} from the second module doesn't get mapped +; onto the abandoned !{i1* @var} node from this module. + +; CHECK: @var = global +@var = global i1 false + +; CHECK: !named.vars = !{!0} +; CHECK: !named.null = !{!1} +!named.vars = !{!0} + +; CHECK: !0 = !{i1* @var} +; CHECK: !1 = !{null} +!0 = !{i1* @var} Index: test/Transforms/GlobalOpt/metadata.ll =================================================================== --- test/Transforms/GlobalOpt/metadata.ll +++ test/Transforms/GlobalOpt/metadata.ll @@ -28,5 +28,5 @@ ; CHECK: !named = !{![[NULL:[0-9]+]]} !0 = !{i8*** @G} -; CHECK-DAG: ![[NULL]] = !{null} +; CHECK-DAG: ![[NULL]] = distinct !{null} ; CHECK-DAG: ![[EMPTY]] = !{} Index: unittests/IR/MetadataTest.cpp =================================================================== --- unittests/IR/MetadataTest.cpp +++ unittests/IR/MetadataTest.cpp @@ -449,6 +449,40 @@ EXPECT_FALSE(Wrapped1->isDistinct()); } +TEST_F(MDNodeTest, UniquedOnDeletedOperand) { + // temp !{} + TempMDTuple T = MDTuple::getTemporary(Context, None); + + // !{temp !{}} + Metadata *Ops[] = {T.get()}; + MDTuple *N = MDTuple::get(Context, Ops); + + // !{temp !{}} => !{null} + T.reset(); + ASSERT_TRUE(N->isUniqued()); + Metadata *NullOps[] = {nullptr}; + ASSERT_EQ(N, MDTuple::get(Context, NullOps)); +} + +TEST_F(MDNodeTest, DistinctOnDeletedValueOperand) { + // i1* @GV + Type *Ty = Type::getInt1PtrTy(Context); + std::unique_ptr GV( + new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); + ConstantAsMetadata *Op = ConstantAsMetadata::get(GV.get()); + + // !{i1* @GV} + Metadata *Ops[] = {Op}; + MDTuple *N = MDTuple::get(Context, Ops); + + // !{i1* @GV} => !{null} + GV.reset(); + ASSERT_TRUE(N->isDistinct()); + ASSERT_EQ(nullptr, N->getOperand(0)); + Metadata *NullOps[] = {nullptr}; + ASSERT_NE(N, MDTuple::get(Context, NullOps)); +} + TEST_F(MDNodeTest, getDistinct) { // !{} MDNode *Empty = MDNode::get(Context, None); @@ -669,7 +703,7 @@ EXPECT_TRUE(N->isResolved()); } -TEST_F(MDNodeTest, replaceWithUniquedChangingOperand) { +TEST_F(MDNodeTest, replaceWithUniquedDeletedOperand) { // i1* @GV Type *Ty = Type::getInt1PtrTy(Context); std::unique_ptr GV( @@ -686,8 +720,33 @@ // !{i1* @GV} => !{null} GV.reset(); - ASSERT_TRUE(N->isUniqued()); + ASSERT_TRUE(N->isDistinct()); + ASSERT_EQ(nullptr, N->getOperand(0)); Metadata *NullOps[] = {nullptr}; + ASSERT_NE(N, MDTuple::get(Context, NullOps)); +} + +TEST_F(MDNodeTest, replaceWithUniquedChangedOperand) { + // i1* @GV + Type *Ty = Type::getInt1PtrTy(Context); + std::unique_ptr GV( + new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); + ConstantAsMetadata *Op = ConstantAsMetadata::get(GV.get()); + + // temp !{i1* @GV} + Metadata *Ops[] = {Op}; + MDTuple *N = MDTuple::getTemporary(Context, Ops).release(); + + // temp !{i1* @GV} => !{i1* @GV} + ASSERT_EQ(N, MDNode::replaceWithUniqued(TempMDTuple(N))); + ASSERT_TRUE(N->isUniqued()); + + // !{i1* @GV} => !{i1* @GV2} + std::unique_ptr GV2( + new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); + GV->replaceAllUsesWith(GV2.get()); + ASSERT_TRUE(N->isUniqued()); + Metadata *NullOps[] = {ConstantAsMetadata::get(GV2.get())}; ASSERT_EQ(N, MDTuple::get(Context, NullOps)); }