xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/sreal.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
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