analyzer: fix feasibility false +ve on jumps through function ptrs [PR107582]
[platform/upstream/gcc.git] / gcc / sreal.h
1 /* Definitions for simple data type for real numbers.
2    Copyright (C) 2002-2022 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19
20 #ifndef GCC_SREAL_H
21 #define GCC_SREAL_H
22
23 #define SREAL_PART_BITS 31
24
25 #define UINT64_BITS     64
26
27 #define SREAL_MIN_SIG ((int64_t) 1 << (SREAL_PART_BITS - 2))
28 #define SREAL_MAX_SIG (((int64_t) 1 << (SREAL_PART_BITS - 1)) - 1)
29 #define SREAL_MAX_EXP (INT_MAX / 4)
30
31 #define SREAL_BITS SREAL_PART_BITS
32
33 #define SREAL_SIGN(v) (v < 0 ? -1: 1)
34 #define SREAL_ABS(v) (v < 0 ? -v: v)
35
36 struct output_block;
37 class lto_input_block;
38
39 /* Structure for holding a simple real number.  */
40 class sreal
41 {
42 public:
43   /* Construct an uninitialized sreal.  */
44   sreal () : m_sig (-1), m_exp (-1) {}
45
46   /* Construct a sreal.  */
47   sreal (int64_t sig, int exp = 0)
48   {
49     normalize (sig, exp);
50   }
51
52   void dump (FILE *) const;
53   int64_t to_int () const;
54   double to_double () const;
55   void stream_out (struct output_block *);
56   static sreal stream_in (class lto_input_block *);
57   sreal operator+ (const sreal &other) const;
58   sreal operator- (const sreal &other) const;
59   sreal operator* (const sreal &other) const;
60   sreal operator/ (const sreal &other) const;
61
62   bool operator< (const sreal &other) const
63   {
64     if (m_exp == other.m_exp)
65       return m_sig < other.m_sig;
66     else
67     {
68       bool negative = m_sig < 0;
69       bool other_negative = other.m_sig < 0;
70
71       if (negative != other_negative)
72         return negative > other_negative;
73
74       bool r = m_exp < other.m_exp;
75       return negative ? !r : r;
76     }
77   }
78
79   bool operator== (const sreal &other) const
80   {
81     return m_exp == other.m_exp && m_sig == other.m_sig;
82   }
83
84   sreal operator- () const
85   {
86     sreal tmp = *this;
87     tmp.m_sig *= -1;
88
89     return tmp;
90   }
91
92   sreal shift (int s) const
93   {
94     /* Zero needs no shifting.  */
95     if (!m_sig)
96       return *this;
97     gcc_checking_assert (s <= SREAL_MAX_EXP);
98     gcc_checking_assert (s >= -SREAL_MAX_EXP);
99
100     /* Overflows/drop to 0 could be handled gracefully, but hopefully we do not
101        need to do so.  */
102     gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
103     gcc_checking_assert (m_exp + s >= -SREAL_MAX_EXP);
104
105     sreal tmp = *this;
106     tmp.m_exp += s;
107
108     return tmp;
109   }
110
111   /* Global minimum sreal can hold.  */
112   inline static sreal min ()
113   {
114     sreal min;
115     /* This never needs normalization.  */
116     min.m_sig = -SREAL_MAX_SIG;
117     min.m_exp = SREAL_MAX_EXP;
118     return min;
119   }
120
121   /* Global minimum sreal can hold.  */
122   inline static sreal max ()
123   {
124     sreal max;
125     /* This never needs normalization.  */
126     max.m_sig = SREAL_MAX_SIG;
127     max.m_exp = SREAL_MAX_EXP;
128     return max;
129   }
130
131 private:
132   inline void normalize (int64_t new_sig, signed int new_exp);
133   inline void normalize_up (int64_t new_sig, signed int new_exp);
134   inline void normalize_down (int64_t new_sig, signed int new_exp);
135   void shift_right (int amount);
136   static sreal signedless_plus (const sreal &a, const sreal &b, bool negative);
137   static sreal signedless_minus (const sreal &a, const sreal &b, bool negative);
138
139   int32_t m_sig;                        /* Significant.  */
140   signed int m_exp;                     /* Exponent.  */
141 };
142
143 extern void debug (const sreal &ref);
144 extern void debug (const sreal *ptr);
145
146 inline sreal &operator+= (sreal &a, const sreal &b)
147 {
148   return a = a + b;
149 }
150
151 inline sreal &operator-= (sreal &a, const sreal &b)
152 {
153   return a = a - b;
154 }
155
156 inline sreal &operator/= (sreal &a, const sreal &b)
157 {
158   return a = a / b;
159 }
160
161 inline sreal &operator*= (sreal &a, const sreal &b)
162 {
163   return a = a  * b;
164 }
165
166 inline bool operator!= (const sreal &a, const sreal &b)
167 {
168   return !(a == b);
169 }
170
171 inline bool operator> (const sreal &a, const sreal &b)
172 {
173   return !(a == b || a < b);
174 }
175
176 inline bool operator<= (const sreal &a, const sreal &b)
177 {
178   return a < b || a == b;
179 }
180
181 inline bool operator>= (const sreal &a, const sreal &b)
182 {
183   return a == b || a > b;
184 }
185
186 inline sreal operator<< (const sreal &a, int exp)
187 {
188   return a.shift (exp);
189 }
190
191 inline sreal operator>> (const sreal &a, int exp)
192 {
193   return a.shift (-exp);
194 }
195
196 /* Make significant to be >= SREAL_MIN_SIG.
197
198    Make this separate method so inliner can handle hot path better.  */
199
200 inline void
201 sreal::normalize_up (int64_t new_sig, signed int new_exp)
202 {
203   unsigned HOST_WIDE_INT sig = absu_hwi (new_sig);
204   int shift = SREAL_PART_BITS - 2 - floor_log2 (sig);
205
206   gcc_checking_assert (shift > 0);
207   sig <<= shift;
208   new_exp -= shift;
209   gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG);
210
211   /* Check underflow.  */
212   if (new_exp < -SREAL_MAX_EXP)
213     {
214       new_exp = -SREAL_MAX_EXP;
215       sig = 0;
216     }
217   m_exp = new_exp;
218   if (SREAL_SIGN (new_sig) == -1)
219     m_sig = -sig;
220   else
221     m_sig = sig;
222 }
223
224 /* Make significant to be <= SREAL_MAX_SIG.
225
226    Make this separate method so inliner can handle hot path better.  */
227
228 inline void
229 sreal::normalize_down (int64_t new_sig, signed int new_exp)
230 {
231   int last_bit;
232   unsigned HOST_WIDE_INT sig = absu_hwi (new_sig);
233   int shift = floor_log2 (sig) - SREAL_PART_BITS + 2;
234
235   gcc_checking_assert (shift > 0);
236   last_bit = (sig >> (shift-1)) & 1;
237   sig >>= shift;
238   new_exp += shift;
239   gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG);
240
241   /* Round the number.  */
242   sig += last_bit;
243   if (sig > SREAL_MAX_SIG)
244     {
245       sig >>= 1;
246       new_exp++;
247     }
248
249   /* Check overflow.  */
250   if (new_exp > SREAL_MAX_EXP)
251     {
252       new_exp = SREAL_MAX_EXP;
253       sig = SREAL_MAX_SIG;
254     }
255   m_exp = new_exp;
256   if (SREAL_SIGN (new_sig) == -1)
257     m_sig = -sig;
258   else
259     m_sig = sig;
260 }
261
262 /* Normalize *this; the hot path.  */
263
264 inline void
265 sreal::normalize (int64_t new_sig, signed int new_exp)
266 {
267   unsigned HOST_WIDE_INT sig = absu_hwi (new_sig);
268
269   if (sig == 0)
270     {
271       m_sig = 0;
272       m_exp = -SREAL_MAX_EXP;
273     }
274   else if (sig > SREAL_MAX_SIG)
275     normalize_down (new_sig, new_exp);
276   else if (sig < SREAL_MIN_SIG)
277     normalize_up (new_sig, new_exp);
278   else
279     {
280       m_sig = new_sig;
281       m_exp = new_exp;
282     }
283 }
284
285 #endif