summaryrefslogtreecommitdiff
path: root/unittests/IR/ValueHandleTest.cpp
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2017-01-24 12:34:47 +0000
committerChandler Carruth <chandlerc@gmail.com>2017-01-24 12:34:47 +0000
commit59fff99fc0302e5f6ae40bde0767c4d8fcf48c1e (patch)
treedd645682404e49c7958f65eb51c6cb5d777a95c9 /unittests/IR/ValueHandleTest.cpp
parenta441aef21cb66b22f99f0cf2175aa2d0bf930cc3 (diff)
[PM] Introduce a PoisoningVH as a (more expensive) alternative to
AssertingVH that delays any reported error until the handle is *used*. This allows data structures to contain handles which become dangling provided the data structure is cleaned up afterward rather than used for anything interesting. The implementation is moderately horrible in part because it works to leave AssertingVH in place, undisturbed. If at some point there is consensus that this is simply how AssertingVH should be used, it can be substantially simplified. This remains a boring pointer in a non-asserts build as you would expect. The only place we pay cost is in asserts builds. I plan to use this as a basis for replacing the asserting VHs that currently dangle in the new PM until invalidation occurs in both LVI and SCEV. Differential Revision: https://reviews.llvm.org/D29061 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@292925 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/IR/ValueHandleTest.cpp')
-rw-r--r--unittests/IR/ValueHandleTest.cpp93
1 files changed, 93 insertions, 0 deletions
diff --git a/unittests/IR/ValueHandleTest.cpp b/unittests/IR/ValueHandleTest.cpp
index 59cd9d7ba37..1abc87c2fdc 100644
--- a/unittests/IR/ValueHandleTest.cpp
+++ b/unittests/IR/ValueHandleTest.cpp
@@ -412,4 +412,97 @@ TEST_F(ValueHandle, AssertingVHCheckedLast) {
BitcastV.reset();
}
+TEST_F(ValueHandle, PoisoningVH_BasicOperation) {
+ PoisoningVH<CastInst> VH(BitcastV.get());
+ CastInst *implicit_to_exact_type = VH;
+ (void)implicit_to_exact_type; // Avoid warning.
+
+ PoisoningVH<Value> GenericVH(BitcastV.get());
+ EXPECT_EQ(BitcastV.get(), GenericVH);
+ GenericVH = ConstantV;
+ EXPECT_EQ(ConstantV, GenericVH);
+
+ // Make sure I can call a method on the underlying CastInst. It
+ // doesn't matter which method.
+ EXPECT_FALSE(VH->mayWriteToMemory());
+ EXPECT_FALSE((*VH).mayWriteToMemory());
+}
+
+TEST_F(ValueHandle, PoisoningVH_Const) {
+ const CastInst *ConstBitcast = BitcastV.get();
+ PoisoningVH<const CastInst> VH(ConstBitcast);
+ const CastInst *implicit_to_exact_type = VH;
+ (void)implicit_to_exact_type; // Avoid warning.
+}
+
+TEST_F(ValueHandle, PoisoningVH_Comparisons) {
+ PoisoningVH<Value> BitcastVH(BitcastV.get());
+ PoisoningVH<Value> ConstantVH(ConstantV);
+
+ EXPECT_TRUE(BitcastVH == BitcastVH);
+ EXPECT_TRUE(BitcastV.get() == BitcastVH);
+ EXPECT_TRUE(BitcastVH == BitcastV.get());
+ EXPECT_FALSE(BitcastVH == ConstantVH);
+
+ EXPECT_TRUE(BitcastVH != ConstantVH);
+ EXPECT_TRUE(BitcastV.get() != ConstantVH);
+ EXPECT_TRUE(BitcastVH != ConstantV);
+ EXPECT_FALSE(BitcastVH != BitcastVH);
+
+ // Cast to Value* so comparisons work.
+ Value *BV = BitcastV.get();
+ Value *CV = ConstantV;
+ EXPECT_EQ(BV < CV, BitcastVH < ConstantVH);
+ EXPECT_EQ(BV <= CV, BitcastVH <= ConstantVH);
+ EXPECT_EQ(BV > CV, BitcastVH > ConstantVH);
+ EXPECT_EQ(BV >= CV, BitcastVH >= ConstantVH);
+
+ EXPECT_EQ(BV < CV, BitcastV.get() < ConstantVH);
+ EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantVH);
+ EXPECT_EQ(BV > CV, BitcastV.get() > ConstantVH);
+ EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantVH);
+
+ EXPECT_EQ(BV < CV, BitcastVH < ConstantV);
+ EXPECT_EQ(BV <= CV, BitcastVH <= ConstantV);
+ EXPECT_EQ(BV > CV, BitcastVH > ConstantV);
+ EXPECT_EQ(BV >= CV, BitcastVH >= ConstantV);
+}
+
+TEST_F(ValueHandle, PoisoningVH_DoesNotFollowRAUW) {
+ PoisoningVH<Value> VH(BitcastV.get());
+ BitcastV->replaceAllUsesWith(ConstantV);
+ EXPECT_TRUE(DenseMapInfo<PoisoningVH<Value>>::isEqual(VH, BitcastV.get()));
+}
+
+#ifdef NDEBUG
+
+TEST_F(ValueHandle, PoisoningVH_ReducesToPointer) {
+ EXPECT_EQ(sizeof(CastInst *), sizeof(PoisoningVH<CastInst>));
+}
+
+#else // !NDEBUG
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+TEST_F(ValueHandle, PoisoningVH_Asserts) {
+ PoisoningVH<Value> VH(BitcastV.get());
+
+ // The poisoned handle shouldn't assert when the value is deleted.
+ BitcastV.reset(new BitCastInst(ConstantV, Type::getInt32Ty(Context)));
+ // But should when we access the handle.
+ EXPECT_DEATH((void)*VH, "Accessed a poisoned value handle!");
+
+ // Now check that poison catches RAUW.
+ VH = BitcastV.get();
+ // The replace doesn't trigger anything immediately.
+ BitcastV->replaceAllUsesWith(ConstantV);
+ // But a use does.
+ EXPECT_DEATH((void)*VH, "Accessed a poisoned value handle!");
+
+ // Don't clear anything out here as destroying the handles should be fine.
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+#endif // NDEBUG
}