Static Value-Flow Analysis
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 
19 namespace SVF
20 {
21 
22 const size_t CoreBitVector::WordSize = sizeof(Word) * CHAR_BIT;
23 
25  : CoreBitVector(0) { }
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 
50 bool 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 
72 bool CoreBitVector::test(u32_t bit) const
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 
92  Word &containingWord = words[(bit - offset) / WordSize];
93  Word mask = (Word)0b1 << (bit % WordSize);
94  containingWord |= mask;
95 }
96 
98 {
99  if (bit < offset || bit >= offset + words.size() * WordSize) return;
100  Word &containingWord = words[(bit - offset) / WordSize];
101  Word mask = ~((Word)0b1 << (bit % WordSize));
102  containingWord &= mask;
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 
117  const CoreBitVector &earlierOffsetCBV = offset <= rhs.offset ? *this : rhs;
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;
122  laterOffset -= earlierOffset;
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 
161  lhsSetIndex = nextSetIndex(lhsSetIndex + 1);
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.
195  Word *thisWords = &words[thisIndex];
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?
207  thisWords[i] = thisWords[i] | rhsWords[i];
208  changed |= oldWord ^ thisWords[i];
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;
235  size_t thisIndex = indexForBit(greaterOffset);
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 
245  Word oldWord;
246  for ( ; thisIndex < words.size() && rhsIndex < rhs.words.size(); ++thisIndex, ++rhsIndex)
247  {
248  if (!changed) oldWord = words[thisIndex];
249  words[thisIndex] &= rhs.words[rhsIndex];
250  if (!changed) changed = oldWord != words[thisIndex];
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;
273  size_t thisIndex = indexForBit(greaterOffset);
274  size_t rhsIndex = rhs.indexForBit(greaterOffset);
275  Word oldWord;
276  for ( ; thisIndex < words.size() && rhsIndex < rhs.words.size(); ++thisIndex, ++rhsIndex)
277  {
278  if (!changed) oldWord = words[thisIndex];
279  words[thisIndex] &= ~rhs.words[rhsIndex];
280  if (!changed) changed = oldWord != words[thisIndex];
281  }
282 
283  return changed;
284 }
285 
287 {
288  return *this -= rhs;
289 }
290 
292 {
293  // TODO: inefficient!
294  *this = lhs;
296 }
297 
298 size_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 
316 {
317  return CoreBitVectorIterator(this);
318 }
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);
330  offset = newOffset;
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 
376 size_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!");
422  CoreBitVectorIterator old = *this;
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
Definition: CoreBitVector.h:34
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
Definition: CoreBitVector.h:33
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.
constexpr std::remove_reference< T >::type && move(T &&t) noexcept
Definition: SVFUtil.h:447
for isBitcode
Definition: BasicTypes.h:68
unsigned u32_t
Definition: GeneralType.h:46
unsigned countPopulation(T Value)