From: Duncan P. N. Exon Smith Date: Tue, 31 Mar 2015 20:50:50 +0000 (+0000) Subject: IR: Enable uniquing callbacks during MDNode::replaceWithUniqued() X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=f067a682079aea312976712e89c9bc44bbb4f80c;p=oota-llvm.git IR: Enable uniquing callbacks during MDNode::replaceWithUniqued() Uniqued nodes have more complete registration with `ReplaceableMetadataImpl` so that they can update themselves when operands change. Fix a bug where `MDNode::replaceWithUniqued()` wasn't enabling these callbacks. The two most obvious ways missing callbacks causes problems is that auto-resolution fails and re-uniquing (on changed operands) just doesn't happen. I've added tests for both -- in both cases, I confirmed that the final check was failing before the fix. rdar://problem/20365935 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@233751 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/IR/Metadata.h b/include/llvm/IR/Metadata.h index a31bdbfac65..825c11e2661 100644 --- a/include/llvm/IR/Metadata.h +++ b/include/llvm/IR/Metadata.h @@ -761,6 +761,11 @@ protected: MDOperand *mutable_begin() { return mutable_end() - NumOperands; } MDOperand *mutable_end() { return reinterpret_cast(this); } + typedef iterator_range mutable_op_range; + mutable_op_range mutable_operands() { + return mutable_op_range(mutable_begin(), mutable_end()); + } + public: static inline MDTuple *get(LLVMContext &Context, ArrayRef MDs); static inline MDTuple *getIfExists(LLVMContext &Context, diff --git a/lib/IR/Metadata.cpp b/lib/IR/Metadata.cpp index 7691ab016cc..93098b9da7e 100644 --- a/lib/IR/Metadata.cpp +++ b/lib/IR/Metadata.cpp @@ -446,6 +446,10 @@ void MDNode::makeUniqued() { assert(isTemporary() && "Expected this to be temporary"); assert(!isResolved() && "Expected this to be unresolved"); + // Enable uniquing callbacks. + for (auto &Op : mutable_operands()) + Op.reset(Op.get(), this); + // Make this 'uniqued'. Storage = Uniqued; if (!countUnresolvedOperands()) diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp index 655551af9d8..270349e226a 100644 --- a/unittests/IR/MetadataTest.cpp +++ b/unittests/IR/MetadataTest.cpp @@ -627,6 +627,48 @@ TEST_F(MDNodeTest, replaceWithUniqued) { } } +TEST_F(MDNodeTest, replaceWithUniquedUnresolved) { + // temp !{} + MDTuple *Op = MDTuple::getTemporary(Context, None).release(); + EXPECT_FALSE(Op->isResolved()); + + // temp !{temp !{}} + Metadata *Ops[] = {Op}; + MDTuple *N = MDTuple::getTemporary(Context, Ops).release(); + EXPECT_FALSE(N->isResolved()); + + // temp !{temp !{}} => !{temp !{}} + ASSERT_EQ(N, MDNode::replaceWithUniqued(TempMDTuple(N))); + EXPECT_FALSE(N->isResolved()); + + // !{temp !{}} => !{!{}} + ASSERT_EQ(Op, MDNode::replaceWithUniqued(TempMDTuple(Op))); + EXPECT_TRUE(Op->isResolved()); + EXPECT_TRUE(N->isResolved()); +} + +TEST_F(MDNodeTest, replaceWithUniquedUnresolvedChangedOperand) { + // 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} => !{null} + GV.reset(); + ASSERT_TRUE(N->isUniqued()); + Metadata *NullOps[] = {nullptr}; + ASSERT_EQ(N, MDTuple::get(Context, NullOps)); +} + TEST_F(MDNodeTest, replaceWithDistinct) { { auto *Empty = MDTuple::get(Context, None);