summaryrefslogtreecommitdiffstats
path: root/llvm/unittests/IR/MetadataTest.cpp
diff options
context:
space:
mode:
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>2015-01-12 19:22:04 +0000
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>2015-01-12 19:22:04 +0000
commit5f4618923cce10f1b2c3e7e646a986d3bcf43a73 (patch)
tree017631c6c219b4baea17c4c77449fec2b85f8e3d /llvm/unittests/IR/MetadataTest.cpp
parent967629e14abc76ecf8f6516ae6fd6b4a0069170a (diff)
downloadbcm5719-llvm-5f4618923cce10f1b2c3e7e646a986d3bcf43a73.tar.gz
bcm5719-llvm-5f4618923cce10f1b2c3e7e646a986d3bcf43a73.zip
IR: Add test for handleChangedOperand() recursion
Turns out this can happen. Remove the `FIXME` and add a testcase that crashes without the extra logic. llvm-svn: 225657
Diffstat (limited to 'llvm/unittests/IR/MetadataTest.cpp')
-rw-r--r--llvm/unittests/IR/MetadataTest.cpp63
1 files changed, 63 insertions, 0 deletions
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index a09cc9cfd7d..ecda5e8820e 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -293,6 +293,69 @@ TEST_F(MDNodeTest, getDistinctWithUnresolvedOperands) {
EXPECT_EQ(Empty, Distinct->getOperand(0));
}
+TEST_F(MDNodeTest, handleChangedOperandRecursion) {
+ // !0 = !{}
+ MDNode *N0 = MDNode::get(Context, None);
+
+ // !1 = !{!3, null}
+ MDNodeFwdDecl *Temp3 = MDNode::getTemporary(Context, None);
+ Metadata *Ops1[] = {Temp3, nullptr};
+ MDNode *N1 = MDNode::get(Context, Ops1);
+
+ // !2 = !{!3, !0}
+ Metadata *Ops2[] = {Temp3, N0};
+ MDNode *N2 = MDNode::get(Context, Ops2);
+
+ // !3 = !{!2}
+ Metadata *Ops3[] = {N2};
+ MDNode *N3 = MDNode::get(Context, Ops3);
+ Temp3->replaceAllUsesWith(N3);
+
+ // !4 = !{!1}
+ Metadata *Ops4[] = {N1};
+ MDNode *N4 = MDNode::get(Context, Ops4);
+
+ // Confirm that the cycle prevented RAUW from getting dropped.
+ EXPECT_TRUE(N0->isResolved());
+ EXPECT_FALSE(N1->isResolved());
+ EXPECT_FALSE(N2->isResolved());
+ EXPECT_FALSE(N3->isResolved());
+ EXPECT_FALSE(N4->isResolved());
+
+ // Create a couple of distinct nodes to observe what's going on.
+ //
+ // !5 = distinct !{!2}
+ // !6 = distinct !{!3}
+ Metadata *Ops5[] = {N2};
+ MDNode *N5 = MDNode::getDistinct(Context, Ops5);
+ Metadata *Ops6[] = {N3};
+ MDNode *N6 = MDNode::getDistinct(Context, Ops6);
+
+ // Mutate !2 to look like !1, causing a uniquing collision (and an RAUW).
+ // This will ripple up, with !3 colliding with !4, and RAUWing. Since !2
+ // references !3, this can cause a re-entry of handleChangedOperand() when !3
+ // is not ready for it.
+ //
+ // !2->replaceOperandWith(1, nullptr)
+ // !2: !{!3, !0} => !{!3, null}
+ // !2->replaceAllUsesWith(!1)
+ // !3: !{!2] => !{!1}
+ // !3->replaceAllUsesWith(!4)
+ N2->replaceOperandWith(1, nullptr);
+
+ // If all has gone well, N2 and N3 will have been RAUW'ed and deleted from
+ // under us. Just check that the other nodes are sane.
+ //
+ // !1 = !{!4, null}
+ // !4 = !{!1}
+ // !5 = distinct !{!1}
+ // !6 = distinct !{!4}
+ EXPECT_EQ(N4, N1->getOperand(0));
+ EXPECT_EQ(N1, N4->getOperand(0));
+ EXPECT_EQ(N1, N5->getOperand(0));
+ EXPECT_EQ(N4, N6->getOperand(0));
+}
+
typedef MetadataTest MetadataAsValueTest;
TEST_F(MetadataAsValueTest, MDNode) {
OpenPOWER on IntegriCloud