tree-optimization/110506 - bogus non-zero mask in CCP for vector types
[official-gcc.git] / gcc / sreal.cc
blob8e99d871420b3bb76fa899a065aa7d1b76bb0606
1 /* Simple data type for real numbers for the GNU compiler.
2 Copyright (C) 2002-2023 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.
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/>. */
20 /* This library supports real numbers;
21 inf and nan are NOT supported.
22 It is written to be simple and fast.
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
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.
36 Invariant: The numbers are normalized before and after each call of sreal_*.
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
43 If the number would be too large, it is set to upper bounds of these
44 conditions.
46 If the number is zero or would be too small it meets following conditions:
47 sig == 0 && exp == -SREAL_MAX_EXP
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"
62 /* Print the content of struct sreal. */
64 void
65 sreal::dump (FILE *file) const
67 fprintf (file, "(%" PRIi64 " * 2^%d)", (int64_t)m_sig, m_exp);
70 DEBUG_FUNCTION void
71 debug (const sreal &ref)
73 ref.dump (stderr);
76 DEBUG_FUNCTION void
77 debug (const sreal *ptr)
79 if (ptr)
80 debug (*ptr);
81 else
82 fprintf (stderr, "<nil>\n");
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).
89 void
90 sreal::shift_right (int s)
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);
99 m_exp += s;
101 m_sig += (int64_t) 1 << (s - 1);
102 m_sig >>= s;
105 /* Return integer value of *this. */
107 int64_t
108 sreal::to_int () const
110 int64_t sign = SREAL_SIGN (m_sig);
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;
123 /* Return value of *this as double.
124 This should be used for debug output only. */
126 double
127 sreal::to_double () const
129 double val = m_sig;
130 if (m_exp)
131 val = ldexp (val, m_exp);
132 return val;
135 /* Return *this + other. */
137 sreal
138 sreal::operator+ (const sreal &other) const
140 int dexp;
141 sreal tmp;
142 int64_t r_sig, r_exp;
144 const sreal *a_p = this, *b_p = &other, *bb;
146 if (a_p->m_exp < b_p->m_exp)
147 std::swap (a_p, b_p);
149 dexp = a_p->m_exp - b_p->m_exp;
150 r_exp = a_p->m_exp;
151 if (dexp > SREAL_BITS)
153 r_sig = a_p->m_sig;
155 sreal r;
156 r.m_sig = r_sig;
157 r.m_exp = r_exp;
158 return r;
161 if (dexp == 0)
162 bb = b_p;
163 else
165 tmp = *b_p;
166 tmp.shift_right (dexp);
167 bb = &tmp;
170 r_sig = a_p->m_sig + (int64_t)bb->m_sig;
171 sreal r (r_sig, r_exp);
172 return r;
176 /* Return *this - other. */
178 sreal
179 sreal::operator- (const sreal &other) const
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;
187 int64_t sign = 1;
188 if (a_p->m_exp < b_p->m_exp)
190 sign = -1;
191 std::swap (a_p, b_p);
194 dexp = a_p->m_exp - b_p->m_exp;
195 r_exp = a_p->m_exp;
196 if (dexp > SREAL_BITS)
198 r_sig = sign * a_p->m_sig;
200 sreal r;
201 r.m_sig = r_sig;
202 r.m_exp = r_exp;
203 return r;
205 if (dexp == 0)
206 bb = b_p;
207 else
209 tmp = *b_p;
210 tmp.shift_right (dexp);
211 bb = &tmp;
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;
219 /* Return *this * other. */
221 sreal
222 sreal::operator* (const sreal &other) const
224 sreal r;
225 if (absu_hwi (m_sig) < SREAL_MIN_SIG
226 || absu_hwi (other.m_sig) < SREAL_MIN_SIG)
228 r.m_sig = 0;
229 r.m_exp = -SREAL_MAX_EXP;
231 else
232 r.normalize (m_sig * (int64_t) other.m_sig, m_exp + other.m_exp);
234 return r;
237 /* Return *this / other. */
239 sreal
240 sreal::operator/ (const sreal &other) const
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;
249 /* Stream sreal value to OB. */
251 void
252 sreal::stream_out (struct output_block *ob)
254 streamer_write_hwi (ob, m_sig);
255 streamer_write_hwi (ob, m_exp);
258 /* Read sreal value from IB. */
260 sreal
261 sreal::stream_in (class lto_input_block *ib)
263 sreal val;
264 val.m_sig = streamer_read_hwi (ib);
265 val.m_exp = streamer_read_hwi (ib);
266 return val;
269 #if CHECKING_P
271 namespace selftest {
273 /* Selftests for sreals. */
275 /* Verify basic sreal operations. */
277 static void
278 sreal_verify_basics (void)
280 sreal minimum = INT_MIN/2;
281 sreal maximum = INT_MAX/2;
283 sreal seven = 7;
284 sreal minus_two = -2;
285 sreal minus_nine = -9;
287 ASSERT_EQ (INT_MIN/2, minimum.to_int ());
288 ASSERT_EQ (INT_MAX/2, maximum.to_int ());
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);
301 /* Helper function that performs basic arithmetics and comparison
302 of given arguments A and B. */
304 static void
305 verify_aritmetics (int64_t a, int64_t b)
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 ());
320 /* Verify arithmetics for interesting numbers. */
322 static void
323 sreal_verify_arithmetics (void)
325 int values[] = {-14123413, -7777, -17, -10, -2, 0, 17, 139, 1234123};
326 unsigned c = sizeof (values) / sizeof (int);
328 for (unsigned i = 0; i < c; i++)
329 for (unsigned j = 0; j < c; j++)
331 int a = values[i];
332 int b = values[j];
334 verify_aritmetics (a, b);
338 /* Helper function that performs various shifting test of a given
339 argument A. */
341 static void
342 verify_shifting (int64_t a)
344 sreal v = a;
346 for (unsigned i = 0; i < 16; i++)
347 ASSERT_EQ (a << i, (v << i).to_int());
349 a = a << 16;
350 v = v << 16;
352 for (unsigned i = 0; i < 16; i++)
353 ASSERT_EQ (a >> i, (v >> i).to_int());
356 /* Verify shifting for interesting numbers. */
358 static void
359 sreal_verify_shifting (void)
361 int values[] = {0, 17, 32, 139, 1024, 55555, 1234123};
362 unsigned c = sizeof (values) / sizeof (int);
364 for (unsigned i = 0; i < c; i++)
365 verify_shifting (values[i]);
368 /* Verify division by (of) a negative value. */
370 static void
371 sreal_verify_negative_division (void)
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));
380 /* Run all of the selftests within this file. */
382 void sreal_cc_tests ()
384 sreal_verify_basics ();
385 sreal_verify_arithmetics ();
386 sreal_verify_shifting ();
387 sreal_verify_negative_division ();
390 } // namespace selftest
391 #endif /* CHECKING_P */