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
/// 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;
/// 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; }
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))
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);
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) {