From: Duncan P. N. Exon Smith Date: Wed, 7 Jan 2015 22:24:46 +0000 (+0000) Subject: IR: Add MDNode::getDistinct() X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=727176d00ece26597636d52cc77c8836e0a43cf9;p=oota-llvm.git IR: Add MDNode::getDistinct() 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 --- diff --git a/include/llvm/IR/Metadata.h b/include/llvm/IR/Metadata.h index 4ae29132100..a7a727fe72e 100644 --- a/include/llvm/IR/Metadata.h +++ b/include/llvm/IR/Metadata.h @@ -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 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 ReplaceableUses; - GenericMDNode(LLVMContext &C, ArrayRef 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 Vals, bool AllowRAUW); ~GenericMDNode(); void setHash(unsigned Hash) { MDNodeSubclassData = Hash; } diff --git a/lib/IR/Metadata.cpp b/lib/IR/Metadata.cpp index cc3d13992b7..bd3805842a5 100644 --- a/lib/IR/Metadata.cpp +++ b/lib/IR/Metadata.cpp @@ -411,8 +411,12 @@ static bool isOperandUnresolved(Metadata *Op) { return false; } -GenericMDNode::GenericMDNode(LLVMContext &C, ArrayRef Vals) +GenericMDNode::GenericMDNode(LLVMContext &C, ArrayRef 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 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 MDs) { + auto *N = new (MDs.size()) GenericMDNode(Context, MDs, /* AllowRAUW */ false); + N->storeDistinctInContext(); + return N; +} + MDNodeFwdDecl *MDNode::getTemporary(LLVMContext &Context, ArrayRef MDs) { MDNodeFwdDecl *N = new (MDs.size()) MDNodeFwdDecl(Context, MDs); diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp index 9c4403c4ce0..2dd54e785bf 100644 --- a/unittests/IR/MetadataTest.cpp +++ b/unittests/IR/MetadataTest.cpp @@ -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) {