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 {
450 assert(false && "divide by zero");
451 abort();
452 }
453 else if (!lhs.is_infinity() && !rhs.is_infinity())
454 return lhs._iVal / rhs._iVal;
455 else if (!lhs.is_infinity() && rhs.is_infinity())
456 return 0;
457 else if (lhs.is_infinity() && !rhs.is_infinity())
458 return ite(rhs._iVal >= 0, lhs, -lhs);
459 else
460 return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
461 }
462
463 // Overload bitwise operators for BoundedInt objects. These operators
464 // directly apply the corresponding bitwise operators to the internal
465 // integer values of the BoundedInt objects.
466
467 // Overloads the bitwise XOR operator for BoundedInt objects.
469 {
470 return lhs._iVal ^ rhs._iVal;
471 }
472
473 // Overloads the bitwise AND operator for BoundedInt objects.
475 {
476 return lhs._iVal & rhs._iVal;
477 }
478
479 // Overloads the bitwise OR operator for BoundedInt objects.
481 {
482 return lhs._iVal | rhs._iVal;
483 }
484
485 // Overload logical operators for BoundedInt objects. These operators
486 // directly apply the corresponding logical operators to the internal
487 // integer values of the BoundedInt objects.
488
489 // Overloads the logical AND operator for BoundedInt objects.
491 {
492 return lhs._iVal && rhs._iVal;
493 }
494
495 // Overloads the logical OR operator for BoundedInt objects.
497 {
498 return lhs._iVal || rhs._iVal;
499 }
500
501 // Overloads the logical NOT operator for BoundedInt objects.
503 {
504 return !lhs._iVal;
505 }
506
507 // Overloads the right shift operator for BoundedInt objects.
508 // This operation is safe as long as the right-hand side is non-negative.
509 // If the left-hand side is zero or infinity, the result is the same as the
510 // left-hand side. If the right-hand side is infinity, the result depends on
511 // the sign of the left-hand side.
513 {
514 assert(rhs.geq(0) && "rhs should be greater or equal than 0");
515 if (lhs.is_zero())
516 return lhs;
517 else if (lhs.is_infinity())
518 return lhs;
519 else if (rhs.is_infinity())
520 return lhs.geq(0) ? 0 : -1;
521 else
522 return lhs._iVal >> rhs._iVal;
523 }
524
525 // Overloads the left shift operator for BoundedInt objects.
526 // This operation is safe as long as the right-hand side is non-negative.
527 // If the left-hand side is zero or infinity, the result is the same as the
528 // left-hand side. If the right-hand side is infinity, the result depends on
529 // the sign of the left-hand side.
531 {
532 assert(rhs.geq(0) && "rhs should be greater or equal than 0");
533 if (lhs.is_zero())
534 return lhs;
535 else if (lhs.is_infinity())
536 return lhs;
537 else if (rhs.is_infinity())
538 return lhs.geq(0) ? plus_infinity() : minus_infinity();
539 else
540 return lhs._iVal << rhs._iVal;
541 }
542
543 // Overloads the ternary if-then-else operator for BoundedInt objects.
544 // The condition is evaluated as a boolean, and the result is either the
545 // second or third argument depending on the condition.
546 friend BoundedInt ite(const BoundedInt& cond, const BoundedInt& lhs,
547 const BoundedInt& rhs)
548 {
549 return cond._iVal != 0 ? lhs : rhs;
550 }
551
552 // Overloads the stream insertion operator for BoundedInt objects.
553 // This allows BoundedInt objects to be printed directly using std::cout or
554 // other output streams.
555 friend std::ostream& operator<<(std::ostream& out, const BoundedInt& expr)
556 {
557 out << expr._iVal;
558 return out;
559 }
560
561 // Defines a function to compare two BoundedInt objects for equality.
562 // This function directly compares the internal integer values of the
563 // BoundedInt objects.
564 friend bool eq(const BoundedInt& lhs, const BoundedInt& rhs)
565 {
566 return lhs._iVal == rhs._iVal && lhs._isInf == rhs._isInf;
567 }
568
569 // Defines a function to find the minimum of two BoundedInt objects.
570 // This function directly compares the internal integer values of the BoundedInt objects,
571 // and also checks if either of them represents infinity.
572 friend BoundedInt min(const BoundedInt& lhs, const BoundedInt& rhs)
573 {
574 if (lhs.is_minus_infinity() || rhs.is_minus_infinity())
575 return minus_infinity();
576 else if(lhs.is_plus_infinity())
577 return rhs;
578 else if(rhs.is_plus_infinity())
579 return lhs;
580 else
581 return BoundedInt(std::min(lhs._iVal, rhs._iVal));
582 }
583
584
585 // Defines a function to find the maximum of two BoundedInt objects.
586 // This function directly compares the internal integer values of the BoundedInt objects,
587 // and also checks if either of them represents infinity.
588 friend BoundedInt max(const BoundedInt& lhs, const BoundedInt& rhs)
589 {
590 if (lhs.is_plus_infinity() || rhs.is_plus_infinity())
591 return plus_infinity();
592 else if(lhs.is_minus_infinity())
593 return rhs;
594 else if(rhs.is_minus_infinity())
595 return lhs;
596 else
597 return BoundedInt(std::max(lhs._iVal, rhs._iVal));
598 }
599
600
601 // Defines a function to find the minimum of a vector of BoundedInt objects.
602 // This function iterates over the vector and returns the smallest
603 // BoundedInt object.
604 static BoundedInt min(std::vector<BoundedInt>& _l)
605 {
607 for (const auto& it : _l)
608 {
609 if (it.is_minus_infinity())
610 return minus_infinity();
611 else if (!it.geq(ret))
612 {
613 ret = it;
614 }
615 }
616 return ret;
617 }
618
619 // Defines a function to find the maximum of a vector of BoundedInt objects.
620 // This function iterates over the vector and returns the largest BoundedInt
621 // object.
622 static BoundedInt max(std::vector<BoundedInt>& _l)
623 {
625 for (const auto& it : _l)
626 {
627 if (it.is_plus_infinity())
628 return plus_infinity();
629 else if (!it.leq(ret))
630 {
631 ret = it;
632 }
633 }
634 return ret;
635 }
636
637 // Defines a function to find the absolute value of a BoundedInt object.
638 // This function directly applies the unary minus operator if the BoundedInt
639 // object is negative.
641 {
642 return lhs.leq(0) ? -lhs : lhs;
643 }
644
645 // Defines a method to check if a BoundedInt object is true.
646 // A BoundedInt object is considered true if its internal integer value is
647 // non-zero.
648 inline bool is_true() const
649 {
650 return _iVal != 0;
651 }
652
664 inline s64_t getNumeral() const
665 {
666 // If the object represents negative infinity, return the minimum
667 // representable 64-bit integer.
668 if (is_minus_infinity())
669 {
670 return std::numeric_limits<s64_t>::min();
671 }
672 // If the object represents positive infinity, return the maximum
673 // representable 64-bit integer.
674 else if (is_plus_infinity())
675 {
676 return std::numeric_limits<s64_t>::max();
677 }
678 // Otherwise, return the actual 64-bit integer value of the object.
679 else
680 {
681 return _iVal;
682 }
683 }
684
685 inline virtual const std::string to_string() const
686 {
687 if (is_minus_infinity())
688 {
689 return "-oo";
690 }
691 if (is_plus_infinity())
692 {
693 return "+oo";
694 }
695 else
696 return std::to_string(_iVal);
697 }
698
699 //%}
700
701 bool is_real() const
702 {
703 return false;
704 }
705
706 inline s64_t getIntNumeral() const
707 {
708 return getNumeral();
709 }
710
711 inline double getRealNumeral() const
712 {
713 assert(false && "cannot get real number for integer!");
714 abort();
715 }
716
717 const double getFVal() const
718 {
719 assert(false && "cannot get real number for integer!");
720 abort();
721 }
722};
727{
728protected:
729 double _fVal;
730
731 BoundedDouble() = default;
732
733public:
735
737
739 {
740 _fVal = rhs._fVal;
741 return *this;
742 }
743
745
747 {
748 _fVal = std::move(rhs._fVal);
749 return *this;
750 }
751
752 virtual ~BoundedDouble() {}
753
754 static bool doubleEqual(double a, double b)
755 {
756 if (std::isinf(a) && std::isinf(b))
757 return a == b;
758 return std::fabs(a - b) < epsilon;
759 }
760
761 const double getFVal() const
762 {
763 return _fVal;
764 }
765
766 bool is_plus_infinity() const
767 {
768 return _fVal == std::numeric_limits<double>::infinity();
769 }
770
771 bool is_minus_infinity() const
772 {
773 return _fVal == -std::numeric_limits<double>::infinity();
774 }
775
776 bool is_infinity() const
777 {
779 }
780
782 {
783 *this = plus_infinity();
784 }
785
787 {
788 *this = minus_infinity();
789 }
790
792 {
793 return std::numeric_limits<double>::infinity();
794 }
795
797 {
798 return -std::numeric_limits<double>::infinity();
799 }
800
801 bool is_zero() const
802 {
803 return doubleEqual(_fVal, 0.0f);
804 }
805
806 static bool isZero(const BoundedDouble& expr)
807 {
808 return doubleEqual(expr.getFVal(), 0.0f);
809 }
810
811 bool equal(const BoundedDouble& rhs) const
812 {
813 return doubleEqual(_fVal, rhs._fVal);
814 }
815
816 bool leq(const BoundedDouble& rhs) const
817 {
818 if (is_infinity() ^ rhs.is_infinity())
819 {
820 if (is_infinity())
821 {
822 return is_minus_infinity();
823 }
824 else
825 {
826 return rhs.is_plus_infinity();
827 }
828 }
829 if (is_infinity() && rhs.is_infinity())
830 {
831 if (is_minus_infinity())
832 return true;
833 else
834 return rhs.is_plus_infinity();
835 }
836 else
837 return _fVal <= rhs._fVal;
838 }
839
840 bool geq(const BoundedDouble& rhs) const
841 {
842 if (is_infinity() ^ rhs.is_infinity())
843 {
844 if (is_infinity())
845 {
846 return is_plus_infinity();
847 }
848 else
849 {
850 return rhs.is_minus_infinity();
851 }
852 }
853 if (is_infinity() && rhs.is_infinity())
854 {
855 if (is_plus_infinity())
856 return true;
857 else
858 return rhs.is_minus_infinity();
859 }
860 else
861 return _fVal >= rhs._fVal;
862 }
863
865 //{%
867 const BoundedDouble& rhs)
868 {
869 return lhs.equal(rhs);
870 }
871
873 const BoundedDouble& rhs)
874 {
875 return !lhs.equal(rhs);
876 }
877
879 const BoundedDouble& rhs)
880 {
881 return !lhs.leq(rhs);
882 }
883
885 const BoundedDouble& rhs)
886 {
887 return !lhs.geq(rhs);
888 }
889
891 const BoundedDouble& rhs)
892 {
893 return lhs.leq(rhs);
894 }
895
897 const BoundedDouble& rhs)
898 {
899 return lhs.geq(rhs);
900 }
901
911 static double safeAdd(double lhs, double rhs)
912 {
913 if ((lhs == std::numeric_limits<double>::infinity() &&
914 rhs == -std::numeric_limits<double>::infinity()) ||
915 (lhs == -std::numeric_limits<double>::infinity() &&
916 rhs == std::numeric_limits<double>::infinity()))
917 {
918 assert(false && "invalid add");
919 }
920 double res =
921 lhs + rhs; // Perform the addition and store the result in 'res'
922
923 // Check if the result is positive infinity due to overflow
924 if (res == std::numeric_limits<double>::infinity())
925 {
926 return res; // Positive overflow has occurred, return positive
927 // infinity
928 }
929
930 // Check if the result is negative infinity, which can indicate a large
931 // negative overflow
932 if (res == -std::numeric_limits<double>::infinity())
933 {
934 return res; // Negative "overflow", effectively an underflow to
935 // negative infinity
936 }
937
938 // Check for positive overflow: verify if both operands are positive and
939 // their sum exceeds the maximum double value
940 if (lhs > 0 && rhs > 0 &&
941 (std::numeric_limits<double>::max() - lhs) < rhs)
942 {
943 res = std::numeric_limits<double>::infinity(); // Set result to
944 // positive infinity to
945 // indicate overflow
946 return res;
947 }
948
949 // Check for an underflow scenario: both numbers are negative and their
950 // sum is more negative than what double can represent
951 if (lhs < 0 && rhs < 0 &&
952 (-std::numeric_limits<double>::max() - lhs) > rhs)
953 {
954 res = -std::numeric_limits<
955 double>::infinity(); // Set result to negative infinity to
956 // clarify extreme negative sum
957 return res;
958 }
959
960 // If none of the above conditions are met, return the result of the
961 // addition
962 return res;
963 }
964
966 const BoundedDouble& rhs)
967 {
968 return safeAdd(lhs._fVal, rhs._fVal);
969 }
970
972 {
973 return -lhs._fVal;
974 }
975
977 const BoundedDouble& rhs)
978 {
979 return safeAdd(lhs._fVal, -rhs._fVal);
980 }
981
991 static double safeMul(double lhs, double rhs)
992 {
993 if (doubleEqual(lhs, 0.0f) || doubleEqual(rhs, 0.0f))
994 return 0.0f;
995 double res = lhs * rhs;
996 // Check if the result is positive infinity due to overflow
997 if (res == std::numeric_limits<double>::infinity())
998 {
999 return res; // Positive overflow has occurred, return positive
1000 // infinity
1001 }
1002
1003 // Check if the result is negative infinity, which can indicate a large
1004 // negative overflow
1005 if (res == -std::numeric_limits<double>::infinity())
1006 {
1007 return res; // Negative "overflow", effectively an underflow to
1008 // negative infinity
1009 }
1010 // Check for overflow scenarios
1011 if (lhs > 0 && rhs > 0 &&
1012 lhs > std::numeric_limits<double>::max() / rhs)
1013 {
1014 return std::numeric_limits<double>::infinity();
1015 }
1016 if (lhs < 0 && rhs < 0 &&
1017 lhs < std::numeric_limits<double>::max() / rhs)
1018 {
1019 return std::numeric_limits<double>::infinity();
1020 }
1021
1022 // Check for "underflow" scenarios (negative overflow)
1023 if (lhs > 0 && rhs < 0 &&
1024 rhs < std::numeric_limits<double>::lowest() / lhs)
1025 {
1026 return -std::numeric_limits<double>::infinity();
1027 }
1028 if (lhs < 0 && rhs > 0 &&
1029 lhs < std::numeric_limits<double>::lowest() / rhs)
1030 {
1031 return -std::numeric_limits<double>::infinity();
1032 }
1033
1034 return res; // If no overflow or underflow, return the product
1035 }
1036
1038 const BoundedDouble& rhs)
1039 {
1040 return safeMul(lhs._fVal, rhs._fVal);
1041 }
1042
1052 static double safeDiv(double lhs, double rhs)
1053 {
1054 // Check for division by zero
1055 if (doubleEqual(rhs, 0.0f))
1056 {
1057 return (lhs >= 0.0f) ? std::numeric_limits<double>::infinity()
1058 : -std::numeric_limits<double>::infinity();
1059 }
1060 double res = lhs / rhs;
1061 // Check if the result is positive infinity due to overflow
1062 if (res == std::numeric_limits<double>::infinity())
1063 {
1064 return res; // Positive overflow has occurred, return positive
1065 // infinity
1066 }
1067
1068 // Check if the result is negative infinity, which can indicate a large
1069 // negative overflow
1070 if (res == -std::numeric_limits<double>::infinity())
1071 {
1072 return res; // Negative "overflow", effectively an underflow to
1073 // negative infinity
1074 }
1075
1076 // Check for overflow when dividing small numbers
1077 if (rhs > 0 && rhs < std::numeric_limits<double>::min() &&
1078 lhs > std::numeric_limits<double>::max() * rhs)
1079 {
1080 return std::numeric_limits<double>::infinity();
1081 }
1082 if (rhs < 0 && rhs > -std::numeric_limits<double>::min() &&
1083 lhs > std::numeric_limits<double>::max() * rhs)
1084 {
1085 return -std::numeric_limits<double>::infinity();
1086 }
1087
1088 return res; // If no special cases, return the quotient
1089 }
1090
1092 const BoundedDouble& rhs)
1093 {
1094 return safeDiv(lhs._fVal, rhs._fVal);
1095 }
1096
1098 const BoundedDouble& rhs)
1099 {
1100 if (rhs.is_zero())
1101 assert(false && "divide by zero");
1102 else if (!lhs.is_infinity() && !rhs.is_infinity())
1103 return std::fmod(lhs._fVal, rhs._fVal);
1104 else if (!lhs.is_infinity() && rhs.is_infinity())
1105 return 0.0f;
1106 // TODO: not sure
1107 else if (lhs.is_infinity() && !rhs.is_infinity())
1108 return ite(rhs._fVal > 0.0f, lhs, -lhs);
1109 else
1110 // TODO: +oo/-oo L'Hôpital's rule?
1111 return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
1112 abort();
1113 }
1114
1115 inline bool is_int() const
1116 {
1117 return _fVal == std::round(_fVal);
1118 }
1119 inline bool is_real() const
1120 {
1121 return !is_int();
1122 }
1123
1125 const BoundedDouble& rhs)
1126 {
1127 int lInt = std::round(lhs._fVal), rInt = std::round(rhs._fVal);
1128 return lInt ^ rInt;
1129 }
1130
1132 const BoundedDouble& rhs)
1133 {
1134 int lInt = std::round(lhs._fVal), rInt = std::round(rhs._fVal);
1135 return lInt & rInt;
1136 }
1137
1139 const BoundedDouble& rhs)
1140 {
1141 int lInt = std::round(lhs._fVal), rInt = std::round(rhs._fVal);
1142 return lInt | rInt;
1143 }
1144
1146 const BoundedDouble& rhs)
1147 {
1148 return lhs._fVal && rhs._fVal;
1149 }
1150
1152 const BoundedDouble& rhs)
1153 {
1154 return lhs._fVal || rhs._fVal;
1155 }
1156
1158 {
1159 return !lhs._fVal;
1160 }
1161
1163 const BoundedDouble& rhs)
1164 {
1165 assert(rhs.geq(0) && "rhs should be greater or equal than 0");
1166 if (lhs.is_zero())
1167 return lhs;
1168 else if (lhs.is_infinity())
1169 return lhs;
1170 else if (rhs.is_infinity())
1171 return lhs.geq(0) ? 0 : -1;
1172 else
1173 return (s32_t)lhs.getNumeral() >> (s32_t)rhs.getNumeral();
1174 }
1175
1177 const BoundedDouble& rhs)
1178 {
1179 assert(rhs.geq(0) && "rhs should be greater or equal than 0");
1180 if (lhs.is_zero())
1181 return lhs;
1182 else if (lhs.is_infinity())
1183 return lhs;
1184 else if (rhs.is_infinity())
1185 return lhs.geq(0) ? plus_infinity() : minus_infinity();
1186 else
1187 return (s32_t)lhs.getNumeral() << (s32_t)rhs.getNumeral();
1188 }
1189
1190 friend BoundedDouble ite(const BoundedDouble& cond,
1191 const BoundedDouble& lhs, const BoundedDouble& rhs)
1192 {
1193 return cond._fVal != 0.0f ? lhs._fVal : rhs._fVal;
1194 }
1195
1196 friend std::ostream& operator<<(std::ostream& out,
1197 const BoundedDouble& expr)
1198 {
1199 out << expr._fVal;
1200 return out;
1201 }
1202
1203 friend bool eq(const BoundedDouble& lhs, const BoundedDouble& rhs)
1204 {
1205 return doubleEqual(lhs._fVal, rhs._fVal);
1206 }
1207
1209 {
1210 return std::min(lhs._fVal, rhs._fVal);
1211 }
1212
1214 {
1215 return std::max(lhs._fVal, rhs._fVal);
1216 }
1217
1218 static BoundedDouble min(std::vector<BoundedDouble>& _l)
1219 {
1221 for (const auto& it : _l)
1222 {
1223 if (it.is_minus_infinity())
1224 return minus_infinity();
1225 else if (!it.geq(ret))
1226 {
1227 ret = it;
1228 }
1229 }
1230 return ret;
1231 }
1232
1233 static BoundedDouble max(std::vector<BoundedDouble>& _l)
1234 {
1236 for (const auto& it : _l)
1237 {
1238 if (it.is_plus_infinity())
1239 return plus_infinity();
1240 else if (!it.leq(ret))
1241 {
1242 ret = it;
1243 }
1244 }
1245 return ret;
1246 }
1247
1249 {
1250 return lhs.leq(0) ? -lhs : lhs;
1251 }
1252
1253 inline bool is_true() const
1254 {
1255 return _fVal != 0.0f;
1256 }
1257
1259 inline s64_t getNumeral() const
1260 {
1261 if (is_minus_infinity())
1262 {
1263 return INT64_MIN;
1264 }
1265 else if (is_plus_infinity())
1266 {
1267 return INT64_MAX;
1268 }
1269 else
1270 {
1271 return std::round(_fVal);
1272 }
1273 }
1274
1275 inline s64_t getIntNumeral() const
1276 {
1277 return getNumeral();
1278 }
1279
1280 inline double getRealNumeral() const
1281 {
1282 return _fVal;
1283 }
1284
1285 inline virtual const std::string to_string() const
1286 {
1287 return std::to_string(_fVal);
1288 }
1289
1290 //%}
1291}; // end class BoundedDouble
1292
1293} // end namespace SVF
1294
1295#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:48
signed long long s64_t
Definition GeneralType.h:50