]>
Commit | Line | Data |
---|---|---|
fd27ffab | 1 | /* Simple data type for real numbers for the GNU compiler. |
8d9254fc | 2 | Copyright (C) 2002-2020 Free Software Foundation, Inc. |
ac5e69da JZ |
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 | |
9dcd6f09 | 8 | Software Foundation; either version 3, or (at your option) any later |
ac5e69da JZ |
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 | |
9dcd6f09 NC |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ | |
ac5e69da | 19 | |
fd27ffab | 20 | /* This library supports real numbers; |
ac5e69da JZ |
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 | |
46c5ad27 | 26 | where |
ac5e69da JZ |
27 | sig = significant |
28 | (for < 64-bit machines sig = sig_lo + sig_hi * 2 ^ SREAL_PART_BITS) | |
29 | exp = exponent | |
30 | ||
618b7f29 | 31 | One uint64_t is used for the significant. |
ac5e69da JZ |
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. | |
618b7f29 | 34 | So the precision is 32-bit. |
46c5ad27 | 35 | |
ac5e69da JZ |
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 | |
46c5ad27 | 41 | -SREAL_MAX_EXP <= exp && exp <= SREAL_MAX_EXP |
ac5e69da JZ |
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" | |
bc1c9c22 | 52 | #include <math.h> |
ac5e69da | 53 | #include "coretypes.h" |
ac5e69da | 54 | #include "sreal.h" |
dcbdb17a | 55 | #include "selftest.h" |
8a267096 JH |
56 | #include "backend.h" |
57 | #include "tree.h" | |
58 | #include "gimple.h" | |
59 | #include "cgraph.h" | |
60 | #include "data-streamer.h" | |
ac5e69da | 61 | |
ac5e69da JZ |
62 | /* Print the content of struct sreal. */ |
63 | ||
64 | void | |
618b7f29 | 65 | sreal::dump (FILE *file) const |
ac5e69da | 66 | { |
a5f4d3d6 | 67 | fprintf (file, "(%" PRIi64 " * 2^%d)", (int64_t)m_sig, m_exp); |
ac5e69da JZ |
68 | } |
69 | ||
7b3b6ae4 | 70 | DEBUG_FUNCTION void |
d1704358 | 71 | debug (const sreal &ref) |
7b3b6ae4 | 72 | { |
618b7f29 | 73 | ref.dump (stderr); |
7b3b6ae4 LC |
74 | } |
75 | ||
76 | DEBUG_FUNCTION void | |
d1704358 | 77 | debug (const sreal *ptr) |
7b3b6ae4 LC |
78 | { |
79 | if (ptr) | |
80 | debug (*ptr); | |
81 | else | |
82 | fprintf (stderr, "<nil>\n"); | |
83 | } | |
84 | ||
618b7f29 TS |
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 | */ | |
7b3b6ae4 | 88 | |
618b7f29 TS |
89 | void |
90 | sreal::shift_right (int s) | |
ac5e69da | 91 | { |
fd27ffab ML |
92 | gcc_checking_assert (s > 0); |
93 | gcc_checking_assert (s <= SREAL_BITS); | |
41374e13 NS |
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. */ | |
fd27ffab | 97 | gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP); |
ac5e69da | 98 | |
618b7f29 | 99 | m_exp += s; |
ac5e69da | 100 | |
d1704358 | 101 | m_sig += (int64_t) 1 << (s - 1); |
618b7f29 | 102 | m_sig >>= s; |
ac5e69da JZ |
103 | } |
104 | ||
618b7f29 | 105 | /* Return integer value of *this. */ |
ac5e69da | 106 | |
618b7f29 TS |
107 | int64_t |
108 | sreal::to_int () const | |
ac5e69da | 109 | { |
a4f28954 | 110 | int64_t sign = SREAL_SIGN (m_sig); |
fd27ffab | 111 | |
618b7f29 | 112 | if (m_exp <= -SREAL_BITS) |
ac5e69da | 113 | return 0; |
618b7f29 | 114 | if (m_exp >= SREAL_PART_BITS) |
fd27ffab | 115 | return sign * INTTYPE_MAXIMUM (int64_t); |
618b7f29 | 116 | if (m_exp > 0) |
a5f4d3d6 | 117 | return sign * (SREAL_ABS ((int64_t)m_sig) << m_exp); |
618b7f29 | 118 | if (m_exp < 0) |
d1704358 ML |
119 | return m_sig >> -m_exp; |
120 | return m_sig; | |
ac5e69da JZ |
121 | } |
122 | ||
2bef63e1 JH |
123 | /* Return value of *this as double. |
124 | This should be used for debug output only. */ | |
125 | ||
126 | double | |
127 | sreal::to_double () const | |
128 | { | |
129 | double val = m_sig; | |
130 | if (m_exp) | |
aadb701b | 131 | val = ldexp (val, m_exp); |
2bef63e1 JH |
132 | return val; |
133 | } | |
134 | ||
618b7f29 | 135 | /* Return *this + other. */ |
ac5e69da | 136 | |
618b7f29 TS |
137 | sreal |
138 | sreal::operator+ (const sreal &other) const | |
ac5e69da | 139 | { |
fd27ffab | 140 | int dexp; |
7a1ce632 JH |
141 | sreal tmp; |
142 | int64_t r_sig, r_exp; | |
d1704358 ML |
143 | |
144 | const sreal *a_p = this, *b_p = &other, *bb; | |
fd27ffab | 145 | |
8301b194 | 146 | if (a_p->m_exp < b_p->m_exp) |
fd27ffab ML |
147 | std::swap (a_p, b_p); |
148 | ||
618b7f29 | 149 | dexp = a_p->m_exp - b_p->m_exp; |
7a1ce632 | 150 | r_exp = a_p->m_exp; |
ac5e69da JZ |
151 | if (dexp > SREAL_BITS) |
152 | { | |
7a1ce632 JH |
153 | r_sig = a_p->m_sig; |
154 | ||
155 | sreal r; | |
156 | r.m_sig = r_sig; | |
157 | r.m_exp = r_exp; | |
ac5e69da JZ |
158 | return r; |
159 | } | |
160 | ||
161 | if (dexp == 0) | |
618b7f29 | 162 | bb = b_p; |
ac5e69da JZ |
163 | else |
164 | { | |
618b7f29 TS |
165 | tmp = *b_p; |
166 | tmp.shift_right (dexp); | |
ac5e69da JZ |
167 | bb = &tmp; |
168 | } | |
169 | ||
a5f4d3d6 | 170 | r_sig = a_p->m_sig + (int64_t)bb->m_sig; |
7a1ce632 | 171 | sreal r (r_sig, r_exp); |
ac5e69da JZ |
172 | return r; |
173 | } | |
174 | ||
d1704358 | 175 | |
618b7f29 | 176 | /* Return *this - other. */ |
ac5e69da | 177 | |
618b7f29 TS |
178 | sreal |
179 | sreal::operator- (const sreal &other) const | |
ac5e69da JZ |
180 | { |
181 | int dexp; | |
7a1ce632 JH |
182 | sreal tmp; |
183 | int64_t r_sig, r_exp; | |
618b7f29 | 184 | const sreal *bb; |
d1704358 | 185 | const sreal *a_p = this, *b_p = &other; |
ac5e69da | 186 | |
d1704358 ML |
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 | } | |
ac5e69da | 193 | |
d1704358 | 194 | dexp = a_p->m_exp - b_p->m_exp; |
7a1ce632 | 195 | r_exp = a_p->m_exp; |
ac5e69da JZ |
196 | if (dexp > SREAL_BITS) |
197 | { | |
7a1ce632 JH |
198 | r_sig = sign * a_p->m_sig; |
199 | ||
200 | sreal r; | |
201 | r.m_sig = r_sig; | |
202 | r.m_exp = r_exp; | |
ac5e69da JZ |
203 | return r; |
204 | } | |
205 | if (dexp == 0) | |
fd27ffab | 206 | bb = b_p; |
ac5e69da JZ |
207 | else |
208 | { | |
fd27ffab | 209 | tmp = *b_p; |
618b7f29 | 210 | tmp.shift_right (dexp); |
ac5e69da JZ |
211 | bb = &tmp; |
212 | } | |
213 | ||
a5f4d3d6 | 214 | r_sig = sign * ((int64_t) a_p->m_sig - (int64_t)bb->m_sig); |
7a1ce632 | 215 | sreal r (r_sig, r_exp); |
ac5e69da JZ |
216 | return r; |
217 | } | |
218 | ||
618b7f29 | 219 | /* Return *this * other. */ |
ac5e69da | 220 | |
618b7f29 TS |
221 | sreal |
222 | sreal::operator* (const sreal &other) const | |
ac5e69da | 223 | { |
fd27ffab | 224 | sreal r; |
7a1ce632 JH |
225 | if (absu_hwi (m_sig) < SREAL_MIN_SIG |
226 | || absu_hwi (other.m_sig) < SREAL_MIN_SIG) | |
ac5e69da | 227 | { |
618b7f29 TS |
228 | r.m_sig = 0; |
229 | r.m_exp = -SREAL_MAX_EXP; | |
ac5e69da JZ |
230 | } |
231 | else | |
7a1ce632 | 232 | r.normalize (m_sig * (int64_t) other.m_sig, m_exp + other.m_exp); |
fd27ffab | 233 | |
ac5e69da JZ |
234 | return r; |
235 | } | |
236 | ||
618b7f29 | 237 | /* Return *this / other. */ |
ac5e69da | 238 | |
618b7f29 TS |
239 | sreal |
240 | sreal::operator/ (const sreal &other) const | |
ac5e69da | 241 | { |
fd27ffab | 242 | gcc_checking_assert (other.m_sig != 0); |
7a1ce632 JH |
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); | |
ac5e69da JZ |
246 | return r; |
247 | } | |
dcbdb17a | 248 | |
8a267096 JH |
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. */ | |
259 | ||
260 | sreal | |
99b1c316 | 261 | sreal::stream_in (class lto_input_block *ib) |
8a267096 JH |
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 | ||
dcbdb17a ML |
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 | { | |
a5f4d3d6 JH |
280 | sreal minimum = INT_MIN/2; |
281 | sreal maximum = INT_MAX/2; | |
dcbdb17a ML |
282 | |
283 | sreal seven = 7; | |
284 | sreal minus_two = -2; | |
285 | sreal minus_nine = -9; | |
286 | ||
a5f4d3d6 JH |
287 | ASSERT_EQ (INT_MIN/2, minimum.to_int ()); |
288 | ASSERT_EQ (INT_MAX/2, maximum.to_int ()); | |
dcbdb17a ML |
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 | } | |
319 | ||
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 | } | |
337 | ||
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; | |
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 | |
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 | ||
a4f28954 ML |
368 | /* Verify division by (of) a negative value. */ |
369 | ||
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)); | |
378 | } | |
379 | ||
dcbdb17a ML |
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 (); | |
a4f28954 | 387 | sreal_verify_negative_division (); |
dcbdb17a ML |
388 | } |
389 | ||
390 | } // namespace selftest | |
391 | #endif /* CHECKING_P */ |