1 /* Simple data type for real numbers for the GNU compiler.
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 /* This library supports real numbers;
21 inf and nan are NOT supported.
22 It is written to be simple and fast.
23
24 Value of sreal is
25 x = sig * 2 ^ exp
26 where
27 sig = significant
28 (for < 64-bit machines sig = sig_lo + sig_hi * 2 ^ SREAL_PART_BITS)
29 exp = exponent
30
31 One uint64_t is used for the significant.
32 Only a half of significant bits is used (in normalized sreals) so that we do
33 not have problems with overflow, for example when c->sig = a->sig * b->sig.
34 So the precision is 32-bit.
35
36 Invariant: The numbers are normalized before and after each call of sreal_*.
37
38 Normalized sreals:
39 All numbers (except zero) meet following conditions:
40 SREAL_MIN_SIG <= sig && sig <= SREAL_MAX_SIG
41 -SREAL_MAX_EXP <= exp && exp <= SREAL_MAX_EXP
42
43 If the number would be too large, it is set to upper bounds of these
44 conditions.
45
46 If the number is zero or would be too small it meets following conditions:
47 sig == 0 && exp == -SREAL_MAX_EXP
48 */
49
50 #include "config.h"
51 #include "system.h"
52 #include <math.h>
53 #include "coretypes.h"
54 #include "sreal.h"
55 #include "selftest.h"
56 #include "backend.h"
57 #include "tree.h"
58 #include "gimple.h"
59 #include "cgraph.h"
60 #include "data-streamer.h"
61
62 /* Print the content of struct sreal. */
63
64 void
dump(FILE * file) const65 sreal::dump (FILE *file) const
66 {
67 fprintf (file, "(%" PRIi64 " * 2^%d)", (int64_t)m_sig, m_exp);
68 }
69
70 DEBUG_FUNCTION void
debug(const sreal & ref)71 debug (const sreal &ref)
72 {
73 ref.dump (stderr);
74 }
75
76 DEBUG_FUNCTION void
debug(const sreal * ptr)77 debug (const sreal *ptr)
78 {
79 if (ptr)
80 debug (*ptr);
81 else
82 fprintf (stderr, "<nil>\n");
83 }
84
85 /* Shift this right by S bits. Needed: 0 < S <= SREAL_BITS.
86 When the most significant bit shifted out is 1, add 1 to this (rounding).
87 */
88
89 void
shift_right(int s)90 sreal::shift_right (int s)
91 {
92 gcc_checking_assert (s > 0);
93 gcc_checking_assert (s <= SREAL_BITS);
94 /* Exponent should never be so large because shift_right is used only by
95 sreal_add and sreal_sub ant thus the number cannot be shifted out from
96 exponent range. */
97 gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
98
99 m_exp += s;
100
101 m_sig += (int64_t) 1 << (s - 1);
102 m_sig >>= s;
103 }
104
105 /* Return integer value of *this. */
106
107 int64_t
to_int() const108 sreal::to_int () const
109 {
110 int64_t sign = SREAL_SIGN (m_sig);
111
112 if (m_exp <= -SREAL_BITS)
113 return 0;
114 if (m_exp >= SREAL_PART_BITS)
115 return sign * INTTYPE_MAXIMUM (int64_t);
116 if (m_exp > 0)
117 return sign * (SREAL_ABS ((int64_t)m_sig) << m_exp);
118 if (m_exp < 0)
119 return m_sig >> -m_exp;
120 return m_sig;
121 }
122
123 /* Return value of *this as double.
124 This should be used for debug output only. */
125
126 double
to_double() const127 sreal::to_double () const
128 {
129 double val = m_sig;
130 if (m_exp)
131 val = ldexp (val, m_exp);
132 return val;
133 }
134
135 /* Return *this + other. */
136
137 sreal
operator +(const sreal & other) const138 sreal::operator+ (const sreal &other) const
139 {
140 int dexp;
141 sreal tmp;
142 int64_t r_sig, r_exp;
143
144 const sreal *a_p = this, *b_p = &other, *bb;
145
146 if (a_p->m_exp < b_p->m_exp)
147 std::swap (a_p, b_p);
148
149 dexp = a_p->m_exp - b_p->m_exp;
150 r_exp = a_p->m_exp;
151 if (dexp > SREAL_BITS)
152 {
153 r_sig = a_p->m_sig;
154
155 sreal r;
156 r.m_sig = r_sig;
157 r.m_exp = r_exp;
158 return r;
159 }
160
161 if (dexp == 0)
162 bb = b_p;
163 else
164 {
165 tmp = *b_p;
166 tmp.shift_right (dexp);
167 bb = &tmp;
168 }
169
170 r_sig = a_p->m_sig + (int64_t)bb->m_sig;
171 sreal r (r_sig, r_exp);
172 return r;
173 }
174
175
176 /* Return *this - other. */
177
178 sreal
operator -(const sreal & other) const179 sreal::operator- (const sreal &other) const
180 {
181 int dexp;
182 sreal tmp;
183 int64_t r_sig, r_exp;
184 const sreal *bb;
185 const sreal *a_p = this, *b_p = &other;
186
187 int64_t sign = 1;
188 if (a_p->m_exp < b_p->m_exp)
189 {
190 sign = -1;
191 std::swap (a_p, b_p);
192 }
193
194 dexp = a_p->m_exp - b_p->m_exp;
195 r_exp = a_p->m_exp;
196 if (dexp > SREAL_BITS)
197 {
198 r_sig = sign * a_p->m_sig;
199
200 sreal r;
201 r.m_sig = r_sig;
202 r.m_exp = r_exp;
203 return r;
204 }
205 if (dexp == 0)
206 bb = b_p;
207 else
208 {
209 tmp = *b_p;
210 tmp.shift_right (dexp);
211 bb = &tmp;
212 }
213
214 r_sig = sign * ((int64_t) a_p->m_sig - (int64_t)bb->m_sig);
215 sreal r (r_sig, r_exp);
216 return r;
217 }
218
219 /* Return *this * other. */
220
221 sreal
operator *(const sreal & other) const222 sreal::operator* (const sreal &other) const
223 {
224 sreal r;
225 if (absu_hwi (m_sig) < SREAL_MIN_SIG
226 || absu_hwi (other.m_sig) < SREAL_MIN_SIG)
227 {
228 r.m_sig = 0;
229 r.m_exp = -SREAL_MAX_EXP;
230 }
231 else
232 r.normalize (m_sig * (int64_t) other.m_sig, m_exp + other.m_exp);
233
234 return r;
235 }
236
237 /* Return *this / other. */
238
239 sreal
operator /(const sreal & other) const240 sreal::operator/ (const sreal &other) const
241 {
242 gcc_checking_assert (other.m_sig != 0);
243 sreal r (SREAL_SIGN (m_sig)
244 * ((int64_t)SREAL_ABS (m_sig) << SREAL_PART_BITS) / other.m_sig,
245 m_exp - other.m_exp - SREAL_PART_BITS);
246 return r;
247 }
248
249 /* Stream sreal value to OB. */
250
251 void
stream_out(struct output_block * ob)252 sreal::stream_out (struct output_block *ob)
253 {
254 streamer_write_hwi (ob, m_sig);
255 streamer_write_hwi (ob, m_exp);
256 }
257
258 /* Read sreal value from IB. */
259
260 sreal
stream_in(class lto_input_block * ib)261 sreal::stream_in (class lto_input_block *ib)
262 {
263 sreal val;
264 val.m_sig = streamer_read_hwi (ib);
265 val.m_exp = streamer_read_hwi (ib);
266 return val;
267 }
268
269 #if CHECKING_P
270
271 namespace selftest {
272
273 /* Selftests for sreals. */
274
275 /* Verify basic sreal operations. */
276
277 static void
sreal_verify_basics(void)278 sreal_verify_basics (void)
279 {
280 sreal minimum = INT_MIN/2;
281 sreal maximum = INT_MAX/2;
282
283 sreal seven = 7;
284 sreal minus_two = -2;
285 sreal minus_nine = -9;
286
287 ASSERT_EQ (INT_MIN/2, minimum.to_int ());
288 ASSERT_EQ (INT_MAX/2, maximum.to_int ());
289
290 ASSERT_FALSE (minus_two < minus_two);
291 ASSERT_FALSE (seven < seven);
292 ASSERT_TRUE (seven > minus_two);
293 ASSERT_TRUE (minus_two < seven);
294 ASSERT_TRUE (minus_two != seven);
295 ASSERT_EQ (minus_two, -2);
296 ASSERT_EQ (seven, 7);
297 ASSERT_EQ ((seven << 10) >> 10, 7);
298 ASSERT_EQ (seven + minus_nine, -2);
299 }
300
301 /* Helper function that performs basic arithmetics and comparison
302 of given arguments A and B. */
303
304 static void
verify_aritmetics(int64_t a,int64_t b)305 verify_aritmetics (int64_t a, int64_t b)
306 {
307 ASSERT_EQ (a, -(-(sreal (a))).to_int ());
308 ASSERT_EQ (a < b, sreal (a) < sreal (b));
309 ASSERT_EQ (a <= b, sreal (a) <= sreal (b));
310 ASSERT_EQ (a == b, sreal (a) == sreal (b));
311 ASSERT_EQ (a != b, sreal (a) != sreal (b));
312 ASSERT_EQ (a > b, sreal (a) > sreal (b));
313 ASSERT_EQ (a >= b, sreal (a) >= sreal (b));
314 ASSERT_EQ (a + b, (sreal (a) + sreal (b)).to_int ());
315 ASSERT_EQ (a - b, (sreal (a) - sreal (b)).to_int ());
316 ASSERT_EQ (b + a, (sreal (b) + sreal (a)).to_int ());
317 ASSERT_EQ (b - a, (sreal (b) - sreal (a)).to_int ());
318 }
319
320 /* Verify arithmetics for interesting numbers. */
321
322 static void
sreal_verify_arithmetics(void)323 sreal_verify_arithmetics (void)
324 {
325 int values[] = {-14123413, -7777, -17, -10, -2, 0, 17, 139, 1234123};
326 unsigned c = sizeof (values) / sizeof (int);
327
328 for (unsigned i = 0; i < c; i++)
329 for (unsigned j = 0; j < c; j++)
330 {
331 int a = values[i];
332 int b = values[j];
333
334 verify_aritmetics (a, b);
335 }
336 }
337
338 /* Helper function that performs various shifting test of a given
339 argument A. */
340
341 static void
verify_shifting(int64_t a)342 verify_shifting (int64_t a)
343 {
344 sreal v = a;
345
346 for (unsigned i = 0; i < 16; i++)
347 ASSERT_EQ (a << i, (v << i).to_int());
348
349 a = a << 16;
350 v = v << 16;
351
352 for (unsigned i = 0; i < 16; i++)
353 ASSERT_EQ (a >> i, (v >> i).to_int());
354 }
355
356 /* Verify shifting for interesting numbers. */
357
358 static void
sreal_verify_shifting(void)359 sreal_verify_shifting (void)
360 {
361 int values[] = {0, 17, 32, 139, 1024, 55555, 1234123};
362 unsigned c = sizeof (values) / sizeof (int);
363
364 for (unsigned i = 0; i < c; i++)
365 verify_shifting (values[i]);
366 }
367
368 /* Verify division by (of) a negative value. */
369
370 static void
sreal_verify_negative_division(void)371 sreal_verify_negative_division (void)
372 {
373 ASSERT_EQ (sreal (1) / sreal (1), sreal (1));
374 ASSERT_EQ (sreal (-1) / sreal (-1), sreal (1));
375 ASSERT_EQ (sreal (-1234567) / sreal (-1234567), sreal (1));
376 ASSERT_EQ (sreal (-1234567) / sreal (1234567), sreal (-1));
377 ASSERT_EQ (sreal (1234567) / sreal (-1234567), sreal (-1));
378 }
379
380 /* Run all of the selftests within this file. */
381
sreal_cc_tests()382 void sreal_cc_tests ()
383 {
384 sreal_verify_basics ();
385 sreal_verify_arithmetics ();
386 sreal_verify_shifting ();
387 sreal_verify_negative_division ();
388 }
389
390 } // namespace selftest
391 #endif /* CHECKING_P */
392