IR: Add MDNode::getDistinct()
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>
Wed, 7 Jan 2015 22:24:46 +0000 (22:24 +0000)
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>
Wed, 7 Jan 2015 22:24:46 +0000 (22:24 +0000)
Allow distinct `MDNode`s to be explicitly created.  There's no way (yet)
of representing their distinctness in assembly/bitcode, however, so this
still isn't first-class.

Part of PR22111.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225406 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 4ae291321001910179ef9fcfcc0b599532951a69..a7a727fe72e1df4f1d58df8346751d829016b120 100644 (file)
@@ -621,6 +621,11 @@ public:
     return getMDNode(Context, MDs, false);
   }
 
+  /// \brief Return a distinct node.
+  ///
+  /// Return a distinct node -- i.e., a node that is not uniqued.
+  static MDNode *getDistinct(LLVMContext &Context, ArrayRef<Metadata *> MDs);
+
   /// \brief Return a temporary MDNode
   ///
   /// For use in constructing cyclic MDNode structures. A temporary MDNode is
@@ -700,7 +705,7 @@ public:
 /// RAUW.  If an operand change (due to RAUW or otherwise) causes a uniquing
 /// collision, the uniquing bit is dropped.
 ///
-/// TODO: Make uniquing opt-out (status: mandatory, sometimes dropped).
+/// TODO: Make 'distinct' survive across assembly/bitcode/ValueMap.
 class GenericMDNode : public MDNode {
   friend class Metadata;
   friend class MDNode;
@@ -717,7 +722,12 @@ class GenericMDNode : public MDNode {
   /// LLVMContext, and adding an LLVMContext reference to RMI.
   std::unique_ptr<ReplaceableMetadataImpl> ReplaceableUses;
 
-  GenericMDNode(LLVMContext &C, ArrayRef<Metadata *> Vals);
+  /// \brief Create a new node.
+  ///
+  /// If \c AllowRAUW, then if any operands are unresolved support RAUW.  RAUW
+  /// will be dropped once all operands have been resolved (or if \a
+  /// resolveCycles() is called).
+  GenericMDNode(LLVMContext &C, ArrayRef<Metadata *> Vals, bool AllowRAUW);
   ~GenericMDNode();
 
   void setHash(unsigned Hash) { MDNodeSubclassData = Hash; }
index cc3d13992b70330b82c0c5bc51d5274c302ee830..bd3805842a58ec3151be9193a00ca1d8e0610fbf 100644 (file)
@@ -411,8 +411,12 @@ static bool isOperandUnresolved(Metadata *Op) {
   return false;
 }
 
-GenericMDNode::GenericMDNode(LLVMContext &C, ArrayRef<Metadata *> Vals)
+GenericMDNode::GenericMDNode(LLVMContext &C, ArrayRef<Metadata *> Vals,
+                             bool AllowRAUW)
     : MDNode(C, GenericMDNodeKind, Vals) {
+  if (!AllowRAUW)
+    return;
+
   // Check whether any operands are unresolved, requiring re-uniquing.
   for (const auto &Op : operands())
     if (isOperandUnresolved(Op))
@@ -581,12 +585,18 @@ MDNode *MDNode::getMDNode(LLVMContext &Context, ArrayRef<Metadata *> MDs,
     return nullptr;
 
   // Coallocate space for the node and Operands together, then placement new.
-  GenericMDNode *N = new (MDs.size()) GenericMDNode(Context, MDs);
+  auto *N = new (MDs.size()) GenericMDNode(Context, MDs, /* AllowRAUW */ true);
   N->setHash(Key.Hash);
   Store.insert(N);
   return N;
 }
 
+MDNode *MDNode::getDistinct(LLVMContext &Context, ArrayRef<Metadata *> MDs) {
+  auto *N = new (MDs.size()) GenericMDNode(Context, MDs, /* AllowRAUW */ false);
+  N->storeDistinctInContext();
+  return N;
+}
+
 MDNodeFwdDecl *MDNode::getTemporary(LLVMContext &Context,
                                     ArrayRef<Metadata *> MDs) {
   MDNodeFwdDecl *N = new (MDs.size()) MDNodeFwdDecl(Context, MDs);
index 9c4403c4ce02f1c99286a9e6c113e2c920c4ffd1..2dd54e785bfdac8f8975e031b955589bd2c5628a 100644 (file)
@@ -249,6 +249,44 @@ TEST_F(MDNodeTest, DistinctOnUniquingCollision) {
   EXPECT_FALSE(Wrapped1->isDistinct());
 }
 
+TEST_F(MDNodeTest, getDistinct) {
+  // !{}
+  MDNode *Empty = MDNode::get(Context, None);
+  ASSERT_TRUE(Empty->isResolved());
+  ASSERT_FALSE(Empty->isDistinct());
+  ASSERT_EQ(Empty, MDNode::get(Context, None));
+
+  // distinct !{}
+  MDNode *Distinct1 = MDNode::getDistinct(Context, None);
+  MDNode *Distinct2 = MDNode::getDistinct(Context, None);
+  EXPECT_TRUE(Distinct1->isResolved());
+  EXPECT_TRUE(Distinct2->isDistinct());
+  EXPECT_NE(Empty, Distinct1);
+  EXPECT_NE(Empty, Distinct2);
+  EXPECT_NE(Distinct1, Distinct2);
+
+  // !{}
+  ASSERT_EQ(Empty, MDNode::get(Context, None));
+}
+
+TEST_F(MDNodeTest, getDistinctWithUnresolvedOperands) {
+  // temporary !{}
+  MDNodeFwdDecl *Temp = MDNode::getTemporary(Context, None);
+  ASSERT_FALSE(Temp->isResolved());
+
+  // distinct !{temporary !{}}
+  Metadata *Ops[] = {Temp};
+  MDNode *Distinct = MDNode::getDistinct(Context, Ops);
+  EXPECT_TRUE(Distinct->isResolved());
+  EXPECT_EQ(Temp, Distinct->getOperand(0));
+
+  // temporary !{} => !{}
+  MDNode *Empty = MDNode::get(Context, None);
+  Temp->replaceAllUsesWith(Empty);
+  MDNode::deleteTemporary(Temp);
+  EXPECT_EQ(Empty, Distinct->getOperand(0));
+}
+
 typedef MetadataTest MetadataAsValueTest;
 
 TEST_F(MetadataAsValueTest, MDNode) {