llvm.org GIT mirror llvm / testing unittests / IR / ValueMapTest.cpp
testing

Tree @testing (Download .tar.gz)

ValueMapTest.cpp @testing

71a5c22
 
 
 
 
 
 
 
 
7225e27
5a88dda
0b8c9a8
 
 
71a5c22
 
 
 
 
 
 
 
 
 
8be7707
71a5c22
f4ccd11
 
71a5c22
8be7707
 
 
 
71a5c22
 
 
 
 
 
 
 
 
b177041
 
71a5c22
 
 
 
 
 
20dead8
71a5c22
 
20dead8
71a5c22
20dead8
 
71a5c22
 
 
 
 
a07cd90
71a5c22
a07cd90
71a5c22
 
 
 
 
 
 
 
e541528
71a5c22
e541528
71a5c22
 
 
 
 
 
e541528
71a5c22
 
 
 
 
 
e541528
71a5c22
 
20dead8
71a5c22
 
e541528
71a5c22
 
 
 
 
3732396
 
71a5c22
3732396
71a5c22
 
 
 
 
 
 
 
 
 
 
 
 
1dd3111
 
71a5c22
 
 
 
 
 
 
 
 
 
a07cd90
71a5c22
 
e541528
71a5c22
 
e541528
71a5c22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a07cd90
71a5c22
 
e541528
71a5c22
e541528
71a5c22
 
 
 
 
 
 
 
 
 
 
 
 
20dead8
71a5c22
 
 
 
 
 
 
84fea77
 
71a5c22
4072aa3
71a5c22
 
 
 
 
d930a30
71a5c22
4ab74cd
71a5c22
d930a30
71a5c22
4072aa3
71a5c22
0123b6e
 
71a5c22
91e18f7
71a5c22
91e18f7
84fea77
 
71a5c22
 
 
 
 
 
b83012a
71a5c22
 
 
 
 
 
 
 
 
 
20dead8
71a5c22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4ab74cd
71a5c22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4ab74cd
71a5c22
 
 
 
 
 
 
 
 
 
20dead8
 
71a5c22
 
20dead8
71a5c22
 
ec78cb0
//===- 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(LLVM_ON_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