diff options
author | Duncan P. N. Exon Smith <dexonsmith@apple.com> | 2015-01-12 19:22:04 +0000 |
---|---|---|
committer | Duncan P. N. Exon Smith <dexonsmith@apple.com> | 2015-01-12 19:22:04 +0000 |
commit | 5f4618923cce10f1b2c3e7e646a986d3bcf43a73 (patch) | |
tree | 017631c6c219b4baea17c4c77449fec2b85f8e3d /llvm/unittests/IR/MetadataTest.cpp | |
parent | 967629e14abc76ecf8f6516ae6fd6b4a0069170a (diff) | |
download | bcm5719-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.cpp | 63 |
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) { |