summaryrefslogtreecommitdiff
path: root/unittests/IR
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2014-03-04 11:17:44 +0000
committerChandler Carruth <chandlerc@gmail.com>2014-03-04 11:17:44 +0000
commiteb3d76da81e2148ed7c577594c873ba147f4f435 (patch)
treebcfe1da7d3cafd8e4fba57297cd7360fafc72e95 /unittests/IR
parentdf3d8e8b4dabcf0437a78a001f91208d264c2387 (diff)
downloadllvm-eb3d76da81e2148ed7c577594c873ba147f4f435.tar.gz
llvm-eb3d76da81e2148ed7c577594c873ba147f4f435.tar.bz2
llvm-eb3d76da81e2148ed7c577594c873ba147f4f435.tar.xz
[Modules] Move ValueHandle into the IR library where Value itself lives.
Move the test for this class into the IR unittests as well. This uncovers that ValueMap too is in the IR library. Ironically, the unittest for ValueMap is useless in the Support library (honestly, so was the ValueHandle test) and so it already lives in the IR unittests. Mmmm, tasty layering. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202821 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/IR')
-rw-r--r--unittests/IR/CMakeLists.txt1
-rw-r--r--unittests/IR/MetadataTest.cpp2
-rw-r--r--unittests/IR/ValueHandleTest.cpp408
3 files changed, 410 insertions, 1 deletions
diff --git a/unittests/IR/CMakeLists.txt b/unittests/IR/CMakeLists.txt
index 305079f2dd..fd8d842c80 100644
--- a/unittests/IR/CMakeLists.txt
+++ b/unittests/IR/CMakeLists.txt
@@ -19,6 +19,7 @@ set(IRSources
PatternMatch.cpp
TypeBuilderTest.cpp
TypesTest.cpp
+ ValueHandleTest.cpp
ValueMapTest.cpp
ValueTest.cpp
VerifierTest.cpp
diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp
index 352e83ee66..00a2783fbf 100644
--- a/unittests/IR/MetadataTest.cpp
+++ b/unittests/IR/MetadataTest.cpp
@@ -13,7 +13,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
-#include "llvm/Support/ValueHandle.h"
+#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
using namespace llvm;
diff --git a/unittests/IR/ValueHandleTest.cpp b/unittests/IR/ValueHandleTest.cpp
new file mode 100644
index 0000000000..bbca701776
--- /dev/null
+++ b/unittests/IR/ValueHandleTest.cpp
@@ -0,0 +1,408 @@
+//===- ValueHandleTest.cpp - ValueHandle tests ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/ValueHandle.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "gtest/gtest.h"
+#include <memory>
+
+using namespace llvm;
+
+namespace {
+
+class ValueHandle : public testing::Test {
+protected:
+ Constant *ConstantV;
+ std::auto_ptr<BitCastInst> BitcastV;
+
+ ValueHandle() :
+ ConstantV(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0)),
+ BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(getGlobalContext()))) {
+ }
+};
+
+class ConcreteCallbackVH : public CallbackVH {
+public:
+ ConcreteCallbackVH(Value *V) : CallbackVH(V) {}
+};
+
+TEST_F(ValueHandle, WeakVH_BasicOperation) {
+ WeakVH WVH(BitcastV.get());
+ EXPECT_EQ(BitcastV.get(), WVH);
+ WVH = ConstantV;
+ EXPECT_EQ(ConstantV, WVH);
+
+ // Make sure I can call a method on the underlying Value. It
+ // doesn't matter which method.
+ EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), WVH->getType());
+ EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (*WVH).getType());
+}
+
+TEST_F(ValueHandle, WeakVH_Comparisons) {
+ WeakVH BitcastWVH(BitcastV.get());
+ WeakVH ConstantWVH(ConstantV);
+
+ EXPECT_TRUE(BitcastWVH == BitcastWVH);
+ EXPECT_TRUE(BitcastV.get() == BitcastWVH);
+ EXPECT_TRUE(BitcastWVH == BitcastV.get());
+ EXPECT_FALSE(BitcastWVH == ConstantWVH);
+
+ EXPECT_TRUE(BitcastWVH != ConstantWVH);
+ EXPECT_TRUE(BitcastV.get() != ConstantWVH);
+ EXPECT_TRUE(BitcastWVH != ConstantV);
+ EXPECT_FALSE(BitcastWVH != BitcastWVH);
+
+ // Cast to Value* so comparisons work.
+ Value *BV = BitcastV.get();
+ Value *CV = ConstantV;
+ EXPECT_EQ(BV < CV, BitcastWVH < ConstantWVH);
+ EXPECT_EQ(BV <= CV, BitcastWVH <= ConstantWVH);
+ EXPECT_EQ(BV > CV, BitcastWVH > ConstantWVH);
+ EXPECT_EQ(BV >= CV, BitcastWVH >= ConstantWVH);
+
+ EXPECT_EQ(BV < CV, BitcastV.get() < ConstantWVH);
+ EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantWVH);
+ EXPECT_EQ(BV > CV, BitcastV.get() > ConstantWVH);
+ EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantWVH);
+
+ EXPECT_EQ(BV < CV, BitcastWVH < ConstantV);
+ EXPECT_EQ(BV <= CV, BitcastWVH <= ConstantV);
+ EXPECT_EQ(BV > CV, BitcastWVH > ConstantV);
+ EXPECT_EQ(BV >= CV, BitcastWVH >= ConstantV);
+}
+
+TEST_F(ValueHandle, WeakVH_FollowsRAUW) {
+ WeakVH WVH(BitcastV.get());
+ WeakVH WVH_Copy(WVH);
+ WeakVH WVH_Recreated(BitcastV.get());
+ BitcastV->replaceAllUsesWith(ConstantV);
+ EXPECT_EQ(ConstantV, WVH);
+ EXPECT_EQ(ConstantV, WVH_Copy);
+ EXPECT_EQ(ConstantV, WVH_Recreated);
+}
+
+TEST_F(ValueHandle, WeakVH_NullOnDeletion) {
+ WeakVH WVH(BitcastV.get());
+ WeakVH WVH_Copy(WVH);
+ WeakVH WVH_Recreated(BitcastV.get());
+ BitcastV.reset();
+ Value *null_value = NULL;
+ EXPECT_EQ(null_value, WVH);
+ EXPECT_EQ(null_value, WVH_Copy);
+ EXPECT_EQ(null_value, WVH_Recreated);
+}
+
+
+TEST_F(ValueHandle, AssertingVH_BasicOperation) {
+ AssertingVH<CastInst> AVH(BitcastV.get());
+ CastInst *implicit_to_exact_type = AVH;
+ (void)implicit_to_exact_type; // Avoid warning.
+
+ AssertingVH<Value> GenericAVH(BitcastV.get());
+ EXPECT_EQ(BitcastV.get(), GenericAVH);
+ GenericAVH = ConstantV;
+ EXPECT_EQ(ConstantV, GenericAVH);
+
+ // Make sure I can call a method on the underlying CastInst. It
+ // doesn't matter which method.
+ EXPECT_FALSE(AVH->mayWriteToMemory());
+ EXPECT_FALSE((*AVH).mayWriteToMemory());
+}
+
+TEST_F(ValueHandle, AssertingVH_Const) {
+ const CastInst *ConstBitcast = BitcastV.get();
+ AssertingVH<const CastInst> AVH(ConstBitcast);
+ const CastInst *implicit_to_exact_type = AVH;
+ (void)implicit_to_exact_type; // Avoid warning.
+}
+
+TEST_F(ValueHandle, AssertingVH_Comparisons) {
+ AssertingVH<Value> BitcastAVH(BitcastV.get());
+ AssertingVH<Value> ConstantAVH(ConstantV);
+
+ EXPECT_TRUE(BitcastAVH == BitcastAVH);
+ EXPECT_TRUE(BitcastV.get() == BitcastAVH);
+ EXPECT_TRUE(BitcastAVH == BitcastV.get());
+ EXPECT_FALSE(BitcastAVH == ConstantAVH);
+
+ EXPECT_TRUE(BitcastAVH != ConstantAVH);
+ EXPECT_TRUE(BitcastV.get() != ConstantAVH);
+ EXPECT_TRUE(BitcastAVH != ConstantV);
+ EXPECT_FALSE(BitcastAVH != BitcastAVH);
+
+ // Cast to Value* so comparisons work.
+ Value *BV = BitcastV.get();
+ Value *CV = ConstantV;
+ EXPECT_EQ(BV < CV, BitcastAVH < ConstantAVH);
+ EXPECT_EQ(BV <= CV, BitcastAVH <= ConstantAVH);
+ EXPECT_EQ(BV > CV, BitcastAVH > ConstantAVH);
+ EXPECT_EQ(BV >= CV, BitcastAVH >= ConstantAVH);
+
+ EXPECT_EQ(BV < CV, BitcastV.get() < ConstantAVH);
+ EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantAVH);
+ EXPECT_EQ(BV > CV, BitcastV.get() > ConstantAVH);
+ EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantAVH);
+
+ EXPECT_EQ(BV < CV, BitcastAVH < ConstantV);
+ EXPECT_EQ(BV <= CV, BitcastAVH <= ConstantV);
+ EXPECT_EQ(BV > CV, BitcastAVH > ConstantV);
+ EXPECT_EQ(BV >= CV, BitcastAVH >= ConstantV);
+}
+
+TEST_F(ValueHandle, AssertingVH_DoesNotFollowRAUW) {
+ AssertingVH<Value> AVH(BitcastV.get());
+ BitcastV->replaceAllUsesWith(ConstantV);
+ EXPECT_EQ(BitcastV.get(), AVH);
+}
+
+#ifdef NDEBUG
+
+TEST_F(ValueHandle, AssertingVH_ReducesToPointer) {
+ EXPECT_EQ(sizeof(CastInst *), sizeof(AssertingVH<CastInst>));
+}
+
+#else // !NDEBUG
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+TEST_F(ValueHandle, AssertingVH_Asserts) {
+ AssertingVH<Value> AVH(BitcastV.get());
+ EXPECT_DEATH({BitcastV.reset();},
+ "An asserting value handle still pointed to this value!");
+ AssertingVH<Value> Copy(AVH);
+ AVH = NULL;
+ EXPECT_DEATH({BitcastV.reset();},
+ "An asserting value handle still pointed to this value!");
+ Copy = NULL;
+ BitcastV.reset();
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+#endif // NDEBUG
+
+TEST_F(ValueHandle, CallbackVH_BasicOperation) {
+ ConcreteCallbackVH CVH(BitcastV.get());
+ EXPECT_EQ(BitcastV.get(), CVH);
+ CVH = ConstantV;
+ EXPECT_EQ(ConstantV, CVH);
+
+ // Make sure I can call a method on the underlying Value. It
+ // doesn't matter which method.
+ EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), CVH->getType());
+ EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (*CVH).getType());
+}
+
+TEST_F(ValueHandle, CallbackVH_Comparisons) {
+ ConcreteCallbackVH BitcastCVH(BitcastV.get());
+ ConcreteCallbackVH ConstantCVH(ConstantV);
+
+ EXPECT_TRUE(BitcastCVH == BitcastCVH);
+ EXPECT_TRUE(BitcastV.get() == BitcastCVH);
+ EXPECT_TRUE(BitcastCVH == BitcastV.get());
+ EXPECT_FALSE(BitcastCVH == ConstantCVH);
+
+ EXPECT_TRUE(BitcastCVH != ConstantCVH);
+ EXPECT_TRUE(BitcastV.get() != ConstantCVH);
+ EXPECT_TRUE(BitcastCVH != ConstantV);
+ EXPECT_FALSE(BitcastCVH != BitcastCVH);
+
+ // Cast to Value* so comparisons work.
+ Value *BV = BitcastV.get();
+ Value *CV = ConstantV;
+ EXPECT_EQ(BV < CV, BitcastCVH < ConstantCVH);
+ EXPECT_EQ(BV <= CV, BitcastCVH <= ConstantCVH);
+ EXPECT_EQ(BV > CV, BitcastCVH > ConstantCVH);
+ EXPECT_EQ(BV >= CV, BitcastCVH >= ConstantCVH);
+
+ EXPECT_EQ(BV < CV, BitcastV.get() < ConstantCVH);
+ EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantCVH);
+ EXPECT_EQ(BV > CV, BitcastV.get() > ConstantCVH);
+ EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantCVH);
+
+ EXPECT_EQ(BV < CV, BitcastCVH < ConstantV);
+ EXPECT_EQ(BV <= CV, BitcastCVH <= ConstantV);
+ EXPECT_EQ(BV > CV, BitcastCVH > ConstantV);
+ EXPECT_EQ(BV >= CV, BitcastCVH >= ConstantV);
+}
+
+TEST_F(ValueHandle, CallbackVH_CallbackOnDeletion) {
+ class RecordingVH : public CallbackVH {
+ public:
+ int DeletedCalls;
+ int AURWCalls;
+
+ RecordingVH() : DeletedCalls(0), AURWCalls(0) {}
+ RecordingVH(Value *V) : CallbackVH(V), DeletedCalls(0), AURWCalls(0) {}
+
+ private:
+ virtual void deleted() { DeletedCalls++; CallbackVH::deleted(); }
+ virtual void allUsesReplacedWith(Value *) { AURWCalls++; }
+ };
+
+ RecordingVH RVH;
+ RVH = BitcastV.get();
+ EXPECT_EQ(0, RVH.DeletedCalls);
+ EXPECT_EQ(0, RVH.AURWCalls);
+ BitcastV.reset();
+ EXPECT_EQ(1, RVH.DeletedCalls);
+ EXPECT_EQ(0, RVH.AURWCalls);
+}
+
+TEST_F(ValueHandle, CallbackVH_CallbackOnRAUW) {
+ class RecordingVH : public CallbackVH {
+ public:
+ int DeletedCalls;
+ Value *AURWArgument;
+
+ RecordingVH() : DeletedCalls(0), AURWArgument(NULL) {}
+ RecordingVH(Value *V)
+ : CallbackVH(V), DeletedCalls(0), AURWArgument(NULL) {}
+
+ private:
+ virtual void deleted() { DeletedCalls++; CallbackVH::deleted(); }
+ virtual void allUsesReplacedWith(Value *new_value) {
+ EXPECT_EQ(NULL, AURWArgument);
+ AURWArgument = new_value;
+ }
+ };
+
+ RecordingVH RVH;
+ RVH = BitcastV.get();
+ EXPECT_EQ(0, RVH.DeletedCalls);
+ EXPECT_EQ(NULL, RVH.AURWArgument);
+ BitcastV->replaceAllUsesWith(ConstantV);
+ EXPECT_EQ(0, RVH.DeletedCalls);
+ EXPECT_EQ(ConstantV, RVH.AURWArgument);
+}
+
+TEST_F(ValueHandle, CallbackVH_DeletionCanRAUW) {
+ class RecoveringVH : public CallbackVH {
+ public:
+ int DeletedCalls;
+ Value *AURWArgument;
+ LLVMContext *Context;
+
+ RecoveringVH() : DeletedCalls(0), AURWArgument(NULL),
+ Context(&getGlobalContext()) {}
+ RecoveringVH(Value *V)
+ : CallbackVH(V), DeletedCalls(0), AURWArgument(NULL),
+ Context(&getGlobalContext()) {}
+
+ private:
+ virtual void deleted() {
+ getValPtr()->replaceAllUsesWith(Constant::getNullValue(Type::getInt32Ty(getGlobalContext())));
+ setValPtr(NULL);
+ }
+ virtual void allUsesReplacedWith(Value *new_value) {
+ ASSERT_TRUE(NULL != getValPtr());
+ EXPECT_EQ(1U, getValPtr()->getNumUses());
+ EXPECT_EQ(NULL, AURWArgument);
+ AURWArgument = new_value;
+ }
+ };
+
+ // Normally, if a value has uses, deleting it will crash. However, we can use
+ // a CallbackVH to remove the uses before the check for no uses.
+ RecoveringVH RVH;
+ RVH = BitcastV.get();
+ std::auto_ptr<BinaryOperator> BitcastUser(
+ BinaryOperator::CreateAdd(RVH,
+ Constant::getNullValue(Type::getInt32Ty(getGlobalContext()))));
+ EXPECT_EQ(BitcastV.get(), BitcastUser->getOperand(0));
+ BitcastV.reset(); // Would crash without the ValueHandler.
+ EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(getGlobalContext())), RVH.AURWArgument);
+ EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(getGlobalContext())),
+ BitcastUser->getOperand(0));
+}
+
+TEST_F(ValueHandle, DestroyingOtherVHOnSameValueDoesntBreakIteration) {
+ // When a CallbackVH modifies other ValueHandles in its callbacks,
+ // that shouldn't interfere with non-modified ValueHandles receiving
+ // their appropriate callbacks.
+ //
+ // We create the active CallbackVH in the middle of a palindromic
+ // arrangement of other VHs so that the bad behavior would be
+ // triggered in whichever order callbacks run.
+
+ class DestroyingVH : public CallbackVH {
+ public:
+ OwningPtr<WeakVH> ToClear[2];
+ DestroyingVH(Value *V) {
+ ToClear[0].reset(new WeakVH(V));
+ setValPtr(V);
+ ToClear[1].reset(new WeakVH(V));
+ }
+ virtual void deleted() {
+ ToClear[0].reset();
+ ToClear[1].reset();
+ CallbackVH::deleted();
+ }
+ virtual void allUsesReplacedWith(Value *) {
+ ToClear[0].reset();
+ ToClear[1].reset();
+ }
+ };
+
+ {
+ WeakVH ShouldBeVisited1(BitcastV.get());
+ DestroyingVH C(BitcastV.get());
+ WeakVH ShouldBeVisited2(BitcastV.get());
+
+ BitcastV->replaceAllUsesWith(ConstantV);
+ EXPECT_EQ(ConstantV, static_cast<Value*>(ShouldBeVisited1));
+ EXPECT_EQ(ConstantV, static_cast<Value*>(ShouldBeVisited2));
+ }
+
+ {
+ WeakVH ShouldBeVisited1(BitcastV.get());
+ DestroyingVH C(BitcastV.get());
+ WeakVH ShouldBeVisited2(BitcastV.get());
+
+ BitcastV.reset();
+ EXPECT_EQ(NULL, static_cast<Value*>(ShouldBeVisited1));
+ EXPECT_EQ(NULL, static_cast<Value*>(ShouldBeVisited2));
+ }
+}
+
+TEST_F(ValueHandle, AssertingVHCheckedLast) {
+ // If a CallbackVH exists to clear out a group of AssertingVHs on
+ // Value deletion, the CallbackVH should get a chance to do so
+ // before the AssertingVHs assert.
+
+ class ClearingVH : public CallbackVH {
+ public:
+ AssertingVH<Value> *ToClear[2];
+ ClearingVH(Value *V,
+ AssertingVH<Value> &A0, AssertingVH<Value> &A1)
+ : CallbackVH(V) {
+ ToClear[0] = &A0;
+ ToClear[1] = &A1;
+ }
+
+ virtual void deleted() {
+ *ToClear[0] = 0;
+ *ToClear[1] = 0;
+ CallbackVH::deleted();
+ }
+ };
+
+ AssertingVH<Value> A1, A2;
+ A1 = BitcastV.get();
+ ClearingVH C(BitcastV.get(), A1, A2);
+ A2 = BitcastV.get();
+ // C.deleted() should run first, clearing the two AssertingVHs,
+ // which should prevent them from asserting.
+ BitcastV.reset();
+}
+
+}