Static Value-Flow Analysis
Loading...
Searching...
No Matches
CoreBitVector.cpp
Go to the documentation of this file.
1//===- CoreBitVector.cpp -- Dynamically sized bit vector data structure ------------//
2
3/*
4 * CoreBitVector.h
5 *
6 * Contiguous bit vector which resizes as required by common operations (implementation).
7 *
8 * Created on: Jan 31, 2021
9 * Author: Mohamad Barbar
10 */
11
12#include <limits.h>
13
14#include "Util/SparseBitVector.h" // For LLVM's countPopulation.
15#include "Util/CoreBitVector.h"
16#include "SVFIR/SVFType.h"
17#include "Util/SVFUtil.h"
18
19namespace SVF
20{
21
22const size_t CoreBitVector::WordSize = sizeof(Word) * CHAR_BIT;
23
26
28 : offset(0), words(n, 0) { }
29
31 : offset(cbv.offset), words(cbv.words) { }
32
34 : offset(cbv.offset), words(std::move(cbv.words)) { }
35
37{
38 this->offset = rhs.offset;
39 this->words = rhs.words;
40 return *this;
41}
42
44{
45 this->offset = rhs.offset;
46 this->words = std::move(rhs.words);
47 return *this;
48}
49
50bool CoreBitVector::empty(void) const
51{
52 for (const Word& w : words)
53 if (w)
54 return false;
55 return true;
56}
57
59{
60 u32_t n = 0;
61 for (const Word &w : words) n += countPopulation(w);
62 return n;
63}
64
66{
67 offset = 0;
68 words.clear();
69 words.shrink_to_fit();
70}
71
73{
74 if (bit < offset || bit >= offset + words.size() * WordSize) return false;
75 const Word &containingWord = words[(bit - offset) / WordSize];
76 const Word mask = (Word)0b1 << (bit % WordSize);
77 return mask & containingWord;
78}
79
81{
82 // TODO: can be faster.
83 if (test(bit)) return false;
84 set(bit);
85 return true;
86}
87
89{
90 extendTo(bit);
91
93 Word mask = (Word)0b1 << (bit % WordSize);
95}
96
98{
99 if (bit < offset || bit >= offset + words.size() * WordSize) return;
101 Word mask = ~((Word)0b1 << (bit % WordSize));
103}
104
106{
107 CoreBitVector tmp(*this);
108 tmp &= rhs;
109 return tmp == rhs;
110}
111
113{
114 // TODO: want some common iteration method.
115 if (empty() && rhs.empty()) return false;
116
118 const CoreBitVector &laterOffsetCBV = offset <= rhs.offset ? rhs : *this;
119
120 size_t earlierOffset = (offset < rhs.offset ? offset : rhs.offset) / WordSize;
121 size_t laterOffset = (offset > rhs.offset ? offset : rhs.offset) / WordSize;
123
124 const Word *eWords = &earlierOffsetCBV.words[0];
125 const size_t eSize = earlierOffsetCBV.words.size();
126 const Word *lWords = &laterOffsetCBV.words[0];
127 const size_t lSize = laterOffsetCBV.words.size();
128
129 size_t e = 0;
130 for ( ; e != laterOffset && e != eSize; ++e) { }
131
132 size_t l = 0;
133 for ( ; e != eSize && l != lSize; ++e, ++l)
134 {
135 if (eWords[e] & lWords[l]) return true;
136 }
137
138 return false;
139}
140
142{
143 if (this == &rhs) return true;
144
145 // TODO: maybe a simple equal offset, equal size path?
146
147 size_t lhsSetIndex = nextSetIndex(0);
148 size_t rhsSetIndex = rhs.nextSetIndex(0);
149 // Iterate comparing only words with set bits, if there is ever a mismatch,
150 // then the bit-vectors aren't equal.
151 while (lhsSetIndex < words.size() && rhsSetIndex < rhs.words.size())
152 {
153 // If the first bit is not the same in the word or words are different,
154 // then we have a mismatch.
155 if (lhsSetIndex * WordSize + offset != rhsSetIndex * WordSize + rhs.offset
156 || words[lhsSetIndex] != rhs.words[rhsSetIndex])
157 {
158 return false;
159 }
160
162 rhsSetIndex = rhs.nextSetIndex(rhsSetIndex + 1);
163 }
164
165 // Make sure both got to the end at the same time.
166 return lhsSetIndex >= words.size() && rhsSetIndex >= rhs.words.size();
167}
168
170{
171 return !(*this == rhs);
172}
173
175{
176 if (words.size() == 0)
177 {
178 *this = rhs;
179 return words.size() != 0;
180 }
181
182 if (rhs.words.size() == 0) return false;
183
184 if (this == &rhs) return false;
185
186 // TODO: some redundancy in extendTo calls.
187 if (finalBit() < rhs.finalBit()) extendForward(rhs.finalBit());
188 if (offset > rhs.offset) extendBackward(rhs.offset);
189
190 // Start counting this where rhs starts.
191 const size_t thisIndex = indexForBit(rhs.offset);
192 size_t rhsIndex = 0;
193
194 // Only need to test against rhs's size since we extended this to hold rhs.
196 const Word *rhsWords = &rhs.words[rhsIndex];
197 const size_t length = rhs.words.size();
198 Word changed = 0;
199
200 // Can start counting from 0 because we took the addresses of both
201 // word vectors at the correct index.
202 // #pragma omp simd
203 for (size_t i = 0 ; i < length; ++i)
204 {
205 const Word oldWord = thisWords[i];
206 // Is there anything in rhs not in *this?
209 }
210
211 return changed;
212}
213
215{
216 // The first bit this and rhs have in common is the greater of
217 // their offsets if the CBV with the smaller offset can hold
218 // the greater offset.
219 u32_t greaterOffset = std::max(offset, rhs.offset);
220
221 // If there is no overlap, then clear this CBV.
222 if (!canHold(greaterOffset) || !rhs.canHold(greaterOffset))
223 {
224 bool changed = false;
225 for (size_t i = 0; i < words.size(); ++i)
226 {
227 if (!changed) changed = words[i] != 0;
228 words[i] = 0;
229 }
230
231 return changed;
232 }
233
234 bool changed = false;
236 size_t rhsIndex = rhs.indexForBit(greaterOffset);
237
238 // Clear everything before the overlapping part.
239 for (size_t i = 0; i < thisIndex; ++i)
240 {
241 if (!changed) changed = words[i] != 0;
242 words[i] = 0;
243 }
244
246 for ( ; thisIndex < words.size() && rhsIndex < rhs.words.size(); ++thisIndex, ++rhsIndex)
247 {
249 words[thisIndex] &= rhs.words[rhsIndex];
251 }
252
253 // Clear the remaining bits with no rhs analogue.
254 for ( ; thisIndex < words.size(); ++thisIndex)
255 {
256 if (!changed && words[thisIndex] != 0) changed = true;
257 words[thisIndex] = 0;
258 }
259
260 return changed;
261}
262
264{
265 // Similar to |= in that we only iterate over rhs within this, but we
266 // don't need to extend anything since nothing from rhs is being added.
267 u32_t greaterOffset = std::max(offset, rhs.offset);
268 // TODO: calling twice.
269 // No overlap if either cannot hold the greater offset.
270 if (!canHold(greaterOffset) || !rhs.canHold(greaterOffset)) return false;
271
272 bool changed = false;
274 size_t rhsIndex = rhs.indexForBit(greaterOffset);
276 for ( ; thisIndex < words.size() && rhsIndex < rhs.words.size(); ++thisIndex, ++rhsIndex)
277 {
279 words[thisIndex] &= ~rhs.words[rhsIndex];
281 }
282
283 return changed;
284}
285
287{
288 return *this -= rhs;
289}
290
292{
293 // TODO: inefficient!
294 *this = lhs;
296}
297
298size_t CoreBitVector::hash(void) const
299{
300 // From https://stackoverflow.com/a/27216842
301 size_t h = words.size();
302 for (const Word &w : words)
303 {
304 h ^= w + 0x9e3779b9 + (h << 6) + (h >> 2);
305 }
306
307 return h + offset;
308}
309
311{
312 return CoreBitVectorIterator(this, true);
313}
314
319
321{
322 // New offset is the starting bit of the word which contains bit.
323 u32_t newOffset = (bit / WordSize) * WordSize;
324
325 // TODO: maybe assertions?
326 // Check if bit can already be included in this BV or if it's extendForward's problem.
327 if (newOffset >= offset) return;
328
329 words.insert(words.begin(), (offset - newOffset) / WordSize, 0);
331}
332
334{
335 // TODO: maybe assertions?
336 // Not our problem; extendBackward's problem, or there is nothing to do.
337 if (bit < offset || canHold(bit)) return;
338
339 // Starting bit of word which would contain bit.
340 u32_t bitsWord = (bit / WordSize) * WordSize;
341
342 // Add 1 to represent the final word starting at bitsWord.
343 u32_t wordsToAdd = 1 + (bitsWord - words.size() * WordSize - offset) / WordSize;
344 words.insert(words.end(), wordsToAdd, 0);
345}
346
348{
349 if (offset == 0 && words.size() == 0)
350 {
351 offset = (bit / WordSize) * WordSize;
352 words.push_back(0);
353 }
354 else if (bit < offset) extendBackward(bit);
355 else if (bit >= offset + words.size() * WordSize) extendForward(bit);
356}
357
359{
360 assert(canHold(bit));
361 // Recall, offset (and the bits in that word) are represented by words[0],
362 // so solve (offset + x) / WordSize == 0... x == -offset.
363 return (bit - offset) / WordSize;
364}
365
367{
368 return bit >= offset && bit < offset + words.size() * WordSize;
369}
370
372{
373 return offset + words.size() * WordSize - 1;
374}
375
376size_t CoreBitVector::nextSetIndex(const size_t start) const
377{
378 size_t index = start;
379 for ( ; index < words.size(); ++index)
380 {
381 if (words[index]) break;
382 }
383
384 return index;
385}
386
388 : cbv(cbv), bit(0)
389{
390 wordIt = end ? cbv->words.end() : cbv->words.begin();
391 // If user didn't request an end iterator, or words is non-empty,
392 // from 0, go to the next bit. But if the 0 bit is set, we don't
393 // need to because that is the first element.
394 if (wordIt != cbv->words.end() && !(cbv->words[0] & (Word)0b1)) ++(*this);
395}
396
398{
399 assert(!atEnd() && "CoreBitVectorIterator::++(pre): incrementing past end!");
400
401 ++bit;
402 // Check if no more bits in wordIt. Find word with a bit set.
403 if (bit == WordSize || (*wordIt >> bit) == 0)
404 {
405 bit = 0;
406 ++wordIt;
407 while (wordIt != cbv->words.end() && *wordIt == 0) ++wordIt;
408 }
409
410 // Find set bit if we're not at the end.
411 if (wordIt != cbv->words.end())
412 {
413 while (bit != WordSize && (*wordIt & ((Word)0b1 << bit)) == 0) ++bit;
414 }
415
416 return *this;
417}
418
420{
421 assert(!atEnd() && "CoreBitVectorIterator::++(pre): incrementing past end!");
423 ++*this;
424 return old;
425}
426
428{
429 assert(!atEnd() && "CoreBitVectorIterator::*: dereferencing end!");
430 size_t wordsIndex = wordIt - cbv->words.begin();
431 // Add where the bit vector starts (offset), with the number of bits
432 // in the passed words (the index encodes how many we have completely
433 // passed since it is position - 1) and the bit we are up to for the
434 // current word (i.e., in the n+1th)
435 return cbv->offset + wordsIndex * WordSize + bit;
436}
437
439{
440 assert(cbv == rhs.cbv && "CoreBitVectorIterator::==: comparing iterators from different CBVs");
441 // When we're at the end we don't care about bit.
442 if (wordIt == cbv->words.end()) return rhs.wordIt == cbv->words.end();
443 return wordIt == rhs.wordIt && bit == rhs.bit;
444}
445
447{
448 assert(cbv == rhs.cbv && "CoreBitVectorIterator::!=: comparing iterators from different CBVs");
449 return !(*this == rhs);
450}
451
453{
454 return wordIt == cbv->words.end();
455}
456
457}; // namespace SVF
buffer offset
Definition cJSON.cpp:1113
cJSON * n
Definition cJSON.cpp:2558
int index
Definition cJSON.h:170
char const int length
Definition cJSON.h:163
const CoreBitVectorIterator & operator++(void)
Pre-increment: ++it.
const CoreBitVector * cbv
CoreBitVector we are iterating over.
std::vector< Word >::const_iterator wordIt
Word in words we are looking at.
bool operator==(const CoreBitVectorIterator &rhs) const
Equality: *this == rhs.
bool operator!=(const CoreBitVectorIterator &rhs) const
Inequality: *this != rhs.
u32_t operator*(void) const
Dereference: *it.
size_t nextSetIndex(const size_t start) const
bool operator==(const CoreBitVector &rhs) const
Returns true if this CBV and rhs have the same bits set.
bool intersects(const CoreBitVector &rhs) const
Returns true if this CBV and rhs share any set bits.
void clear(void)
Empty the CBV.
bool test_and_set(u32_t bit)
CoreBitVector & operator=(const CoreBitVector &rhs)
Copy assignment.
bool canHold(u32_t bit) const
Returns true if bit can fit in this CBV without resizing.
void reset(u32_t bit)
Resets bit in the CBV.
void set(u32_t bit)
Sets bit in the CBV.
bool operator-=(const CoreBitVector &rhs)
void extendForward(u32_t bit)
Add enough words (append) to be able to include bit.
static const size_t WordSize
bool operator&=(const CoreBitVector &rhs)
void extendTo(u32_t bit)
Add enough words (append xor prepend) to be able to include bit.
u32_t offset
The first bit of the first word.
bool test(u32_t bit) const
Returns true if bit is set in this CBV.
std::vector< Word > words
Our actual bit vector.
const_iterator begin(void) const
u32_t finalBit(void) const
Returns the last bit that this CBV can hold.
bool intersectWithComplement(const CoreBitVector &rhs)
const_iterator end(void) const
bool empty(void) const
Returns true if no bits are set.
unsigned long long Word
void extendBackward(u32_t bit)
Add enough words (prepend) to be able to include bit.
u32_t count(void) const
Returns number of bits set.
size_t indexForBit(u32_t bit) const
Returns the index into words which would hold bit.
CoreBitVector(void)
Construct empty CBV.
bool contains(const CoreBitVector &rhs) const
Returns true if this CBV is a superset of rhs.
bool operator!=(const CoreBitVector &rhs) const
Returns true if either this CBV or rhs has a bit set unique to the other.
bool operator|=(const CoreBitVector &rhs)
size_t hash(void) const
Hash for this CBV.
for isBitcode
Definition BasicTypes.h:68
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74
unsigned u32_t
Definition GeneralType.h:46
unsigned countPopulation(T Value)