| //===- 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/IR/ValueMap.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: | 
 |   LLVMContext Context; | 
 |   Constant *ConstantV; | 
 |   std::unique_ptr<BitCastInst> BitcastV; | 
 |   std::unique_ptr<BinaryOperator> AddV; | 
 |  | 
 |   ValueMapTest() | 
 |       : ConstantV(ConstantInt::get(Type::getInt32Ty(Context), 0)), | 
 |         BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(Context))), | 
 |         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[nullptr] = 7; | 
 |   EXPECT_EQ(7, VM1.lookup(nullptr)); | 
 | } | 
 |  | 
 | TYPED_TEST(ValueMapTest, FollowsValue) { | 
 |   ValueMap<TypeParam*, int> VM; | 
 |   VM[this->BitcastV.get()] = 7; | 
 |   EXPECT_EQ(7, VM.lookup(this->BitcastV.get())); | 
 |   EXPECT_EQ(0u, VM.count(this->AddV.get())); | 
 |   this->BitcastV->replaceAllUsesWith(this->AddV.get()); | 
 |   EXPECT_EQ(7, VM.lookup(this->AddV.get())); | 
 |   EXPECT_EQ(0u, VM.count(this->BitcastV.get())); | 
 |   this->AddV.reset(); | 
 |   EXPECT_EQ(0u, VM.count(this->AddV.get())); | 
 |   EXPECT_EQ(0u, 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(1u, 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) { | 
 |   static_assert(std::is_same<ExpectedType, VarType>::value, | 
 |                 "Not the same type"); | 
 | } | 
 |  | 
 | 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(0u, 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, typename MutexT> | 
 | struct LockMutex : ValueMapConfig<KeyT, MutexT> { | 
 |   struct ExtraData { | 
 |     MutexT *M; | 
 |     bool *CalledRAUW; | 
 |     bool *CalledDeleted; | 
 |   }; | 
 |   static void onRAUW(const ExtraData &Data, KeyT Old, KeyT New) { | 
 |     *Data.CalledRAUW = true; | 
 |     EXPECT_FALSE(Data.M->try_lock()) << "Mutex should already be locked."; | 
 |   } | 
 |   static void onDelete(const ExtraData &Data, KeyT Old) { | 
 |     *Data.CalledDeleted = true; | 
 |     EXPECT_FALSE(Data.M->try_lock()) << "Mutex should already be locked."; | 
 |   } | 
 |   static MutexT *getMutex(const ExtraData &Data) { return Data.M; } | 
 | }; | 
 | // FIXME: These tests started failing on Windows. | 
 | #if LLVM_ENABLE_THREADS && !defined(_WIN32) | 
 | TYPED_TEST(ValueMapTest, LocksMutex) { | 
 |   sys::Mutex M(false);  // Not recursive. | 
 |   bool CalledRAUW = false, CalledDeleted = false; | 
 |   typedef LockMutex<TypeParam*, sys::Mutex> ConfigType; | 
 |   typename ConfigType::ExtraData Data = {&M, &CalledRAUW, &CalledDeleted}; | 
 |   ValueMap<TypeParam*, int, ConfigType> 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(0u, 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_EQ(0u, VM.count(this->BitcastV.get())); | 
 |   EXPECT_EQ(0u, VM.count(this->AddV.get())); | 
 |   VM[this->AddV.get()] = 7; | 
 |   this->AddV.reset(); | 
 |   EXPECT_EQ(0u, VM.count(this->AddV.get())); | 
 | } | 
 |  | 
 | } // end namespace |