]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/sreal.c
Update copyright years.
[thirdparty/gcc.git] / gcc / sreal.c
CommitLineData
8201d1f6 1/* Simple data type for real numbers for the GNU compiler.
fbd26352 2 Copyright (C) 2002-2019 Free Software Foundation, Inc.
e9d7220b 3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8c4c00c1 8Software Foundation; either version 3, or (at your option) any later
e9d7220b 9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
8c4c00c1 17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
e9d7220b 19
8201d1f6 20/* This library supports real numbers;
e9d7220b 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
60b8c5b3 26 where
e9d7220b 27 sig = significant
28 (for < 64-bit machines sig = sig_lo + sig_hi * 2 ^ SREAL_PART_BITS)
29 exp = exponent
30
23a92fc7 31 One uint64_t is used for the significant.
e9d7220b 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.
23a92fc7 34 So the precision is 32-bit.
60b8c5b3 35
e9d7220b 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
60b8c5b3 41 -SREAL_MAX_EXP <= exp && exp <= SREAL_MAX_EXP
e9d7220b 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"
5df86efa 52#include <math.h>
e9d7220b 53#include "coretypes.h"
e9d7220b 54#include "sreal.h"
f5b88ba1 55#include "selftest.h"
50b1eab3 56#include "backend.h"
57#include "tree.h"
58#include "gimple.h"
59#include "cgraph.h"
60#include "data-streamer.h"
e9d7220b 61
e9d7220b 62/* Print the content of struct sreal. */
63
64void
23a92fc7 65sreal::dump (FILE *file) const
e9d7220b 66{
e8a89d32 67 fprintf (file, "(%" PRIi64 " * 2^%d)", (int64_t)m_sig, m_exp);
e9d7220b 68}
69
c7d89805 70DEBUG_FUNCTION void
b0410238 71debug (const sreal &ref)
c7d89805 72{
23a92fc7 73 ref.dump (stderr);
c7d89805 74}
75
76DEBUG_FUNCTION void
b0410238 77debug (const sreal *ptr)
c7d89805 78{
79 if (ptr)
80 debug (*ptr);
81 else
82 fprintf (stderr, "<nil>\n");
83}
84
23a92fc7 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 */
c7d89805 88
23a92fc7 89void
90sreal::shift_right (int s)
e9d7220b 91{
8201d1f6 92 gcc_checking_assert (s > 0);
93 gcc_checking_assert (s <= SREAL_BITS);
04e579b6 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. */
8201d1f6 97 gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
e9d7220b 98
23a92fc7 99 m_exp += s;
e9d7220b 100
b0410238 101 m_sig += (int64_t) 1 << (s - 1);
23a92fc7 102 m_sig >>= s;
e9d7220b 103}
104
23a92fc7 105/* Return integer value of *this. */
e9d7220b 106
23a92fc7 107int64_t
108sreal::to_int () const
e9d7220b 109{
8d022ef4 110 int64_t sign = SREAL_SIGN (m_sig);
8201d1f6 111
23a92fc7 112 if (m_exp <= -SREAL_BITS)
e9d7220b 113 return 0;
23a92fc7 114 if (m_exp >= SREAL_PART_BITS)
8201d1f6 115 return sign * INTTYPE_MAXIMUM (int64_t);
23a92fc7 116 if (m_exp > 0)
e8a89d32 117 return sign * (SREAL_ABS ((int64_t)m_sig) << m_exp);
23a92fc7 118 if (m_exp < 0)
b0410238 119 return m_sig >> -m_exp;
120 return m_sig;
e9d7220b 121}
122
eb9db6ce 123/* Return value of *this as double.
124 This should be used for debug output only. */
125
126double
127sreal::to_double () const
128{
129 double val = m_sig;
130 if (m_exp)
e031f282 131 val = ldexp (val, m_exp);
eb9db6ce 132 return val;
133}
134
23a92fc7 135/* Return *this + other. */
e9d7220b 136
23a92fc7 137sreal
138sreal::operator+ (const sreal &other) const
e9d7220b 139{
8201d1f6 140 int dexp;
6784be9e 141 sreal tmp;
142 int64_t r_sig, r_exp;
b0410238 143
144 const sreal *a_p = this, *b_p = &other, *bb;
8201d1f6 145
e90b28a5 146 if (a_p->m_exp < b_p->m_exp)
8201d1f6 147 std::swap (a_p, b_p);
148
23a92fc7 149 dexp = a_p->m_exp - b_p->m_exp;
6784be9e 150 r_exp = a_p->m_exp;
e9d7220b 151 if (dexp > SREAL_BITS)
152 {
6784be9e 153 r_sig = a_p->m_sig;
154
155 sreal r;
156 r.m_sig = r_sig;
157 r.m_exp = r_exp;
e9d7220b 158 return r;
159 }
160
161 if (dexp == 0)
23a92fc7 162 bb = b_p;
e9d7220b 163 else
164 {
23a92fc7 165 tmp = *b_p;
166 tmp.shift_right (dexp);
e9d7220b 167 bb = &tmp;
168 }
169
e8a89d32 170 r_sig = a_p->m_sig + (int64_t)bb->m_sig;
6784be9e 171 sreal r (r_sig, r_exp);
e9d7220b 172 return r;
173}
174
b0410238 175
23a92fc7 176/* Return *this - other. */
e9d7220b 177
23a92fc7 178sreal
179sreal::operator- (const sreal &other) const
e9d7220b 180{
181 int dexp;
6784be9e 182 sreal tmp;
183 int64_t r_sig, r_exp;
23a92fc7 184 const sreal *bb;
b0410238 185 const sreal *a_p = this, *b_p = &other;
e9d7220b 186
b0410238 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 }
e9d7220b 193
b0410238 194 dexp = a_p->m_exp - b_p->m_exp;
6784be9e 195 r_exp = a_p->m_exp;
e9d7220b 196 if (dexp > SREAL_BITS)
197 {
6784be9e 198 r_sig = sign * a_p->m_sig;
199
200 sreal r;
201 r.m_sig = r_sig;
202 r.m_exp = r_exp;
e9d7220b 203 return r;
204 }
205 if (dexp == 0)
8201d1f6 206 bb = b_p;
e9d7220b 207 else
208 {
8201d1f6 209 tmp = *b_p;
23a92fc7 210 tmp.shift_right (dexp);
e9d7220b 211 bb = &tmp;
212 }
213
e8a89d32 214 r_sig = sign * ((int64_t) a_p->m_sig - (int64_t)bb->m_sig);
6784be9e 215 sreal r (r_sig, r_exp);
e9d7220b 216 return r;
217}
218
23a92fc7 219/* Return *this * other. */
e9d7220b 220
23a92fc7 221sreal
222sreal::operator* (const sreal &other) const
e9d7220b 223{
8201d1f6 224 sreal r;
6784be9e 225 if (absu_hwi (m_sig) < SREAL_MIN_SIG
226 || absu_hwi (other.m_sig) < SREAL_MIN_SIG)
e9d7220b 227 {
23a92fc7 228 r.m_sig = 0;
229 r.m_exp = -SREAL_MAX_EXP;
e9d7220b 230 }
231 else
6784be9e 232 r.normalize (m_sig * (int64_t) other.m_sig, m_exp + other.m_exp);
8201d1f6 233
e9d7220b 234 return r;
235}
236
23a92fc7 237/* Return *this / other. */
e9d7220b 238
23a92fc7 239sreal
240sreal::operator/ (const sreal &other) const
e9d7220b 241{
8201d1f6 242 gcc_checking_assert (other.m_sig != 0);
6784be9e 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);
e9d7220b 246 return r;
247}
f5b88ba1 248
50b1eab3 249/* Stream sreal value to OB. */
250
251void
252sreal::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
260sreal
261sreal::stream_in (struct 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
f5b88ba1 269#if CHECKING_P
270
271namespace selftest {
272
273/* Selftests for sreals. */
274
275/* Verify basic sreal operations. */
276
277static void
278sreal_verify_basics (void)
279{
e8a89d32 280 sreal minimum = INT_MIN/2;
281 sreal maximum = INT_MAX/2;
f5b88ba1 282
283 sreal seven = 7;
284 sreal minus_two = -2;
285 sreal minus_nine = -9;
286
e8a89d32 287 ASSERT_EQ (INT_MIN/2, minimum.to_int ());
288 ASSERT_EQ (INT_MAX/2, maximum.to_int ());
f5b88ba1 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
304static void
305verify_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
322static void
323sreal_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
341static void
342verify_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
358static void
359sreal_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
8d022ef4 368/* Verify division by (of) a negative value. */
369
370static void
371sreal_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
f5b88ba1 380/* Run all of the selftests within this file. */
381
382void sreal_c_tests ()
383{
384 sreal_verify_basics ();
385 sreal_verify_arithmetics ();
386 sreal_verify_shifting ();
8d022ef4 387 sreal_verify_negative_division ();
f5b88ba1 388}
389
390} // namespace selftest
391#endif /* CHECKING_P */