forked from OSchip/llvm-project
				
			[sanitizer] added a bit vector class to be used in a deadlock detector
llvm-svn: 201210
This commit is contained in:
		
							parent
							
								
									4c991ef3ef
								
							
						
					
					
						commit
						083d657845
					
				| 
						 | 
				
			
			@ -44,6 +44,7 @@ set(SANITIZER_HEADERS
 | 
			
		|||
  sanitizer_atomic.h
 | 
			
		||||
  sanitizer_atomic_clang.h
 | 
			
		||||
  sanitizer_atomic_msvc.h
 | 
			
		||||
  sanitizer_bitvector.h
 | 
			
		||||
  sanitizer_common.h
 | 
			
		||||
  sanitizer_common_interceptors.inc
 | 
			
		||||
  sanitizer_common_interceptors_ioctl.inc
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,143 @@
 | 
			
		|||
//===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===//
 | 
			
		||||
//
 | 
			
		||||
//                     The LLVM Compiler Infrastructure
 | 
			
		||||
//
 | 
			
		||||
// This file is distributed under the University of Illinois Open Source
 | 
			
		||||
// License. See LICENSE.TXT for details.
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
//
 | 
			
		||||
// Specializer BitVector implementation.
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
 | 
			
		||||
#ifndef SANITIZER_BITVECTOR_H
 | 
			
		||||
#define SANITIZER_BITVECTOR_H
 | 
			
		||||
 | 
			
		||||
#include "sanitizer_common.h"
 | 
			
		||||
 | 
			
		||||
namespace __sanitizer {
 | 
			
		||||
 | 
			
		||||
// Fixed size bit vector based on a single basic integer.
 | 
			
		||||
template <class basic_int_t = uptr>
 | 
			
		||||
class BasicBitVector {
 | 
			
		||||
 public:
 | 
			
		||||
  enum SizeEnum { kSize = sizeof(basic_int_t) * 8 };
 | 
			
		||||
  uptr size() const { return kSize; }
 | 
			
		||||
  // No CTOR.
 | 
			
		||||
  void clear() { bits_ = 0; }
 | 
			
		||||
  bool empty() const { return bits_ == 0; }
 | 
			
		||||
  void setBit(uptr idx) { bits_ |= mask(idx); }
 | 
			
		||||
  void clearBit(uptr idx) { bits_ &= ~mask(idx); }
 | 
			
		||||
  bool getBit(uptr idx) const { return bits_ & mask(idx); }
 | 
			
		||||
  uptr getAndClearFirstOne() {
 | 
			
		||||
    CHECK(!empty());
 | 
			
		||||
    // FIXME: change to LeastSignificantSetBitIndex?
 | 
			
		||||
    uptr idx = MostSignificantSetBitIndex(bits_);
 | 
			
		||||
    clearBit(idx);
 | 
			
		||||
    return idx;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  basic_int_t mask(uptr idx) const {
 | 
			
		||||
    CHECK_LE(idx, size());
 | 
			
		||||
    return (basic_int_t)1UL << idx;
 | 
			
		||||
  }
 | 
			
		||||
  basic_int_t bits_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Fixed size bit vector of (kLevel1Size*BV::kSize**2) bits.
 | 
			
		||||
// The implementation is optimized for a sparse bit vector, i.e. the one
 | 
			
		||||
// that has few set bits.
 | 
			
		||||
template <uptr kLevel1Size = 1, class BV = BasicBitVector<> >
 | 
			
		||||
class TwoLevelBitVector {
 | 
			
		||||
  // This is essentially a 2-level bit vector.
 | 
			
		||||
  // Set bit in the first level BV indicates that there are set bits
 | 
			
		||||
  // in the corresponding BV of the second level.
 | 
			
		||||
  // This structure allows O(kLevel1Size) time for clear() and empty(),
 | 
			
		||||
  // as well fast handling of sparse BVs.
 | 
			
		||||
 public:
 | 
			
		||||
  enum SizeEnum { kSize = BV::kSize * BV::kSize * kLevel1Size };
 | 
			
		||||
  // No CTOR.
 | 
			
		||||
  uptr size() const { return kSize; }
 | 
			
		||||
  void clear() {
 | 
			
		||||
    for (uptr i = 0; i < kLevel1Size; i++)
 | 
			
		||||
      l1_[i].clear();
 | 
			
		||||
  }
 | 
			
		||||
  bool empty() {
 | 
			
		||||
    for (uptr i = 0; i < kLevel1Size; i++)
 | 
			
		||||
      if (!l1_[i].empty())
 | 
			
		||||
        return false;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  void setBit(uptr idx) {
 | 
			
		||||
    check(idx);
 | 
			
		||||
    uptr i0 = idx0(idx);
 | 
			
		||||
    uptr i1 = idx1(idx);
 | 
			
		||||
    uptr i2 = idx2(idx);
 | 
			
		||||
    if (!l1_[i0].getBit(i1)) {
 | 
			
		||||
      l1_[i0].setBit(i1);
 | 
			
		||||
      l2_[i0][i1].clear();
 | 
			
		||||
    }
 | 
			
		||||
    l2_[i0][i1].setBit(i2);
 | 
			
		||||
    // Printf("%s: %zd => %zd %zd %zd\n", __FUNCTION__, idx, i0, i1, i2);
 | 
			
		||||
  }
 | 
			
		||||
  void clearBit(uptr idx) {
 | 
			
		||||
    check(idx);
 | 
			
		||||
    uptr i0 = idx0(idx);
 | 
			
		||||
    uptr i1 = idx1(idx);
 | 
			
		||||
    uptr i2 = idx2(idx);
 | 
			
		||||
    if (l1_[i0].getBit(i1)) {
 | 
			
		||||
      l2_[i0][i1].clearBit(i2);
 | 
			
		||||
      if (l2_[i0][i1].empty())
 | 
			
		||||
        l1_[i0].clearBit(i1);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  bool getBit(uptr idx) {
 | 
			
		||||
    check(idx);
 | 
			
		||||
    uptr i0 = idx0(idx);
 | 
			
		||||
    uptr i1 = idx1(idx);
 | 
			
		||||
    uptr i2 = idx2(idx);
 | 
			
		||||
    // Printf("%s: %zd => %zd %zd %zd\n", __FUNCTION__, idx, i0, i1, i2);
 | 
			
		||||
    return l1_[i0].getBit(i1) && l2_[i0][i1].getBit(i2);
 | 
			
		||||
  }
 | 
			
		||||
  uptr getAndClearFirstOne() {
 | 
			
		||||
    for (uptr i0 = 0; i0 < kLevel1Size; i0++) {
 | 
			
		||||
      if (l1_[i0].empty()) continue;
 | 
			
		||||
      uptr i1 = l1_[i0].getAndClearFirstOne();
 | 
			
		||||
      uptr i2 = l2_[i0][i1].getAndClearFirstOne();
 | 
			
		||||
      if (!l2_[i0][i1].empty())
 | 
			
		||||
        l1_[i0].setBit(i1);
 | 
			
		||||
      uptr res = i0 * BV::kSize * BV::kSize + i1 * BV::kSize + i2;
 | 
			
		||||
      // Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res);
 | 
			
		||||
      return res;
 | 
			
		||||
    }
 | 
			
		||||
    CHECK(0);
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  void check(uptr idx) { CHECK_LE(idx, size()); }
 | 
			
		||||
  uptr idx0(uptr idx) {
 | 
			
		||||
    uptr res = idx / (BV::kSize * BV::kSize);
 | 
			
		||||
    CHECK_LE(res, kLevel1Size);
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
  uptr idx1(uptr idx) {
 | 
			
		||||
    uptr res = (idx / BV::kSize) % BV::kSize;
 | 
			
		||||
    CHECK_LE(res, BV::kSize);
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
  uptr idx2(uptr idx) {
 | 
			
		||||
    uptr res = idx % BV::kSize;
 | 
			
		||||
    CHECK_LE(res, BV::kSize);
 | 
			
		||||
    return res;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  BV l1_[kLevel1Size];
 | 
			
		||||
  BV l2_[kLevel1Size][BV::kSize];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace __sanitizer
 | 
			
		||||
 | 
			
		||||
#endif // SANITIZER_BITVECTOR_H
 | 
			
		||||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ include(CompilerRTCompile)
 | 
			
		|||
set(SANITIZER_UNITTESTS
 | 
			
		||||
  sanitizer_allocator_test.cc
 | 
			
		||||
  sanitizer_atomic_test.cc
 | 
			
		||||
  sanitizer_bitvector_test.cc
 | 
			
		||||
  sanitizer_common_test.cc
 | 
			
		||||
  sanitizer_flags_test.cc
 | 
			
		||||
  sanitizer_format_interceptor_test.cc
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,91 @@
 | 
			
		|||
//===-- sanitizer_bitvector_test.cc ---------------------------------------===//
 | 
			
		||||
//
 | 
			
		||||
//                     The LLVM Compiler Infrastructure
 | 
			
		||||
//
 | 
			
		||||
// This file is distributed under the University of Illinois Open Source
 | 
			
		||||
// License. See LICENSE.TXT for details.
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
//
 | 
			
		||||
// This file is a part of Sanitizer runtime.
 | 
			
		||||
// Tests for sanitizer_bitvector.h.
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
#include "sanitizer_common/sanitizer_bitvector.h"
 | 
			
		||||
 | 
			
		||||
#include "sanitizer_test_utils.h"
 | 
			
		||||
 | 
			
		||||
#include "gtest/gtest.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <set>
 | 
			
		||||
 | 
			
		||||
using namespace __sanitizer;
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
template <class BV>
 | 
			
		||||
void TestBitVector(uptr expected_size) {
 | 
			
		||||
  BV bv;
 | 
			
		||||
  EXPECT_EQ(expected_size, BV::kSize);
 | 
			
		||||
  bv.clear();
 | 
			
		||||
  EXPECT_TRUE(bv.empty());
 | 
			
		||||
  bv.setBit(13);
 | 
			
		||||
  EXPECT_FALSE(bv.empty());
 | 
			
		||||
  EXPECT_FALSE(bv.getBit(12));
 | 
			
		||||
  EXPECT_FALSE(bv.getBit(14));
 | 
			
		||||
  EXPECT_TRUE(bv.getBit(13));
 | 
			
		||||
  bv.clearBit(13);
 | 
			
		||||
  EXPECT_FALSE(bv.getBit(13));
 | 
			
		||||
 | 
			
		||||
  // test random bits
 | 
			
		||||
  bv.clear();
 | 
			
		||||
  set<uptr> s;
 | 
			
		||||
  for (uptr it = 0; it < 1000; it++) {
 | 
			
		||||
    uptr bit = ((uptr)my_rand() % bv.size());
 | 
			
		||||
    EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
 | 
			
		||||
    switch (my_rand() % 2) {
 | 
			
		||||
      case 0:
 | 
			
		||||
        bv.setBit(bit);
 | 
			
		||||
        s.insert(bit);
 | 
			
		||||
        break;
 | 
			
		||||
      case 1:
 | 
			
		||||
        bv.clearBit(bit);
 | 
			
		||||
        s.erase(bit);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    EXPECT_EQ(bv.getBit(bit), s.count(bit) == 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // test getAndClearFirstOne.
 | 
			
		||||
  vector<uptr>bits(bv.size());
 | 
			
		||||
  for (uptr it = 0; it < 30; it++) {
 | 
			
		||||
    // iota
 | 
			
		||||
    for (size_t j = 0; j < bits.size(); j++) bits[j] = j;
 | 
			
		||||
    random_shuffle(bits.begin(), bits.end());
 | 
			
		||||
    uptr n_bits = ((uptr)my_rand() % bv.size()) + 1;
 | 
			
		||||
    EXPECT_TRUE(n_bits > 0 && n_bits <= bv.size());
 | 
			
		||||
    bv.clear();
 | 
			
		||||
    set<uptr> s(bits.begin(), bits.begin() + n_bits);
 | 
			
		||||
    for (uptr i = 0; i < n_bits; i++) {
 | 
			
		||||
      bv.setBit(bits[i]);
 | 
			
		||||
      s.insert(bits[i]);
 | 
			
		||||
    }
 | 
			
		||||
    while (!bv.empty()) {
 | 
			
		||||
      uptr idx = bv.getAndClearFirstOne();
 | 
			
		||||
      EXPECT_TRUE(s.erase(idx));
 | 
			
		||||
    }
 | 
			
		||||
    EXPECT_TRUE(s.empty());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(SanitizerCommon, BasicBitVector) {
 | 
			
		||||
  TestBitVector<BasicBitVector<> >(SANITIZER_WORDSIZE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(SanitizerCommon, TwoLevelBitVector) {
 | 
			
		||||
  uptr ws = SANITIZER_WORDSIZE;
 | 
			
		||||
  TestBitVector<TwoLevelBitVector<> >(ws * ws);
 | 
			
		||||
  TestBitVector<TwoLevelBitVector<2> >(ws * ws * 2);
 | 
			
		||||
  TestBitVector<TwoLevelBitVector<3> >(ws * ws * 3);
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue