10b57cec5SDimitry Andric //===-- sanitizer_bitvector.h -----------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // Specializer BitVector implementation. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #ifndef SANITIZER_BITVECTOR_H 140b57cec5SDimitry Andric #define SANITIZER_BITVECTOR_H 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "sanitizer_common.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric namespace __sanitizer { 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric // Fixed size bit vector based on a single basic integer. 210b57cec5SDimitry Andric template <class basic_int_t = uptr> 220b57cec5SDimitry Andric class BasicBitVector { 230b57cec5SDimitry Andric public: 240b57cec5SDimitry Andric enum SizeEnum : uptr { kSize = sizeof(basic_int_t) * 8 }; 250b57cec5SDimitry Andric size()260b57cec5SDimitry Andric uptr size() const { return kSize; } 270b57cec5SDimitry Andric // No CTOR. clear()280b57cec5SDimitry Andric void clear() { bits_ = 0; } setAll()290b57cec5SDimitry Andric void setAll() { bits_ = ~(basic_int_t)0; } empty()300b57cec5SDimitry Andric bool empty() const { return bits_ == 0; } 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric // Returns true if the bit has changed from 0 to 1. setBit(uptr idx)330b57cec5SDimitry Andric bool setBit(uptr idx) { 340b57cec5SDimitry Andric basic_int_t old = bits_; 350b57cec5SDimitry Andric bits_ |= mask(idx); 360b57cec5SDimitry Andric return bits_ != old; 370b57cec5SDimitry Andric } 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric // Returns true if the bit has changed from 1 to 0. clearBit(uptr idx)400b57cec5SDimitry Andric bool clearBit(uptr idx) { 410b57cec5SDimitry Andric basic_int_t old = bits_; 420b57cec5SDimitry Andric bits_ &= ~mask(idx); 430b57cec5SDimitry Andric return bits_ != old; 440b57cec5SDimitry Andric } 450b57cec5SDimitry Andric getBit(uptr idx)460b57cec5SDimitry Andric bool getBit(uptr idx) const { return (bits_ & mask(idx)) != 0; } 470b57cec5SDimitry Andric getAndClearFirstOne()480b57cec5SDimitry Andric uptr getAndClearFirstOne() { 490b57cec5SDimitry Andric CHECK(!empty()); 500b57cec5SDimitry Andric uptr idx = LeastSignificantSetBitIndex(bits_); 510b57cec5SDimitry Andric clearBit(idx); 520b57cec5SDimitry Andric return idx; 530b57cec5SDimitry Andric } 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric // Do "this |= v" and return whether new bits have been added. setUnion(const BasicBitVector & v)560b57cec5SDimitry Andric bool setUnion(const BasicBitVector &v) { 570b57cec5SDimitry Andric basic_int_t old = bits_; 580b57cec5SDimitry Andric bits_ |= v.bits_; 590b57cec5SDimitry Andric return bits_ != old; 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric // Do "this &= v" and return whether any bits have been removed. setIntersection(const BasicBitVector & v)630b57cec5SDimitry Andric bool setIntersection(const BasicBitVector &v) { 640b57cec5SDimitry Andric basic_int_t old = bits_; 650b57cec5SDimitry Andric bits_ &= v.bits_; 660b57cec5SDimitry Andric return bits_ != old; 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric // Do "this &= ~v" and return whether any bits have been removed. setDifference(const BasicBitVector & v)700b57cec5SDimitry Andric bool setDifference(const BasicBitVector &v) { 710b57cec5SDimitry Andric basic_int_t old = bits_; 720b57cec5SDimitry Andric bits_ &= ~v.bits_; 730b57cec5SDimitry Andric return bits_ != old; 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric copyFrom(const BasicBitVector & v)760b57cec5SDimitry Andric void copyFrom(const BasicBitVector &v) { bits_ = v.bits_; } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric // Returns true if 'this' intersects with 'v'. intersectsWith(const BasicBitVector & v)790b57cec5SDimitry Andric bool intersectsWith(const BasicBitVector &v) const { 800b57cec5SDimitry Andric return (bits_ & v.bits_) != 0; 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric // for (BasicBitVector<>::Iterator it(bv); it.hasNext();) { 840b57cec5SDimitry Andric // uptr idx = it.next(); 850b57cec5SDimitry Andric // use(idx); 860b57cec5SDimitry Andric // } 870b57cec5SDimitry Andric class Iterator { 880b57cec5SDimitry Andric public: Iterator()890b57cec5SDimitry Andric Iterator() { } Iterator(const BasicBitVector & bv)900b57cec5SDimitry Andric explicit Iterator(const BasicBitVector &bv) : bv_(bv) {} hasNext()910b57cec5SDimitry Andric bool hasNext() const { return !bv_.empty(); } next()920b57cec5SDimitry Andric uptr next() { return bv_.getAndClearFirstOne(); } clear()930b57cec5SDimitry Andric void clear() { bv_.clear(); } 940b57cec5SDimitry Andric private: 950b57cec5SDimitry Andric BasicBitVector bv_; 960b57cec5SDimitry Andric }; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric private: mask(uptr idx)990b57cec5SDimitry Andric basic_int_t mask(uptr idx) const { 1000b57cec5SDimitry Andric CHECK_LT(idx, size()); 1010b57cec5SDimitry Andric return (basic_int_t)1UL << idx; 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric basic_int_t bits_; 1040b57cec5SDimitry Andric }; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric // Fixed size bit vector of (kLevel1Size*BV::kSize**2) bits. 1070b57cec5SDimitry Andric // The implementation is optimized for better performance on 1080b57cec5SDimitry Andric // sparse bit vectors, i.e. the those with few set bits. 1090b57cec5SDimitry Andric template <uptr kLevel1Size = 1, class BV = BasicBitVector<> > 1100b57cec5SDimitry Andric class TwoLevelBitVector { 1110b57cec5SDimitry Andric // This is essentially a 2-level bit vector. 1120b57cec5SDimitry Andric // Set bit in the first level BV indicates that there are set bits 1130b57cec5SDimitry Andric // in the corresponding BV of the second level. 1140b57cec5SDimitry Andric // This structure allows O(kLevel1Size) time for clear() and empty(), 1150b57cec5SDimitry Andric // as well fast handling of sparse BVs. 1160b57cec5SDimitry Andric public: 1170b57cec5SDimitry Andric enum SizeEnum : uptr { kSize = BV::kSize * BV::kSize * kLevel1Size }; 1180b57cec5SDimitry Andric // No CTOR. 1190b57cec5SDimitry Andric size()1200b57cec5SDimitry Andric uptr size() const { return kSize; } 1210b57cec5SDimitry Andric clear()1220b57cec5SDimitry Andric void clear() { 1230b57cec5SDimitry Andric for (uptr i = 0; i < kLevel1Size; i++) 1240b57cec5SDimitry Andric l1_[i].clear(); 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric setAll()1270b57cec5SDimitry Andric void setAll() { 1280b57cec5SDimitry Andric for (uptr i0 = 0; i0 < kLevel1Size; i0++) { 1290b57cec5SDimitry Andric l1_[i0].setAll(); 1300b57cec5SDimitry Andric for (uptr i1 = 0; i1 < BV::kSize; i1++) 1310b57cec5SDimitry Andric l2_[i0][i1].setAll(); 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric empty()1350b57cec5SDimitry Andric bool empty() const { 1360b57cec5SDimitry Andric for (uptr i = 0; i < kLevel1Size; i++) 1370b57cec5SDimitry Andric if (!l1_[i].empty()) 1380b57cec5SDimitry Andric return false; 1390b57cec5SDimitry Andric return true; 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric // Returns true if the bit has changed from 0 to 1. setBit(uptr idx)1430b57cec5SDimitry Andric bool setBit(uptr idx) { 1440b57cec5SDimitry Andric check(idx); 1450b57cec5SDimitry Andric uptr i0 = idx0(idx); 1460b57cec5SDimitry Andric uptr i1 = idx1(idx); 1470b57cec5SDimitry Andric uptr i2 = idx2(idx); 1480b57cec5SDimitry Andric if (!l1_[i0].getBit(i1)) { 1490b57cec5SDimitry Andric l1_[i0].setBit(i1); 1500b57cec5SDimitry Andric l2_[i0][i1].clear(); 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric bool res = l2_[i0][i1].setBit(i2); 1530b57cec5SDimitry Andric // Printf("%s: %zd => %zd %zd %zd; %d\n", __func__, 1540b57cec5SDimitry Andric // idx, i0, i1, i2, res); 1550b57cec5SDimitry Andric return res; 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric clearBit(uptr idx)1580b57cec5SDimitry Andric bool clearBit(uptr idx) { 1590b57cec5SDimitry Andric check(idx); 1600b57cec5SDimitry Andric uptr i0 = idx0(idx); 1610b57cec5SDimitry Andric uptr i1 = idx1(idx); 1620b57cec5SDimitry Andric uptr i2 = idx2(idx); 1630b57cec5SDimitry Andric bool res = false; 1640b57cec5SDimitry Andric if (l1_[i0].getBit(i1)) { 1650b57cec5SDimitry Andric res = l2_[i0][i1].clearBit(i2); 1660b57cec5SDimitry Andric if (l2_[i0][i1].empty()) 1670b57cec5SDimitry Andric l1_[i0].clearBit(i1); 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric return res; 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric getBit(uptr idx)1720b57cec5SDimitry Andric bool getBit(uptr idx) const { 1730b57cec5SDimitry Andric check(idx); 1740b57cec5SDimitry Andric uptr i0 = idx0(idx); 1750b57cec5SDimitry Andric uptr i1 = idx1(idx); 1760b57cec5SDimitry Andric uptr i2 = idx2(idx); 1770b57cec5SDimitry Andric // Printf("%s: %zd => %zd %zd %zd\n", __func__, idx, i0, i1, i2); 1780b57cec5SDimitry Andric return l1_[i0].getBit(i1) && l2_[i0][i1].getBit(i2); 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric getAndClearFirstOne()1810b57cec5SDimitry Andric uptr getAndClearFirstOne() { 1820b57cec5SDimitry Andric for (uptr i0 = 0; i0 < kLevel1Size; i0++) { 1830b57cec5SDimitry Andric if (l1_[i0].empty()) continue; 1840b57cec5SDimitry Andric uptr i1 = l1_[i0].getAndClearFirstOne(); 1850b57cec5SDimitry Andric uptr i2 = l2_[i0][i1].getAndClearFirstOne(); 1860b57cec5SDimitry Andric if (!l2_[i0][i1].empty()) 1870b57cec5SDimitry Andric l1_[i0].setBit(i1); 1880b57cec5SDimitry Andric uptr res = i0 * BV::kSize * BV::kSize + i1 * BV::kSize + i2; 1890b57cec5SDimitry Andric // Printf("getAndClearFirstOne: %zd %zd %zd => %zd\n", i0, i1, i2, res); 1900b57cec5SDimitry Andric return res; 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric CHECK(0); 1930b57cec5SDimitry Andric return 0; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric // Do "this |= v" and return whether new bits have been added. setUnion(const TwoLevelBitVector & v)1970b57cec5SDimitry Andric bool setUnion(const TwoLevelBitVector &v) { 1980b57cec5SDimitry Andric bool res = false; 1990b57cec5SDimitry Andric for (uptr i0 = 0; i0 < kLevel1Size; i0++) { 2000b57cec5SDimitry Andric BV t = v.l1_[i0]; 2010b57cec5SDimitry Andric while (!t.empty()) { 2020b57cec5SDimitry Andric uptr i1 = t.getAndClearFirstOne(); 2030b57cec5SDimitry Andric if (l1_[i0].setBit(i1)) 2040b57cec5SDimitry Andric l2_[i0][i1].clear(); 2050b57cec5SDimitry Andric if (l2_[i0][i1].setUnion(v.l2_[i0][i1])) 2060b57cec5SDimitry Andric res = true; 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric return res; 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric // Do "this &= v" and return whether any bits have been removed. setIntersection(const TwoLevelBitVector & v)2130b57cec5SDimitry Andric bool setIntersection(const TwoLevelBitVector &v) { 2140b57cec5SDimitry Andric bool res = false; 2150b57cec5SDimitry Andric for (uptr i0 = 0; i0 < kLevel1Size; i0++) { 2160b57cec5SDimitry Andric if (l1_[i0].setIntersection(v.l1_[i0])) 2170b57cec5SDimitry Andric res = true; 2180b57cec5SDimitry Andric if (!l1_[i0].empty()) { 2190b57cec5SDimitry Andric BV t = l1_[i0]; 2200b57cec5SDimitry Andric while (!t.empty()) { 2210b57cec5SDimitry Andric uptr i1 = t.getAndClearFirstOne(); 2220b57cec5SDimitry Andric if (l2_[i0][i1].setIntersection(v.l2_[i0][i1])) 2230b57cec5SDimitry Andric res = true; 2240b57cec5SDimitry Andric if (l2_[i0][i1].empty()) 2250b57cec5SDimitry Andric l1_[i0].clearBit(i1); 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric } 2290b57cec5SDimitry Andric return res; 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric // Do "this &= ~v" and return whether any bits have been removed. setDifference(const TwoLevelBitVector & v)2330b57cec5SDimitry Andric bool setDifference(const TwoLevelBitVector &v) { 2340b57cec5SDimitry Andric bool res = false; 2350b57cec5SDimitry Andric for (uptr i0 = 0; i0 < kLevel1Size; i0++) { 2360b57cec5SDimitry Andric BV t = l1_[i0]; 2370b57cec5SDimitry Andric t.setIntersection(v.l1_[i0]); 2380b57cec5SDimitry Andric while (!t.empty()) { 2390b57cec5SDimitry Andric uptr i1 = t.getAndClearFirstOne(); 2400b57cec5SDimitry Andric if (l2_[i0][i1].setDifference(v.l2_[i0][i1])) 2410b57cec5SDimitry Andric res = true; 2420b57cec5SDimitry Andric if (l2_[i0][i1].empty()) 2430b57cec5SDimitry Andric l1_[i0].clearBit(i1); 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric } 2460b57cec5SDimitry Andric return res; 2470b57cec5SDimitry Andric } 2480b57cec5SDimitry Andric copyFrom(const TwoLevelBitVector & v)2490b57cec5SDimitry Andric void copyFrom(const TwoLevelBitVector &v) { 2500b57cec5SDimitry Andric clear(); 2510b57cec5SDimitry Andric setUnion(v); 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric // Returns true if 'this' intersects with 'v'. intersectsWith(const TwoLevelBitVector & v)2550b57cec5SDimitry Andric bool intersectsWith(const TwoLevelBitVector &v) const { 2560b57cec5SDimitry Andric for (uptr i0 = 0; i0 < kLevel1Size; i0++) { 2570b57cec5SDimitry Andric BV t = l1_[i0]; 2580b57cec5SDimitry Andric t.setIntersection(v.l1_[i0]); 2590b57cec5SDimitry Andric while (!t.empty()) { 2600b57cec5SDimitry Andric uptr i1 = t.getAndClearFirstOne(); 2610b57cec5SDimitry Andric if (!v.l1_[i0].getBit(i1)) continue; 2620b57cec5SDimitry Andric if (l2_[i0][i1].intersectsWith(v.l2_[i0][i1])) 2630b57cec5SDimitry Andric return true; 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric return false; 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric // for (TwoLevelBitVector<>::Iterator it(bv); it.hasNext();) { 2700b57cec5SDimitry Andric // uptr idx = it.next(); 2710b57cec5SDimitry Andric // use(idx); 2720b57cec5SDimitry Andric // } 2730b57cec5SDimitry Andric class Iterator { 2740b57cec5SDimitry Andric public: Iterator()2750b57cec5SDimitry Andric Iterator() { } Iterator(const TwoLevelBitVector & bv)2760b57cec5SDimitry Andric explicit Iterator(const TwoLevelBitVector &bv) : bv_(bv), i0_(0), i1_(0) { 2770b57cec5SDimitry Andric it1_.clear(); 2780b57cec5SDimitry Andric it2_.clear(); 2790b57cec5SDimitry Andric } 2800b57cec5SDimitry Andric hasNext()2810b57cec5SDimitry Andric bool hasNext() const { 2820b57cec5SDimitry Andric if (it1_.hasNext()) return true; 2830b57cec5SDimitry Andric for (uptr i = i0_; i < kLevel1Size; i++) 2840b57cec5SDimitry Andric if (!bv_.l1_[i].empty()) return true; 2850b57cec5SDimitry Andric return false; 2860b57cec5SDimitry Andric } 2870b57cec5SDimitry Andric next()2880b57cec5SDimitry Andric uptr next() { 2890b57cec5SDimitry Andric // Printf("++++: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(), 2900b57cec5SDimitry Andric // it2_.hasNext(), kSize); 2910b57cec5SDimitry Andric if (!it1_.hasNext() && !it2_.hasNext()) { 2920b57cec5SDimitry Andric for (; i0_ < kLevel1Size; i0_++) { 2930b57cec5SDimitry Andric if (bv_.l1_[i0_].empty()) continue; 2940b57cec5SDimitry Andric it1_ = typename BV::Iterator(bv_.l1_[i0_]); 2950b57cec5SDimitry Andric // Printf("+i0: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(), 2960b57cec5SDimitry Andric // it2_.hasNext(), kSize); 2970b57cec5SDimitry Andric break; 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric if (!it2_.hasNext()) { 3010b57cec5SDimitry Andric CHECK(it1_.hasNext()); 3020b57cec5SDimitry Andric i1_ = it1_.next(); 3030b57cec5SDimitry Andric it2_ = typename BV::Iterator(bv_.l2_[i0_][i1_]); 3040b57cec5SDimitry Andric // Printf("++i1: %zd %zd; %d %d; size %zd\n", i0_, i1_, it1_.hasNext(), 3050b57cec5SDimitry Andric // it2_.hasNext(), kSize); 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric CHECK(it2_.hasNext()); 3080b57cec5SDimitry Andric uptr i2 = it2_.next(); 3090b57cec5SDimitry Andric uptr res = i0_ * BV::kSize * BV::kSize + i1_ * BV::kSize + i2; 3100b57cec5SDimitry Andric // Printf("+ret: %zd %zd; %d %d; size %zd; res: %zd\n", i0_, i1_, 3110b57cec5SDimitry Andric // it1_.hasNext(), it2_.hasNext(), kSize, res); 3120b57cec5SDimitry Andric if (!it1_.hasNext() && !it2_.hasNext()) 3130b57cec5SDimitry Andric i0_++; 3140b57cec5SDimitry Andric return res; 3150b57cec5SDimitry Andric } 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric private: 3180b57cec5SDimitry Andric const TwoLevelBitVector &bv_; 3190b57cec5SDimitry Andric uptr i0_, i1_; 3200b57cec5SDimitry Andric typename BV::Iterator it1_, it2_; 3210b57cec5SDimitry Andric }; 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric private: check(uptr idx)324*0fca6ea1SDimitry Andric void check(uptr idx) const { CHECK_LT(idx, size()); } 3250b57cec5SDimitry Andric idx0(uptr idx)3260b57cec5SDimitry Andric uptr idx0(uptr idx) const { 3270b57cec5SDimitry Andric uptr res = idx / (BV::kSize * BV::kSize); 328*0fca6ea1SDimitry Andric CHECK_LT(res, kLevel1Size); 3290b57cec5SDimitry Andric return res; 3300b57cec5SDimitry Andric } 3310b57cec5SDimitry Andric idx1(uptr idx)3320b57cec5SDimitry Andric uptr idx1(uptr idx) const { 3330b57cec5SDimitry Andric uptr res = (idx / BV::kSize) % BV::kSize; 334*0fca6ea1SDimitry Andric CHECK_LT(res, BV::kSize); 3350b57cec5SDimitry Andric return res; 3360b57cec5SDimitry Andric } 3370b57cec5SDimitry Andric idx2(uptr idx)3380b57cec5SDimitry Andric uptr idx2(uptr idx) const { 3390b57cec5SDimitry Andric uptr res = idx % BV::kSize; 340*0fca6ea1SDimitry Andric CHECK_LT(res, BV::kSize); 3410b57cec5SDimitry Andric return res; 3420b57cec5SDimitry Andric } 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric BV l1_[kLevel1Size]; 3450b57cec5SDimitry Andric BV l2_[kLevel1Size][BV::kSize]; 3460b57cec5SDimitry Andric }; 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric } // namespace __sanitizer 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric #endif // SANITIZER_BITVECTOR_H 351