Static Value-Flow Analysis
IntervalValue.h
Go to the documentation of this file.
1 //===- IntervalValue.h ----Interval Value for Abstract Domain-------------//
2 //
3 // SVF: Static Value-Flow Analysis
4 //
5 // Copyright (C) <2013-2022> <Yulei Sui>
6 //
7 
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as published by
10 // the Free Software Foundation, either version 3 of the License, or
11 // (at your option) any later version.
12 
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
17 
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 //
21 //===----------------------------------------------------------------------===//
22 /*
23  * IntervalValue.h
24  *
25  * Created on: Aug 4, 2022
26  * Author: Jiawei Wang, Xiao Cheng
27  *
28  */
29 // The implementation is based on
30 // Xiao Cheng, Jiawei Wang and Yulei Sui. Precise Sparse Abstract Execution via Cross-Domain Interaction.
31 // 46th International Conference on Software Engineering. (ICSE24)
32 
33 #ifndef Z3_EXAMPLE_IntervalValue_H
34 #define Z3_EXAMPLE_IntervalValue_H
35 
36 #include <sstream>
37 #include "AE/Core/NumericValue.h"
38 
39 namespace SVF
40 {
41 
46 {
47 private:
48  // Lower bound
50 
51  // Upper bound
53 
54  // Invariant: isBottom() <=> _lb = +inf && _ub = -inf
55 public:
56  friend IntervalValue operator+(const IntervalValue &lhs, const IntervalValue &rhs);
57  friend IntervalValue operator-(const IntervalValue &lhs, const IntervalValue &rhs);
58  friend IntervalValue operator*(const IntervalValue &lhs, const IntervalValue &rhs);
59  friend IntervalValue operator/(const IntervalValue &lhs, const IntervalValue &rhs);
60  friend IntervalValue operator<<(const IntervalValue &lhs, const IntervalValue &rhs);
61  friend IntervalValue operator>>(const IntervalValue &lhs, const IntervalValue &rhs);
62  friend IntervalValue operator&(const IntervalValue &lhs, const IntervalValue &rhs);
63  friend IntervalValue operator|(const IntervalValue &lhs, const IntervalValue &rhs);
64  friend IntervalValue operator^(const IntervalValue &lhs, const IntervalValue &rhs);
65 
66  bool isTop() const
67  {
69  }
70 
71  bool isBottom() const
72  {
74  }
75 
78  {
80  }
81 
84  {
86  }
87 
88  static bool is_infinite(const BoundedInt &e)
89  {
90  return e.is_infinity();
91  }
92 
94  static IntervalValue top()
95  {
97  }
98 
101  {
103  }
104 
107 
109  explicit IntervalValue(s64_t n) : _lb(n), _ub(n) {}
110 
112 
114 
115  explicit IntervalValue(double n) : _lb(n), _ub(n) {}
116 
118 
120  explicit IntervalValue(BoundedInt lb, BoundedInt ub) : _lb(std::move(lb)), _ub(std::move(ub))
121  {
122  assert((isBottom() || _lb.leq(_ub)) && "lower bound should be less than or equal to upper bound");
123  }
124 
126 
127  explicit IntervalValue(double lb, double ub) : IntervalValue(BoundedInt(lb), BoundedInt(ub)) {}
128 
129  explicit IntervalValue(float lb, float ub) : IntervalValue(BoundedInt(lb), BoundedInt(ub)) {}
130 
132 
134 
136 
138  IntervalValue(const IntervalValue &) = default;
139 
142 
145 
148 
151  {
152  if (this->isBottom() || other.isBottom())
153  {
154  return bottom();
155  }
156  else if (this->isTop() || other.isTop())
157  {
158  return top();
159  }
160  else
161  {
162  if (this->is_numeral() && other.is_numeral())
163  {
164  return eq(this->_lb, other._lb) ? IntervalValue(1, 1) : IntervalValue(0, 0);
165  }
166  else
167  {
168  IntervalValue value = *this;
169  value.meet_with(other);
170  if (value.isBottom())
171  {
172  return IntervalValue(0, 0);
173  }
174  else
175  {
176  // return top();
177  return IntervalValue(0, 1);
178  }
179  }
180  }
181  }
182 
185  {
186  if (this->isBottom() || other.isBottom())
187  {
188  return bottom();
189  }
190  else if (this->isTop() || other.isTop())
191  {
192  return top();
193  }
194  else
195  {
196  if (this->is_numeral() && other.is_numeral())
197  {
198  return eq(this->_lb, other._lb) ? IntervalValue(0, 0) : IntervalValue(1, 1);
199  }
200  else
201  {
202  IntervalValue value = *this;
203  value.meet_with(other);
204  if (!value.isBottom())
205  {
206  return IntervalValue(0, 1);
207  }
208  else
209  {
210  return IntervalValue(1, 1);
211  }
212  }
213  }
214  }
215 
217  ~IntervalValue() = default;
218 
220  const BoundedInt &lb() const
221  {
222  assert(!this->isBottom() && "bottom interval does not have lower bound");
223  return this->_lb;
224  }
225 
227  const BoundedInt &ub() const
228  {
229  assert(!this->isBottom() && "bottom interval does not have upper bound");
230  return this->_ub;
231  }
232 
234  bool is_zero() const
235  {
236  return _lb.is_zero() && _ub.is_zero();
237  }
238 
240  bool is_infinite() const
241  {
242  return _lb.is_infinity() || _ub.is_infinity();
243  }
244 
245  bool is_int() const
246  {
247  return !is_real();
248  }
249 
250  bool is_real() const
251  {
252  bool lb_real = _lb.is_real();
253  bool ub_real = _ub.is_real();
254  return lb_real || ub_real;
255  }
256 
259  {
260  assert(is_numeral() && "this IntervalValue is not numeral");
261  return _lb.getNumeral();
262  }
263 
265  {
266  assert(is_numeral() && "this IntervalValue is not numeral");
267  return _lb.getIntNumeral();
268  }
269 
270  double getRealNumeral() const
271  {
272  assert(is_numeral() && "this IntervalValue is not numeral");
273  return _lb.getRealNumeral();
274  }
275 
277  bool is_numeral() const
278  {
279  return eq(_lb, _ub);
280  }
281 
284  {
285  this->_lb = plus_infinity();
286  this->_ub = minus_infinity();
287  }
288 
290  void set_to_top()
291  {
292  this->_lb = minus_infinity();
293  this->_ub = plus_infinity();
294  }
295 
300  bool containedWithin(const IntervalValue &other) const
301  {
302  if (this->isBottom())
303  {
304  return true;
305  }
306  else if (other.isBottom())
307  {
308  return false;
309  }
310  else
311  {
312  return other._lb.leq(this->_lb) && this->_ub.leq(other._ub);
313  }
314 
315  }
316 
321  bool contain(const IntervalValue &other) const
322  {
323  if (this->isBottom())
324  {
325  return true;
326  }
327  else if (other.isBottom())
328  {
329  return false;
330  }
331  else
332  {
333  return other._lb.geq(this->_lb) && this->_ub.geq(other._ub);
334  }
335  }
336 
339  bool leq(const IntervalValue &other) const
340  {
341  if (this->isBottom())
342  {
343  return true;
344  }
345  else if (other.isBottom())
346  {
347  return false;
348  }
349  else
350  {
351  return this->_ub.leq(other._lb);
352  }
353  }
354 
357  bool geq(const IntervalValue &other) const
358  {
359  if (this->isBottom())
360  {
361  return true;
362  }
363  else if (other.isBottom())
364  {
365  return false;
366  }
367  else
368  {
369  return this->_lb.geq(other._ub);
370  }
371  }
372 
373 
375  bool equals(const IntervalValue &other) const
376  {
377  if (this->isBottom())
378  {
379  return other.isBottom();
380  }
381  else if (other.isBottom())
382  {
383  return false;
384  }
385  else
386  {
387  if (this->is_real() && other.is_real())
388  {
389  return this->_lb.equal(other._lb) && this->_ub.equal(other._ub);
390  }
391  else if (this->is_int() && other.is_int())
392  {
393  return this->_lb.equal(other._lb) && this->_ub.equal(other._ub);
394  }
395  else if (this->is_int())
396  {
397  double thislb = this->_lb.getIntNumeral();
398  double thisub = this->_ub.getIntNumeral();
399  double otherlb = other._lb.getRealNumeral();
400  double otherub = other._ub.getRealNumeral();
401  return thislb == otherlb && thisub == otherub;
402  }
403  else
404  {
405  double thislb = this->_lb.getRealNumeral();
406  double thisub = this->_ub.getRealNumeral();
407  double otherlb = other._lb.getIntNumeral();
408  double otherub = other._ub.getIntNumeral();
409  return thislb == otherlb && thisub == otherub;
410  }
411  assert(false && "not implemented");
412  }
413  }
414 
416  void join_with(const IntervalValue &other)
417  {
418  if (this->isBottom())
419  {
420  if (other.isBottom())
421  {
422  return;
423  }
424  else
425  {
426  setValue(other.lb(), other.ub());
427  }
428  }
429  else if (other.isBottom())
430  {
431  return;
432  }
433  else
434  {
435  setValue(min(this->lb(), other.lb()), max(this->ub(), other.ub()));
436  }
437  }
438 
440  void widen_with(const IntervalValue &other)
441  {
442  if (this->isBottom())
443  {
444  this->_lb = other._lb;
445  this->_ub = other._ub;
446  }
447  else if (other.isBottom())
448  {
449  return;
450  }
451  else
452  {
453  setValue(!lb().leq(other.lb()) ? minus_infinity() : this->lb(), !ub().geq(other.ub()) ? plus_infinity() : this->ub());
454  }
455  }
456 
458  void narrow_with(const IntervalValue &other)
459  {
460  if (this->isBottom() || other.isBottom())
461  {
462  this->set_to_bottom();
463  }
464  else if (other.isBottom())
465  {
466  return;
467  }
468  else
469  {
470  setValue(is_infinite(this->lb()) ? other._lb : this->_lb, is_infinite(this->ub()) ? other._ub : this->_ub);
471  }
472  }
473 
475  void meet_with(const IntervalValue &other)
476  {
477  if (this->isBottom() || other.isBottom())
478  {
479  this->set_to_bottom();
480  }
481  else
482  {
483  if (!(max(this->_lb, other.lb()).leq(min(this->_ub, other.ub()))))
484  {
485  this->set_to_bottom();
486  }
487  else
488  {
489  setValue(max(this->_lb, other.lb()), min(this->_ub, other.ub()));
490  }
491  }
492  }
493 
495  bool contains(int n) const
496  {
497  return this->_lb.leq(n) && this->_ub.geq(n);
498  }
499 
500  void dump(std::ostream &o) const
501  {
502  if (this->isBottom())
503  {
504  o << "⊥";
505  }
506  else
507  {
508  o << "[" << this->_lb << ", " << this->_ub << "]";
509  }
510  }
511 
512  const std::string toString() const
513  {
514  std::string str;
515  std::stringstream rawStr(str);
516  if (this->isBottom())
517  {
518  rawStr << "⊥";
519  }
520  else
521  {
522  rawStr << "[" << lb().to_string() << ", " << ub().to_string() << "]";
523  }
524  return rawStr.str();
525  }
526 private:
528  void setValue(const BoundedInt &lb, const BoundedInt &ub)
529  {
530  assert((isBottom() || _lb.leq(_ub)) && "lower bound should be less than or equal to upper bound");
531  this->_lb = lb;
532  this->_ub = ub;
533  }
534 
535 private:
536  // internal use for create bottom-tolerant IntervalValue
538  {
539  if (!lb.leq(ub))
540  return IntervalValue::bottom();
541  else
542  return IntervalValue(lb, ub);
543  }
544 }; // end class IntervalValue
545 
548  const IntervalValue &rhs)
549 {
550  if (lhs.isBottom() || rhs.isBottom())
551  {
552  return IntervalValue::bottom();
553  }
554  else if (lhs.isTop() || rhs.isTop())
555  {
556  return IntervalValue::top();
557  }
558  else
559  {
560  return IntervalValue(lhs.lb() + rhs.lb(), lhs.ub() + rhs.ub());
561  }
562 }
563 
566  const IntervalValue &rhs)
567 {
568  if (lhs.isBottom() || rhs.isBottom())
569  {
570  return IntervalValue::bottom();
571  }
572  else if (lhs.isTop() || rhs.isTop())
573  {
574  return IntervalValue::top();
575  }
576  else
577  {
578  return IntervalValue(lhs.lb() - rhs.ub(), lhs.ub() - rhs.lb());
579  }
580 }
581 
584  const IntervalValue &rhs)
585 {
586  if (lhs.isBottom() || rhs.isBottom())
587  {
588  return IntervalValue::bottom();
589  }
590  else
591  {
592  BoundedInt ll = lhs.lb() * rhs.lb();
593  BoundedInt lu = lhs.lb() * rhs.ub();
594  BoundedInt ul = lhs.ub() * rhs.lb();
595  BoundedInt uu = lhs.ub() * rhs.ub();
596  std::vector<BoundedInt> vec{ll, lu, ul, uu};
597  return IntervalValue(BoundedInt::min(vec),
598  BoundedInt::max(vec));
599  }
600 }
601 
604  const IntervalValue &rhs)
605 {
606  if (lhs.isBottom() || rhs.isBottom())
607  {
608  return IntervalValue::bottom();
609  }
610  else if (rhs.contains(0))
611  {
612  IntervalValue lb = IntervalValue::create(rhs.lb(), -1);
613  IntervalValue ub = IntervalValue::create(1, rhs.ub());
614  IntervalValue l_res = lhs / lb;
615  IntervalValue r_res = lhs / ub;
616  l_res.join_with(r_res);
617  return l_res;
618  }
619  else if (lhs.contains(0))
620  {
621  IntervalValue lb = IntervalValue::create(lhs.lb(), -1);
622  IntervalValue ub = IntervalValue::create(1, lhs.ub());
623  IntervalValue l_res = lb / rhs;
624  IntervalValue r_res = ub / rhs;
625  l_res.join_with(r_res);
626  l_res.join_with(IntervalValue(0));
627  return l_res;
628  }
629  else
630  {
631  // Neither the dividend nor the divisor contains 0
632  BoundedInt ll = lhs.lb() / rhs.lb();
633  BoundedInt lu = lhs.lb() / rhs.ub();
634  BoundedInt ul = lhs.ub() / rhs.lb();
635  BoundedInt uu = lhs.ub() / rhs.ub();
636  std::vector<BoundedInt> vec{ll, lu, ul, uu};
637 
639  BoundedInt::max(vec));
640  return res;
641  }
642 }
643 
646  const IntervalValue &rhs)
647 {
648  if (lhs.isBottom() || rhs.isBottom())
649  {
650  return IntervalValue::bottom();
651  }
652  else if (rhs.contains(0))
653  {
654  return lhs.is_zero() ? IntervalValue(0, 0) : IntervalValue::top();
655  }
656  else if (lhs.is_numeral() && rhs.is_numeral())
657  {
658  return IntervalValue(lhs.lb() % rhs.lb(), lhs.lb() % rhs.lb());
659  }
660  else
661  {
662  BoundedInt n_ub = max(abs(lhs.lb()), abs(lhs.ub()));
663  BoundedInt d_ub = max(abs(rhs.lb()), rhs.ub()) - 1;
664  BoundedInt ub = min(n_ub, d_ub);
665 
666  if (lhs.lb().getNumeral() < 0)
667  {
668  if (lhs.ub().getNumeral() > 0)
669  {
670  return IntervalValue(-ub, ub);
671  }
672  else
673  {
674  return IntervalValue(-ub, 0);
675  }
676  }
677  else
678  {
679  return IntervalValue(0, ub);
680  }
681  }
682 }
683 
684 // Compare two IntervalValues for greater than
685 inline IntervalValue operator>(const IntervalValue &lhs, const IntervalValue &rhs)
686 {
687  // If either lhs or rhs is bottom, the result is bottom
688  if (lhs.isBottom() || rhs.isBottom())
689  {
690  return IntervalValue::bottom();
691  }
692  // If either lhs or rhs is top, the result is top
693  else if (lhs.isTop() || rhs.isTop())
694  {
695  return IntervalValue::top();
696  }
697  else
698  {
699  // If both lhs and rhs are numerals (lb = ub), directly compare their values
700  if (lhs.is_numeral() && rhs.is_numeral())
701  {
702  // It means lhs.lb() > rhs.lb()? true: false
703  return lhs.lb().leq(rhs.lb()) ? IntervalValue(0, 0) : IntervalValue(1, 1);
704  }
705  else
706  {
707  // Return [1,1] means lhs is totally greater than rhs
708  // When lhs.lb > rhs.ub, e.g., lhs:[3, 4] rhs:[1, 2]
709  // lhs.lb(3) > rhs.ub(2)
710  // It means lhs.lb() > rhs.ub()
711  if (!lhs.lb().leq(rhs.ub()))
712  {
713  return IntervalValue(1, 1);
714  }
715  // Return [0,0] means lhs is totally impossible to be greater than rhs
716  // i.e., lhs is totally less than or equal to rhs
717  // When lhs.ub <= rhs.lb, e.g., lhs:[3, 4] rhs:[4,5]
718  // lhs.ub(4) <= rhs.lb(4)
719  else if (lhs.ub().leq(rhs.lb()))
720  {
721  return IntervalValue(0, 0);
722  }
723  // For other cases, lhs can be greater than or not, depending on the values
724  // e.g., lhs: [2,4], rhs: [1,3],
725  // lhs can be greater than rhs if lhs is 4 and rhs is 1.
726  // lhs can also not be greater than rhs if lhs is 2 and rhs is 3
727  else
728  {
729  return IntervalValue(0, 1);
730  }
731  }
732  }
733 }
734 
735 // Compare two IntervalValues for less than
736 inline IntervalValue operator<(const IntervalValue &lhs, const IntervalValue &rhs)
737 {
738  // If either lhs or rhs is bottom, the result is bottom
739  if (lhs.isBottom() || rhs.isBottom())
740  {
741  return IntervalValue::bottom();
742  }
743  // If either lhs or rhs is top, the result is top
744  else if (lhs.isTop() || rhs.isTop())
745  {
746  return IntervalValue::top();
747  }
748  else
749  {
750  // If both lhs and rhs are numerals (lb = ub), directly compare their values
751  if (lhs.is_numeral() && rhs.is_numeral())
752  {
753  // It means lhs.lb() < rhs.lb()? true: false
754  return lhs.lb().geq(rhs.lb()) ? IntervalValue(0, 0) : IntervalValue(1, 1);
755  }
756  else
757  {
758  // Return [1,1] means lhs is totally less than rhs
759  // When lhs.ub < rhs.lb, e.g., lhs:[1, 2] rhs:[3, 4]
760  // lhs.ub(2) < rhs.lb(3)
761  // It means lhs.ub() < rhs.lb()
762  if (!lhs.ub().geq(rhs.lb()))
763  {
764  return IntervalValue(1, 1);
765  }
766  // Return [0,0] means lhs is totally impossible to be less than rhs
767  // i.e., lhs is totally greater than or equal to rhs
768  // When lhs.lb >= rhs.ub, e.g., lhs:[4,5] rhs:[3,4]
769  // lhs.lb(4) >= rhs.ub(4)
770  else if (lhs.lb().geq(rhs.ub()))
771  {
772  return IntervalValue(0, 0);
773  }
774  // For other cases, lhs can be less than rhs or not, depending on the values
775  // e.g., lhs: [2,4], rhs: [1,3],
776  // lhs can be less than rhs if lhs is 2, rhs is 3.
777  // lhs can also not be less than rhs if lhs is 4 and rhs is 1
778  else
779  {
780  return IntervalValue(0, 1);
781  }
782  }
783  }
784 }
785 
786 
787 // Compare two IntervalValues for greater than or equal to
788 inline IntervalValue operator>=(const IntervalValue &lhs, const IntervalValue &rhs)
789 {
790  // If either lhs or rhs is bottom, the result is bottom
791  if (lhs.isBottom() || rhs.isBottom())
792  {
793  return IntervalValue::bottom();
794  }
795  // If either lhs or rhs is top, the result is top
796  else if (lhs.isTop() || rhs.isTop())
797  {
798  return IntervalValue::top();
799  }
800  else
801  {
802  // If both lhs and rhs are numerals (lb = ub), directly compare their values
803  if (lhs.is_numeral() && rhs.is_numeral())
804  {
805  return lhs.lb().geq(rhs.lb()) ? IntervalValue(1, 1) : IntervalValue(0, 0);
806  }
807  else
808  {
809  // Return [1,1] means lhs is totally greater than or equal to rhs
810  // When lhs.lb >= rhs.ub, e.g., lhs:[2, 3] rhs:[1, 2]
811  // lhs.lb(2) >= rhs.ub(2)
812  if (lhs.lb().geq(rhs.ub()))
813  {
814  return IntervalValue(1, 1);
815  }
816  // Return [0,0] means lhs is totally impossible to be greater than or equal to rhs
817  // i.e., lhs is totally less than rhs
818  // When lhs.ub < rhs.lb, e.g., lhs:[1, 2] rhs:[3, 4]
819  // lhs.ub(2) < rhs.lb(3)
820  // It means lhs.ub() < rhs.lb()
821  else if (!lhs.ub().geq(rhs.lb()))
822  {
823  return IntervalValue(0, 0);
824  }
825  // For other cases, lhs can be greater than or equal to rhs or not, depending on the values
826  // e.g., lhs: [2,4], rhs: [1,3],
827  // lhs can be greater than or equal to rhs if lhs is 3, rhs is 2.
828  // lhs can also not be greater than or equal to rhs if lhs is 2 and rhs is 3
829  else
830  {
831  return IntervalValue(0, 1);
832  }
833  }
834  }
835 }
836 
837 // Compare two IntervalValues for less than or equal to
838 inline IntervalValue operator<=(const IntervalValue &lhs, const IntervalValue &rhs)
839 {
840  // If either lhs or rhs is bottom, the result is bottom
841  if (lhs.isBottom() || rhs.isBottom())
842  {
843  return IntervalValue::bottom();
844  }
845  // If either lhs or rhs is top, the result is top
846  else if (lhs.isTop() || rhs.isTop())
847  {
848  return IntervalValue::top();
849  }
850  else
851  {
852  // If both lhs and rhs are numerals (lb = ub), directly compare their values
853  if (lhs.is_numeral() && rhs.is_numeral())
854  {
855  return lhs.lb().leq(rhs.lb()) ? IntervalValue(1, 1) : IntervalValue(0, 0);
856  }
857  else
858  {
859  // Return [1,1] means lhs is totally less than or equal to rhs
860  // When lhs.ub <= rhs.lb, e.g., lhs:[1, 2] rhs:[2, 3]
861  // lhs.ub(2) <= rhs.lb(2)
862  if (lhs.ub().leq(rhs.lb()))
863  {
864  return IntervalValue(1, 1);
865  }
866  // Return [0,0] means lhs is totally impossible to be less than or equal to rhs
867  // i.e., lhs is totally greater than rhs
868  // When lhs.lb > rhs.ub, e.g., lhs:[3, 4] rhs:[1, 2]
869  // lhs.lb(3) > rhs.ub(2)
870  // It means lhs.lb() > rhs.ub()
871  else if (!lhs.lb().leq(rhs.ub()))
872  {
873  return IntervalValue(0, 0);
874  }
875  // For other cases, lhs can be less than or equal to rhs or not, depending on the values
876  // e.g., lhs: [2,4], rhs: [1,3],
877  // lhs can be less than or equal to rhs if lhs is 3, rhs is 3.
878  // lhs can also not be less than or equal to rhs if lhs is 3 and rhs is 2
879  else
880  {
881  return IntervalValue(0, 1);
882  }
883  }
884  }
885 }
886 
888 inline IntervalValue operator<<(const IntervalValue &lhs, const IntervalValue &rhs)
889 {
890  //TODO: implement <<
891  if (lhs.isBottom() || rhs.isBottom())
892  return IntervalValue::bottom();
893  if (lhs.isTop() && rhs.isTop())
894  return IntervalValue::top();
895  else
896  {
897  IntervalValue shift = rhs;
899  if (shift.isBottom())
900  return IntervalValue::bottom();
901  BoundedInt lb = 0;
902  // If the shift is greater than 32, the result is always 0
903  if ((s32_t) shift.lb().getNumeral() >= 32 || shift.lb().is_infinity())
904  {
906  }
907  else
908  {
909  lb = (1 << (s32_t) shift.lb().getNumeral());
910  }
911  BoundedInt ub = 0;
912  if (shift.ub().is_infinity())
913  {
915  }
916  else
917  {
918  ub = (1 << (s32_t) shift.ub().getNumeral());
919  }
920  IntervalValue coeff(lb, ub);
921  return lhs * coeff;
922  }
923 }
924 
926 inline IntervalValue operator>>(const IntervalValue &lhs, const IntervalValue &rhs)
927 {
928  //TODO: implement >>
929  if (lhs.isBottom() || rhs.isBottom())
930  return IntervalValue::bottom();
931  else if (lhs.isTop() && rhs.isTop())
932  return IntervalValue::top();
933  else
934  {
935  IntervalValue shift = rhs;
937  if (shift.isBottom())
938  return IntervalValue::bottom();
939  if (lhs.contains(0))
940  {
941  IntervalValue l = IntervalValue::create(lhs.lb(), -1);
942  IntervalValue u = IntervalValue::create(1, lhs.ub());
943  IntervalValue tmp = l >> rhs;
944  tmp.join_with(u >> rhs);
945  tmp.join_with(IntervalValue(0));
946  return tmp;
947  }
948  else
949  {
950  BoundedInt ll = lhs.lb() >> shift.lb();
951  BoundedInt lu = lhs.lb() >> shift.ub();
952  BoundedInt ul = lhs.ub() >> shift.lb();
953  BoundedInt uu = lhs.ub() >> shift.ub();
954  std::vector<BoundedInt> vec{ll, lu, ul, uu};
955  return IntervalValue(BoundedInt::min(vec),
956  BoundedInt::max(vec));
957  }
958  }
959 }
960 
962 inline IntervalValue operator&(const IntervalValue &lhs, const IntervalValue &rhs)
963 {
964  if (lhs.isBottom() || rhs.isBottom())
965  return IntervalValue::bottom();
966  else if (lhs.is_numeral() && rhs.is_numeral())
967  {
968  return IntervalValue(lhs.lb() & rhs.lb());
969  }
970  else if (lhs.lb().getNumeral() >= 0 && rhs.lb().getNumeral() >= 0)
971  {
972  return IntervalValue((s64_t) 0, min(lhs.ub(), rhs.ub()));
973  }
974  else if (lhs.lb().getNumeral() >= 0)
975  {
976  return IntervalValue((s64_t) 0, lhs.ub());
977  }
978  else if (rhs.lb().getNumeral() >= 0)
979  {
980  return IntervalValue((s64_t) 0, rhs.ub());
981  }
982  else
983  {
984  return IntervalValue::top();
985  }
986 }
987 
989 inline IntervalValue operator|(const IntervalValue &lhs, const IntervalValue &rhs)
990 {
991  auto next_power_of_2 = [](s64_t num)
992  {
993  int i = 1;
994  while ((num >> i) != 0)
995  {
996  ++i;
997  }
998  return 1 << i;
999  };
1000  if (lhs.isBottom() || rhs.isBottom())
1001  return IntervalValue::bottom();
1002  else if (lhs.is_numeral() && rhs.is_numeral())
1003  return IntervalValue(lhs.lb() | rhs.lb());
1004  else if (lhs.lb().getNumeral() >= 0 && !lhs.ub().is_infinity() &&
1005  rhs.lb().getNumeral() >= 0 && !rhs.ub().is_infinity())
1006  {
1007  s64_t m = std::max(lhs.ub().getNumeral(), rhs.ub().getNumeral());
1008  s64_t ub = next_power_of_2(s64_t(m)) - 1;
1009  return IntervalValue((s64_t) 0, (s64_t) ub);
1010  }
1011  else
1012  {
1013  return IntervalValue::top();
1014  }
1015 }
1016 
1018 inline IntervalValue operator^(const IntervalValue &lhs, const IntervalValue &rhs)
1019 {
1020  auto next_power_of_2 = [](s64_t num)
1021  {
1022  int i = 1;
1023  while ((num >> i) != 0)
1024  {
1025  ++i;
1026  }
1027  return 1 << i;
1028  };
1029  if (lhs.isBottom() || rhs.isBottom())
1030  return IntervalValue::bottom();
1031  else if (lhs.is_numeral() && rhs.is_numeral())
1032  return IntervalValue(lhs.lb() ^ rhs.lb());
1033  else if (lhs.lb().getNumeral() >= 0 && !lhs.ub().is_infinity() &&
1034  rhs.lb().getNumeral() >= 0 && !rhs.ub().is_infinity())
1035  {
1036  s64_t m = std::max(lhs.ub().getNumeral(), rhs.ub().getNumeral());
1037  s64_t ub = next_power_of_2(s64_t(m)) - 1;
1038  return IntervalValue((s64_t) 0, (s64_t) ub);
1039  }
1040  else
1041  {
1042  return IntervalValue::top();
1043  }
1044 }
1045 
1047 inline std::ostream &operator<<(std::ostream &o,
1049 {
1050  IntervalValue.dump(o);
1051  return o;
1052 }
1053 
1054 } // end namespace SVF
1055 #endif //Z3_EXAMPLE_IntervalValue_H
cJSON * a
Definition: cJSON.cpp:2560
cJSON * n
Definition: cJSON.cpp:2558
const char *const string
Definition: cJSON.h:172
A class representing a bounded 64-bit integer.
Definition: NumericValue.h:55
static BoundedInt plus_infinity()
Definition: NumericValue.h:131
bool is_minus_infinity() const
Definition: NumericValue.h:107
s64_t getNumeral() const
Retrieves the numeral value of the BoundedInt object.
Definition: NumericValue.h:661
bool is_plus_infinity() const
Definition: NumericValue.h:101
bool is_infinity() const
Definition: NumericValue.h:113
friend BoundedInt max(const BoundedInt &lhs, const BoundedInt &rhs)
Definition: NumericValue.h:585
s64_t getIntNumeral() const
Definition: NumericValue.h:703
bool is_zero() const
Definition: NumericValue.h:143
static BoundedInt minus_infinity()
Definition: NumericValue.h:137
friend BoundedInt min(const BoundedInt &lhs, const BoundedInt &rhs)
Definition: NumericValue.h:569
bool geq(const BoundedInt &rhs) const
Definition: NumericValue.h:189
bool equal(const BoundedInt &rhs) const
Definition: NumericValue.h:155
bool leq(const BoundedInt &rhs) const
Definition: NumericValue.h:161
double getRealNumeral() const
Definition: NumericValue.h:708
bool is_real() const
Definition: NumericValue.h:698
virtual const std::string to_string() const
Definition: NumericValue.h:682
void meet_with(const IntervalValue &other)
Return a intersected IntervalValue.
IntervalValue operator!=(const IntervalValue &other) const
Equality comparison.
friend IntervalValue operator/(const IntervalValue &lhs, const IntervalValue &rhs)
Divide IntervalValues.
static BoundedInt minus_infinity()
Get minus infinity -inf.
Definition: IntervalValue.h:77
bool isTop() const
Definition: IntervalValue.h:66
bool is_int() const
IntervalValue(s64_t n)
Create the IntervalValue [n, n].
bool leq(const IntervalValue &other) const
IntervalValue(u32_t lb, u32_t ub)
bool geq(const IntervalValue &other) const
IntervalValue(u64_t lb, u64_t ub)
void join_with(const IntervalValue &other)
Current IntervalValue joins with another IntervalValue.
IntervalValue operator==(const IntervalValue &other) const
Equality comparison.
IntervalValue & operator=(const IntervalValue &a)=default
Copy assignment operator.
friend IntervalValue operator&(const IntervalValue &lhs, const IntervalValue &rhs)
Bitwise AND of IntervalValues.
s64_t getIntNumeral() const
IntervalValue(double lb, double ub)
bool is_numeral() const
Return true if the IntervalValue is a number [num, num].
const BoundedInt & lb() const
Return the lower bound.
friend IntervalValue operator>>(const IntervalValue &lhs, const IntervalValue &rhs)
Left binary shift of IntervalValues.
const std::string toString() const
friend IntervalValue operator^(const IntervalValue &lhs, const IntervalValue &rhs)
Bitwise XOR of IntervalValues.
bool isBottom() const
Definition: IntervalValue.h:71
void narrow_with(const IntervalValue &other)
Current IntervalValue narrow with another IntervalValue.
IntervalValue(s64_t lb, s64_t ub)
bool is_infinite() const
Return true if the IntervalValue is infinite IntervalValue.
const BoundedInt & ub() const
Return the upper bound.
IntervalValue(BoundedInt n)
void set_to_top()
Set current IntervalValue as top.
IntervalValue & operator=(IntervalValue &&)=default
Move assignment operator.
friend IntervalValue operator|(const IntervalValue &lhs, const IntervalValue &rhs)
Bitwise OR of IntervalValues.
~IntervalValue()=default
Destructor.
friend IntervalValue operator*(const IntervalValue &lhs, const IntervalValue &rhs)
Multiply IntervalValues.
friend IntervalValue operator<<(const IntervalValue &lhs, const IntervalValue &rhs)
Left binary shift of IntervalValues.
bool is_zero() const
Return true if the IntervalValue is [0, 0].
static IntervalValue bottom()
Create the bottom IntervalValue [+inf, -inf].
double getRealNumeral() const
bool contain(const IntervalValue &other) const
friend IntervalValue operator-(const IntervalValue &lhs, const IntervalValue &rhs)
Subtract IntervalValues.
static BoundedInt plus_infinity()
Get plus infinity +inf.
Definition: IntervalValue.h:83
void widen_with(const IntervalValue &other)
Current IntervalValue widen with another IntervalValue.
IntervalValue(float lb, float ub)
static IntervalValue create(const BoundedInt &lb, const BoundedInt &ub)
bool containedWithin(const IntervalValue &other) const
bool equals(const IntervalValue &other) const
Equality comparison.
IntervalValue(s32_t lb, s32_t ub)
void dump(std::ostream &o) const
void set_to_bottom()
Set current IntervalValue as bottom.
void setValue(const BoundedInt &lb, const BoundedInt &ub)
Set the lower bound.
IntervalValue(double n)
IntervalValue()
Create default IntervalValue.
IntervalValue(BoundedInt lb, BoundedInt ub)
Create the IntervalValue [lb, ub].
static IntervalValue top()
Create the IntervalValue [-inf, +inf].
Definition: IntervalValue.h:94
s64_t getNumeral() const
Return.
IntervalValue(IntervalValue &&)=default
Move constructor.
friend IntervalValue operator+(const IntervalValue &lhs, const IntervalValue &rhs)
Add IntervalValues.
static bool is_infinite(const BoundedInt &e)
Definition: IntervalValue.h:88
bool is_real() const
IntervalValue(const IntervalValue &)=default
Copy constructor.
bool contains(int n) const
Return true if the IntervalValue contains n.
constexpr std::remove_reference< T >::type && move(T &&t) noexcept
Definition: SVFUtil.h:447
for isBitcode
Definition: BasicTypes.h:68
IntervalValue operator>=(const IntervalValue &lhs, const IntervalValue &rhs)
IntervalValue operator<=(const IntervalValue &lhs, const IntervalValue &rhs)
IntervalValue operator/(const IntervalValue &lhs, const IntervalValue &rhs)
Divide IntervalValues.
IntervalValue operator%(const IntervalValue &lhs, const IntervalValue &rhs)
Divide IntervalValues.
unsigned long long u64_t
Definition: GeneralType.h:48
IntervalValue operator>>(const IntervalValue &lhs, const IntervalValue &rhs)
Left binary shift of IntervalValues.
IntervalValue operator-(const IntervalValue &lhs, const IntervalValue &rhs)
Subtract IntervalValues.
IntervalValue operator^(const IntervalValue &lhs, const IntervalValue &rhs)
Bitwise XOR of IntervalValues.
IntervalValue operator&(const IntervalValue &lhs, const IntervalValue &rhs)
Bitwise AND of IntervalValues.
signed s32_t
Definition: GeneralType.h:47
IntervalValue operator|(const IntervalValue &lhs, const IntervalValue &rhs)
Bitwise OR of IntervalValues.
IntervalValue operator*(const IntervalValue &lhs, const IntervalValue &rhs)
Multiply IntervalValues.
unsigned u32_t
Definition: GeneralType.h:46
signed long long s64_t
Definition: GeneralType.h:49
IntervalValue operator+(const IntervalValue &lhs, const IntervalValue &rhs)
Add IntervalValues.
IntervalValue operator<(const IntervalValue &lhs, const IntervalValue &rhs)
IntervalValue operator>(const IntervalValue &lhs, const IntervalValue &rhs)
IntervalValue operator<<(const IntervalValue &lhs, const IntervalValue &rhs)
Left binary shift of IntervalValues.