summaryrefslogtreecommitdiff
path: root/unittests
diff options
context:
space:
mode:
authorJeffrey Yasskin <jyasskin@google.com>2009-10-22 20:10:20 +0000
committerJeffrey Yasskin <jyasskin@google.com>2009-10-22 20:10:20 +0000
commite0a234029b1b65f21169536f4c45e83743ed3cfa (patch)
tree47c339af1f2fbc95bfa69c64488190662f759a32 /unittests
parent9d89df169027035bf692b3d397bb93cff7bdc860 (diff)
downloadllvm-e0a234029b1b65f21169536f4c45e83743ed3cfa.tar.gz
llvm-e0a234029b1b65f21169536f4c45e83743ed3cfa.tar.bz2
llvm-e0a234029b1b65f21169536f4c45e83743ed3cfa.tar.xz
Add a ValueMap<ValueOrSubclass*, T> type. ValueMap<Value*, T> is safe to use
even when keys get RAUWed and deleted during its lifetime. By default the keys act like WeakVHs, but users can pass a third template parameter to configure how updates work and whether to do anything beyond updating the map on each action. It's also possible to automatically acquire a lock around ValueMap updates triggered by RAUWs and deletes, to support the ExecutionEngine. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@84890 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests')
-rw-r--r--unittests/ADT/ValueMapTest.cpp291
1 files changed, 291 insertions, 0 deletions
diff --git a/unittests/ADT/ValueMapTest.cpp b/unittests/ADT/ValueMapTest.cpp
new file mode 100644
index 0000000000..9de340c3f3
--- /dev/null
+++ b/unittests/ADT/ValueMapTest.cpp
@@ -0,0 +1,291 @@
+//===- llvm/unittest/ADT/ValueMapTest.cpp - ValueMap unit tests -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ValueMap.h"
+
+#include "llvm/Instructions.h"
+#include "llvm/ADT/OwningPtr.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+// Test fixture
+template<typename T>
+class ValueMapTest : public testing::Test {
+protected:
+ Constant *ConstantV;
+ OwningPtr<BitCastInst> BitcastV;
+ OwningPtr<BinaryOperator> AddV;
+
+ ValueMapTest() :
+ ConstantV(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0)),
+ BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(getGlobalContext()))),
+ AddV(BinaryOperator::CreateAdd(ConstantV, ConstantV)) {
+ }
+};
+
+// Run everything on Value*, a subtype to make sure that casting works as
+// expected, and a const subtype to make sure we cast const correctly.
+typedef ::testing::Types<Value, Instruction, const Instruction> KeyTypes;
+TYPED_TEST_CASE(ValueMapTest, KeyTypes);
+
+TYPED_TEST(ValueMapTest, Null) {
+ ValueMap<TypeParam*, int> VM1;
+ VM1[NULL] = 7;
+ EXPECT_EQ(7, VM1.lookup(NULL));
+}
+
+TYPED_TEST(ValueMapTest, FollowsValue) {
+ ValueMap<TypeParam*, int> VM;
+ VM[this->BitcastV.get()] = 7;
+ EXPECT_EQ(7, VM.lookup(this->BitcastV.get()));
+ EXPECT_EQ(0, VM.count(this->AddV.get()));
+ this->BitcastV->replaceAllUsesWith(this->AddV.get());
+ EXPECT_EQ(7, VM.lookup(this->AddV.get()));
+ EXPECT_EQ(0, VM.count(this->BitcastV.get()));
+ this->AddV.reset();
+ EXPECT_EQ(0, VM.count(this->AddV.get()));
+ EXPECT_EQ(0, VM.count(this->BitcastV.get()));
+ EXPECT_EQ(0U, VM.size());
+}
+
+TYPED_TEST(ValueMapTest, OperationsWork) {
+ ValueMap<TypeParam*, int> VM;
+ ValueMap<TypeParam*, int> VM2(16);
+ typename ValueMapConfig<TypeParam*>::ExtraData Data;
+ ValueMap<TypeParam*, int> VM3(Data, 16);
+ EXPECT_TRUE(VM.empty());
+
+ VM[this->BitcastV.get()] = 7;
+
+ // Find:
+ typename ValueMap<TypeParam*, int>::iterator I =
+ VM.find(this->BitcastV.get());
+ ASSERT_TRUE(I != VM.end());
+ EXPECT_EQ(this->BitcastV.get(), I->first);
+ EXPECT_EQ(7, I->second);
+ EXPECT_TRUE(VM.find(this->AddV.get()) == VM.end());
+
+ // Const find:
+ const ValueMap<TypeParam*, int> &CVM = VM;
+ typename ValueMap<TypeParam*, int>::const_iterator CI =
+ CVM.find(this->BitcastV.get());
+ ASSERT_TRUE(CI != CVM.end());
+ EXPECT_EQ(this->BitcastV.get(), CI->first);
+ EXPECT_EQ(7, CI->second);
+ EXPECT_TRUE(CVM.find(this->AddV.get()) == CVM.end());
+
+ // Insert:
+ std::pair<typename ValueMap<TypeParam*, int>::iterator, bool> InsertResult1 =
+ VM.insert(std::make_pair(this->AddV.get(), 3));
+ EXPECT_EQ(this->AddV.get(), InsertResult1.first->first);
+ EXPECT_EQ(3, InsertResult1.first->second);
+ EXPECT_TRUE(InsertResult1.second);
+ EXPECT_EQ(true, VM.count(this->AddV.get()));
+ std::pair<typename ValueMap<TypeParam*, int>::iterator, bool> InsertResult2 =
+ VM.insert(std::make_pair(this->AddV.get(), 5));
+ EXPECT_EQ(this->AddV.get(), InsertResult2.first->first);
+ EXPECT_EQ(3, InsertResult2.first->second);
+ EXPECT_FALSE(InsertResult2.second);
+
+ // Erase:
+ VM.erase(InsertResult2.first);
+ EXPECT_EQ(false, VM.count(this->AddV.get()));
+ EXPECT_EQ(true, VM.count(this->BitcastV.get()));
+ VM.erase(this->BitcastV.get());
+ EXPECT_EQ(false, VM.count(this->BitcastV.get()));
+ EXPECT_EQ(0U, VM.size());
+
+ // Range insert:
+ SmallVector<std::pair<Instruction*, int>, 2> Elems;
+ Elems.push_back(std::make_pair(this->AddV.get(), 1));
+ Elems.push_back(std::make_pair(this->BitcastV.get(), 2));
+ VM.insert(Elems.begin(), Elems.end());
+ EXPECT_EQ(1, VM.lookup(this->AddV.get()));
+ EXPECT_EQ(2, VM.lookup(this->BitcastV.get()));
+}
+
+template<typename ExpectedType, typename VarType>
+void CompileAssertHasType(VarType) {
+ typedef char assert[is_same<ExpectedType, VarType>::value ? 1 : -1];
+}
+
+TYPED_TEST(ValueMapTest, Iteration) {
+ ValueMap<TypeParam*, int> VM;
+ VM[this->BitcastV.get()] = 2;
+ VM[this->AddV.get()] = 3;
+ size_t size = 0;
+ for (typename ValueMap<TypeParam*, int>::iterator I = VM.begin(), E = VM.end();
+ I != E; ++I) {
+ ++size;
+ std::pair<TypeParam*, int> value = *I;
+ CompileAssertHasType<TypeParam*>(I->first);
+ if (I->second == 2) {
+ EXPECT_EQ(this->BitcastV.get(), I->first);
+ I->second = 5;
+ } else if (I->second == 3) {
+ EXPECT_EQ(this->AddV.get(), I->first);
+ I->second = 6;
+ } else {
+ ADD_FAILURE() << "Iterated through an extra value.";
+ }
+ }
+ EXPECT_EQ(2U, size);
+ EXPECT_EQ(5, VM[this->BitcastV.get()]);
+ EXPECT_EQ(6, VM[this->AddV.get()]);
+
+ size = 0;
+ // Cast to const ValueMap to avoid a bug in DenseMap's iterators.
+ const ValueMap<TypeParam*, int>& CVM = VM;
+ for (typename ValueMap<TypeParam*, int>::const_iterator I = CVM.begin(),
+ E = CVM.end(); I != E; ++I) {
+ ++size;
+ std::pair<TypeParam*, int> value = *I;
+ CompileAssertHasType<TypeParam*>(I->first);
+ if (I->second == 5) {
+ EXPECT_EQ(this->BitcastV.get(), I->first);
+ } else if (I->second == 6) {
+ EXPECT_EQ(this->AddV.get(), I->first);
+ } else {
+ ADD_FAILURE() << "Iterated through an extra value.";
+ }
+ }
+ EXPECT_EQ(2U, size);
+}
+
+TYPED_TEST(ValueMapTest, DefaultCollisionBehavior) {
+ // By default, we overwrite the old value with the replaced value.
+ ValueMap<TypeParam*, int> VM;
+ VM[this->BitcastV.get()] = 7;
+ VM[this->AddV.get()] = 9;
+ this->BitcastV->replaceAllUsesWith(this->AddV.get());
+ EXPECT_EQ(0, VM.count(this->BitcastV.get()));
+ EXPECT_EQ(9, VM.lookup(this->AddV.get()));
+}
+
+TYPED_TEST(ValueMapTest, ConfiguredCollisionBehavior) {
+ // TODO: Implement this when someone needs it.
+}
+
+template<typename KeyT>
+struct LockMutex : ValueMapConfig<KeyT> {
+ struct ExtraData {
+ sys::Mutex *M;
+ bool *CalledRAUW;
+ bool *CalledDeleted;
+ };
+ static void onRAUW(const ExtraData &Data, KeyT Old, KeyT New) {
+ *Data.CalledRAUW = true;
+ EXPECT_FALSE(Data.M->tryacquire()) << "Mutex should already be locked.";
+ }
+ static void onDeleted(const ExtraData &Data, KeyT Old) {
+ *Data.CalledDeleted = true;
+ EXPECT_FALSE(Data.M->tryacquire()) << "Mutex should already be locked.";
+ }
+ static sys::Mutex *getMutex(const ExtraData &Data) { return Data.M; }
+};
+TYPED_TEST(ValueMapTest, LocksMutex) {
+ sys::Mutex M(false); // Not recursive.
+ bool CalledRAUW = false, CalledDeleted = false;
+ typename LockMutex<TypeParam*>::ExtraData Data =
+ {&M, &CalledRAUW, &CalledDeleted};
+ ValueMap<TypeParam*, int, LockMutex<TypeParam*> > VM(Data);
+ VM[this->BitcastV.get()] = 7;
+ this->BitcastV->replaceAllUsesWith(this->AddV.get());
+ this->AddV.reset();
+ EXPECT_TRUE(CalledRAUW);
+ EXPECT_TRUE(CalledDeleted);
+}
+
+template<typename KeyT>
+struct NoFollow : ValueMapConfig<KeyT> {
+ enum { FollowRAUW = false };
+};
+
+TYPED_TEST(ValueMapTest, NoFollowRAUW) {
+ ValueMap<TypeParam*, int, NoFollow<TypeParam*> > VM;
+ VM[this->BitcastV.get()] = 7;
+ EXPECT_EQ(7, VM.lookup(this->BitcastV.get()));
+ EXPECT_EQ(0, VM.count(this->AddV.get()));
+ this->BitcastV->replaceAllUsesWith(this->AddV.get());
+ EXPECT_EQ(7, VM.lookup(this->BitcastV.get()));
+ EXPECT_EQ(0, VM.lookup(this->AddV.get()));
+ this->AddV.reset();
+ EXPECT_EQ(7, VM.lookup(this->BitcastV.get()));
+ EXPECT_EQ(0, VM.lookup(this->AddV.get()));
+ this->BitcastV.reset();
+ EXPECT_EQ(0, VM.lookup(this->BitcastV.get()));
+ EXPECT_EQ(0, VM.lookup(this->AddV.get()));
+ EXPECT_EQ(0U, VM.size());
+}
+
+template<typename KeyT>
+struct CountOps : ValueMapConfig<KeyT> {
+ struct ExtraData {
+ int *Deletions;
+ int *RAUWs;
+ };
+
+ static void onRAUW(const ExtraData &Data, KeyT Old, KeyT New) {
+ ++*Data.RAUWs;
+ }
+ static void onDeleted(const ExtraData &Data, KeyT Old) {
+ ++*Data.Deletions;
+ }
+};
+
+TYPED_TEST(ValueMapTest, CallsConfig) {
+ int Deletions = 0, RAUWs = 0;
+ typename CountOps<TypeParam*>::ExtraData Data = {&Deletions, &RAUWs};
+ ValueMap<TypeParam*, int, CountOps<TypeParam*> > VM(Data);
+ VM[this->BitcastV.get()] = 7;
+ this->BitcastV->replaceAllUsesWith(this->AddV.get());
+ EXPECT_EQ(0, Deletions);
+ EXPECT_EQ(1, RAUWs);
+ this->AddV.reset();
+ EXPECT_EQ(1, Deletions);
+ EXPECT_EQ(1, RAUWs);
+ this->BitcastV.reset();
+ EXPECT_EQ(1, Deletions);
+ EXPECT_EQ(1, RAUWs);
+}
+
+template<typename KeyT>
+struct ModifyingConfig : ValueMapConfig<KeyT> {
+ // We'll put a pointer here back to the ValueMap this key is in, so
+ // that we can modify it (and clobber *this) before the ValueMap
+ // tries to do the same modification. In previous versions of
+ // ValueMap, that exploded.
+ typedef ValueMap<KeyT, int, ModifyingConfig<KeyT> > **ExtraData;
+
+ static void onRAUW(ExtraData Map, KeyT Old, KeyT New) {
+ (*Map)->erase(Old);
+ }
+ static void onDeleted(ExtraData Map, KeyT Old) {
+ (*Map)->erase(Old);
+ }
+};
+TYPED_TEST(ValueMapTest, SurvivesModificationByConfig) {
+ ValueMap<TypeParam*, int, ModifyingConfig<TypeParam*> > *MapAddress;
+ ValueMap<TypeParam*, int, ModifyingConfig<TypeParam*> > VM(&MapAddress);
+ MapAddress = &VM;
+ // Now the ModifyingConfig can modify the Map inside a callback.
+ VM[this->BitcastV.get()] = 7;
+ this->BitcastV->replaceAllUsesWith(this->AddV.get());
+ EXPECT_FALSE(VM.count(this->BitcastV.get()));
+ EXPECT_FALSE(VM.count(this->AddV.get()));
+ VM[this->AddV.get()] = 7;
+ this->AddV.reset();
+ EXPECT_FALSE(VM.count(this->AddV.get()));
+}
+
+}