Static Value-Flow Analysis
Loading...
Searching...
No Matches
NumericValue.h
Go to the documentation of this file.
1//===- NumericValue.h ----Numeric Value-------------------------//
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 * Numeri Value.h
24 *
25 * Created on: May 11, 2024
26 * Author: Xiao Cheng, Jiawei Ren
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 SVF_NUMERICVALUE_H
34#define SVF_NUMERICVALUE_H
35
36#include "SVFIR/SVFType.h"
37#include <cfloat> // For DBL_MAX
38#include <cmath>
39#include <utility>
40
41#define epsilon std::numeric_limits<double>::epsilon();
42namespace SVF
43{
44
55{
56protected:
57 s64_t _iVal; // The 64-bit integer value.
58 bool _isInf; // True if the value is infinite. If true, _iVal == 1
59 // represents positive infinity and _iVal == 0 represents
60 // negative infinity.
61
62 // Default constructor is protected to prevent creating an object without
63 // initializing _iVal and _isInf.
64 BoundedInt() = default;
65
66public:
67 // Constructs a BoundedInt with the given 64-bit integer value. The value is
68 // not infinite.
70
71 // Constructs a BoundedInt with the given 64-bit integer value and infinity
72 // flag.
74
75 // Copy constructor.
77
78 // Copy assignment operator.
80 {
81 _iVal = rhs._iVal;
82 _isInf = rhs._isInf;
83 return *this;
84 }
85
86 // Move constructor.
88
89 // Move assignment operator.
91 {
92 _iVal = rhs._iVal;
93 _isInf = rhs._isInf;
94 return *this;
95 }
96
97 // Virtual destructor.
98 virtual ~BoundedInt() {}
99
100 // Checks if the BoundedInt represents positive infinity.
101 bool is_plus_infinity() const
102 {
103 return _isInf && _iVal == 1;
104 }
105
106 // Checks if the BoundedInt represents negative infinity.
107 bool is_minus_infinity() const
108 {
109 return _isInf && _iVal == -1;
110 }
111
112 // Checks if the BoundedInt represents either positive or negative infinity.
113 bool is_infinity() const
114 {
116 }
117
118 // Sets the BoundedInt to represent positive infinity.
120 {
121 *this = plus_infinity();
122 }
123
124 // Sets the BoundedInt to represent negative infinity.
126 {
127 *this = minus_infinity();
128 }
129
130 // Returns a BoundedInt representing positive infinity.
132 {
133 return {1, true};
134 }
135
136 // Returns a BoundedInt representing negative infinity.
138 {
139 return {-1, true};
140 }
141
142 // Checks if the BoundedInt represents zero.
143 bool is_zero() const
144 {
145 return _iVal == 0;
146 }
147
148 // Checks if the given BoundedInt represents zero.
149 static bool isZero(const BoundedInt& expr)
150 {
151 return expr._iVal == 0;
152 }
153
154 // Checks if the BoundedInt is equal to another BoundedInt.
155 bool equal(const BoundedInt& rhs) const
156 {
157 return _iVal == rhs._iVal && _isInf == rhs._isInf;
158 }
159
160 // Checks if the BoundedInt is less than or equal to another BoundedInt.
161 bool leq(const BoundedInt& rhs) const
162 {
163 // If only one of the two BoundedInts is infinite.
164 if (is_infinity() ^ rhs.is_infinity())
165 {
166 if (is_infinity())
167 {
168 return is_minus_infinity();
169 }
170 else
171 {
172 return rhs.is_plus_infinity();
173 }
174 }
175 // If both BoundedInts are infinite.
176 if (is_infinity() && rhs.is_infinity())
177 {
178 if (is_minus_infinity())
179 return true;
180 else
181 return rhs.is_plus_infinity();
182 }
183 // If neither BoundedInt is infinite.
184 else
185 return _iVal <= rhs._iVal;
186 }
187
188 // Checks if the BoundedInt is greater than or equal to another BoundedInt.
189 bool geq(const BoundedInt& rhs) const
190 {
191 // If only one of the two BoundedInts is infinite.
192 if (is_infinity() ^ rhs.is_infinity())
193 {
194 if (is_infinity())
195 {
196 return is_plus_infinity();
197 }
198 else
199 {
200 return rhs.is_minus_infinity();
201 }
202 }
203 // If both BoundedInts are infinite.
204 if (is_infinity() && rhs.is_infinity())
205 {
206 if (is_plus_infinity())
207 return true;
208 else
209 return rhs.is_minus_infinity();
210 }
211 // If neither BoundedInt is infinite.
212 else
213 return _iVal >= rhs._iVal;
214 }
215
217 //{%
218 // Overloads the equality operator to compare two BoundedInt objects.
220 {
221 return lhs.equal(rhs);
222 }
223
224 // Overloads the inequality operator to compare two BoundedInt objects.
226 {
227 return !lhs.equal(rhs);
228 }
229
230 // Overloads the greater than operator to compare two BoundedInt objects.
232 {
233 return !lhs.leq(rhs);
234 }
235
236 // Overloads the less than operator to compare two BoundedInt objects.
238 {
239 return !lhs.geq(rhs);
240 }
241
242 // Overloads the less than or equal to operator to compare two BoundedInt
243 // objects.
245 {
246 return lhs.leq(rhs);
247 }
248
249 // Overloads the greater than or equal to operator to compare two BoundedInt
250 // objects.
252 {
253 return lhs.geq(rhs);
254 }
255
281 {
282 // If one number is positive infinity and the other is negative
283 // infinity, this is an invalid operation, so we assert false.
284 if ((lhs.is_plus_infinity() && rhs.is_minus_infinity()) ||
285 (lhs.is_minus_infinity() && rhs.is_plus_infinity()))
286 {
287 assert(false && "invalid add");
288 }
289
290 // If either number is positive infinity, the result is positive
291 // infinity.
292 if (lhs.is_plus_infinity() || rhs.is_plus_infinity())
293 {
294 return plus_infinity();
295 }
296
297 // If either number is negative infinity, the result is negative
298 // infinity.
299 if (lhs.is_minus_infinity() || rhs.is_minus_infinity())
300 {
301 return minus_infinity();
302 }
303
304 // If both numbers are positive and their sum would exceed the maximum
305 // representable number, the result is positive infinity.
306 if (lhs._iVal > 0 && rhs._iVal > 0 &&
307 (std::numeric_limits<s64_t>::max() - lhs._iVal) < rhs._iVal)
308 {
309 return plus_infinity();
310 }
311
312 // If both numbers are negative and their sum would be less than the
313 // most negative representable number, the result is negative infinity.
314 if (lhs._iVal < 0 && rhs._iVal < 0 &&
315 (-std::numeric_limits<s64_t>::max() - lhs._iVal) > rhs._iVal)
316 {
317 return minus_infinity();
318 }
319
320 // If none of the above conditions are met, the numbers can be safely
321 // added.
322 return lhs._iVal + rhs._iVal;
323 }
324
325 // Overloads the addition operator to safely add two BoundedInt objects.
326 // Utilizes the safeAdd method to handle potential overflow and underflow.
328 {
329 return safeAdd(lhs, rhs);
330 }
331
332 // Overloads the unary minus operator to negate a BoundedInt object.
333 // The operation simply negates the internal integer value.
335 {
336 return {-lhs._iVal, lhs._isInf};
337 }
338
339 // Overloads the subtraction operator to safely subtract one BoundedInt
340 // object from another. This is implemented as the addition of the lhs and
341 // the negation of the rhs, using the safeAdd method for safety.
343 {
344 return safeAdd(lhs, -rhs);
345 }
346
365 {
366 // If either number is zero, the result is zero.
367 if (lhs._iVal == 0 || rhs._iVal == 0)
368 return 0;
369
370 // If either number is infinity, the result depends on the signs of the
371 // numbers.
372 if (lhs.is_infinity() || rhs.is_infinity())
373 {
374 // If the signs of the numbers are the same, the result is positive
375 // infinity. If the signs of the numbers are different, the result
376 // is negative infinity.
377 if (lhs._iVal * rhs._iVal > 0)
378 {
379 return plus_infinity();
380 }
381 else
382 {
383 return minus_infinity();
384 }
385 }
386
387 // If both numbers are positive and their product would exceed the
388 // maximum representable number, the result is positive infinity.
389 if (lhs._iVal > 0 && rhs._iVal > 0 &&
390 (std::numeric_limits<s64_t>::max() / lhs._iVal) < rhs._iVal)
391 {
392 return plus_infinity();
393 }
394
395 // If both numbers are negative and their product would exceed the
396 // maximum representable number, the result is positive infinity.
397 if (lhs._iVal < 0 && rhs._iVal < 0 &&
398 (std::numeric_limits<s64_t>::max() / lhs._iVal) > rhs._iVal)
399 {
400 return plus_infinity();
401 }
402
403 // If one number is positive and the other is negative and their product
404 // would be less than the most negative representable number, the result
405 // is negative infinity.
406 if ((lhs._iVal > 0 && rhs._iVal < 0 &&
407 (-std::numeric_limits<s64_t>::max() / lhs._iVal) > rhs._iVal) ||
408 (lhs._iVal < 0 && rhs._iVal > 0 &&
409 (-std::numeric_limits<s64_t>::max() / rhs._iVal) > lhs._iVal))
410 {
411 return minus_infinity();
412 }
413
414 // If none of the above conditions are met, the numbers can be safely
415 // multiplied.
416 return lhs._iVal * rhs._iVal;
417 }
418
419
421 {
422 if (rhs.is_zero())
423 assert(false && "divide by zero");
424 else if (!lhs.is_infinity() && !rhs.is_infinity())
425 return lhs._iVal % rhs._iVal;
426 else if (!lhs.is_infinity() && rhs.is_infinity())
427 return 0;
428 // TODO: not sure
429 else if (lhs.is_infinity() && !rhs.is_infinity())
430 return ite(rhs._iVal > 0, lhs, -lhs);
431 else
432 // TODO: +oo/-oo L'Hôpital's rule?
433 return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
434 abort();
435 }
436 // Overloads the multiplication operator to safely multiply two BoundedInt
437 // objects. Utilizes the safeMul method to handle potential overflow.
439 {
440 return safeMul(lhs, rhs);
441 }
442
443 // Overloads the division operator to safely divide a BoundedInt object by
444 // another. Utilizes the safeDiv method to handle potential division by zero
445 // and overflow.
447 {
448 if (rhs.is_zero())
449 assert(false && "divide by zero");
450 else if (!lhs.is_infinity() && !rhs.is_infinity())
451 return lhs._iVal / rhs._iVal;
452 else if (!lhs.is_infinity() && rhs.is_infinity())
453 return 0;
454 else if (lhs.is_infinity() && !rhs.is_infinity())
455 return ite(rhs._iVal >= 0, lhs, -lhs);
456 else
457 return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
458 }
459
460 // Overload bitwise operators for BoundedInt objects. These operators
461 // directly apply the corresponding bitwise operators to the internal
462 // integer values of the BoundedInt objects.
463
464 // Overloads the bitwise XOR operator for BoundedInt objects.
466 {
467 return lhs._iVal ^ rhs._iVal;
468 }
469
470 // Overloads the bitwise AND operator for BoundedInt objects.
472 {
473 return lhs._iVal & rhs._iVal;
474 }
475
476 // Overloads the bitwise OR operator for BoundedInt objects.
478 {
479 return lhs._iVal | rhs._iVal;
480 }
481
482 // Overload logical operators for BoundedInt objects. These operators
483 // directly apply the corresponding logical operators to the internal
484 // integer values of the BoundedInt objects.
485
486 // Overloads the logical AND operator for BoundedInt objects.
488 {
489 return lhs._iVal && rhs._iVal;
490 }
491
492 // Overloads the logical OR operator for BoundedInt objects.
494 {
495 return lhs._iVal || rhs._iVal;
496 }
497
498 // Overloads the logical NOT operator for BoundedInt objects.
500 {
501 return !lhs._iVal;
502 }
503
504 // Overloads the right shift operator for BoundedInt objects.
505 // This operation is safe as long as the right-hand side is non-negative.
506 // If the left-hand side is zero or infinity, the result is the same as the
507 // left-hand side. If the right-hand side is infinity, the result depends on
508 // the sign of the left-hand side.
510 {
511 assert(rhs.geq(0) && "rhs should be greater or equal than 0");
512 if (lhs.is_zero())
513 return lhs;
514 else if (lhs.is_infinity())
515 return lhs;
516 else if (rhs.is_infinity())
517 return lhs.geq(0) ? 0 : -1;
518 else
519 return lhs._iVal >> rhs._iVal;
520 }
521
522 // Overloads the left shift operator for BoundedInt objects.
523 // This operation is safe as long as the right-hand side is non-negative.
524 // If the left-hand side is zero or infinity, the result is the same as the
525 // left-hand side. If the right-hand side is infinity, the result depends on
526 // the sign of the left-hand side.
528 {
529 assert(rhs.geq(0) && "rhs should be greater or equal than 0");
530 if (lhs.is_zero())
531 return lhs;
532 else if (lhs.is_infinity())
533 return lhs;
534 else if (rhs.is_infinity())
535 return lhs.geq(0) ? plus_infinity() : minus_infinity();
536 else
537 return lhs._iVal << rhs._iVal;
538 }
539
540 // Overloads the ternary if-then-else operator for BoundedInt objects.
541 // The condition is evaluated as a boolean, and the result is either the
542 // second or third argument depending on the condition.
543 friend BoundedInt ite(const BoundedInt& cond, const BoundedInt& lhs,
544 const BoundedInt& rhs)
545 {
546 return cond._iVal != 0 ? lhs : rhs;
547 }
548
549 // Overloads the stream insertion operator for BoundedInt objects.
550 // This allows BoundedInt objects to be printed directly using std::cout or
551 // other output streams.
552 friend std::ostream& operator<<(std::ostream& out, const BoundedInt& expr)
553 {
554 out << expr._iVal;
555 return out;
556 }
557
558 // Defines a function to compare two BoundedInt objects for equality.
559 // This function directly compares the internal integer values of the
560 // BoundedInt objects.
561 friend bool eq(const BoundedInt& lhs, const BoundedInt& rhs)
562 {
563 return lhs._iVal == rhs._iVal && lhs._isInf == rhs._isInf;
564 }
565
566 // Defines a function to find the minimum of two BoundedInt objects.
567 // This function directly compares the internal integer values of the BoundedInt objects,
568 // and also checks if either of them represents infinity.
569 friend BoundedInt min(const BoundedInt& lhs, const BoundedInt& rhs)
570 {
571 if (lhs.is_minus_infinity() || rhs.is_minus_infinity())
572 return minus_infinity();
573 else if(lhs.is_plus_infinity())
574 return rhs;
575 else if(rhs.is_plus_infinity())
576 return lhs;
577 else
578 return BoundedInt(std::min(lhs._iVal, rhs._iVal));
579 }
580
581
582 // Defines a function to find the maximum of two BoundedInt objects.
583 // This function directly compares the internal integer values of the BoundedInt objects,
584 // and also checks if either of them represents infinity.
585 friend BoundedInt max(const BoundedInt& lhs, const BoundedInt& rhs)
586 {
587 if (lhs.is_plus_infinity() || rhs.is_plus_infinity())
588 return plus_infinity();
589 else if(lhs.is_minus_infinity())
590 return rhs;
591 else if(rhs.is_minus_infinity())
592 return lhs;
593 else
594 return BoundedInt(std::max(lhs._iVal, rhs._iVal));
595 }
596
597
598 // Defines a function to find the minimum of a vector of BoundedInt objects.
599 // This function iterates over the vector and returns the smallest
600 // BoundedInt object.
601 static BoundedInt min(std::vector<BoundedInt>& _l)
602 {
604 for (const auto& it : _l)
605 {
606 if (it.is_minus_infinity())
607 return minus_infinity();
608 else if (!it.geq(ret))
609 {
610 ret = it;
611 }
612 }
613 return ret;
614 }
615
616 // Defines a function to find the maximum of a vector of BoundedInt objects.
617 // This function iterates over the vector and returns the largest BoundedInt
618 // object.
619 static BoundedInt max(std::vector<BoundedInt>& _l)
620 {
622 for (const auto& it : _l)
623 {
624 if (it.is_plus_infinity())
625 return plus_infinity();
626 else if (!it.leq(ret))
627 {
628 ret = it;
629 }
630 }
631 return ret;
632 }
633
634 // Defines a function to find the absolute value of a BoundedInt object.
635 // This function directly applies the unary minus operator if the BoundedInt
636 // object is negative.
638 {
639 return lhs.leq(0) ? -lhs : lhs;
640 }
641
642 // Defines a method to check if a BoundedInt object is true.
643 // A BoundedInt object is considered true if its internal integer value is
644 // non-zero.
645 inline bool is_true() const
646 {
647 return _iVal != 0;
648 }
649
661 inline s64_t getNumeral() const
662 {
663 // If the object represents negative infinity, return the minimum
664 // representable 64-bit integer.
665 if (is_minus_infinity())
666 {
667 return std::numeric_limits<s64_t>::min();
668 }
669 // If the object represents positive infinity, return the maximum
670 // representable 64-bit integer.
671 else if (is_plus_infinity())
672 {
673 return std::numeric_limits<s64_t>::max();
674 }
675 // Otherwise, return the actual 64-bit integer value of the object.
676 else
677 {
678 return _iVal;
679 }
680 }
681
682 inline virtual const std::string to_string() const
683 {
684 if (is_minus_infinity())
685 {
686 return "-oo";
687 }
688 if (is_plus_infinity())
689 {
690 return "+oo";
691 }
692 else
693 return std::to_string(_iVal);
694 }
695
696 //%}
697
698 bool is_real() const
699 {
700 return false;
701 }
702
703 inline s64_t getIntNumeral() const
704 {
705 return getNumeral();
706 }
707
708 inline double getRealNumeral() const
709 {
710 assert(false && "cannot get real number for integer!");
711 abort();
712 }
713
714 const double getFVal() const
715 {
716 assert(false && "cannot get real number for integer!");
717 abort();
718 }
719};
724{
725protected:
726 double _fVal;
727
728 BoundedDouble() = default;
729
730public:
732
734
736 {
737 _fVal = rhs._fVal;
738 return *this;
739 }
740
742
744 {
745 _fVal = std::move(rhs._fVal);
746 return *this;
747 }
748
749 virtual ~BoundedDouble() {}
750
751 static bool doubleEqual(double a, double b)
752 {
753 if (std::isinf(a) && std::isinf(b))
754 return a == b;
755 return std::fabs(a - b) < epsilon;
756 }
757
758 const double getFVal() const
759 {
760 return _fVal;
761 }
762
763 bool is_plus_infinity() const
764 {
765 return _fVal == std::numeric_limits<double>::infinity();
766 }
767
768 bool is_minus_infinity() const
769 {
770 return _fVal == -std::numeric_limits<double>::infinity();
771 }
772
773 bool is_infinity() const
774 {
776 }
777
779 {
780 *this = plus_infinity();
781 }
782
784 {
785 *this = minus_infinity();
786 }
787
789 {
790 return std::numeric_limits<double>::infinity();
791 }
792
794 {
795 return -std::numeric_limits<double>::infinity();
796 }
797
798 bool is_zero() const
799 {
800 return doubleEqual(_fVal, 0.0f);
801 }
802
803 static bool isZero(const BoundedDouble& expr)
804 {
805 return doubleEqual(expr.getFVal(), 0.0f);
806 }
807
808 bool equal(const BoundedDouble& rhs) const
809 {
810 return doubleEqual(_fVal, rhs._fVal);
811 }
812
813 bool leq(const BoundedDouble& rhs) const
814 {
815 if (is_infinity() ^ rhs.is_infinity())
816 {
817 if (is_infinity())
818 {
819 return is_minus_infinity();
820 }
821 else
822 {
823 return rhs.is_plus_infinity();
824 }
825 }
826 if (is_infinity() && rhs.is_infinity())
827 {
828 if (is_minus_infinity())
829 return true;
830 else
831 return rhs.is_plus_infinity();
832 }
833 else
834 return _fVal <= rhs._fVal;
835 }
836
837 bool geq(const BoundedDouble& rhs) const
838 {
839 if (is_infinity() ^ rhs.is_infinity())
840 {
841 if (is_infinity())
842 {
843 return is_plus_infinity();
844 }
845 else
846 {
847 return rhs.is_minus_infinity();
848 }
849 }
850 if (is_infinity() && rhs.is_infinity())
851 {
852 if (is_plus_infinity())
853 return true;
854 else
855 return rhs.is_minus_infinity();
856 }
857 else
858 return _fVal >= rhs._fVal;
859 }
860
862 //{%
864 const BoundedDouble& rhs)
865 {
866 return lhs.equal(rhs);
867 }
868
870 const BoundedDouble& rhs)
871 {
872 return !lhs.equal(rhs);
873 }
874
876 const BoundedDouble& rhs)
877 {
878 return !lhs.leq(rhs);
879 }
880
882 const BoundedDouble& rhs)
883 {
884 return !lhs.geq(rhs);
885 }
886
888 const BoundedDouble& rhs)
889 {
890 return lhs.leq(rhs);
891 }
892
894 const BoundedDouble& rhs)
895 {
896 return lhs.geq(rhs);
897 }
898
908 static double safeAdd(double lhs, double rhs)
909 {
910 if ((lhs == std::numeric_limits<double>::infinity() &&
911 rhs == -std::numeric_limits<double>::infinity()) ||
912 (lhs == -std::numeric_limits<double>::infinity() &&
913 rhs == std::numeric_limits<double>::infinity()))
914 {
915 assert(false && "invalid add");
916 }
917 double res =
918 lhs + rhs; // Perform the addition and store the result in 'res'
919
920 // Check if the result is positive infinity due to overflow
921 if (res == std::numeric_limits<double>::infinity())
922 {
923 return res; // Positive overflow has occurred, return positive
924 // infinity
925 }
926
927 // Check if the result is negative infinity, which can indicate a large
928 // negative overflow
929 if (res == -std::numeric_limits<double>::infinity())
930 {
931 return res; // Negative "overflow", effectively an underflow to
932 // negative infinity
933 }
934
935 // Check for positive overflow: verify if both operands are positive and
936 // their sum exceeds the maximum double value
937 if (lhs > 0 && rhs > 0 &&
938 (std::numeric_limits<double>::max() - lhs) < rhs)
939 {
940 res = std::numeric_limits<double>::infinity(); // Set result to
941 // positive infinity to
942 // indicate overflow
943 return res;
944 }
945
946 // Check for an underflow scenario: both numbers are negative and their
947 // sum is more negative than what double can represent
948 if (lhs < 0 && rhs < 0 &&
949 (-std::numeric_limits<double>::max() - lhs) > rhs)
950 {
951 res = -std::numeric_limits<
952 double>::infinity(); // Set result to negative infinity to
953 // clarify extreme negative sum
954 return res;
955 }
956
957 // If none of the above conditions are met, return the result of the
958 // addition
959 return res;
960 }
961
963 const BoundedDouble& rhs)
964 {
965 return safeAdd(lhs._fVal, rhs._fVal);
966 }
967
969 {
970 return -lhs._fVal;
971 }
972
974 const BoundedDouble& rhs)
975 {
976 return safeAdd(lhs._fVal, -rhs._fVal);
977 }
978
988 static double safeMul(double lhs, double rhs)
989 {
990 if (doubleEqual(lhs, 0.0f) || doubleEqual(rhs, 0.0f))
991 return 0.0f;
992 double res = lhs * rhs;
993 // Check if the result is positive infinity due to overflow
994 if (res == std::numeric_limits<double>::infinity())
995 {
996 return res; // Positive overflow has occurred, return positive
997 // infinity
998 }
999
1000 // Check if the result is negative infinity, which can indicate a large
1001 // negative overflow
1002 if (res == -std::numeric_limits<double>::infinity())
1003 {
1004 return res; // Negative "overflow", effectively an underflow to
1005 // negative infinity
1006 }
1007 // Check for overflow scenarios
1008 if (lhs > 0 && rhs > 0 &&
1009 lhs > std::numeric_limits<double>::max() / rhs)
1010 {
1011 return std::numeric_limits<double>::infinity();
1012 }
1013 if (lhs < 0 && rhs < 0 &&
1014 lhs < std::numeric_limits<double>::max() / rhs)
1015 {
1016 return std::numeric_limits<double>::infinity();
1017 }
1018
1019 // Check for "underflow" scenarios (negative overflow)
1020 if (lhs > 0 && rhs < 0 &&
1021 rhs < std::numeric_limits<double>::lowest() / lhs)
1022 {
1023 return -std::numeric_limits<double>::infinity();
1024 }
1025 if (lhs < 0 && rhs > 0 &&
1026 lhs < std::numeric_limits<double>::lowest() / rhs)
1027 {
1028 return -std::numeric_limits<double>::infinity();
1029 }
1030
1031 return res; // If no overflow or underflow, return the product
1032 }
1033
1035 const BoundedDouble& rhs)
1036 {
1037 return safeMul(lhs._fVal, rhs._fVal);
1038 }
1039
1049 static double safeDiv(double lhs, double rhs)
1050 {
1051 // Check for division by zero
1052 if (doubleEqual(rhs, 0.0f))
1053 {
1054 return (lhs >= 0.0f) ? std::numeric_limits<double>::infinity()
1055 : -std::numeric_limits<double>::infinity();
1056 }
1057 double res = lhs / rhs;
1058 // Check if the result is positive infinity due to overflow
1059 if (res == std::numeric_limits<double>::infinity())
1060 {
1061 return res; // Positive overflow has occurred, return positive
1062 // infinity
1063 }
1064
1065 // Check if the result is negative infinity, which can indicate a large
1066 // negative overflow
1067 if (res == -std::numeric_limits<double>::infinity())
1068 {
1069 return res; // Negative "overflow", effectively an underflow to
1070 // negative infinity
1071 }
1072
1073 // Check for overflow when dividing small numbers
1074 if (rhs > 0 && rhs < std::numeric_limits<double>::min() &&
1075 lhs > std::numeric_limits<double>::max() * rhs)
1076 {
1077 return std::numeric_limits<double>::infinity();
1078 }
1079 if (rhs < 0 && rhs > -std::numeric_limits<double>::min() &&
1080 lhs > std::numeric_limits<double>::max() * rhs)
1081 {
1082 return -std::numeric_limits<double>::infinity();
1083 }
1084
1085 return res; // If no special cases, return the quotient
1086 }
1087
1089 const BoundedDouble& rhs)
1090 {
1091 return safeDiv(lhs._fVal, rhs._fVal);
1092 }
1093
1095 const BoundedDouble& rhs)
1096 {
1097 if (rhs.is_zero())
1098 assert(false && "divide by zero");
1099 else if (!lhs.is_infinity() && !rhs.is_infinity())
1100 return std::fmod(lhs._fVal, rhs._fVal);
1101 else if (!lhs.is_infinity() && rhs.is_infinity())
1102 return 0.0f;
1103 // TODO: not sure
1104 else if (lhs.is_infinity() && !rhs.is_infinity())
1105 return ite(rhs._fVal > 0.0f, lhs, -lhs);
1106 else
1107 // TODO: +oo/-oo L'Hôpital's rule?
1108 return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
1109 abort();
1110 }
1111
1112 inline bool is_int() const
1113 {
1114 return _fVal == std::round(_fVal);
1115 }
1116 inline bool is_real() const
1117 {
1118 return !is_int();
1119 }
1120
1122 const BoundedDouble& rhs)
1123 {
1124 int lInt = std::round(lhs._fVal), rInt = std::round(rhs._fVal);
1125 return lInt ^ rInt;
1126 }
1127
1129 const BoundedDouble& rhs)
1130 {
1131 int lInt = std::round(lhs._fVal), rInt = std::round(rhs._fVal);
1132 return lInt & rInt;
1133 }
1134
1136 const BoundedDouble& rhs)
1137 {
1138 int lInt = std::round(lhs._fVal), rInt = std::round(rhs._fVal);
1139 return lInt | rInt;
1140 }
1141
1143 const BoundedDouble& rhs)
1144 {
1145 return lhs._fVal && rhs._fVal;
1146 }
1147
1149 const BoundedDouble& rhs)
1150 {
1151 return lhs._fVal || rhs._fVal;
1152 }
1153
1155 {
1156 return !lhs._fVal;
1157 }
1158
1160 const BoundedDouble& rhs)
1161 {
1162 assert(rhs.geq(0) && "rhs should be greater or equal than 0");
1163 if (lhs.is_zero())
1164 return lhs;
1165 else if (lhs.is_infinity())
1166 return lhs;
1167 else if (rhs.is_infinity())
1168 return lhs.geq(0) ? 0 : -1;
1169 else
1170 return (s32_t)lhs.getNumeral() >> (s32_t)rhs.getNumeral();
1171 }
1172
1174 const BoundedDouble& rhs)
1175 {
1176 assert(rhs.geq(0) && "rhs should be greater or equal than 0");
1177 if (lhs.is_zero())
1178 return lhs;
1179 else if (lhs.is_infinity())
1180 return lhs;
1181 else if (rhs.is_infinity())
1182 return lhs.geq(0) ? plus_infinity() : minus_infinity();
1183 else
1184 return (s32_t)lhs.getNumeral() << (s32_t)rhs.getNumeral();
1185 }
1186
1187 friend BoundedDouble ite(const BoundedDouble& cond,
1188 const BoundedDouble& lhs, const BoundedDouble& rhs)
1189 {
1190 return cond._fVal != 0.0f ? lhs._fVal : rhs._fVal;
1191 }
1192
1193 friend std::ostream& operator<<(std::ostream& out,
1194 const BoundedDouble& expr)
1195 {
1196 out << expr._fVal;
1197 return out;
1198 }
1199
1200 friend bool eq(const BoundedDouble& lhs, const BoundedDouble& rhs)
1201 {
1202 return doubleEqual(lhs._fVal, rhs._fVal);
1203 }
1204
1206 {
1207 return std::min(lhs._fVal, rhs._fVal);
1208 }
1209
1211 {
1212 return std::max(lhs._fVal, rhs._fVal);
1213 }
1214
1215 static BoundedDouble min(std::vector<BoundedDouble>& _l)
1216 {
1218 for (const auto& it : _l)
1219 {
1220 if (it.is_minus_infinity())
1221 return minus_infinity();
1222 else if (!it.geq(ret))
1223 {
1224 ret = it;
1225 }
1226 }
1227 return ret;
1228 }
1229
1230 static BoundedDouble max(std::vector<BoundedDouble>& _l)
1231 {
1233 for (const auto& it : _l)
1234 {
1235 if (it.is_plus_infinity())
1236 return plus_infinity();
1237 else if (!it.leq(ret))
1238 {
1239 ret = it;
1240 }
1241 }
1242 return ret;
1243 }
1244
1246 {
1247 return lhs.leq(0) ? -lhs : lhs;
1248 }
1249
1250 inline bool is_true() const
1251 {
1252 return _fVal != 0.0f;
1253 }
1254
1256 inline s64_t getNumeral() const
1257 {
1258 if (is_minus_infinity())
1259 {
1260 return INT64_MIN;
1261 }
1262 else if (is_plus_infinity())
1263 {
1264 return INT64_MAX;
1265 }
1266 else
1267 {
1268 return std::round(_fVal);
1269 }
1270 }
1271
1272 inline s64_t getIntNumeral() const
1273 {
1274 return getNumeral();
1275 }
1276
1277 inline double getRealNumeral() const
1278 {
1279 return _fVal;
1280 }
1281
1282 inline virtual const std::string to_string() const
1283 {
1284 return std::to_string(_fVal);
1285 }
1286
1287 //%}
1288}; // end class BoundedDouble
1289
1290} // end namespace SVF
1291
1292#endif // SVF_NUMERICVALUE_H
#define epsilon
#define false
Definition cJSON.cpp:70
cJSON * a
Definition cJSON.cpp:2560
const cJSON *const b
Definition cJSON.h:255
BoundedDouble & operator=(const BoundedDouble &rhs)
friend BoundedDouble max(const BoundedDouble &lhs, const BoundedDouble &rhs)
bool is_int() const
friend BoundedDouble operator<(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend BoundedDouble operator%(const BoundedDouble &lhs, const BoundedDouble &rhs)
const double getFVal() const
BoundedDouble()=default
friend BoundedDouble operator>>(const BoundedDouble &lhs, const BoundedDouble &rhs)
static double safeDiv(double lhs, double rhs)
friend BoundedDouble operator*(const BoundedDouble &lhs, const BoundedDouble &rhs)
virtual ~BoundedDouble()
friend BoundedDouble operator==(const BoundedDouble &lhs, const BoundedDouble &rhs)
Reload operator.
static double safeMul(double lhs, double rhs)
static BoundedDouble minus_infinity()
friend BoundedDouble operator!(const BoundedDouble &lhs)
friend BoundedDouble ite(const BoundedDouble &cond, const BoundedDouble &lhs, const BoundedDouble &rhs)
friend BoundedDouble operator>(const BoundedDouble &lhs, const BoundedDouble &rhs)
static BoundedDouble plus_infinity()
friend BoundedDouble operator&&(const BoundedDouble &lhs, const BoundedDouble &rhs)
bool equal(const BoundedDouble &rhs) const
BoundedDouble & operator=(BoundedDouble &&rhs)
s64_t getIntNumeral() const
friend BoundedDouble operator<=(const BoundedDouble &lhs, const BoundedDouble &rhs)
static bool isZero(const BoundedDouble &expr)
static bool doubleEqual(double a, double b)
bool is_real() const
bool geq(const BoundedDouble &rhs) const
friend BoundedDouble operator-(const BoundedDouble &lhs)
friend BoundedDouble operator-(const BoundedDouble &lhs, const BoundedDouble &rhs)
s64_t getNumeral() const
Return Numeral.
friend BoundedDouble operator|(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend BoundedDouble min(const BoundedDouble &lhs, const BoundedDouble &rhs)
bool is_true() const
friend BoundedDouble operator^(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend BoundedDouble operator>=(const BoundedDouble &lhs, const BoundedDouble &rhs)
static double safeAdd(double lhs, double rhs)
friend BoundedDouble abs(const BoundedDouble &lhs)
friend BoundedDouble operator<<(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend BoundedDouble operator/(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend BoundedDouble operator!=(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend bool eq(const BoundedDouble &lhs, const BoundedDouble &rhs)
static BoundedDouble min(std::vector< BoundedDouble > &_l)
friend BoundedDouble operator+(const BoundedDouble &lhs, const BoundedDouble &rhs)
BoundedDouble(const BoundedDouble &rhs)
bool is_minus_infinity() const
BoundedDouble(BoundedDouble &&rhs)
bool leq(const BoundedDouble &rhs) const
bool is_plus_infinity() const
virtual const std::string to_string() const
static BoundedDouble max(std::vector< BoundedDouble > &_l)
friend BoundedDouble operator&(const BoundedDouble &lhs, const BoundedDouble &rhs)
double getRealNumeral() const
BoundedDouble(double fVal)
friend BoundedDouble operator||(const BoundedDouble &lhs, const BoundedDouble &rhs)
bool is_zero() const
friend std::ostream & operator<<(std::ostream &out, const BoundedDouble &expr)
bool is_infinity() const
A class representing a bounded 64-bit integer.
friend BoundedInt operator>=(const BoundedInt &lhs, const BoundedInt &rhs)
BoundedInt()=default
static BoundedInt plus_infinity()
friend BoundedInt operator||(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt operator<=(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt ite(const BoundedInt &cond, const BoundedInt &lhs, const BoundedInt &rhs)
bool is_minus_infinity() const
friend BoundedInt operator!=(const BoundedInt &lhs, const BoundedInt &rhs)
s64_t getNumeral() const
Retrieves the numeral value of the BoundedInt object.
virtual ~BoundedInt()
bool is_plus_infinity() const
friend BoundedInt operator%(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt operator<<(const BoundedInt &lhs, const BoundedInt &rhs)
static BoundedInt min(std::vector< BoundedInt > &_l)
friend BoundedInt operator&(const BoundedInt &lhs, const BoundedInt &rhs)
static BoundedInt safeMul(const BoundedInt &lhs, const BoundedInt &rhs)
Performs safe multiplication of two BoundedInt objects.
bool is_infinity() const
const double getFVal() const
friend BoundedInt operator*(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt abs(const BoundedInt &lhs)
BoundedInt(BoundedInt &&rhs)
friend BoundedInt operator|(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt operator/(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt max(const BoundedInt &lhs, const BoundedInt &rhs)
s64_t getIntNumeral() const
friend BoundedInt operator+(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt operator>>(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt operator!(const BoundedInt &lhs)
friend BoundedInt operator^(const BoundedInt &lhs, const BoundedInt &rhs)
bool is_zero() const
friend BoundedInt operator&&(const BoundedInt &lhs, const BoundedInt &rhs)
bool is_true() const
BoundedInt & operator=(const BoundedInt &rhs)
friend std::ostream & operator<<(std::ostream &out, const BoundedInt &expr)
static BoundedInt max(std::vector< BoundedInt > &_l)
friend bool eq(const BoundedInt &lhs, const BoundedInt &rhs)
static BoundedInt safeAdd(const BoundedInt &lhs, const BoundedInt &rhs)
static BoundedInt minus_infinity()
friend BoundedInt min(const BoundedInt &lhs, const BoundedInt &rhs)
bool geq(const BoundedInt &rhs) const
friend BoundedInt operator<(const BoundedInt &lhs, const BoundedInt &rhs)
bool equal(const BoundedInt &rhs) const
friend BoundedInt operator==(const BoundedInt &lhs, const BoundedInt &rhs)
Reload operator.
BoundedInt & operator=(BoundedInt &&rhs)
bool leq(const BoundedInt &rhs) const
static bool isZero(const BoundedInt &expr)
double getRealNumeral() const
friend BoundedInt operator>(const BoundedInt &lhs, const BoundedInt &rhs)
BoundedInt(s64_t fVal, bool isInf)
void set_minus_infinity()
bool is_real() const
friend BoundedInt operator-(const BoundedInt &lhs)
void set_plus_infinity()
friend BoundedInt operator-(const BoundedInt &lhs, const BoundedInt &rhs)
BoundedInt(const BoundedInt &rhs)
virtual const std::string to_string() const
BoundedInt(s64_t fVal)
for isBitcode
Definition BasicTypes.h:68
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74
signed s32_t
Definition GeneralType.h:47
signed long long s64_t
Definition GeneralType.h:49