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 {
54 if (w)
55 return false;
56 }
57 return true;
58}
59
61{
62 u32_t n = 0;
63 for (const Word &w : words) n += countPopulation(w);
64 return n;
65}
66
68{
69 offset = 0;
70 words.clear();
71 words.shrink_to_fit();
72}
73
75{
76 if (bit < offset || bit >= offset + words.size() * WordSize) return false;
77 const Word &containingWord = words[(bit - offset) / WordSize];
78 const Word mask = (Word)0b1 << (bit % WordSize);
79 return mask & containingWord;
80}
81
83{
84 // TODO: can be faster.
85 if (test(bit)) return false;
86 set(bit);
87 return true;
88}
89
91{
92 extendTo(bit);
93
95 Word mask = (Word)0b1 << (bit % WordSize);
97}
98
100{
101 if (bit < offset || bit >= offset + words.size() * WordSize) return;
103 Word mask = ~((Word)0b1 << (bit % WordSize));
105}
106
108{
109 CoreBitVector tmp(*this);
110 tmp &= rhs;
111 return tmp == rhs;
112}
113
115{
116 // TODO: want some common iteration method.
117 if (empty() && rhs.empty()) return false;
118
120 const CoreBitVector &laterOffsetCBV = offset <= rhs.offset ? rhs : *this;
121
122 size_t earlierOffset = (offset < rhs.offset ? offset : rhs.offset) / WordSize;
123 size_t laterOffset = (offset > rhs.offset ? offset : rhs.offset) / WordSize;
125
126 const Word *eWords = &earlierOffsetCBV.words[0];
127 const size_t eSize = earlierOffsetCBV.words.size();
128 const Word *lWords = &laterOffsetCBV.words[0];
129 const size_t lSize = laterOffsetCBV.words.size();
130
131 size_t e = 0;
132 for ( ; e != laterOffset && e != eSize; ++e) { }
133
134 size_t l = 0;
135 for ( ; e != eSize && l != lSize; ++e, ++l)
136 {
137 if (eWords[e] & lWords[l]) return true;
138 }
139
140 return false;
141}
142
144{
145 if (this == &rhs) return true;
146
147 // TODO: maybe a simple equal offset, equal size path?
148
149 size_t lhsSetIndex = nextSetIndex(0);
150 size_t rhsSetIndex = rhs.nextSetIndex(0);
151 // Iterate comparing only words with set bits, if there is ever a mismatch,
152 // then the bit-vectors aren't equal.
153 while (lhsSetIndex < words.size() && rhsSetIndex < rhs.words.size())
154 {
155 // If the first bit is not the same in the word or words are different,
156 // then we have a mismatch.
157 if (lhsSetIndex * WordSize + offset != rhsSetIndex * WordSize + rhs.offset
158 || words[lhsSetIndex] != rhs.words[rhsSetIndex])
159 {
160 return false;
161 }
162
164 rhsSetIndex = rhs.nextSetIndex(rhsSetIndex + 1);
165 }
166
167 // Make sure both got to the end at the same time.
168 return lhsSetIndex >= words.size() && rhsSetIndex >= rhs.words.size();
169}
170
172{
173 return !(*this == rhs);
174}
175
177{
178 if (words.size() == 0)
179 {
180 *this = rhs;
181 return words.size() != 0;
182 }
183
184 if (rhs.words.size() == 0) return false;
185
186 if (this == &rhs) return false;
187
188 // TODO: some redundancy in extendTo calls.
189 if (finalBit() < rhs.finalBit()) extendForward(rhs.finalBit());
190 if (offset > rhs.offset) extendBackward(rhs.offset);
191
192 // Start counting this where rhs starts.
193 const size_t thisIndex = indexForBit(rhs.offset);
194 size_t rhsIndex = 0;
195
196 // Only need to test against rhs's size since we extended this to hold rhs.
198 const Word *rhsWords = &rhs.words[rhsIndex];
199 const size_t length = rhs.words.size();
200 Word changed = 0;
201
202 // Can start counting from 0 because we took the addresses of both
203 // word vectors at the correct index.
204 // #pragma omp simd
205 for (size_t i = 0 ; i < length; ++i)
206 {
207 const Word oldWord = thisWords[i];
208 // Is there anything in rhs not in *this?
211 }
212
213 return changed;
214}
215
217{
218 // The first bit this and rhs have in common is the greater of
219 // their offsets if the CBV with the smaller offset can hold
220 // the greater offset.
221 u32_t greaterOffset = std::max(offset, rhs.offset);
222
223 // If there is no overlap, then clear this CBV.
224 if (!canHold(greaterOffset) || !rhs.canHold(greaterOffset))
225 {
226 bool changed = false;
227 for (size_t i = 0; i < words.size(); ++i)
228 {
229 if (!changed) changed = words[i] != 0;
230 words[i] = 0;
231 }
232
233 return changed;
234 }
235
236 bool changed = false;
238 size_t rhsIndex = rhs.indexForBit(greaterOffset);
239
240 // Clear everything before the overlapping part.
241 for (size_t i = 0; i < thisIndex; ++i)
242 {
243 if (!changed) changed = words[i] != 0;
244 words[i] = 0;
245 }
246
248 for ( ; thisIndex < words.size() && rhsIndex < rhs.words.size(); ++thisIndex, ++rhsIndex)
249 {
251 words[thisIndex] &= rhs.words[rhsIndex];
253 }
254
255 // Clear the remaining bits with no rhs analogue.
256 for ( ; thisIndex < words.size(); ++thisIndex)
257 {
258 if (!changed && words[thisIndex] != 0) changed = true;
259 words[thisIndex] = 0;
260 }
261
262 return changed;
263}
264
266{
267 // Similar to |= in that we only iterate over rhs within this, but we
268 // don't need to extend anything since nothing from rhs is being added.
269 u32_t greaterOffset = std::max(offset, rhs.offset);
270 // TODO: calling twice.
271 // No overlap if either cannot hold the greater offset.
272 if (!canHold(greaterOffset) || !rhs.canHold(greaterOffset)) return false;
273
274 bool changed = false;
276 size_t rhsIndex = rhs.indexForBit(greaterOffset);
278 for ( ; thisIndex < words.size() && rhsIndex < rhs.words.size(); ++thisIndex, ++rhsIndex)
279 {
281 words[thisIndex] &= ~rhs.words[rhsIndex];
283 }
284
285 return changed;
286}
287
289{
290 return *this -= rhs;
291}
292
294{
295 // TODO: inefficient!
296 *this = lhs;
298}
299
300size_t CoreBitVector::hash(void) const
301{
302 // From https://stackoverflow.com/a/27216842
303 size_t h = words.size();
304 for (const Word &w : words)
305 {
306 h ^= w + 0x9e3779b9 + (h << 6) + (h >> 2);
307 }
308
309 return h + offset;
310}
311
313{
314 return CoreBitVectorIterator(this, true);
315}
316
321
323{
324 // New offset is the starting bit of the word which contains bit.
325 u32_t newOffset = (bit / WordSize) * WordSize;
326
327 // TODO: maybe assertions?
328 // Check if bit can already be included in this BV or if it's extendForward's problem.
329 if (newOffset >= offset) return;
330
331 words.insert(words.begin(), (offset - newOffset) / WordSize, 0);
333}
334
336{
337 // TODO: maybe assertions?
338 // Not our problem; extendBackward's problem, or there is nothing to do.
339 if (bit < offset || canHold(bit)) return;
340
341 // Starting bit of word which would contain bit.
342 u32_t bitsWord = (bit / WordSize) * WordSize;
343
344 // Add 1 to represent the final word starting at bitsWord.
345 u32_t wordsToAdd = 1 + (bitsWord - words.size() * WordSize - offset) / WordSize;
346 words.insert(words.end(), wordsToAdd, 0);
347}
348
350{
351 if (offset == 0 && words.size() == 0)
352 {
353 offset = (bit / WordSize) * WordSize;
354 words.push_back(0);
355 }
356 else if (bit < offset) extendBackward(bit);
357 else if (bit >= offset + words.size() * WordSize) extendForward(bit);
358}
359
361{
362 assert(canHold(bit));
363 // Recall, offset (and the bits in that word) are represented by words[0],
364 // so solve (offset + x) / WordSize == 0... x == -offset.
365 return (bit - offset) / WordSize;
366}
367
369{
370 return bit >= offset && bit < offset + words.size() * WordSize;
371}
372
374{
375 return offset + words.size() * WordSize - 1;
376}
377
378size_t CoreBitVector::nextSetIndex(const size_t start) const
379{
380 size_t index = start;
381 for ( ; index < words.size(); ++index)
382 {
383 if (words[index]) break;
384 }
385
386 return index;
387}
388
390 : cbv(cbv), bit(0)
391{
392 wordIt = end ? cbv->words.end() : cbv->words.begin();
393 // If user didn't request an end iterator, or words is non-empty,
394 // from 0, go to the next bit. But if the 0 bit is set, we don't
395 // need to because that is the first element.
396 if (wordIt != cbv->words.end() && !(cbv->words[0] & (Word)0b1)) ++(*this);
397}
398
400{
401 assert(!atEnd() && "CoreBitVectorIterator::++(pre): incrementing past end!");
402
403 ++bit;
404 // Check if no more bits in wordIt. Find word with a bit set.
405 if (bit == WordSize || (*wordIt >> bit) == 0)
406 {
407 bit = 0;
408 ++wordIt;
409 while (wordIt != cbv->words.end() && *wordIt == 0) ++wordIt;
410 }
411
412 // Find set bit if we're not at the end.
413 if (wordIt != cbv->words.end())
414 {
415 while (bit != WordSize && (*wordIt & ((Word)0b1 << bit)) == 0) ++bit;
416 }
417
418 return *this;
419}
420
422{
423 assert(!atEnd() && "CoreBitVectorIterator::++(pre): incrementing past end!");
425 ++*this;
426 return old;
427}
428
430{
431 assert(!atEnd() && "CoreBitVectorIterator::*: dereferencing end!");
432 size_t wordsIndex = wordIt - cbv->words.begin();
433 // Add where the bit vector starts (offset), with the number of bits
434 // in the passed words (the index encodes how many we have completely
435 // passed since it is position - 1) and the bit we are up to for the
436 // current word (i.e., in the n+1th)
437 return cbv->offset + wordsIndex * WordSize + bit;
438}
439
441{
442 assert(cbv == rhs.cbv && "CoreBitVectorIterator::==: comparing iterators from different CBVs");
443 // When we're at the end we don't care about bit.
444 if (wordIt == cbv->words.end()) return rhs.wordIt == cbv->words.end();
445 return wordIt == rhs.wordIt && bit == rhs.bit;
446}
447
449{
450 assert(cbv == rhs.cbv && "CoreBitVectorIterator::!=: comparing iterators from different CBVs");
451 return !(*this == rhs);
452}
453
455{
456 return wordIt == cbv->words.end();
457}
458
459}; // 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:70
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
unsigned u32_t
Definition GeneralType.h:47
unsigned countPopulation(T Value)