IR: Enable uniquing callbacks during MDNode::replaceWithUniqued()
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>
Tue, 31 Mar 2015 20:50:50 +0000 (20:50 +0000)
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>
Tue, 31 Mar 2015 20:50:50 +0000 (20:50 +0000)
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

include/llvm/IR/Metadata.h
lib/IR/Metadata.cpp
unittests/IR/MetadataTest.cpp

index a31bdbfac65f19f4370b504ae0e6df93c368959f..825c11e26615c1d9febc323d8c4e1227ccf98e7b 100644 (file)
@@ -761,6 +761,11 @@ protected:
   MDOperand *mutable_begin() { return mutable_end() - NumOperands; }
   MDOperand *mutable_end() { return reinterpret_cast<MDOperand *>(this); }
 
+  typedef iterator_range<MDOperand *> mutable_op_range;
+  mutable_op_range mutable_operands() {
+    return mutable_op_range(mutable_begin(), mutable_end());
+  }
+
 public:
   static inline MDTuple *get(LLVMContext &Context, ArrayRef<Metadata *> MDs);
   static inline MDTuple *getIfExists(LLVMContext &Context,
index 7691ab016cc3f5580e967350781cba0d91450571..93098b9da7ec9bd11c82cfcc94611e8973d82700 100644 (file)
@@ -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())
index 655551af9d80807ca465b32c9ddc8f64a06f12e1..270349e226a9b87661ffdae99dc44cc965db1ef6 100644 (file)
@@ -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<GlobalVariable> 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);