of the floating point routines in libgcc1.c for targets without
hardware floating point. */
-/* Copyright (C) 1994,1997-1998 Free Software Foundation, Inc.
-
-This file is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
-
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file with other programs, and to distribute
-those programs without any restriction coming from the use of this
-file. (The General Public License restrictions do apply in other
-respects; for example, they cover modification of the file, and
-distribution when not linked into another program.)
-
-This file is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
+/* Copyright 1994-2016 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with this program; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, if you link this library with other files,
some of which are compiled with GCC, to produce an executable,
#include "sim-assert.h"
-/* Debugging support. */
+/* Debugging support.
+ If digits is -1, then print all digits. */
static void
print_bits (unsigned64 x,
int msbit,
+ int digits,
sim_fpu_print_func print,
void *arg)
{
unsigned64 bit = LSBIT64 (msbit);
int i = 4;
- while (bit)
+ while (bit && digits)
{
if (i == 0)
print (arg, ",");
+
if ((x & bit))
print (arg, "1");
else
print (arg, "0");
bit >>= 1;
+
+ if (digits > 0)
+ digits--;
i = (i + 1) % 4;
}
}
/* Quick and dirty conversion between a host double and host 64bit int */
-typedef union {
+typedef union
+{
double d;
unsigned64 i;
-} sim_fpu_map;
+} sim_fpu_map;
/* A packed IEEE floating point number.
Zero (0 == BIASEDEXP && FRAC == 0):
(sign ? "-" : "+") 0.0
-
+
Infinity (BIASEDEXP == EXPMAX && FRAC == 0):
(sign ? "-" : "+") "infinity"
/* force fraction to correct class */
fraction = src->fraction;
fraction >>= NR_GUARDS;
+#ifdef SIM_QUIET_NAN_NEGATED
+ fraction |= QUIET_NAN - 1;
+#else
fraction |= QUIET_NAN;
+#endif
break;
case sim_fpu_class_snan:
sign = src->sign;
/* force fraction to correct class */
fraction = src->fraction;
fraction >>= NR_GUARDS;
+#ifdef SIM_QUIET_NAN_NEGATED
+ fraction |= QUIET_NAN;
+#else
fraction &= ~QUIET_NAN;
+#endif
break;
case sim_fpu_class_infinity:
sign = src->sign;
/* Infinity */
sign = src->sign;
exp = EXPMAX;
- fraction = 0;
+ fraction = 0;
}
else
{
(long) LSEXTRACTED32 (packed, 23 - 1, 0));
}
#endif
-
+
return packed;
}
/* tastes like zero */
dst->class = sim_fpu_class_zero;
dst->sign = sign;
+ dst->normal_exp = 0;
}
else
{
}
else
{
+ int qnan;
+
/* Non zero fraction, means NaN */
dst->sign = sign;
dst->fraction = (fraction << NR_GUARDS);
- if (fraction >= QUIET_NAN)
+#ifdef SIM_QUIET_NAN_NEGATED
+ qnan = (fraction & QUIET_NAN) == 0;
+#else
+ qnan = fraction >= QUIET_NAN;
+#endif
+ if (qnan)
dst->class = sim_fpu_class_qnan;
else
dst->class = sim_fpu_class_snan;
{
f->class = sim_fpu_class_zero;
f->sign = 0;
+ f->normal_exp = 0;
}
else
{
f->sign = (i < 0);
f->normal_exp = NR_FRAC_GUARD;
- if (f->sign)
+ if (f->sign)
{
/* Special case for minint, since there is no corresponding
+ve integer representation for it */
if (f->fraction >= IMPLICIT_2)
{
- do
+ do
{
f->fraction = (f->fraction >> 1) | (f->fraction & 1);
f->normal_exp += 1;
{
f->class = sim_fpu_class_zero;
f->sign = 0;
+ f->normal_exp = 0;
}
else
{
return 0;
break;
case sim_fpu_class_snan:
- /* Quieten a SignalingNaN */
+ /* Quieten a SignalingNaN */
f->class = sim_fpu_class_qnan;
return sim_fpu_status_invalid_snan;
break;
/* sign? */
f->class = sim_fpu_class_number;
- if ((signed64) f->fraction >= 0)
+ if (((signed64) f->fraction) >= 0)
f->sign = 0;
else
{
/* sign? */
f->class = sim_fpu_class_number;
- if ((signed64) f->fraction >= 0)
+ if (((signed64) f->fraction) >= 0)
f->sign = 0;
else
{
res2 += ((ps_hh__ >> 32) & 0xffffffff) + pp_hh;
high = res2;
low = res0;
-
+
f->normal_exp = l->normal_exp + r->normal_exp;
f->sign = l->sign ^ r->sign;
f->class = sim_fpu_class_number;
/* Input is bounded by [1,2) ; [2^60,2^61)
Output is bounded by [1,4) ; [2^120,2^122) */
-
+
/* Adjust the exponent according to where the decimal point ended
up in the high 64 bit word. In the source the decimal point
was at NR_FRAC_GUARD. */
ASSERT (high >= LSBIT64 ((NR_FRAC_GUARD * 2) - 64));
ASSERT (LSBIT64 (((NR_FRAC_GUARD + 1) * 2) - 64) < IMPLICIT_1);
-#if 0
- printf ("\n");
- print_bits (high, 63, (sim_fpu_print_func*)fprintf, stdout);
- printf (";");
- print_bits (low, 63, (sim_fpu_print_func*)fprintf, stdout);
- printf ("\n");
-#endif
-
/* normalize */
do
{
}
while (high < IMPLICIT_1);
-#if 0
- print_bits (high, 63, (sim_fpu_print_func*)fprintf, stdout);
- printf (";");
- print_bits (low, 63, (sim_fpu_print_func*)fprintf, stdout);
- printf ("\n");
-#endif
-
ASSERT (high >= IMPLICIT_1 && high < IMPLICIT_2);
if (low != 0)
{
f->normal_exp--;
}
ASSERT (numerator >= denominator);
-
+
/* Gain extra precision, already used one spare bit */
numerator <<= NR_SPARE;
denominator <<= NR_SPARE;
numerator <<= 1;
}
-#if 0
- printf ("\n");
- print_bits (quotient, 63, (sim_fpu_print_func*)fprintf, stdout);
- printf ("\n");
- print_bits (numerator, 63, (sim_fpu_print_func*)fprintf, stdout);
- printf ("\n");
- print_bits (denominator, 63, (sim_fpu_print_func*)fprintf, stdout);
- printf ("\n");
-#endif
-
/* discard (but save) the extra bits */
if ((quotient & LSMASK64 (NR_SPARE -1, 0)))
quotient = (quotient >> NR_SPARE) | 1;
}
ASSERT (l->sign == r->sign);
if (l->normal_exp > r->normal_exp
- || (l->normal_exp == r->normal_exp &&
+ || (l->normal_exp == r->normal_exp &&
l->fraction > r->fraction))
{
/* |l| > |r| */
}
ASSERT (l->sign == r->sign);
if (l->normal_exp > r->normal_exp
- || (l->normal_exp == r->normal_exp &&
+ || (l->normal_exp == r->normal_exp &&
l->fraction > r->fraction))
{
/* |l| > |r| */
sim_fpu_abs (sim_fpu *f,
const sim_fpu *r)
{
+ *f = *r;
+ f->sign = 0;
if (sim_fpu_is_snan (r))
{
- *f = *r;
f->class = sim_fpu_class_qnan;
return sim_fpu_status_invalid_snan;
}
- if (sim_fpu_is_qnan (r))
- {
- *f = *r;
- return 0;
- }
- *f = *r;
- f->sign = 0;
return 0;
}
sim_fpu_inv (sim_fpu *f,
const sim_fpu *r)
{
- if (sim_fpu_is_snan (r))
- {
- *f = *r;
- f->class = sim_fpu_class_qnan;
- return sim_fpu_status_invalid_snan;
- }
- if (sim_fpu_is_qnan (r))
- {
- *f = *r;
- f->class = sim_fpu_class_qnan;
- return 0;
- }
- if (sim_fpu_is_infinity (r))
- {
- *f = sim_fpu_zero;
- f->sign = r->sign;
- return 0;
- }
- if (sim_fpu_is_zero (r))
- {
- f->class = sim_fpu_class_infinity;
- f->sign = r->sign;
- return sim_fpu_status_invalid_div0;
- }
- *f = *r;
- f->normal_exp = - r->normal_exp;
- return 0;
+ return sim_fpu_div (f, &sim_fpu_one, r);
}
{
f->class = sim_fpu_class_zero;
f->sign = r->sign;
+ f->normal_exp = 0;
return 0;
}
if (sim_fpu_is_infinity (r))
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
+ * software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
-
+
/* __ieee754_sqrt(x)
* Return correctly rounded sqrt.
* ------------------------------------------
* | Use the hardware sqrt if you have one |
* ------------------------------------------
- * Method:
- * Bit by bit method using integer arithmetic. (Slow, but portable)
+ * Method:
+ * Bit by bit method using integer arithmetic. (Slow, but portable)
* 1. Normalization
- * Scale x to y in [1,4) with even powers of 2:
+ * Scale x to y in [1,4) with even powers of 2:
* find an integer k such that 1 <= (y=x*2^(2k)) < 4, then
* sqrt(x) = 2^k * sqrt(y)
-
* i+1 2
* s = 2*q , and y = 2 * ( y - q ). (1)
* i i i i
- *
- * To compute q from q , one checks whether
- * i+1 i
+ *
+ * To compute q from q , one checks whether
+ * i+1 i
*
* -(i+1) 2
* (q + 2 ) <= y. (2)
* i+1 i i+1 i
*
* With some algebric manipulation, it is not difficult to see
- * that (2) is equivalent to
+ * that (2) is equivalent to
* -(i+1)
* s + 2 <= y (3)
* i i
*
- * The advantage of (3) is that s and y can be computed by
+ * The advantage of (3) is that s and y can be computed by
* i i
* the following recurrence formula:
* if (3) is false
* -i -(i+1)
* s = s + 2 , y = y - s - 2 (5)
* i+1 i i+1 i i
- *
+ *
-
- -(i+1)
- - NOTE: y = 2 (y - s - 2 )
+ - NOTE: y = 2 (y - s - 2 )
- i+1 i i
-
- * One may easily use induction to prove (4) and (5).
+ * One may easily use induction to prove (4) and (5).
* Note. Since the left hand side of (3) contain only i+2 bits,
- * it does not necessary to do a full (53-bit) comparison
+ * it does not necessary to do a full (53-bit) comparison
* in (3).
* 3. Final rounding
* After generating the 53 bits result, we compute one more bit.
* The rounding mode can be detected by checking whether
* huge + tiny is equal to huge, and whether huge - tiny is
* equal to huge for some floating point number "huge" and "tiny".
- *
+ *
* Special cases:
* sqrt(+-0) = +-0 ... exact
* sqrt(inf) = inf
b = IMPLICIT_1;
q = 0;
s = 0;
-
+
while (b)
{
unsigned64 t = s + b;
}
+INLINE_SIM_FPU (unsigned64)
+sim_fpu_fraction (const sim_fpu *d)
+{
+ return d->fraction;
+}
+
+
+INLINE_SIM_FPU (unsigned64)
+sim_fpu_guard (const sim_fpu *d, int is_double)
+{
+ unsigned64 rv;
+ unsigned64 guardmask = LSMASK64 (NR_GUARDS - 1, 0);
+ rv = (d->fraction & guardmask) >> NR_PAD;
+ return rv;
+}
+
INLINE_SIM_FPU (int)
sim_fpu_is (const sim_fpu *d)
#if EXTERN_SIM_FPU_P
const sim_fpu sim_fpu_zero = {
- sim_fpu_class_zero,
+ sim_fpu_class_zero, 0, 0, 0
};
const sim_fpu sim_fpu_qnan = {
- sim_fpu_class_qnan,
+ sim_fpu_class_qnan, 0, 0, 0
};
const sim_fpu sim_fpu_one = {
- sim_fpu_class_number, 0, IMPLICIT_1, 1
+ sim_fpu_class_number, 0, IMPLICIT_1, 0
};
const sim_fpu sim_fpu_two = {
- sim_fpu_class_number, 0, IMPLICIT_1, 2
+ sim_fpu_class_number, 0, IMPLICIT_1, 1
};
const sim_fpu sim_fpu_max32 = {
sim_fpu_class_number, 0, LSMASK64 (NR_FRAC_GUARD, NR_GUARDS32), NORMAL_EXPMAX32
sim_fpu_print_func *print,
void *arg)
{
+ sim_fpu_printn_fpu (f, print, -1, arg);
+}
+
+INLINE_SIM_FPU (void)
+sim_fpu_printn_fpu (const sim_fpu *f,
+ sim_fpu_print_func *print,
+ int digits,
+ void *arg)
+{
print (arg, "%s", f->sign ? "-" : "+");
switch (f->class)
{
case sim_fpu_class_qnan:
print (arg, "0.");
- print_bits (f->fraction, NR_FRAC_GUARD - 1, print, arg);
+ print_bits (f->fraction, NR_FRAC_GUARD - 1, digits, print, arg);
print (arg, "*QuietNaN");
break;
case sim_fpu_class_snan:
print (arg, "0.");
- print_bits (f->fraction, NR_FRAC_GUARD - 1, print, arg);
+ print_bits (f->fraction, NR_FRAC_GUARD - 1, digits, print, arg);
print (arg, "*SignalNaN");
break;
case sim_fpu_class_zero:
case sim_fpu_class_number:
case sim_fpu_class_denorm:
print (arg, "1.");
- print_bits (f->fraction, NR_FRAC_GUARD - 1, print, arg);
- print (arg, "*2^%+-5d", f->normal_exp);
+ print_bits (f->fraction, NR_FRAC_GUARD - 1, digits, print, arg);
+ print (arg, "*2^%+d", f->normal_exp);
ASSERT (f->fraction >= IMPLICIT_1);
ASSERT (f->fraction < IMPLICIT_2);
}
void *arg)
{
int i = 1;
- char *prefix = "";
+ const char *prefix = "";
while (status >= i)
{
switch ((sim_fpu_status) (status & i))
case sim_fpu_status_invalid_sqrt:
print (arg, "%sSQRT", prefix);
break;
- break;
case sim_fpu_status_inexact:
print (arg, "%sX", prefix);
break;
- break;
case sim_fpu_status_overflow:
print (arg, "%sO", prefix);
break;
- break;
case sim_fpu_status_underflow:
print (arg, "%sU", prefix);
break;
- break;
case sim_fpu_status_invalid_div0:
print (arg, "%s/", prefix);
break;
- break;
case sim_fpu_status_rounded:
print (arg, "%sR", prefix);
break;
- break;
}
i <<= 1;
prefix = ",";