]>
Commit | Line | Data |
---|---|---|
fd27ffab | 1 | /* Simple data type for real numbers for the GNU compiler. |
85ec4feb | 2 | Copyright (C) 2002-2018 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 | { |
ce9401b4 | 67 | fprintf (file, "(%" PRIi64 " * 2^%d)", 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) |
a4f28954 | 117 | return sign * (SREAL_ABS (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; |
d1704358 ML |
141 | sreal tmp, r; |
142 | ||
143 | const sreal *a_p = this, *b_p = &other, *bb; | |
fd27ffab | 144 | |
8301b194 | 145 | if (a_p->m_exp < b_p->m_exp) |
fd27ffab ML |
146 | std::swap (a_p, b_p); |
147 | ||
618b7f29 TS |
148 | dexp = a_p->m_exp - b_p->m_exp; |
149 | r.m_exp = a_p->m_exp; | |
ac5e69da JZ |
150 | if (dexp > SREAL_BITS) |
151 | { | |
618b7f29 | 152 | r.m_sig = a_p->m_sig; |
ac5e69da JZ |
153 | return r; |
154 | } | |
155 | ||
156 | if (dexp == 0) | |
618b7f29 | 157 | bb = b_p; |
ac5e69da JZ |
158 | else |
159 | { | |
618b7f29 TS |
160 | tmp = *b_p; |
161 | tmp.shift_right (dexp); | |
ac5e69da JZ |
162 | bb = &tmp; |
163 | } | |
164 | ||
618b7f29 TS |
165 | r.m_sig = a_p->m_sig + bb->m_sig; |
166 | r.normalize (); | |
ac5e69da JZ |
167 | return r; |
168 | } | |
169 | ||
d1704358 | 170 | |
618b7f29 | 171 | /* Return *this - other. */ |
ac5e69da | 172 | |
618b7f29 TS |
173 | sreal |
174 | sreal::operator- (const sreal &other) const | |
ac5e69da JZ |
175 | { |
176 | int dexp; | |
618b7f29 TS |
177 | sreal tmp, r; |
178 | const sreal *bb; | |
d1704358 | 179 | const sreal *a_p = this, *b_p = &other; |
ac5e69da | 180 | |
d1704358 ML |
181 | int64_t sign = 1; |
182 | if (a_p->m_exp < b_p->m_exp) | |
183 | { | |
184 | sign = -1; | |
185 | std::swap (a_p, b_p); | |
186 | } | |
ac5e69da | 187 | |
d1704358 | 188 | dexp = a_p->m_exp - b_p->m_exp; |
fd27ffab | 189 | r.m_exp = a_p->m_exp; |
ac5e69da JZ |
190 | if (dexp > SREAL_BITS) |
191 | { | |
d1704358 | 192 | r.m_sig = sign * a_p->m_sig; |
ac5e69da JZ |
193 | return r; |
194 | } | |
195 | if (dexp == 0) | |
fd27ffab | 196 | bb = b_p; |
ac5e69da JZ |
197 | else |
198 | { | |
fd27ffab | 199 | tmp = *b_p; |
618b7f29 | 200 | tmp.shift_right (dexp); |
ac5e69da JZ |
201 | bb = &tmp; |
202 | } | |
203 | ||
d1704358 | 204 | r.m_sig = sign * (a_p->m_sig - bb->m_sig); |
618b7f29 | 205 | r.normalize (); |
ac5e69da JZ |
206 | return r; |
207 | } | |
208 | ||
618b7f29 | 209 | /* Return *this * other. */ |
ac5e69da | 210 | |
618b7f29 TS |
211 | sreal |
212 | sreal::operator* (const sreal &other) const | |
ac5e69da | 213 | { |
fd27ffab | 214 | sreal r; |
5007f798 | 215 | if (absu_hwi (m_sig) < SREAL_MIN_SIG || absu_hwi (other.m_sig) < SREAL_MIN_SIG) |
ac5e69da | 216 | { |
618b7f29 TS |
217 | r.m_sig = 0; |
218 | r.m_exp = -SREAL_MAX_EXP; | |
ac5e69da JZ |
219 | } |
220 | else | |
221 | { | |
618b7f29 TS |
222 | r.m_sig = m_sig * other.m_sig; |
223 | r.m_exp = m_exp + other.m_exp; | |
224 | r.normalize (); | |
ac5e69da | 225 | } |
fd27ffab | 226 | |
ac5e69da JZ |
227 | return r; |
228 | } | |
229 | ||
618b7f29 | 230 | /* Return *this / other. */ |
ac5e69da | 231 | |
618b7f29 TS |
232 | sreal |
233 | sreal::operator/ (const sreal &other) const | |
ac5e69da | 234 | { |
fd27ffab ML |
235 | gcc_checking_assert (other.m_sig != 0); |
236 | sreal r; | |
a4f28954 ML |
237 | r.m_sig |
238 | = SREAL_SIGN (m_sig) * (SREAL_ABS (m_sig) << SREAL_PART_BITS) / other.m_sig; | |
618b7f29 TS |
239 | r.m_exp = m_exp - other.m_exp - SREAL_PART_BITS; |
240 | r.normalize (); | |
ac5e69da JZ |
241 | return r; |
242 | } | |
dcbdb17a | 243 | |
8a267096 JH |
244 | /* Stream sreal value to OB. */ |
245 | ||
246 | void | |
247 | sreal::stream_out (struct output_block *ob) | |
248 | { | |
249 | streamer_write_hwi (ob, m_sig); | |
250 | streamer_write_hwi (ob, m_exp); | |
251 | } | |
252 | ||
253 | /* Read sreal value from IB. */ | |
254 | ||
255 | sreal | |
256 | sreal::stream_in (struct lto_input_block *ib) | |
257 | { | |
258 | sreal val; | |
259 | val.m_sig = streamer_read_hwi (ib); | |
260 | val.m_exp = streamer_read_hwi (ib); | |
261 | return val; | |
262 | } | |
263 | ||
dcbdb17a ML |
264 | #if CHECKING_P |
265 | ||
266 | namespace selftest { | |
267 | ||
268 | /* Selftests for sreals. */ | |
269 | ||
270 | /* Verify basic sreal operations. */ | |
271 | ||
272 | static void | |
273 | sreal_verify_basics (void) | |
274 | { | |
275 | sreal minimum = INT_MIN; | |
276 | sreal maximum = INT_MAX; | |
277 | ||
278 | sreal seven = 7; | |
279 | sreal minus_two = -2; | |
280 | sreal minus_nine = -9; | |
281 | ||
282 | ASSERT_EQ (INT_MIN, minimum.to_int ()); | |
283 | ASSERT_EQ (INT_MAX, maximum.to_int ()); | |
284 | ||
285 | ASSERT_FALSE (minus_two < minus_two); | |
286 | ASSERT_FALSE (seven < seven); | |
287 | ASSERT_TRUE (seven > minus_two); | |
288 | ASSERT_TRUE (minus_two < seven); | |
289 | ASSERT_TRUE (minus_two != seven); | |
290 | ASSERT_EQ (minus_two, -2); | |
291 | ASSERT_EQ (seven, 7); | |
292 | ASSERT_EQ ((seven << 10) >> 10, 7); | |
293 | ASSERT_EQ (seven + minus_nine, -2); | |
294 | } | |
295 | ||
296 | /* Helper function that performs basic arithmetics and comparison | |
297 | of given arguments A and B. */ | |
298 | ||
299 | static void | |
300 | verify_aritmetics (int64_t a, int64_t b) | |
301 | { | |
302 | ASSERT_EQ (a, -(-(sreal (a))).to_int ()); | |
303 | ASSERT_EQ (a < b, sreal (a) < sreal (b)); | |
304 | ASSERT_EQ (a <= b, sreal (a) <= sreal (b)); | |
305 | ASSERT_EQ (a == b, sreal (a) == sreal (b)); | |
306 | ASSERT_EQ (a != b, sreal (a) != sreal (b)); | |
307 | ASSERT_EQ (a > b, sreal (a) > sreal (b)); | |
308 | ASSERT_EQ (a >= b, sreal (a) >= sreal (b)); | |
309 | ASSERT_EQ (a + b, (sreal (a) + sreal (b)).to_int ()); | |
310 | ASSERT_EQ (a - b, (sreal (a) - sreal (b)).to_int ()); | |
311 | ASSERT_EQ (b + a, (sreal (b) + sreal (a)).to_int ()); | |
312 | ASSERT_EQ (b - a, (sreal (b) - sreal (a)).to_int ()); | |
313 | } | |
314 | ||
315 | /* Verify arithmetics for interesting numbers. */ | |
316 | ||
317 | static void | |
318 | sreal_verify_arithmetics (void) | |
319 | { | |
320 | int values[] = {-14123413, -7777, -17, -10, -2, 0, 17, 139, 1234123}; | |
321 | unsigned c = sizeof (values) / sizeof (int); | |
322 | ||
323 | for (unsigned i = 0; i < c; i++) | |
324 | for (unsigned j = 0; j < c; j++) | |
325 | { | |
326 | int a = values[i]; | |
327 | int b = values[j]; | |
328 | ||
329 | verify_aritmetics (a, b); | |
330 | } | |
331 | } | |
332 | ||
333 | /* Helper function that performs various shifting test of a given | |
334 | argument A. */ | |
335 | ||
336 | static void | |
337 | verify_shifting (int64_t a) | |
338 | { | |
339 | sreal v = a; | |
340 | ||
341 | for (unsigned i = 0; i < 16; i++) | |
342 | ASSERT_EQ (a << i, (v << i).to_int()); | |
343 | ||
344 | a = a << 16; | |
345 | v = v << 16; | |
346 | ||
347 | for (unsigned i = 0; i < 16; i++) | |
348 | ASSERT_EQ (a >> i, (v >> i).to_int()); | |
349 | } | |
350 | ||
351 | /* Verify shifting for interesting numbers. */ | |
352 | ||
353 | static void | |
354 | sreal_verify_shifting (void) | |
355 | { | |
356 | int values[] = {0, 17, 32, 139, 1024, 55555, 1234123}; | |
357 | unsigned c = sizeof (values) / sizeof (int); | |
358 | ||
359 | for (unsigned i = 0; i < c; i++) | |
360 | verify_shifting (values[i]); | |
361 | } | |
362 | ||
a4f28954 ML |
363 | /* Verify division by (of) a negative value. */ |
364 | ||
365 | static void | |
366 | sreal_verify_negative_division (void) | |
367 | { | |
368 | ASSERT_EQ (sreal (1) / sreal (1), sreal (1)); | |
369 | ASSERT_EQ (sreal (-1) / sreal (-1), sreal (1)); | |
370 | ASSERT_EQ (sreal (-1234567) / sreal (-1234567), sreal (1)); | |
371 | ASSERT_EQ (sreal (-1234567) / sreal (1234567), sreal (-1)); | |
372 | ASSERT_EQ (sreal (1234567) / sreal (-1234567), sreal (-1)); | |
373 | } | |
374 | ||
dcbdb17a ML |
375 | /* Run all of the selftests within this file. */ |
376 | ||
377 | void sreal_c_tests () | |
378 | { | |
379 | sreal_verify_basics (); | |
380 | sreal_verify_arithmetics (); | |
381 | sreal_verify_shifting (); | |
a4f28954 | 382 | sreal_verify_negative_division (); |
dcbdb17a ML |
383 | } |
384 | ||
385 | } // namespace selftest | |
386 | #endif /* CHECKING_P */ |