111
|
1 /* Simple data type for real numbers for the GNU compiler.
|
145
|
2 Copyright (C) 2002-2020 Free Software Foundation, Inc.
|
0
|
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
|
111
|
20 /* This library supports real numbers;
|
0
|
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
|
111
|
31 One uint64_t is used for the significant.
|
0
|
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.
|
111
|
34 So the precision is 32-bit.
|
0
|
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"
|
111
|
52 #include <math.h>
|
0
|
53 #include "coretypes.h"
|
|
54 #include "sreal.h"
|
111
|
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"
|
0
|
61
|
|
62 /* Print the content of struct sreal. */
|
|
63
|
|
64 void
|
111
|
65 sreal::dump (FILE *file) const
|
0
|
66 {
|
131
|
67 fprintf (file, "(%" PRIi64 " * 2^%d)", (int64_t)m_sig, m_exp);
|
111
|
68 }
|
|
69
|
|
70 DEBUG_FUNCTION void
|
|
71 debug (const sreal &ref)
|
|
72 {
|
|
73 ref.dump (stderr);
|
0
|
74 }
|
|
75
|
111
|
76 DEBUG_FUNCTION void
|
|
77 debug (const sreal *ptr)
|
0
|
78 {
|
111
|
79 if (ptr)
|
|
80 debug (*ptr);
|
|
81 else
|
|
82 fprintf (stderr, "<nil>\n");
|
0
|
83 }
|
|
84
|
111
|
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 */
|
0
|
88
|
111
|
89 void
|
|
90 sreal::shift_right (int s)
|
0
|
91 {
|
111
|
92 gcc_checking_assert (s > 0);
|
|
93 gcc_checking_assert (s <= SREAL_BITS);
|
0
|
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. */
|
111
|
97 gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
|
|
98
|
|
99 m_exp += s;
|
0
|
100
|
111
|
101 m_sig += (int64_t) 1 << (s - 1);
|
|
102 m_sig >>= s;
|
|
103 }
|
|
104
|
|
105 /* Return integer value of *this. */
|
0
|
106
|
111
|
107 int64_t
|
|
108 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)
|
131
|
117 return sign * (SREAL_ABS ((int64_t)m_sig) << m_exp);
|
111
|
118 if (m_exp < 0)
|
|
119 return m_sig >> -m_exp;
|
|
120 return m_sig;
|
0
|
121 }
|
|
122
|
111
|
123 /* Return value of *this as double.
|
|
124 This should be used for debug output only. */
|
0
|
125
|
111
|
126 double
|
|
127 sreal::to_double () const
|
|
128 {
|
|
129 double val = m_sig;
|
|
130 if (m_exp)
|
|
131 val = ldexp (val, m_exp);
|
|
132 return val;
|
0
|
133 }
|
|
134
|
111
|
135 /* Return *this + other. */
|
0
|
136
|
111
|
137 sreal
|
|
138 sreal::operator+ (const sreal &other) const
|
0
|
139 {
|
|
140 int dexp;
|
131
|
141 sreal tmp;
|
|
142 int64_t r_sig, r_exp;
|
111
|
143
|
|
144 const sreal *a_p = this, *b_p = &other, *bb;
|
0
|
145
|
111
|
146 if (a_p->m_exp < b_p->m_exp)
|
|
147 std::swap (a_p, b_p);
|
0
|
148
|
111
|
149 dexp = a_p->m_exp - b_p->m_exp;
|
131
|
150 r_exp = a_p->m_exp;
|
0
|
151 if (dexp > SREAL_BITS)
|
|
152 {
|
131
|
153 r_sig = a_p->m_sig;
|
|
154
|
|
155 sreal r;
|
|
156 r.m_sig = r_sig;
|
|
157 r.m_exp = r_exp;
|
0
|
158 return r;
|
|
159 }
|
|
160
|
|
161 if (dexp == 0)
|
111
|
162 bb = b_p;
|
0
|
163 else
|
|
164 {
|
111
|
165 tmp = *b_p;
|
|
166 tmp.shift_right (dexp);
|
0
|
167 bb = &tmp;
|
|
168 }
|
|
169
|
131
|
170 r_sig = a_p->m_sig + (int64_t)bb->m_sig;
|
|
171 sreal r (r_sig, r_exp);
|
0
|
172 return r;
|
|
173 }
|
|
174
|
111
|
175
|
|
176 /* Return *this - other. */
|
0
|
177
|
111
|
178 sreal
|
|
179 sreal::operator- (const sreal &other) const
|
0
|
180 {
|
|
181 int dexp;
|
131
|
182 sreal tmp;
|
|
183 int64_t r_sig, r_exp;
|
111
|
184 const sreal *bb;
|
|
185 const sreal *a_p = this, *b_p = &other;
|
0
|
186
|
111
|
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 }
|
0
|
193
|
111
|
194 dexp = a_p->m_exp - b_p->m_exp;
|
131
|
195 r_exp = a_p->m_exp;
|
0
|
196 if (dexp > SREAL_BITS)
|
|
197 {
|
131
|
198 r_sig = sign * a_p->m_sig;
|
|
199
|
|
200 sreal r;
|
|
201 r.m_sig = r_sig;
|
|
202 r.m_exp = r_exp;
|
0
|
203 return r;
|
|
204 }
|
|
205 if (dexp == 0)
|
111
|
206 bb = b_p;
|
0
|
207 else
|
|
208 {
|
111
|
209 tmp = *b_p;
|
|
210 tmp.shift_right (dexp);
|
0
|
211 bb = &tmp;
|
|
212 }
|
|
213
|
131
|
214 r_sig = sign * ((int64_t) a_p->m_sig - (int64_t)bb->m_sig);
|
|
215 sreal r (r_sig, r_exp);
|
0
|
216 return r;
|
|
217 }
|
|
218
|
111
|
219 /* Return *this * other. */
|
0
|
220
|
111
|
221 sreal
|
|
222 sreal::operator* (const sreal &other) const
|
0
|
223 {
|
111
|
224 sreal r;
|
131
|
225 if (absu_hwi (m_sig) < SREAL_MIN_SIG
|
|
226 || absu_hwi (other.m_sig) < SREAL_MIN_SIG)
|
0
|
227 {
|
111
|
228 r.m_sig = 0;
|
|
229 r.m_exp = -SREAL_MAX_EXP;
|
0
|
230 }
|
|
231 else
|
131
|
232 r.normalize (m_sig * (int64_t) other.m_sig, m_exp + other.m_exp);
|
0
|
233
|
111
|
234 return r;
|
|
235 }
|
0
|
236
|
111
|
237 /* Return *this / other. */
|
0
|
238
|
111
|
239 sreal
|
|
240 sreal::operator/ (const sreal &other) const
|
|
241 {
|
|
242 gcc_checking_assert (other.m_sig != 0);
|
131
|
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);
|
0
|
246 return r;
|
|
247 }
|
|
248
|
111
|
249 /* Stream sreal value to OB. */
|
|
250
|
|
251 void
|
|
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. */
|
0
|
259
|
111
|
260 sreal
|
145
|
261 sreal::stream_in (class lto_input_block *ib)
|
0
|
262 {
|
111
|
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
|
|
278 sreal_verify_basics (void)
|
|
279 {
|
131
|
280 sreal minimum = INT_MIN/2;
|
|
281 sreal maximum = INT_MAX/2;
|
0
|
282
|
111
|
283 sreal seven = 7;
|
|
284 sreal minus_two = -2;
|
|
285 sreal minus_nine = -9;
|
|
286
|
131
|
287 ASSERT_EQ (INT_MIN/2, minimum.to_int ());
|
|
288 ASSERT_EQ (INT_MAX/2, maximum.to_int ());
|
111
|
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
|
|
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 }
|
0
|
319
|
111
|
320 /* Verify arithmetics for interesting numbers. */
|
|
321
|
|
322 static 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 }
|
0
|
337
|
111
|
338 /* Helper function that performs various shifting test of a given
|
|
339 argument A. */
|
|
340
|
|
341 static void
|
|
342 verify_shifting (int64_t a)
|
|
343 {
|
|
344 sreal v = a;
|
0
|
345
|
111
|
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 }
|
0
|
355
|
111
|
356 /* Verify shifting for interesting numbers. */
|
|
357
|
|
358 static 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. */
|
0
|
369
|
111
|
370 static 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));
|
0
|
378 }
|
111
|
379
|
|
380 /* Run all of the selftests within this file. */
|
|
381
|
|
382 void sreal_c_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 */
|