|  | //===- 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/Constants.h" | 
|  | #include "llvm/Instructions.h" | 
|  | #include "llvm/LLVMContext.h" | 
|  | #include "llvm/ADT/OwningPtr.h" | 
|  | #include "llvm/Config/config.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);  (void)VM2; | 
|  | typename ValueMapConfig<TypeParam*>::ExtraData Data; | 
|  | ValueMap<TypeParam*, int> VM3(Data, 16);  (void)VM3; | 
|  | 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(0U, VM.count(this->AddV.get())); | 
|  | EXPECT_EQ(1U, VM.count(this->BitcastV.get())); | 
|  | VM.erase(this->BitcastV.get()); | 
|  | EXPECT_EQ(0U, 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; (void)value; | 
|  | 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;  (void)value; | 
|  | 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 onDelete(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; } | 
|  | }; | 
|  | #if ENABLE_THREADS | 
|  | 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); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | 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 onDelete(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 onDelete(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())); | 
|  | } | 
|  |  | 
|  | } |