| //===- 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/ADT/OwningPtr.h" |
| #include "llvm/Config/llvm-config.h" |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/IR/LLVMContext.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 LLVM_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())); |
| } |
| |
| } |