11debfc3dSmrg /* Simple data type for real numbers for the GNU compiler.
2*8feb0f0bSmrg Copyright (C) 2002-2020 Free Software Foundation, Inc.
31debfc3dSmrg
41debfc3dSmrg This file is part of GCC.
51debfc3dSmrg
61debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
71debfc3dSmrg the terms of the GNU General Public License as published by the Free
81debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
91debfc3dSmrg version.
101debfc3dSmrg
111debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
121debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
131debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
141debfc3dSmrg for more details.
151debfc3dSmrg
161debfc3dSmrg You should have received a copy of the GNU General Public License
171debfc3dSmrg along with GCC; see the file COPYING3. If not see
181debfc3dSmrg <http://www.gnu.org/licenses/>. */
191debfc3dSmrg
201debfc3dSmrg /* This library supports real numbers;
211debfc3dSmrg inf and nan are NOT supported.
221debfc3dSmrg It is written to be simple and fast.
231debfc3dSmrg
241debfc3dSmrg Value of sreal is
251debfc3dSmrg x = sig * 2 ^ exp
261debfc3dSmrg where
271debfc3dSmrg sig = significant
281debfc3dSmrg (for < 64-bit machines sig = sig_lo + sig_hi * 2 ^ SREAL_PART_BITS)
291debfc3dSmrg exp = exponent
301debfc3dSmrg
311debfc3dSmrg One uint64_t is used for the significant.
321debfc3dSmrg Only a half of significant bits is used (in normalized sreals) so that we do
331debfc3dSmrg not have problems with overflow, for example when c->sig = a->sig * b->sig.
341debfc3dSmrg So the precision is 32-bit.
351debfc3dSmrg
361debfc3dSmrg Invariant: The numbers are normalized before and after each call of sreal_*.
371debfc3dSmrg
381debfc3dSmrg Normalized sreals:
391debfc3dSmrg All numbers (except zero) meet following conditions:
401debfc3dSmrg SREAL_MIN_SIG <= sig && sig <= SREAL_MAX_SIG
411debfc3dSmrg -SREAL_MAX_EXP <= exp && exp <= SREAL_MAX_EXP
421debfc3dSmrg
431debfc3dSmrg If the number would be too large, it is set to upper bounds of these
441debfc3dSmrg conditions.
451debfc3dSmrg
461debfc3dSmrg If the number is zero or would be too small it meets following conditions:
471debfc3dSmrg sig == 0 && exp == -SREAL_MAX_EXP
481debfc3dSmrg */
491debfc3dSmrg
501debfc3dSmrg #include "config.h"
511debfc3dSmrg #include "system.h"
521debfc3dSmrg #include <math.h>
531debfc3dSmrg #include "coretypes.h"
541debfc3dSmrg #include "sreal.h"
551debfc3dSmrg #include "selftest.h"
56a2dc1f3fSmrg #include "backend.h"
57a2dc1f3fSmrg #include "tree.h"
58a2dc1f3fSmrg #include "gimple.h"
59a2dc1f3fSmrg #include "cgraph.h"
60a2dc1f3fSmrg #include "data-streamer.h"
611debfc3dSmrg
621debfc3dSmrg /* Print the content of struct sreal. */
631debfc3dSmrg
641debfc3dSmrg void
dump(FILE * file)651debfc3dSmrg sreal::dump (FILE *file) const
661debfc3dSmrg {
67c0a68be4Smrg fprintf (file, "(%" PRIi64 " * 2^%d)", (int64_t)m_sig, m_exp);
681debfc3dSmrg }
691debfc3dSmrg
701debfc3dSmrg DEBUG_FUNCTION void
debug(const sreal & ref)711debfc3dSmrg debug (const sreal &ref)
721debfc3dSmrg {
731debfc3dSmrg ref.dump (stderr);
741debfc3dSmrg }
751debfc3dSmrg
761debfc3dSmrg DEBUG_FUNCTION void
debug(const sreal * ptr)771debfc3dSmrg debug (const sreal *ptr)
781debfc3dSmrg {
791debfc3dSmrg if (ptr)
801debfc3dSmrg debug (*ptr);
811debfc3dSmrg else
821debfc3dSmrg fprintf (stderr, "<nil>\n");
831debfc3dSmrg }
841debfc3dSmrg
851debfc3dSmrg /* Shift this right by S bits. Needed: 0 < S <= SREAL_BITS.
861debfc3dSmrg When the most significant bit shifted out is 1, add 1 to this (rounding).
871debfc3dSmrg */
881debfc3dSmrg
891debfc3dSmrg void
shift_right(int s)901debfc3dSmrg sreal::shift_right (int s)
911debfc3dSmrg {
921debfc3dSmrg gcc_checking_assert (s > 0);
931debfc3dSmrg gcc_checking_assert (s <= SREAL_BITS);
941debfc3dSmrg /* Exponent should never be so large because shift_right is used only by
951debfc3dSmrg sreal_add and sreal_sub ant thus the number cannot be shifted out from
961debfc3dSmrg exponent range. */
971debfc3dSmrg gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
981debfc3dSmrg
991debfc3dSmrg m_exp += s;
1001debfc3dSmrg
1011debfc3dSmrg m_sig += (int64_t) 1 << (s - 1);
1021debfc3dSmrg m_sig >>= s;
1031debfc3dSmrg }
1041debfc3dSmrg
1051debfc3dSmrg /* Return integer value of *this. */
1061debfc3dSmrg
1071debfc3dSmrg int64_t
to_int()1081debfc3dSmrg sreal::to_int () const
1091debfc3dSmrg {
1101debfc3dSmrg int64_t sign = SREAL_SIGN (m_sig);
1111debfc3dSmrg
1121debfc3dSmrg if (m_exp <= -SREAL_BITS)
1131debfc3dSmrg return 0;
1141debfc3dSmrg if (m_exp >= SREAL_PART_BITS)
1151debfc3dSmrg return sign * INTTYPE_MAXIMUM (int64_t);
1161debfc3dSmrg if (m_exp > 0)
117c0a68be4Smrg return sign * (SREAL_ABS ((int64_t)m_sig) << m_exp);
1181debfc3dSmrg if (m_exp < 0)
1191debfc3dSmrg return m_sig >> -m_exp;
1201debfc3dSmrg return m_sig;
1211debfc3dSmrg }
1221debfc3dSmrg
1231debfc3dSmrg /* Return value of *this as double.
1241debfc3dSmrg This should be used for debug output only. */
1251debfc3dSmrg
1261debfc3dSmrg double
to_double()1271debfc3dSmrg sreal::to_double () const
1281debfc3dSmrg {
1291debfc3dSmrg double val = m_sig;
1301debfc3dSmrg if (m_exp)
1311debfc3dSmrg val = ldexp (val, m_exp);
1321debfc3dSmrg return val;
1331debfc3dSmrg }
1341debfc3dSmrg
1351debfc3dSmrg /* Return *this + other. */
1361debfc3dSmrg
1371debfc3dSmrg sreal
1381debfc3dSmrg sreal::operator+ (const sreal &other) const
1391debfc3dSmrg {
1401debfc3dSmrg int dexp;
141c0a68be4Smrg sreal tmp;
142c0a68be4Smrg int64_t r_sig, r_exp;
1431debfc3dSmrg
1441debfc3dSmrg const sreal *a_p = this, *b_p = &other, *bb;
1451debfc3dSmrg
1461debfc3dSmrg if (a_p->m_exp < b_p->m_exp)
1471debfc3dSmrg std::swap (a_p, b_p);
1481debfc3dSmrg
1491debfc3dSmrg dexp = a_p->m_exp - b_p->m_exp;
150c0a68be4Smrg r_exp = a_p->m_exp;
1511debfc3dSmrg if (dexp > SREAL_BITS)
1521debfc3dSmrg {
153c0a68be4Smrg r_sig = a_p->m_sig;
154c0a68be4Smrg
155c0a68be4Smrg sreal r;
156c0a68be4Smrg r.m_sig = r_sig;
157c0a68be4Smrg r.m_exp = r_exp;
1581debfc3dSmrg return r;
1591debfc3dSmrg }
1601debfc3dSmrg
1611debfc3dSmrg if (dexp == 0)
1621debfc3dSmrg bb = b_p;
1631debfc3dSmrg else
1641debfc3dSmrg {
1651debfc3dSmrg tmp = *b_p;
1661debfc3dSmrg tmp.shift_right (dexp);
1671debfc3dSmrg bb = &tmp;
1681debfc3dSmrg }
1691debfc3dSmrg
170c0a68be4Smrg r_sig = a_p->m_sig + (int64_t)bb->m_sig;
171c0a68be4Smrg sreal r (r_sig, r_exp);
1721debfc3dSmrg return r;
1731debfc3dSmrg }
1741debfc3dSmrg
1751debfc3dSmrg
1761debfc3dSmrg /* Return *this - other. */
1771debfc3dSmrg
1781debfc3dSmrg sreal
1791debfc3dSmrg sreal::operator- (const sreal &other) const
1801debfc3dSmrg {
1811debfc3dSmrg int dexp;
182c0a68be4Smrg sreal tmp;
183c0a68be4Smrg int64_t r_sig, r_exp;
1841debfc3dSmrg const sreal *bb;
1851debfc3dSmrg const sreal *a_p = this, *b_p = &other;
1861debfc3dSmrg
1871debfc3dSmrg int64_t sign = 1;
1881debfc3dSmrg if (a_p->m_exp < b_p->m_exp)
1891debfc3dSmrg {
1901debfc3dSmrg sign = -1;
1911debfc3dSmrg std::swap (a_p, b_p);
1921debfc3dSmrg }
1931debfc3dSmrg
1941debfc3dSmrg dexp = a_p->m_exp - b_p->m_exp;
195c0a68be4Smrg r_exp = a_p->m_exp;
1961debfc3dSmrg if (dexp > SREAL_BITS)
1971debfc3dSmrg {
198c0a68be4Smrg r_sig = sign * a_p->m_sig;
199c0a68be4Smrg
200c0a68be4Smrg sreal r;
201c0a68be4Smrg r.m_sig = r_sig;
202c0a68be4Smrg r.m_exp = r_exp;
2031debfc3dSmrg return r;
2041debfc3dSmrg }
2051debfc3dSmrg if (dexp == 0)
2061debfc3dSmrg bb = b_p;
2071debfc3dSmrg else
2081debfc3dSmrg {
2091debfc3dSmrg tmp = *b_p;
2101debfc3dSmrg tmp.shift_right (dexp);
2111debfc3dSmrg bb = &tmp;
2121debfc3dSmrg }
2131debfc3dSmrg
214c0a68be4Smrg r_sig = sign * ((int64_t) a_p->m_sig - (int64_t)bb->m_sig);
215c0a68be4Smrg sreal r (r_sig, r_exp);
2161debfc3dSmrg return r;
2171debfc3dSmrg }
2181debfc3dSmrg
2191debfc3dSmrg /* Return *this * other. */
2201debfc3dSmrg
2211debfc3dSmrg sreal
2221debfc3dSmrg sreal::operator* (const sreal &other) const
2231debfc3dSmrg {
2241debfc3dSmrg sreal r;
225c0a68be4Smrg if (absu_hwi (m_sig) < SREAL_MIN_SIG
226c0a68be4Smrg || absu_hwi (other.m_sig) < SREAL_MIN_SIG)
2271debfc3dSmrg {
2281debfc3dSmrg r.m_sig = 0;
2291debfc3dSmrg r.m_exp = -SREAL_MAX_EXP;
2301debfc3dSmrg }
2311debfc3dSmrg else
232c0a68be4Smrg r.normalize (m_sig * (int64_t) other.m_sig, m_exp + other.m_exp);
2331debfc3dSmrg
2341debfc3dSmrg return r;
2351debfc3dSmrg }
2361debfc3dSmrg
2371debfc3dSmrg /* Return *this / other. */
2381debfc3dSmrg
2391debfc3dSmrg sreal
2401debfc3dSmrg sreal::operator/ (const sreal &other) const
2411debfc3dSmrg {
2421debfc3dSmrg gcc_checking_assert (other.m_sig != 0);
243c0a68be4Smrg sreal r (SREAL_SIGN (m_sig)
244c0a68be4Smrg * ((int64_t)SREAL_ABS (m_sig) << SREAL_PART_BITS) / other.m_sig,
245c0a68be4Smrg m_exp - other.m_exp - SREAL_PART_BITS);
2461debfc3dSmrg return r;
2471debfc3dSmrg }
2481debfc3dSmrg
249a2dc1f3fSmrg /* Stream sreal value to OB. */
250a2dc1f3fSmrg
251a2dc1f3fSmrg void
stream_out(struct output_block * ob)252a2dc1f3fSmrg sreal::stream_out (struct output_block *ob)
253a2dc1f3fSmrg {
254a2dc1f3fSmrg streamer_write_hwi (ob, m_sig);
255a2dc1f3fSmrg streamer_write_hwi (ob, m_exp);
256a2dc1f3fSmrg }
257a2dc1f3fSmrg
258a2dc1f3fSmrg /* Read sreal value from IB. */
259a2dc1f3fSmrg
260a2dc1f3fSmrg sreal
stream_in(class lto_input_block * ib)261*8feb0f0bSmrg sreal::stream_in (class lto_input_block *ib)
262a2dc1f3fSmrg {
263a2dc1f3fSmrg sreal val;
264a2dc1f3fSmrg val.m_sig = streamer_read_hwi (ib);
265a2dc1f3fSmrg val.m_exp = streamer_read_hwi (ib);
266a2dc1f3fSmrg return val;
267a2dc1f3fSmrg }
268a2dc1f3fSmrg
2691debfc3dSmrg #if CHECKING_P
2701debfc3dSmrg
2711debfc3dSmrg namespace selftest {
2721debfc3dSmrg
2731debfc3dSmrg /* Selftests for sreals. */
2741debfc3dSmrg
2751debfc3dSmrg /* Verify basic sreal operations. */
2761debfc3dSmrg
2771debfc3dSmrg static void
sreal_verify_basics(void)2781debfc3dSmrg sreal_verify_basics (void)
2791debfc3dSmrg {
280c0a68be4Smrg sreal minimum = INT_MIN/2;
281c0a68be4Smrg sreal maximum = INT_MAX/2;
2821debfc3dSmrg
2831debfc3dSmrg sreal seven = 7;
2841debfc3dSmrg sreal minus_two = -2;
2851debfc3dSmrg sreal minus_nine = -9;
2861debfc3dSmrg
287c0a68be4Smrg ASSERT_EQ (INT_MIN/2, minimum.to_int ());
288c0a68be4Smrg ASSERT_EQ (INT_MAX/2, maximum.to_int ());
2891debfc3dSmrg
2901debfc3dSmrg ASSERT_FALSE (minus_two < minus_two);
2911debfc3dSmrg ASSERT_FALSE (seven < seven);
2921debfc3dSmrg ASSERT_TRUE (seven > minus_two);
2931debfc3dSmrg ASSERT_TRUE (minus_two < seven);
2941debfc3dSmrg ASSERT_TRUE (minus_two != seven);
2951debfc3dSmrg ASSERT_EQ (minus_two, -2);
2961debfc3dSmrg ASSERT_EQ (seven, 7);
2971debfc3dSmrg ASSERT_EQ ((seven << 10) >> 10, 7);
2981debfc3dSmrg ASSERT_EQ (seven + minus_nine, -2);
2991debfc3dSmrg }
3001debfc3dSmrg
3011debfc3dSmrg /* Helper function that performs basic arithmetics and comparison
3021debfc3dSmrg of given arguments A and B. */
3031debfc3dSmrg
3041debfc3dSmrg static void
verify_aritmetics(int64_t a,int64_t b)3051debfc3dSmrg verify_aritmetics (int64_t a, int64_t b)
3061debfc3dSmrg {
3071debfc3dSmrg ASSERT_EQ (a, -(-(sreal (a))).to_int ());
3081debfc3dSmrg ASSERT_EQ (a < b, sreal (a) < sreal (b));
3091debfc3dSmrg ASSERT_EQ (a <= b, sreal (a) <= sreal (b));
3101debfc3dSmrg ASSERT_EQ (a == b, sreal (a) == sreal (b));
3111debfc3dSmrg ASSERT_EQ (a != b, sreal (a) != sreal (b));
3121debfc3dSmrg ASSERT_EQ (a > b, sreal (a) > sreal (b));
3131debfc3dSmrg ASSERT_EQ (a >= b, sreal (a) >= sreal (b));
3141debfc3dSmrg ASSERT_EQ (a + b, (sreal (a) + sreal (b)).to_int ());
3151debfc3dSmrg ASSERT_EQ (a - b, (sreal (a) - sreal (b)).to_int ());
3161debfc3dSmrg ASSERT_EQ (b + a, (sreal (b) + sreal (a)).to_int ());
3171debfc3dSmrg ASSERT_EQ (b - a, (sreal (b) - sreal (a)).to_int ());
3181debfc3dSmrg }
3191debfc3dSmrg
3201debfc3dSmrg /* Verify arithmetics for interesting numbers. */
3211debfc3dSmrg
3221debfc3dSmrg static void
sreal_verify_arithmetics(void)3231debfc3dSmrg sreal_verify_arithmetics (void)
3241debfc3dSmrg {
3251debfc3dSmrg int values[] = {-14123413, -7777, -17, -10, -2, 0, 17, 139, 1234123};
3261debfc3dSmrg unsigned c = sizeof (values) / sizeof (int);
3271debfc3dSmrg
3281debfc3dSmrg for (unsigned i = 0; i < c; i++)
3291debfc3dSmrg for (unsigned j = 0; j < c; j++)
3301debfc3dSmrg {
3311debfc3dSmrg int a = values[i];
3321debfc3dSmrg int b = values[j];
3331debfc3dSmrg
3341debfc3dSmrg verify_aritmetics (a, b);
3351debfc3dSmrg }
3361debfc3dSmrg }
3371debfc3dSmrg
3381debfc3dSmrg /* Helper function that performs various shifting test of a given
3391debfc3dSmrg argument A. */
3401debfc3dSmrg
3411debfc3dSmrg static void
verify_shifting(int64_t a)3421debfc3dSmrg verify_shifting (int64_t a)
3431debfc3dSmrg {
3441debfc3dSmrg sreal v = a;
3451debfc3dSmrg
3461debfc3dSmrg for (unsigned i = 0; i < 16; i++)
3471debfc3dSmrg ASSERT_EQ (a << i, (v << i).to_int());
3481debfc3dSmrg
3491debfc3dSmrg a = a << 16;
3501debfc3dSmrg v = v << 16;
3511debfc3dSmrg
3521debfc3dSmrg for (unsigned i = 0; i < 16; i++)
3531debfc3dSmrg ASSERT_EQ (a >> i, (v >> i).to_int());
3541debfc3dSmrg }
3551debfc3dSmrg
3561debfc3dSmrg /* Verify shifting for interesting numbers. */
3571debfc3dSmrg
3581debfc3dSmrg static void
sreal_verify_shifting(void)3591debfc3dSmrg sreal_verify_shifting (void)
3601debfc3dSmrg {
3611debfc3dSmrg int values[] = {0, 17, 32, 139, 1024, 55555, 1234123};
3621debfc3dSmrg unsigned c = sizeof (values) / sizeof (int);
3631debfc3dSmrg
3641debfc3dSmrg for (unsigned i = 0; i < c; i++)
3651debfc3dSmrg verify_shifting (values[i]);
3661debfc3dSmrg }
3671debfc3dSmrg
3681debfc3dSmrg /* Verify division by (of) a negative value. */
3691debfc3dSmrg
3701debfc3dSmrg static void
sreal_verify_negative_division(void)3711debfc3dSmrg sreal_verify_negative_division (void)
3721debfc3dSmrg {
3731debfc3dSmrg ASSERT_EQ (sreal (1) / sreal (1), sreal (1));
3741debfc3dSmrg ASSERT_EQ (sreal (-1) / sreal (-1), sreal (1));
3751debfc3dSmrg ASSERT_EQ (sreal (-1234567) / sreal (-1234567), sreal (1));
3761debfc3dSmrg ASSERT_EQ (sreal (-1234567) / sreal (1234567), sreal (-1));
3771debfc3dSmrg ASSERT_EQ (sreal (1234567) / sreal (-1234567), sreal (-1));
3781debfc3dSmrg }
3791debfc3dSmrg
3801debfc3dSmrg /* Run all of the selftests within this file. */
3811debfc3dSmrg
sreal_c_tests()3821debfc3dSmrg void sreal_c_tests ()
3831debfc3dSmrg {
3841debfc3dSmrg sreal_verify_basics ();
3851debfc3dSmrg sreal_verify_arithmetics ();
3861debfc3dSmrg sreal_verify_shifting ();
3871debfc3dSmrg sreal_verify_negative_division ();
3881debfc3dSmrg }
3891debfc3dSmrg
3901debfc3dSmrg } // namespace selftest
3911debfc3dSmrg #endif /* CHECKING_P */
392