#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "toplev.h"
#include "real.h"
#include "tm_p.h"
#include "dfp.h"
#define CLASS2(A, B) ((A) << 2 | (B))
#if HOST_BITS_PER_LONG != 64 && HOST_BITS_PER_LONG != 32
#error "Some constant folding done by hand to avoid shift count warnings"
#endif
static void get_zero (REAL_VALUE_TYPE *, int);
static void get_canonical_qnan (REAL_VALUE_TYPE *, int);
static void get_canonical_snan (REAL_VALUE_TYPE *, int);
static void get_inf (REAL_VALUE_TYPE *, int);
static bool sticky_rshift_significand (REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *, unsigned int);
static void rshift_significand (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
unsigned int);
static void lshift_significand (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
unsigned int);
static void lshift_significand_1 (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
static bool add_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *);
static bool sub_significands (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *, int);
static void neg_significand (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
static int cmp_significands (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
static int cmp_significand_0 (const REAL_VALUE_TYPE *);
static void set_significand_bit (REAL_VALUE_TYPE *, unsigned int);
static void clear_significand_bit (REAL_VALUE_TYPE *, unsigned int);
static bool test_significand_bit (REAL_VALUE_TYPE *, unsigned int);
static void clear_significand_below (REAL_VALUE_TYPE *, unsigned int);
static bool div_significands (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *);
static void normalize (REAL_VALUE_TYPE *);
static bool do_add (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *, int);
static bool do_multiply (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *);
static bool do_divide (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
const REAL_VALUE_TYPE *);
static int do_compare (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, int);
static void do_fix_trunc (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
static unsigned long rtd_divmod (REAL_VALUE_TYPE *, REAL_VALUE_TYPE *);
static const REAL_VALUE_TYPE * ten_to_ptwo (int);
static const REAL_VALUE_TYPE * ten_to_mptwo (int);
static const REAL_VALUE_TYPE * real_digit (int);
static void times_pten (REAL_VALUE_TYPE *, int);
static void round_for_format (const struct real_format *, REAL_VALUE_TYPE *);
static inline void
get_zero (REAL_VALUE_TYPE *r, int sign)
{
memset (r, 0, sizeof (*r));
r->sign = sign;
}
static inline void
get_canonical_qnan (REAL_VALUE_TYPE *r, int sign)
{
memset (r, 0, sizeof (*r));
r->cl = rvc_nan;
r->sign = sign;
r->canonical = 1;
}
static inline void
get_canonical_snan (REAL_VALUE_TYPE *r, int sign)
{
memset (r, 0, sizeof (*r));
r->cl = rvc_nan;
r->sign = sign;
r->signalling = 1;
r->canonical = 1;
}
static inline void
get_inf (REAL_VALUE_TYPE *r, int sign)
{
memset (r, 0, sizeof (*r));
r->cl = rvc_inf;
r->sign = sign;
}
static bool
sticky_rshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
unsigned int n)
{
unsigned long sticky = 0;
unsigned int i, ofs = 0;
if (n >= HOST_BITS_PER_LONG)
{
for (i = 0, ofs = n / HOST_BITS_PER_LONG; i < ofs; ++i)
sticky |= a->sig[i];
n &= HOST_BITS_PER_LONG - 1;
}
if (n != 0)
{
sticky |= a->sig[ofs] & (((unsigned long)1 << n) - 1);
for (i = 0; i < SIGSZ; ++i)
{
r->sig[i]
= (((ofs + i >= SIGSZ ? 0 : a->sig[ofs + i]) >> n)
| ((ofs + i + 1 >= SIGSZ ? 0 : a->sig[ofs + i + 1])
<< (HOST_BITS_PER_LONG - n)));
}
}
else
{
for (i = 0; ofs + i < SIGSZ; ++i)
r->sig[i] = a->sig[ofs + i];
for (; i < SIGSZ; ++i)
r->sig[i] = 0;
}
return sticky != 0;
}
static void
rshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
unsigned int n)
{
unsigned int i, ofs = n / HOST_BITS_PER_LONG;
n &= HOST_BITS_PER_LONG - 1;
if (n != 0)
{
for (i = 0; i < SIGSZ; ++i)
{
r->sig[i]
= (((ofs + i >= SIGSZ ? 0 : a->sig[ofs + i]) >> n)
| ((ofs + i + 1 >= SIGSZ ? 0 : a->sig[ofs + i + 1])
<< (HOST_BITS_PER_LONG - n)));
}
}
else
{
for (i = 0; ofs + i < SIGSZ; ++i)
r->sig[i] = a->sig[ofs + i];
for (; i < SIGSZ; ++i)
r->sig[i] = 0;
}
}
static void
lshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
unsigned int n)
{
unsigned int i, ofs = n / HOST_BITS_PER_LONG;
n &= HOST_BITS_PER_LONG - 1;
if (n == 0)
{
for (i = 0; ofs + i < SIGSZ; ++i)
r->sig[SIGSZ-1-i] = a->sig[SIGSZ-1-i-ofs];
for (; i < SIGSZ; ++i)
r->sig[SIGSZ-1-i] = 0;
}
else
for (i = 0; i < SIGSZ; ++i)
{
r->sig[SIGSZ-1-i]
= (((ofs + i >= SIGSZ ? 0 : a->sig[SIGSZ-1-i-ofs]) << n)
| ((ofs + i + 1 >= SIGSZ ? 0 : a->sig[SIGSZ-1-i-ofs-1])
>> (HOST_BITS_PER_LONG - n)));
}
}
static inline void
lshift_significand_1 (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
{
unsigned int i;
for (i = SIGSZ - 1; i > 0; --i)
r->sig[i] = (a->sig[i] << 1) | (a->sig[i-1] >> (HOST_BITS_PER_LONG - 1));
r->sig[0] = a->sig[0] << 1;
}
static inline bool
add_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
const REAL_VALUE_TYPE *b)
{
bool carry = false;
int i;
for (i = 0; i < SIGSZ; ++i)
{
unsigned long ai = a->sig[i];
unsigned long ri = ai + b->sig[i];
if (carry)
{
carry = ri < ai;
carry |= ++ri == 0;
}
else
carry = ri < ai;
r->sig[i] = ri;
}
return carry;
}
static inline bool
sub_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
const REAL_VALUE_TYPE *b, int carry)
{
int i;
for (i = 0; i < SIGSZ; ++i)
{
unsigned long ai = a->sig[i];
unsigned long ri = ai - b->sig[i];
if (carry)
{
carry = ri > ai;
carry |= ~--ri == 0;
}
else
carry = ri > ai;
r->sig[i] = ri;
}
return carry;
}
static inline void
neg_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
{
bool carry = true;
int i;
for (i = 0; i < SIGSZ; ++i)
{
unsigned long ri, ai = a->sig[i];
if (carry)
{
if (ai)
{
ri = -ai;
carry = false;
}
else
ri = ai;
}
else
ri = ~ai;
r->sig[i] = ri;
}
}
static inline int
cmp_significands (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b)
{
int i;
for (i = SIGSZ - 1; i >= 0; --i)
{
unsigned long ai = a->sig[i];
unsigned long bi = b->sig[i];
if (ai > bi)
return 1;
if (ai < bi)
return -1;
}
return 0;
}
static inline int
cmp_significand_0 (const REAL_VALUE_TYPE *a)
{
int i;
for (i = SIGSZ - 1; i >= 0; --i)
if (a->sig[i])
return 1;
return 0;
}
static inline void
set_significand_bit (REAL_VALUE_TYPE *r, unsigned int n)
{
r->sig[n / HOST_BITS_PER_LONG]
|= (unsigned long)1 << (n % HOST_BITS_PER_LONG);
}
static inline void
clear_significand_bit (REAL_VALUE_TYPE *r, unsigned int n)
{
r->sig[n / HOST_BITS_PER_LONG]
&= ~((unsigned long)1 << (n % HOST_BITS_PER_LONG));
}
static inline bool
test_significand_bit (REAL_VALUE_TYPE *r, unsigned int n)
{
int t = (r->sig[n / HOST_BITS_PER_LONG] >> (n % HOST_BITS_PER_LONG)) & 1;
return t;
}
static void
clear_significand_below (REAL_VALUE_TYPE *r, unsigned int n)
{
int i, w = n / HOST_BITS_PER_LONG;
for (i = 0; i < w; ++i)
r->sig[i] = 0;
r->sig[w] &= ~(((unsigned long)1 << (n % HOST_BITS_PER_LONG)) - 1);
}
static inline bool
div_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
const REAL_VALUE_TYPE *b)
{
REAL_VALUE_TYPE u;
int i, bit = SIGNIFICAND_BITS - 1;
unsigned long msb, inexact;
u = *a;
memset (r->sig, 0, sizeof (r->sig));
msb = 0;
goto start;
do
{
msb = u.sig[SIGSZ-1] & SIG_MSB;
lshift_significand_1 (&u, &u);
start:
if (msb || cmp_significands (&u, b) >= 0)
{
sub_significands (&u, &u, b, 0);
set_significand_bit (r, bit);
}
}
while (--bit >= 0);
for (i = 0, inexact = 0; i < SIGSZ; i++)
inexact |= u.sig[i];
return inexact != 0;
}
static void
normalize (REAL_VALUE_TYPE *r)
{
int shift = 0, exp;
int i, j;
if (r->decimal)
return;
for (i = SIGSZ - 1; i >= 0; i--)
if (r->sig[i] == 0)
shift += HOST_BITS_PER_LONG;
else
break;
if (i < 0)
{
r->cl = rvc_zero;
SET_REAL_EXP (r, 0);
return;
}
for (j = 0; ; j++)
if (r->sig[i] & ((unsigned long)1 << (HOST_BITS_PER_LONG - 1 - j)))
break;
shift += j;
if (shift > 0)
{
exp = REAL_EXP (r) - shift;
if (exp > MAX_EXP)
get_inf (r, r->sign);
else if (exp < -MAX_EXP)
get_zero (r, r->sign);
else
{
SET_REAL_EXP (r, exp);
lshift_significand (r, r, shift);
}
}
}
static bool
do_add (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
const REAL_VALUE_TYPE *b, int subtract_p)
{
int dexp, sign, exp;
REAL_VALUE_TYPE t;
bool inexact = false;
sign = a->sign;
subtract_p = (sign ^ b->sign) ^ subtract_p;
switch (CLASS2 (a->cl, b->cl))
{
case CLASS2 (rvc_zero, rvc_zero):
get_zero (r, sign & !subtract_p);
return false;
case CLASS2 (rvc_zero, rvc_normal):
case CLASS2 (rvc_zero, rvc_inf):
case CLASS2 (rvc_zero, rvc_nan):
case CLASS2 (rvc_normal, rvc_nan):
case CLASS2 (rvc_inf, rvc_nan):
case CLASS2 (rvc_nan, rvc_nan):
case CLASS2 (rvc_normal, rvc_inf):
*r = *b;
r->sign = sign ^ subtract_p;
return false;
case CLASS2 (rvc_normal, rvc_zero):
case CLASS2 (rvc_inf, rvc_zero):
case CLASS2 (rvc_nan, rvc_zero):
case CLASS2 (rvc_nan, rvc_normal):
case CLASS2 (rvc_nan, rvc_inf):
case CLASS2 (rvc_inf, rvc_normal):
*r = *a;
return false;
case CLASS2 (rvc_inf, rvc_inf):
if (subtract_p)
get_canonical_qnan (r, 0);
else
*r = *a;
return false;
case CLASS2 (rvc_normal, rvc_normal):
break;
default:
gcc_unreachable ();
}
dexp = REAL_EXP (a) - REAL_EXP (b);
if (dexp < 0)
{
const REAL_VALUE_TYPE *t;
t = a, a = b, b = t;
dexp = -dexp;
sign ^= subtract_p;
}
exp = REAL_EXP (a);
if (dexp > 0)
{
if (dexp >= SIGNIFICAND_BITS)
{
*r = *a;
r->sign = sign;
return true;
}
inexact |= sticky_rshift_significand (&t, b, dexp);
b = &t;
}
if (subtract_p)
{
if (sub_significands (r, a, b, inexact))
{
sign ^= 1;
neg_significand (r, r);
}
}
else
{
if (add_significands (r, a, b))
{
inexact |= sticky_rshift_significand (r, r, 1);
r->sig[SIGSZ-1] |= SIG_MSB;
if (++exp > MAX_EXP)
{
get_inf (r, sign);
return true;
}
}
}
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, exp);
r->signalling = 0;
r->canonical = 0;
r->decimal = 0;
normalize (r);
if (r->cl == rvc_zero)
r->sign = 0;
else
r->sig[0] |= inexact;
return inexact;
}
static bool
do_multiply (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
const REAL_VALUE_TYPE *b)
{
REAL_VALUE_TYPE u, t, *rr;
unsigned int i, j, k;
int sign = a->sign ^ b->sign;
bool inexact = false;
switch (CLASS2 (a->cl, b->cl))
{
case CLASS2 (rvc_zero, rvc_zero):
case CLASS2 (rvc_zero, rvc_normal):
case CLASS2 (rvc_normal, rvc_zero):
get_zero (r, sign);
return false;
case CLASS2 (rvc_zero, rvc_nan):
case CLASS2 (rvc_normal, rvc_nan):
case CLASS2 (rvc_inf, rvc_nan):
case CLASS2 (rvc_nan, rvc_nan):
*r = *b;
r->sign = sign;
return false;
case CLASS2 (rvc_nan, rvc_zero):
case CLASS2 (rvc_nan, rvc_normal):
case CLASS2 (rvc_nan, rvc_inf):
*r = *a;
r->sign = sign;
return false;
case CLASS2 (rvc_zero, rvc_inf):
case CLASS2 (rvc_inf, rvc_zero):
get_canonical_qnan (r, sign);
return false;
case CLASS2 (rvc_inf, rvc_inf):
case CLASS2 (rvc_normal, rvc_inf):
case CLASS2 (rvc_inf, rvc_normal):
get_inf (r, sign);
return false;
case CLASS2 (rvc_normal, rvc_normal):
break;
default:
gcc_unreachable ();
}
if (r == a || r == b)
rr = &t;
else
rr = r;
get_zero (rr, 0);
for (i = 0; i < SIGSZ * 2; ++i)
{
unsigned long ai = a->sig[i / 2];
if (i & 1)
ai >>= HOST_BITS_PER_LONG / 2;
else
ai &= ((unsigned long)1 << (HOST_BITS_PER_LONG / 2)) - 1;
if (ai == 0)
continue;
for (j = 0; j < 2; ++j)
{
int exp = (REAL_EXP (a) - (2*SIGSZ-1-i)*(HOST_BITS_PER_LONG/2)
+ (REAL_EXP (b) - (1-j)*(HOST_BITS_PER_LONG/2)));
if (exp > MAX_EXP)
{
get_inf (r, sign);
return true;
}
if (exp < -MAX_EXP)
{
inexact = true;
continue;
}
memset (&u, 0, sizeof (u));
u.cl = rvc_normal;
SET_REAL_EXP (&u, exp);
for (k = j; k < SIGSZ * 2; k += 2)
{
unsigned long bi = b->sig[k / 2];
if (k & 1)
bi >>= HOST_BITS_PER_LONG / 2;
else
bi &= ((unsigned long)1 << (HOST_BITS_PER_LONG / 2)) - 1;
u.sig[k / 2] = ai * bi;
}
normalize (&u);
inexact |= do_add (rr, rr, &u, 0);
}
}
rr->sign = sign;
if (rr != r)
*r = t;
return inexact;
}
static bool
do_divide (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
const REAL_VALUE_TYPE *b)
{
int exp, sign = a->sign ^ b->sign;
REAL_VALUE_TYPE t, *rr;
bool inexact;
switch (CLASS2 (a->cl, b->cl))
{
case CLASS2 (rvc_zero, rvc_zero):
case CLASS2 (rvc_inf, rvc_inf):
get_canonical_qnan (r, sign);
return false;
case CLASS2 (rvc_zero, rvc_normal):
case CLASS2 (rvc_zero, rvc_inf):
case CLASS2 (rvc_normal, rvc_inf):
get_zero (r, sign);
return false;
case CLASS2 (rvc_normal, rvc_zero):
case CLASS2 (rvc_inf, rvc_zero):
get_inf (r, sign);
return false;
case CLASS2 (rvc_zero, rvc_nan):
case CLASS2 (rvc_normal, rvc_nan):
case CLASS2 (rvc_inf, rvc_nan):
case CLASS2 (rvc_nan, rvc_nan):
*r = *b;
r->sign = sign;
return false;
case CLASS2 (rvc_nan, rvc_zero):
case CLASS2 (rvc_nan, rvc_normal):
case CLASS2 (rvc_nan, rvc_inf):
*r = *a;
r->sign = sign;
return false;
case CLASS2 (rvc_inf, rvc_normal):
get_inf (r, sign);
return false;
case CLASS2 (rvc_normal, rvc_normal):
break;
default:
gcc_unreachable ();
}
if (r == a || r == b)
rr = &t;
else
rr = r;
get_zero (rr, 0);
rr->cl = rvc_normal;
rr->sign = sign;
exp = REAL_EXP (a) - REAL_EXP (b) + 1;
if (exp > MAX_EXP)
{
get_inf (r, sign);
return true;
}
if (exp < -MAX_EXP)
{
get_zero (r, sign);
return true;
}
SET_REAL_EXP (rr, exp);
inexact = div_significands (rr, a, b);
normalize (rr);
rr->sig[0] |= inexact;
if (rr != r)
*r = t;
return inexact;
}
static int
do_compare (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b,
int nan_result)
{
int ret;
switch (CLASS2 (a->cl, b->cl))
{
case CLASS2 (rvc_zero, rvc_zero):
return 0;
case CLASS2 (rvc_inf, rvc_zero):
case CLASS2 (rvc_inf, rvc_normal):
case CLASS2 (rvc_normal, rvc_zero):
return (a->sign ? -1 : 1);
case CLASS2 (rvc_inf, rvc_inf):
return -a->sign - -b->sign;
case CLASS2 (rvc_zero, rvc_normal):
case CLASS2 (rvc_zero, rvc_inf):
case CLASS2 (rvc_normal, rvc_inf):
return (b->sign ? 1 : -1);
case CLASS2 (rvc_zero, rvc_nan):
case CLASS2 (rvc_normal, rvc_nan):
case CLASS2 (rvc_inf, rvc_nan):
case CLASS2 (rvc_nan, rvc_nan):
case CLASS2 (rvc_nan, rvc_zero):
case CLASS2 (rvc_nan, rvc_normal):
case CLASS2 (rvc_nan, rvc_inf):
return nan_result;
case CLASS2 (rvc_normal, rvc_normal):
break;
default:
gcc_unreachable ();
}
if (a->sign != b->sign)
return -a->sign - -b->sign;
if (a->decimal || b->decimal)
return decimal_do_compare (a, b, nan_result);
if (REAL_EXP (a) > REAL_EXP (b))
ret = 1;
else if (REAL_EXP (a) < REAL_EXP (b))
ret = -1;
else
ret = cmp_significands (a, b);
return (a->sign ? -ret : ret);
}
static void
do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
{
*r = *a;
switch (r->cl)
{
case rvc_zero:
case rvc_inf:
case rvc_nan:
break;
case rvc_normal:
if (r->decimal)
{
decimal_do_fix_trunc (r, a);
return;
}
if (REAL_EXP (r) <= 0)
get_zero (r, r->sign);
else if (REAL_EXP (r) < SIGNIFICAND_BITS)
clear_significand_below (r, SIGNIFICAND_BITS - REAL_EXP (r));
break;
default:
gcc_unreachable ();
}
}
bool
real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
const REAL_VALUE_TYPE *op1)
{
enum tree_code code = icode;
if (op0->decimal || (op1 && op1->decimal))
return decimal_real_arithmetic (r, icode, op0, op1);
switch (code)
{
case PLUS_EXPR:
return do_add (r, op0, op1, 0);
case MINUS_EXPR:
return do_add (r, op0, op1, 1);
case MULT_EXPR:
return do_multiply (r, op0, op1);
case RDIV_EXPR:
return do_divide (r, op0, op1);
case MIN_EXPR:
if (op1->cl == rvc_nan)
*r = *op1;
else if (do_compare (op0, op1, -1) < 0)
*r = *op0;
else
*r = *op1;
break;
case MAX_EXPR:
if (op1->cl == rvc_nan)
*r = *op1;
else if (do_compare (op0, op1, 1) < 0)
*r = *op1;
else
*r = *op0;
break;
case NEGATE_EXPR:
*r = *op0;
r->sign ^= 1;
break;
case ABS_EXPR:
*r = *op0;
r->sign = 0;
break;
case FIX_TRUNC_EXPR:
do_fix_trunc (r, op0);
break;
default:
gcc_unreachable ();
}
return false;
}
REAL_VALUE_TYPE
real_arithmetic2 (int icode, const REAL_VALUE_TYPE *op0,
const REAL_VALUE_TYPE *op1)
{
REAL_VALUE_TYPE r;
real_arithmetic (&r, icode, op0, op1);
return r;
}
bool
real_compare (int icode, const REAL_VALUE_TYPE *op0,
const REAL_VALUE_TYPE *op1)
{
enum tree_code code = icode;
switch (code)
{
case LT_EXPR:
return do_compare (op0, op1, 1) < 0;
case LE_EXPR:
return do_compare (op0, op1, 1) <= 0;
case GT_EXPR:
return do_compare (op0, op1, -1) > 0;
case GE_EXPR:
return do_compare (op0, op1, -1) >= 0;
case EQ_EXPR:
return do_compare (op0, op1, -1) == 0;
case NE_EXPR:
return do_compare (op0, op1, -1) != 0;
case UNORDERED_EXPR:
return op0->cl == rvc_nan || op1->cl == rvc_nan;
case ORDERED_EXPR:
return op0->cl != rvc_nan && op1->cl != rvc_nan;
case UNLT_EXPR:
return do_compare (op0, op1, -1) < 0;
case UNLE_EXPR:
return do_compare (op0, op1, -1) <= 0;
case UNGT_EXPR:
return do_compare (op0, op1, 1) > 0;
case UNGE_EXPR:
return do_compare (op0, op1, 1) >= 0;
case UNEQ_EXPR:
return do_compare (op0, op1, 0) == 0;
case LTGT_EXPR:
return do_compare (op0, op1, 0) != 0;
default:
gcc_unreachable ();
}
}
int
real_exponent (const REAL_VALUE_TYPE *r)
{
switch (r->cl)
{
case rvc_zero:
return 0;
case rvc_inf:
case rvc_nan:
return (unsigned int)-1 >> 1;
case rvc_normal:
return REAL_EXP (r);
default:
gcc_unreachable ();
}
}
void
real_ldexp (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0, int exp)
{
*r = *op0;
switch (r->cl)
{
case rvc_zero:
case rvc_inf:
case rvc_nan:
break;
case rvc_normal:
exp += REAL_EXP (op0);
if (exp > MAX_EXP)
get_inf (r, r->sign);
else if (exp < -MAX_EXP)
get_zero (r, r->sign);
else
SET_REAL_EXP (r, exp);
break;
default:
gcc_unreachable ();
}
}
bool
real_isinf (const REAL_VALUE_TYPE *r)
{
return (r->cl == rvc_inf);
}
bool
real_isnan (const REAL_VALUE_TYPE *r)
{
return (r->cl == rvc_nan);
}
bool
real_isneg (const REAL_VALUE_TYPE *r)
{
return r->sign;
}
bool
real_isnegzero (const REAL_VALUE_TYPE *r)
{
return r->sign && r->cl == rvc_zero;
}
bool
real_identical (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b)
{
int i;
if (a->cl != b->cl)
return false;
if (a->sign != b->sign)
return false;
switch (a->cl)
{
case rvc_zero:
case rvc_inf:
return true;
case rvc_normal:
if (a->decimal != b->decimal)
return false;
if (REAL_EXP (a) != REAL_EXP (b))
return false;
break;
case rvc_nan:
if (a->signalling != b->signalling)
return false;
if (a->canonical || b->canonical)
return a->canonical == b->canonical;
break;
default:
gcc_unreachable ();
}
for (i = 0; i < SIGSZ; ++i)
if (a->sig[i] != b->sig[i])
return false;
return true;
}
bool
exact_real_inverse (enum machine_mode mode, REAL_VALUE_TYPE *r)
{
const REAL_VALUE_TYPE *one = real_digit (1);
REAL_VALUE_TYPE u;
int i;
if (r->cl != rvc_normal)
return false;
for (i = 0; i < SIGSZ-1; ++i)
if (r->sig[i] != 0)
return false;
if (r->sig[SIGSZ-1] != SIG_MSB)
return false;
do_divide (&u, one, r);
real_convert (&u, mode, &u);
if (u.cl != rvc_normal)
return false;
for (i = 0; i < SIGSZ-1; ++i)
if (u.sig[i] != 0)
return false;
if (u.sig[SIGSZ-1] != SIG_MSB)
return false;
*r = u;
return true;
}
HOST_WIDE_INT
real_to_integer (const REAL_VALUE_TYPE *r)
{
unsigned HOST_WIDE_INT i;
switch (r->cl)
{
case rvc_zero:
underflow:
return 0;
case rvc_inf:
case rvc_nan:
overflow:
i = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1);
if (!r->sign)
i--;
return i;
case rvc_normal:
if (r->decimal)
return decimal_real_to_integer (r);
if (REAL_EXP (r) <= 0)
goto underflow;
if (REAL_EXP (r) > HOST_BITS_PER_WIDE_INT)
goto overflow;
if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG)
i = r->sig[SIGSZ-1];
else
{
gcc_assert (HOST_BITS_PER_WIDE_INT == 2 * HOST_BITS_PER_LONG);
i = r->sig[SIGSZ-1];
i = i << (HOST_BITS_PER_LONG - 1) << 1;
i |= r->sig[SIGSZ-2];
}
i >>= HOST_BITS_PER_WIDE_INT - REAL_EXP (r);
if (r->sign)
i = -i;
return i;
default:
gcc_unreachable ();
}
}
void
real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh,
const REAL_VALUE_TYPE *r)
{
REAL_VALUE_TYPE t;
HOST_WIDE_INT low, high;
int exp;
switch (r->cl)
{
case rvc_zero:
underflow:
low = high = 0;
break;
case rvc_inf:
case rvc_nan:
overflow:
high = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1);
if (r->sign)
low = 0;
else
{
high--;
low = -1;
}
break;
case rvc_normal:
if (r->decimal)
{
decimal_real_to_integer2 (plow, phigh, r);
return;
}
exp = REAL_EXP (r);
if (exp <= 0)
goto underflow;
if (exp > 2*HOST_BITS_PER_WIDE_INT)
goto overflow;
rshift_significand (&t, r, 2*HOST_BITS_PER_WIDE_INT - exp);
if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG)
{
high = t.sig[SIGSZ-1];
low = t.sig[SIGSZ-2];
}
else
{
gcc_assert (HOST_BITS_PER_WIDE_INT == 2*HOST_BITS_PER_LONG);
high = t.sig[SIGSZ-1];
high = high << (HOST_BITS_PER_LONG - 1) << 1;
high |= t.sig[SIGSZ-2];
low = t.sig[SIGSZ-3];
low = low << (HOST_BITS_PER_LONG - 1) << 1;
low |= t.sig[SIGSZ-4];
}
if (r->sign)
{
if (low == 0)
high = -high;
else
low = -low, high = ~high;
}
break;
default:
gcc_unreachable ();
}
*plow = low;
*phigh = high;
}
static unsigned long
rtd_divmod (REAL_VALUE_TYPE *num, REAL_VALUE_TYPE *den)
{
unsigned long q, msb;
int expn = REAL_EXP (num), expd = REAL_EXP (den);
if (expn < expd)
return 0;
q = msb = 0;
goto start;
do
{
msb = num->sig[SIGSZ-1] & SIG_MSB;
q <<= 1;
lshift_significand_1 (num, num);
start:
if (msb || cmp_significands (num, den) >= 0)
{
sub_significands (num, num, den, 0);
q |= 1;
}
}
while (--expn >= expd);
SET_REAL_EXP (num, expd);
normalize (num);
return q;
}
#define M_LOG10_2 0.30102999566398119521
void
real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
size_t digits, int crop_trailing_zeros)
{
const REAL_VALUE_TYPE *one, *ten;
REAL_VALUE_TYPE r, pten, u, v;
int dec_exp, cmp_one, digit;
size_t max_digits;
char *p, *first, *last;
bool sign;
r = *r_orig;
switch (r.cl)
{
case rvc_zero:
strcpy (str, (r.sign ? "-0.0" : "0.0"));
return;
case rvc_normal:
break;
case rvc_inf:
strcpy (str, (r.sign ? "-Inf" : "+Inf"));
return;
case rvc_nan:
strcpy (str, (r.sign ? "-NaN" : "+NaN"));
return;
default:
gcc_unreachable ();
}
if (r.decimal)
{
decimal_real_to_decimal (str, &r, buf_size, digits, crop_trailing_zeros);
return;
}
max_digits = SIGNIFICAND_BITS * M_LOG10_2;
if (digits == 0 || digits > max_digits)
digits = max_digits;
dec_exp = REAL_EXP (&r) * M_LOG10_2;
for (max_digits = 1; dec_exp ; max_digits++)
dec_exp /= 10;
max_digits = buf_size - 1 - 1 - 2 - max_digits - 1;
gcc_assert (max_digits <= buf_size);
if (digits > max_digits)
digits = max_digits;
one = real_digit (1);
ten = ten_to_ptwo (0);
sign = r.sign;
r.sign = 0;
dec_exp = 0;
pten = *one;
cmp_one = do_compare (&r, one, 0);
if (cmp_one > 0)
{
int m;
u = r;
SET_REAL_EXP (&u, SIGNIFICAND_BITS - 1);
m = floor_log2 (max_digits);
do
{
REAL_VALUE_TYPE t;
do_divide (&t, &u, ten_to_ptwo (m));
do_fix_trunc (&v, &t);
if (cmp_significands (&v, &t) == 0)
{
u = t;
dec_exp += 1 << m;
}
}
while (--m >= 0);
SET_REAL_EXP (&u, REAL_EXP (&u) + REAL_EXP (&r)
- (SIGNIFICAND_BITS - 1));
r = u;
if (REAL_EXP (&r) > 0)
{
m = floor_log2 ((int)(REAL_EXP (&r) * M_LOG10_2)) + 1;
do
{
const REAL_VALUE_TYPE *ptentwo = ten_to_ptwo (m);
if (do_compare (&u, ptentwo, 0) >= 0)
{
do_divide (&u, &u, ptentwo);
do_multiply (&pten, &pten, ptentwo);
dec_exp += 1 << m;
}
}
while (--m >= 0);
}
else
cmp_one = -1;
}
if (cmp_one < 0)
{
int m;
v = r;
while (1)
{
if (v.sig[0] & 7)
break;
do_multiply (&u, &v, ten);
if (REAL_EXP (&u) > 0)
break;
v = u;
dec_exp -= 1;
}
r = v;
m = floor_log2 ((int)(-REAL_EXP (&r) * M_LOG10_2)) + 1;
do
{
const REAL_VALUE_TYPE *ptentwo = ten_to_ptwo (m);
const REAL_VALUE_TYPE *ptenmtwo = ten_to_mptwo (m);
if (do_compare (&v, ptenmtwo, 0) <= 0)
{
do_multiply (&v, &v, ptentwo);
do_multiply (&pten, &pten, ptentwo);
dec_exp -= 1 << m;
}
}
while (--m >= 0);
do_divide (&pten, one, &pten);
}
p = str;
if (sign)
*p++ = '-';
first = p++;
digit = rtd_divmod (&r, &pten);
if (digit == 0 && cmp_significand_0 (&r))
{
do_multiply (&r, &r, ten);
digit = rtd_divmod (&r, &pten);
dec_exp -= 1;
gcc_assert (digit != 0);
}
if (digit == 10)
{
*p++ = '1';
if (--digits > 0)
*p++ = '0';
dec_exp += 1;
}
else
{
gcc_assert (digit <= 10);
*p++ = digit + '0';
}
while (--digits > 0)
{
do_multiply (&r, &r, ten);
digit = rtd_divmod (&r, &pten);
*p++ = digit + '0';
}
last = p;
do_multiply (&r, &r, ten);
digit = rtd_divmod (&r, &pten);
if (digit == 5)
{
if (cmp_significand_0 (&r))
digit++;
else if ((p[-1] - '0') & 1)
digit++;
}
if (digit > 5)
{
while (p > first)
{
digit = *--p;
if (digit == '9')
*p = '0';
else
{
*p = digit + 1;
break;
}
}
if (p == first)
{
first[1] = '1';
dec_exp++;
}
}
first[0] = first[1];
first[1] = '.';
if (crop_trailing_zeros)
while (last > first + 3 && last[-1] == '0')
last--;
sprintf (last, "e%+d", dec_exp);
}
void
real_to_hexadecimal (char *str, const REAL_VALUE_TYPE *r, size_t buf_size,
size_t digits, int crop_trailing_zeros)
{
int i, j, exp = REAL_EXP (r);
char *p, *first;
char exp_buf[16];
size_t max_digits;
switch (r->cl)
{
case rvc_zero:
exp = 0;
break;
case rvc_normal:
break;
case rvc_inf:
strcpy (str, (r->sign ? "-Inf" : "+Inf"));
return;
case rvc_nan:
strcpy (str, (r->sign ? "-NaN" : "+NaN"));
return;
default:
gcc_unreachable ();
}
if (r->decimal)
{
strcpy (str, "N/A");
return;
}
if (digits == 0)
digits = SIGNIFICAND_BITS / 4;
sprintf (exp_buf, "p%+d", exp);
max_digits = buf_size - strlen (exp_buf) - r->sign - 4 - 1;
gcc_assert (max_digits <= buf_size);
if (digits > max_digits)
digits = max_digits;
p = str;
if (r->sign)
*p++ = '-';
*p++ = '0';
*p++ = 'x';
*p++ = '0';
*p++ = '.';
first = p;
for (i = SIGSZ - 1; i >= 0; --i)
for (j = HOST_BITS_PER_LONG - 4; j >= 0; j -= 4)
{
*p++ = "0123456789abcdef"[(r->sig[i] >> j) & 15];
if (--digits == 0)
goto out;
}
out:
if (crop_trailing_zeros)
while (p > first + 1 && p[-1] == '0')
p--;
sprintf (p, "p%+d", exp);
}
void
real_from_string (REAL_VALUE_TYPE *r, const char *str)
{
int exp = 0;
bool sign = false;
get_zero (r, 0);
if (*str == '-')
{
sign = true;
str++;
}
else if (*str == '+')
str++;
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
{
int pos = SIGNIFICAND_BITS - 4, d;
str += 2;
while (*str == '0')
str++;
while (1)
{
d = hex_value (*str);
if (d == _hex_bad)
break;
if (pos >= 0)
{
r->sig[pos / HOST_BITS_PER_LONG]
|= (unsigned long) d << (pos % HOST_BITS_PER_LONG);
pos -= 4;
}
else if (d)
r->sig[0] |= 1;
exp += 4;
str++;
}
if (*str == '.')
{
str++;
if (pos == SIGNIFICAND_BITS - 4)
{
while (*str == '0')
str++, exp -= 4;
}
while (1)
{
d = hex_value (*str);
if (d == _hex_bad)
break;
if (pos >= 0)
{
r->sig[pos / HOST_BITS_PER_LONG]
|= (unsigned long) d << (pos % HOST_BITS_PER_LONG);
pos -= 4;
}
else if (d)
r->sig[0] |= 1;
str++;
}
}
if (!cmp_significand_0 (r))
goto underflow;
if (*str == 'p' || *str == 'P')
{
bool exp_neg = false;
str++;
if (*str == '-')
{
exp_neg = true;
str++;
}
else if (*str == '+')
str++;
d = 0;
while (ISDIGIT (*str))
{
d *= 10;
d += *str - '0';
if (d > MAX_EXP)
{
if (exp_neg)
goto underflow;
else
goto overflow;
}
str++;
}
if (exp_neg)
d = -d;
exp += d;
}
r->cl = rvc_normal;
SET_REAL_EXP (r, exp);
normalize (r);
}
else
{
const REAL_VALUE_TYPE *ten = ten_to_ptwo (0);
int d;
while (*str == '0')
str++;
while (ISDIGIT (*str))
{
d = *str++ - '0';
do_multiply (r, r, ten);
if (d)
do_add (r, r, real_digit (d), 0);
}
if (*str == '.')
{
str++;
if (r->cl == rvc_zero)
{
while (*str == '0')
str++, exp--;
}
while (ISDIGIT (*str))
{
d = *str++ - '0';
do_multiply (r, r, ten);
if (d)
do_add (r, r, real_digit (d), 0);
exp--;
}
}
if (r->cl == rvc_zero)
goto underflow;
if (*str == 'e' || *str == 'E')
{
bool exp_neg = false;
str++;
if (*str == '-')
{
exp_neg = true;
str++;
}
else if (*str == '+')
str++;
d = 0;
while (ISDIGIT (*str))
{
d *= 10;
d += *str - '0';
if (d > MAX_EXP)
{
if (exp_neg)
goto underflow;
else
goto overflow;
}
str++;
}
if (exp_neg)
d = -d;
exp += d;
}
if (exp)
times_pten (r, exp);
}
r->sign = sign;
return;
underflow:
get_zero (r, sign);
return;
overflow:
get_inf (r, sign);
return;
}
REAL_VALUE_TYPE
real_from_string2 (const char *s, enum machine_mode mode)
{
REAL_VALUE_TYPE r;
real_from_string (&r, s);
if (mode != VOIDmode)
real_convert (&r, mode, &r);
return r;
}
void
real_from_string3 (REAL_VALUE_TYPE *r, const char *s, enum machine_mode mode)
{
if (DECIMAL_FLOAT_MODE_P (mode))
decimal_real_from_string (r, s);
else
real_from_string (r, s);
if (mode != VOIDmode)
real_convert (r, mode, r);
}
void
real_from_integer (REAL_VALUE_TYPE *r, enum machine_mode mode,
unsigned HOST_WIDE_INT low, HOST_WIDE_INT high,
int unsigned_p)
{
if (low == 0 && high == 0)
get_zero (r, 0);
else
{
memset (r, 0, sizeof (*r));
r->cl = rvc_normal;
r->sign = high < 0 && !unsigned_p;
SET_REAL_EXP (r, 2 * HOST_BITS_PER_WIDE_INT);
if (r->sign)
{
high = ~high;
if (low == 0)
high += 1;
else
low = -low;
}
if (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT)
{
r->sig[SIGSZ-1] = high;
r->sig[SIGSZ-2] = low;
}
else
{
gcc_assert (HOST_BITS_PER_LONG*2 == HOST_BITS_PER_WIDE_INT);
r->sig[SIGSZ-1] = high >> (HOST_BITS_PER_LONG - 1) >> 1;
r->sig[SIGSZ-2] = high;
r->sig[SIGSZ-3] = low >> (HOST_BITS_PER_LONG - 1) >> 1;
r->sig[SIGSZ-4] = low;
}
normalize (r);
}
if (mode != VOIDmode)
real_convert (r, mode, r);
}
static const REAL_VALUE_TYPE *
ten_to_ptwo (int n)
{
static REAL_VALUE_TYPE tens[EXP_BITS];
gcc_assert (n >= 0);
gcc_assert (n < EXP_BITS);
if (tens[n].cl == rvc_zero)
{
if (n < (HOST_BITS_PER_WIDE_INT == 64 ? 5 : 4))
{
HOST_WIDE_INT t = 10;
int i;
for (i = 0; i < n; ++i)
t *= t;
real_from_integer (&tens[n], VOIDmode, t, 0, 1);
}
else
{
const REAL_VALUE_TYPE *t = ten_to_ptwo (n - 1);
do_multiply (&tens[n], t, t);
}
}
return &tens[n];
}
static const REAL_VALUE_TYPE *
ten_to_mptwo (int n)
{
static REAL_VALUE_TYPE tens[EXP_BITS];
gcc_assert (n >= 0);
gcc_assert (n < EXP_BITS);
if (tens[n].cl == rvc_zero)
do_divide (&tens[n], real_digit (1), ten_to_ptwo (n));
return &tens[n];
}
static const REAL_VALUE_TYPE *
real_digit (int n)
{
static REAL_VALUE_TYPE num[10];
gcc_assert (n >= 0);
gcc_assert (n <= 9);
if (n > 0 && num[n].cl == rvc_zero)
real_from_integer (&num[n], VOIDmode, n, 0, 1);
return &num[n];
}
static void
times_pten (REAL_VALUE_TYPE *r, int exp)
{
REAL_VALUE_TYPE pten, *rr;
bool negative = (exp < 0);
int i;
if (negative)
{
exp = -exp;
pten = *real_digit (1);
rr = &pten;
}
else
rr = r;
for (i = 0; exp > 0; ++i, exp >>= 1)
if (exp & 1)
do_multiply (rr, rr, ten_to_ptwo (i));
if (negative)
do_divide (r, r, &pten);
}
void
real_inf (REAL_VALUE_TYPE *r)
{
get_inf (r, 0);
}
bool
real_nan (REAL_VALUE_TYPE *r, const char *str, int quiet,
enum machine_mode mode)
{
const struct real_format *fmt;
fmt = REAL_MODE_FORMAT (mode);
gcc_assert (fmt);
if (*str == 0)
{
if (quiet)
get_canonical_qnan (r, 0);
else
get_canonical_snan (r, 0);
}
else
{
int base = 10, d;
memset (r, 0, sizeof (*r));
r->cl = rvc_nan;
while (ISSPACE (*str))
str++;
if (*str == '-')
str++;
else if (*str == '+')
str++;
if (*str == '0')
{
str++;
if (*str == 'x' || *str == 'X')
{
base = 16;
str++;
}
else
base = 8;
}
while ((d = hex_value (*str)) < base)
{
REAL_VALUE_TYPE u;
switch (base)
{
case 8:
lshift_significand (r, r, 3);
break;
case 16:
lshift_significand (r, r, 4);
break;
case 10:
lshift_significand_1 (&u, r);
lshift_significand (r, r, 3);
add_significands (r, r, &u);
break;
default:
gcc_unreachable ();
}
get_zero (&u, 0);
u.sig[0] = d;
add_significands (r, r, &u);
str++;
}
if (*str != 0)
return false;
lshift_significand (r, r, SIGNIFICAND_BITS - fmt->pnan);
r->sig[SIGSZ-1] &= ~SIG_MSB;
r->signalling = !quiet;
}
return true;
}
void
real_maxval (REAL_VALUE_TYPE *r, int sign, enum machine_mode mode)
{
const struct real_format *fmt;
int np2;
fmt = REAL_MODE_FORMAT (mode);
gcc_assert (fmt);
memset (r, 0, sizeof (*r));
if (fmt->b == 10)
decimal_real_maxval (r, sign, mode);
else
{
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, fmt->emax * fmt->log2_b);
np2 = SIGNIFICAND_BITS - fmt->p * fmt->log2_b;
memset (r->sig, -1, SIGSZ * sizeof (unsigned long));
clear_significand_below (r, np2);
if (fmt->pnan < fmt->p)
clear_significand_bit (r, SIGNIFICAND_BITS - fmt->pnan);
}
}
void
real_2expN (REAL_VALUE_TYPE *r, int n)
{
memset (r, 0, sizeof (*r));
n++;
if (n > MAX_EXP)
r->cl = rvc_inf;
else if (n < -MAX_EXP)
;
else
{
r->cl = rvc_normal;
SET_REAL_EXP (r, n);
r->sig[SIGSZ-1] = SIG_MSB;
}
}
static void
round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
{
int p2, np2, i, w;
unsigned long sticky;
bool guard, lsb;
int emin2m1, emax2;
if (r->decimal)
{
if (fmt->b == 10)
{
decimal_round_for_format (fmt, r);
return;
}
decimal_real_convert (r, DFmode, r);
}
p2 = fmt->p * fmt->log2_b;
emin2m1 = (fmt->emin - 1) * fmt->log2_b;
emax2 = fmt->emax * fmt->log2_b;
np2 = SIGNIFICAND_BITS - p2;
switch (r->cl)
{
underflow:
get_zero (r, r->sign);
case rvc_zero:
if (!fmt->has_signed_zero)
r->sign = 0;
return;
overflow:
get_inf (r, r->sign);
case rvc_inf:
return;
case rvc_nan:
clear_significand_below (r, np2);
return;
case rvc_normal:
break;
default:
gcc_unreachable ();
}
if (fmt->log2_b != 1)
{
int shift;
gcc_assert (fmt->b != 10);
shift = REAL_EXP (r) & (fmt->log2_b - 1);
if (shift)
{
shift = fmt->log2_b - shift;
r->sig[0] |= sticky_rshift_significand (r, r, shift);
SET_REAL_EXP (r, REAL_EXP (r) + shift);
}
}
if (REAL_EXP (r) > emax2)
goto overflow;
else if (REAL_EXP (r) <= emin2m1)
{
int diff;
if (!fmt->has_denorm)
{
if (REAL_EXP (r) < emin2m1)
goto underflow;
}
else
{
diff = emin2m1 - REAL_EXP (r) + 1;
if (diff > p2)
goto underflow;
r->sig[0] |= sticky_rshift_significand (r, r, diff);
SET_REAL_EXP (r, REAL_EXP (r) + diff);
}
}
sticky = 0;
for (i = 0, w = (np2 - 1) / HOST_BITS_PER_LONG; i < w; ++i)
sticky |= r->sig[i];
sticky |=
r->sig[w] & (((unsigned long)1 << ((np2 - 1) % HOST_BITS_PER_LONG)) - 1);
guard = test_significand_bit (r, np2 - 1);
lsb = test_significand_bit (r, np2);
if (guard && (sticky || lsb))
{
REAL_VALUE_TYPE u;
get_zero (&u, 0);
set_significand_bit (&u, np2);
if (add_significands (r, r, &u))
{
SET_REAL_EXP (r, REAL_EXP (r) + 1);
if (REAL_EXP (r) > emax2)
goto overflow;
r->sig[SIGSZ-1] = SIG_MSB;
if (fmt->log2_b != 1)
{
int shift = REAL_EXP (r) & (fmt->log2_b - 1);
if (shift)
{
shift = fmt->log2_b - shift;
rshift_significand (r, r, shift);
SET_REAL_EXP (r, REAL_EXP (r) + shift);
if (REAL_EXP (r) > emax2)
goto overflow;
}
}
}
}
if (REAL_EXP (r) <= emin2m1)
goto underflow;
clear_significand_below (r, np2);
}
void
real_convert (REAL_VALUE_TYPE *r, enum machine_mode mode,
const REAL_VALUE_TYPE *a)
{
const struct real_format *fmt;
fmt = REAL_MODE_FORMAT (mode);
gcc_assert (fmt);
*r = *a;
if (a->decimal || fmt->b == 10)
decimal_real_convert (r, mode, a);
round_for_format (fmt, r);
if (r->cl == rvc_normal)
normalize (r);
}
REAL_VALUE_TYPE
real_value_truncate (enum machine_mode mode, REAL_VALUE_TYPE a)
{
REAL_VALUE_TYPE r;
real_convert (&r, mode, &a);
return r;
}
bool
exact_real_truncate (enum machine_mode mode, const REAL_VALUE_TYPE *a)
{
const struct real_format *fmt;
REAL_VALUE_TYPE t;
int emin2m1;
fmt = REAL_MODE_FORMAT (mode);
gcc_assert (fmt);
emin2m1 = (fmt->emin - 1) * fmt->log2_b;
if (REAL_EXP (a) <= emin2m1)
return false;
real_convert (&t, mode, a);
return real_identical (&t, a);
}
long
real_to_target_fmt (long *buf, const REAL_VALUE_TYPE *r_orig,
const struct real_format *fmt)
{
REAL_VALUE_TYPE r;
long buf1;
r = *r_orig;
round_for_format (fmt, &r);
if (!buf)
buf = &buf1;
(*fmt->encode) (fmt, buf, &r);
return *buf;
}
long
real_to_target (long *buf, const REAL_VALUE_TYPE *r, enum machine_mode mode)
{
const struct real_format *fmt;
fmt = REAL_MODE_FORMAT (mode);
gcc_assert (fmt);
return real_to_target_fmt (buf, r, fmt);
}
void
real_from_target_fmt (REAL_VALUE_TYPE *r, const long *buf,
const struct real_format *fmt)
{
(*fmt->decode) (fmt, r, buf);
}
void
real_from_target (REAL_VALUE_TYPE *r, const long *buf, enum machine_mode mode)
{
const struct real_format *fmt;
fmt = REAL_MODE_FORMAT (mode);
gcc_assert (fmt);
(*fmt->decode) (fmt, r, buf);
}
int
significand_size (enum machine_mode mode)
{
const struct real_format *fmt;
fmt = REAL_MODE_FORMAT (mode);
if (fmt == NULL)
return 0;
if (fmt->b == 10)
{
double log2_10 = 3.3219281;
return fmt->p * log2_10;
}
return fmt->p * fmt->log2_b;
}
unsigned int
real_hash (const REAL_VALUE_TYPE *r)
{
unsigned int h;
size_t i;
h = r->cl | (r->sign << 2);
switch (r->cl)
{
case rvc_zero:
case rvc_inf:
return h;
case rvc_normal:
h |= REAL_EXP (r) << 3;
break;
case rvc_nan:
if (r->signalling)
h ^= (unsigned int)-1;
if (r->canonical)
return h;
break;
default:
gcc_unreachable ();
}
if (sizeof(unsigned long) > sizeof(unsigned int))
for (i = 0; i < SIGSZ; ++i)
{
unsigned long s = r->sig[i];
h ^= s ^ (s >> (HOST_BITS_PER_LONG / 2));
}
else
for (i = 0; i < SIGSZ; ++i)
h ^= r->sig[i];
return h;
}
static void encode_ieee_single (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_ieee_single (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void
encode_ieee_single (const struct real_format *fmt, long *buf,
const REAL_VALUE_TYPE *r)
{
unsigned long image, sig, exp;
unsigned long sign = r->sign;
bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
image = sign << 31;
sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff;
switch (r->cl)
{
case rvc_zero:
break;
case rvc_inf:
if (fmt->has_inf)
image |= 255 << 23;
else
image |= 0x7fffffff;
break;
case rvc_nan:
if (fmt->has_nans)
{
if (r->canonical)
sig = 0;
if (r->signalling == fmt->qnan_msb_set)
sig &= ~(1 << 22);
else
sig |= 1 << 22;
if (r->canonical && !fmt->qnan_msb_set)
sig |= (1 << 22) - 1;
else if (sig == 0)
sig = 1 << 21;
image |= 255 << 23;
image |= sig;
}
else
image |= 0x7fffffff;
break;
case rvc_normal:
if (denormal)
exp = 0;
else
exp = REAL_EXP (r) + 127 - 1;
image |= exp << 23;
image |= sig;
break;
default:
gcc_unreachable ();
}
buf[0] = image;
}
static void
decode_ieee_single (const struct real_format *fmt, REAL_VALUE_TYPE *r,
const long *buf)
{
unsigned long image = buf[0] & 0xffffffff;
bool sign = (image >> 31) & 1;
int exp = (image >> 23) & 0xff;
memset (r, 0, sizeof (*r));
image <<= HOST_BITS_PER_LONG - 24;
image &= ~SIG_MSB;
if (exp == 0)
{
if (image && fmt->has_denorm)
{
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, -126);
r->sig[SIGSZ-1] = image << 1;
normalize (r);
}
else if (fmt->has_signed_zero)
r->sign = sign;
}
else if (exp == 255 && (fmt->has_nans || fmt->has_inf))
{
if (image)
{
r->cl = rvc_nan;
r->sign = sign;
r->signalling = (((image >> (HOST_BITS_PER_LONG - 2)) & 1)
^ fmt->qnan_msb_set);
r->sig[SIGSZ-1] = image;
}
else
{
r->cl = rvc_inf;
r->sign = sign;
}
}
else
{
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, exp - 127 + 1);
r->sig[SIGSZ-1] = image | SIG_MSB;
}
}
const struct real_format ieee_single_format =
{
encode_ieee_single,
decode_ieee_single,
2,
1,
24,
24,
-125,
128,
31,
31,
true,
true,
true,
true,
true
};
const struct real_format mips_single_format =
{
encode_ieee_single,
decode_ieee_single,
2,
1,
24,
24,
-125,
128,
31,
31,
true,
true,
true,
true,
false
};
static void encode_ieee_double (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_ieee_double (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void
encode_ieee_double (const struct real_format *fmt, long *buf,
const REAL_VALUE_TYPE *r)
{
unsigned long image_lo, image_hi, sig_lo, sig_hi, exp;
bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
image_hi = r->sign << 31;
image_lo = 0;
if (HOST_BITS_PER_LONG == 64)
{
sig_hi = r->sig[SIGSZ-1];
sig_lo = (sig_hi >> (64 - 53)) & 0xffffffff;
sig_hi = (sig_hi >> (64 - 53 + 1) >> 31) & 0xfffff;
}
else
{
sig_hi = r->sig[SIGSZ-1];
sig_lo = r->sig[SIGSZ-2];
sig_lo = (sig_hi << 21) | (sig_lo >> 11);
sig_hi = (sig_hi >> 11) & 0xfffff;
}
switch (r->cl)
{
case rvc_zero:
break;
case rvc_inf:
if (fmt->has_inf)
image_hi |= 2047 << 20;
else
{
image_hi |= 0x7fffffff;
image_lo = 0xffffffff;
}
break;
case rvc_nan:
if (fmt->has_nans)
{
if (r->canonical)
sig_hi = sig_lo = 0;
if (r->signalling == fmt->qnan_msb_set)
sig_hi &= ~(1 << 19);
else
sig_hi |= 1 << 19;
if (r->canonical && !fmt->qnan_msb_set)
{
sig_hi |= (1 << 19) - 1;
sig_lo = 0xffffffff;
}
else if (sig_hi == 0 && sig_lo == 0)
sig_hi = 1 << 18;
image_hi |= 2047 << 20;
image_hi |= sig_hi;
image_lo = sig_lo;
}
else
{
image_hi |= 0x7fffffff;
image_lo = 0xffffffff;
}
break;
case rvc_normal:
if (denormal)
exp = 0;
else
exp = REAL_EXP (r) + 1023 - 1;
image_hi |= exp << 20;
image_hi |= sig_hi;
image_lo = sig_lo;
break;
default:
gcc_unreachable ();
}
if (FLOAT_WORDS_BIG_ENDIAN)
buf[0] = image_hi, buf[1] = image_lo;
else
buf[0] = image_lo, buf[1] = image_hi;
}
static void
decode_ieee_double (const struct real_format *fmt, REAL_VALUE_TYPE *r,
const long *buf)
{
unsigned long image_hi, image_lo;
bool sign;
int exp;
if (FLOAT_WORDS_BIG_ENDIAN)
image_hi = buf[0], image_lo = buf[1];
else
image_lo = buf[0], image_hi = buf[1];
image_lo &= 0xffffffff;
image_hi &= 0xffffffff;
sign = (image_hi >> 31) & 1;
exp = (image_hi >> 20) & 0x7ff;
memset (r, 0, sizeof (*r));
image_hi <<= 32 - 21;
image_hi |= image_lo >> 21;
image_hi &= 0x7fffffff;
image_lo <<= 32 - 21;
if (exp == 0)
{
if ((image_hi || image_lo) && fmt->has_denorm)
{
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, -1022);
if (HOST_BITS_PER_LONG == 32)
{
image_hi = (image_hi << 1) | (image_lo >> 31);
image_lo <<= 1;
r->sig[SIGSZ-1] = image_hi;
r->sig[SIGSZ-2] = image_lo;
}
else
{
image_hi = (image_hi << 31 << 2) | (image_lo << 1);
r->sig[SIGSZ-1] = image_hi;
}
normalize (r);
}
else if (fmt->has_signed_zero)
r->sign = sign;
}
else if (exp == 2047 && (fmt->has_nans || fmt->has_inf))
{
if (image_hi || image_lo)
{
r->cl = rvc_nan;
r->sign = sign;
r->signalling = ((image_hi >> 30) & 1) ^ fmt->qnan_msb_set;
if (HOST_BITS_PER_LONG == 32)
{
r->sig[SIGSZ-1] = image_hi;
r->sig[SIGSZ-2] = image_lo;
}
else
r->sig[SIGSZ-1] = (image_hi << 31 << 1) | image_lo;
}
else
{
r->cl = rvc_inf;
r->sign = sign;
}
}
else
{
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, exp - 1023 + 1);
if (HOST_BITS_PER_LONG == 32)
{
r->sig[SIGSZ-1] = image_hi | SIG_MSB;
r->sig[SIGSZ-2] = image_lo;
}
else
r->sig[SIGSZ-1] = (image_hi << 31 << 1) | image_lo | SIG_MSB;
}
}
const struct real_format ieee_double_format =
{
encode_ieee_double,
decode_ieee_double,
2,
1,
53,
53,
-1021,
1024,
63,
63,
true,
true,
true,
true,
true
};
const struct real_format mips_double_format =
{
encode_ieee_double,
decode_ieee_double,
2,
1,
53,
53,
-1021,
1024,
63,
63,
true,
true,
true,
true,
false
};
static void
encode_ieee_extended (const struct real_format *fmt, long *buf,
const REAL_VALUE_TYPE *r)
{
unsigned long image_hi, sig_hi, sig_lo;
bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
image_hi = r->sign << 15;
sig_hi = sig_lo = 0;
switch (r->cl)
{
case rvc_zero:
break;
case rvc_inf:
if (fmt->has_inf)
{
image_hi |= 32767;
sig_hi = 0x80000000;
}
else
{
image_hi |= 32767;
sig_lo = sig_hi = 0xffffffff;
}
break;
case rvc_nan:
if (fmt->has_nans)
{
image_hi |= 32767;
if (HOST_BITS_PER_LONG == 32)
{
sig_hi = r->sig[SIGSZ-1];
sig_lo = r->sig[SIGSZ-2];
}
else
{
sig_lo = r->sig[SIGSZ-1];
sig_hi = sig_lo >> 31 >> 1;
sig_lo &= 0xffffffff;
}
if (r->signalling == fmt->qnan_msb_set)
sig_hi &= ~(1 << 30);
else
sig_hi |= 1 << 30;
if ((sig_hi & 0x7fffffff) == 0 && sig_lo == 0)
sig_hi = 1 << 29;
sig_hi |= 0x80000000;
}
else
{
image_hi |= 32767;
sig_lo = sig_hi = 0xffffffff;
}
break;
case rvc_normal:
{
int exp = REAL_EXP (r);
if (denormal)
exp = 0;
else
{
exp += 16383 - 1;
gcc_assert (exp >= 0);
}
image_hi |= exp;
if (HOST_BITS_PER_LONG == 32)
{
sig_hi = r->sig[SIGSZ-1];
sig_lo = r->sig[SIGSZ-2];
}
else
{
sig_lo = r->sig[SIGSZ-1];
sig_hi = sig_lo >> 31 >> 1;
sig_lo &= 0xffffffff;
}
}
break;
default:
gcc_unreachable ();
}
buf[0] = sig_lo, buf[1] = sig_hi, buf[2] = image_hi;
}
static void
encode_ieee_extended_motorola (const struct real_format *fmt, long *buf,
const REAL_VALUE_TYPE *r)
{
long intermed[3];
encode_ieee_extended (fmt, intermed, r);
buf[0] = intermed[2] << 16;
buf[1] = intermed[1];
buf[2] = intermed[0];
}
static void
encode_ieee_extended_intel_96 (const struct real_format *fmt, long *buf,
const REAL_VALUE_TYPE *r)
{
if (FLOAT_WORDS_BIG_ENDIAN)
{
long intermed[3];
encode_ieee_extended (fmt, intermed, r);
buf[0] = ((intermed[2] << 16) | ((unsigned long)(intermed[1] & 0xFFFF0000) >> 16));
buf[1] = ((intermed[1] << 16) | ((unsigned long)(intermed[0] & 0xFFFF0000) >> 16));
buf[2] = (intermed[0] << 16);
}
else
encode_ieee_extended (fmt, buf, r);
}
static void
encode_ieee_extended_intel_128 (const struct real_format *fmt, long *buf,
const REAL_VALUE_TYPE *r)
{
encode_ieee_extended_intel_96 (fmt, buf, r);
buf[3] = 0;
}
static void
decode_ieee_extended (const struct real_format *fmt, REAL_VALUE_TYPE *r,
const long *buf)
{
unsigned long image_hi, sig_hi, sig_lo;
bool sign;
int exp;
sig_lo = buf[0], sig_hi = buf[1], image_hi = buf[2];
sig_lo &= 0xffffffff;
sig_hi &= 0xffffffff;
image_hi &= 0xffffffff;
sign = (image_hi >> 15) & 1;
exp = image_hi & 0x7fff;
memset (r, 0, sizeof (*r));
if (exp == 0)
{
if ((sig_hi || sig_lo) && fmt->has_denorm)
{
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, fmt->emin);
if (HOST_BITS_PER_LONG == 32)
{
r->sig[SIGSZ-1] = sig_hi;
r->sig[SIGSZ-2] = sig_lo;
}
else
r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo;
normalize (r);
}
else if (fmt->has_signed_zero)
r->sign = sign;
}
else if (exp == 32767 && (fmt->has_nans || fmt->has_inf))
{
sig_hi &= 0x7fffffff;
if (sig_hi || sig_lo)
{
r->cl = rvc_nan;
r->sign = sign;
r->signalling = ((sig_hi >> 30) & 1) ^ fmt->qnan_msb_set;
if (HOST_BITS_PER_LONG == 32)
{
r->sig[SIGSZ-1] = sig_hi;
r->sig[SIGSZ-2] = sig_lo;
}
else
r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo;
}
else
{
r->cl = rvc_inf;
r->sign = sign;
}
}
else
{
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, exp - 16383 + 1);
if (HOST_BITS_PER_LONG == 32)
{
r->sig[SIGSZ-1] = sig_hi;
r->sig[SIGSZ-2] = sig_lo;
}
else
r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo;
}
}
static void
decode_ieee_extended_motorola (const struct real_format *fmt, REAL_VALUE_TYPE *r,
const long *buf)
{
long intermed[3];
intermed[0] = buf[2];
intermed[1] = buf[1];
intermed[2] = (unsigned long)buf[0] >> 16;
decode_ieee_extended (fmt, r, intermed);
}
static void
decode_ieee_extended_intel_96 (const struct real_format *fmt, REAL_VALUE_TYPE *r,
const long *buf)
{
if (FLOAT_WORDS_BIG_ENDIAN)
{
long intermed[3];
intermed[0] = (((unsigned long)buf[2] >> 16) | (buf[1] << 16));
intermed[1] = (((unsigned long)buf[1] >> 16) | (buf[0] << 16));
intermed[2] = ((unsigned long)buf[0] >> 16);
decode_ieee_extended (fmt, r, intermed);
}
else
decode_ieee_extended (fmt, r, buf);
}
static void
decode_ieee_extended_intel_128 (const struct real_format *fmt, REAL_VALUE_TYPE *r,
const long *buf)
{
decode_ieee_extended_intel_96 (fmt, r, buf);
}
const struct real_format ieee_extended_motorola_format =
{
encode_ieee_extended_motorola,
decode_ieee_extended_motorola,
2,
1,
64,
64,
-16382,
16384,
95,
95,
true,
true,
true,
true,
true
};
const struct real_format ieee_extended_intel_96_format =
{
encode_ieee_extended_intel_96,
decode_ieee_extended_intel_96,
2,
1,
64,
64,
-16381,
16384,
79,
79,
true,
true,
true,
true,
true
};
const struct real_format ieee_extended_intel_128_format =
{
encode_ieee_extended_intel_128,
decode_ieee_extended_intel_128,
2,
1,
64,
64,
-16381,
16384,
79,
79,
true,
true,
true,
true,
true
};
const struct real_format ieee_extended_intel_96_round_53_format =
{
encode_ieee_extended_intel_96,
decode_ieee_extended_intel_96,
2,
1,
53,
53,
-16381,
16384,
79,
79,
true,
true,
true,
true,
true
};
static void encode_ibm_extended (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_ibm_extended (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void
encode_ibm_extended (const struct real_format *fmt, long *buf,
const REAL_VALUE_TYPE *r)
{
REAL_VALUE_TYPE u, normr, v;
const struct real_format *base_fmt;
base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format;
normr = *r;
if (normr.cl == rvc_normal)
normalize (&normr);
u = normr;
round_for_format (base_fmt, &u);
encode_ieee_double (base_fmt, &buf[0], &u);
if (u.cl == rvc_normal)
{
do_add (&v, &normr, &u, 1);
round_for_format (base_fmt, &v);
encode_ieee_double (base_fmt, &buf[2], &v);
}
else
{
buf[2] = 0;
buf[3] = 0;
}
}
static void
decode_ibm_extended (const struct real_format *fmt ATTRIBUTE_UNUSED, REAL_VALUE_TYPE *r,
const long *buf)
{
REAL_VALUE_TYPE u, v;
const struct real_format *base_fmt;
base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format;
decode_ieee_double (base_fmt, &u, &buf[0]);
if (u.cl != rvc_zero && u.cl != rvc_inf && u.cl != rvc_nan)
{
decode_ieee_double (base_fmt, &v, &buf[2]);
do_add (r, &u, &v, 0);
}
else
*r = u;
}
const struct real_format ibm_extended_format =
{
encode_ibm_extended,
decode_ibm_extended,
2,
1,
53 + 53,
53,
-1021 + 53,
1024,
127,
-1,
true,
true,
true,
true,
true
};
const struct real_format mips_extended_format =
{
encode_ibm_extended,
decode_ibm_extended,
2,
1,
53 + 53,
53,
-1021 + 53,
1024,
127,
-1,
true,
true,
true,
true,
false
};
static void encode_ieee_quad (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_ieee_quad (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void
encode_ieee_quad (const struct real_format *fmt, long *buf,
const REAL_VALUE_TYPE *r)
{
unsigned long image3, image2, image1, image0, exp;
bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
REAL_VALUE_TYPE u;
image3 = r->sign << 31;
image2 = 0;
image1 = 0;
image0 = 0;
rshift_significand (&u, r, SIGNIFICAND_BITS - 113);
switch (r->cl)
{
case rvc_zero:
break;
case rvc_inf:
if (fmt->has_inf)
image3 |= 32767 << 16;
else
{
image3 |= 0x7fffffff;
image2 = 0xffffffff;
image1 = 0xffffffff;
image0 = 0xffffffff;
}
break;
case rvc_nan:
if (fmt->has_nans)
{
image3 |= 32767 << 16;
if (r->canonical)
{
}
else if (HOST_BITS_PER_LONG == 32)
{
image0 = u.sig[0];
image1 = u.sig[1];
image2 = u.sig[2];
image3 |= u.sig[3] & 0xffff;
}
else
{
image0 = u.sig[0];
image1 = image0 >> 31 >> 1;
image2 = u.sig[1];
image3 |= (image2 >> 31 >> 1) & 0xffff;
image0 &= 0xffffffff;
image2 &= 0xffffffff;
}
if (r->signalling == fmt->qnan_msb_set)
image3 &= ~0x8000;
else
image3 |= 0x8000;
if (r->canonical && !fmt->qnan_msb_set)
{
image3 |= 0x7fff;
image2 = image1 = image0 = 0xffffffff;
}
else if (((image3 & 0xffff) | image2 | image1 | image0) == 0)
image3 |= 0x4000;
}
else
{
image3 |= 0x7fffffff;
image2 = 0xffffffff;
image1 = 0xffffffff;
image0 = 0xffffffff;
}
break;
case rvc_normal:
if (denormal)
exp = 0;
else
exp = REAL_EXP (r) + 16383 - 1;
image3 |= exp << 16;
if (HOST_BITS_PER_LONG == 32)
{
image0 = u.sig[0];
image1 = u.sig[1];
image2 = u.sig[2];
image3 |= u.sig[3] & 0xffff;
}
else
{
image0 = u.sig[0];
image1 = image0 >> 31 >> 1;
image2 = u.sig[1];
image3 |= (image2 >> 31 >> 1) & 0xffff;
image0 &= 0xffffffff;
image2 &= 0xffffffff;
}
break;
default:
gcc_unreachable ();
}
if (FLOAT_WORDS_BIG_ENDIAN)
{
buf[0] = image3;
buf[1] = image2;
buf[2] = image1;
buf[3] = image0;
}
else
{
buf[0] = image0;
buf[1] = image1;
buf[2] = image2;
buf[3] = image3;
}
}
static void
decode_ieee_quad (const struct real_format *fmt, REAL_VALUE_TYPE *r,
const long *buf)
{
unsigned long image3, image2, image1, image0;
bool sign;
int exp;
if (FLOAT_WORDS_BIG_ENDIAN)
{
image3 = buf[0];
image2 = buf[1];
image1 = buf[2];
image0 = buf[3];
}
else
{
image0 = buf[0];
image1 = buf[1];
image2 = buf[2];
image3 = buf[3];
}
image0 &= 0xffffffff;
image1 &= 0xffffffff;
image2 &= 0xffffffff;
sign = (image3 >> 31) & 1;
exp = (image3 >> 16) & 0x7fff;
image3 &= 0xffff;
memset (r, 0, sizeof (*r));
if (exp == 0)
{
if ((image3 | image2 | image1 | image0) && fmt->has_denorm)
{
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, -16382 + (SIGNIFICAND_BITS - 112));
if (HOST_BITS_PER_LONG == 32)
{
r->sig[0] = image0;
r->sig[1] = image1;
r->sig[2] = image2;
r->sig[3] = image3;
}
else
{
r->sig[0] = (image1 << 31 << 1) | image0;
r->sig[1] = (image3 << 31 << 1) | image2;
}
normalize (r);
}
else if (fmt->has_signed_zero)
r->sign = sign;
}
else if (exp == 32767 && (fmt->has_nans || fmt->has_inf))
{
if (image3 | image2 | image1 | image0)
{
r->cl = rvc_nan;
r->sign = sign;
r->signalling = ((image3 >> 15) & 1) ^ fmt->qnan_msb_set;
if (HOST_BITS_PER_LONG == 32)
{
r->sig[0] = image0;
r->sig[1] = image1;
r->sig[2] = image2;
r->sig[3] = image3;
}
else
{
r->sig[0] = (image1 << 31 << 1) | image0;
r->sig[1] = (image3 << 31 << 1) | image2;
}
lshift_significand (r, r, SIGNIFICAND_BITS - 113);
}
else
{
r->cl = rvc_inf;
r->sign = sign;
}
}
else
{
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, exp - 16383 + 1);
if (HOST_BITS_PER_LONG == 32)
{
r->sig[0] = image0;
r->sig[1] = image1;
r->sig[2] = image2;
r->sig[3] = image3;
}
else
{
r->sig[0] = (image1 << 31 << 1) | image0;
r->sig[1] = (image3 << 31 << 1) | image2;
}
lshift_significand (r, r, SIGNIFICAND_BITS - 113);
r->sig[SIGSZ-1] |= SIG_MSB;
}
}
const struct real_format ieee_quad_format =
{
encode_ieee_quad,
decode_ieee_quad,
2,
1,
113,
113,
-16381,
16384,
127,
127,
true,
true,
true,
true,
true
};
const struct real_format mips_quad_format =
{
encode_ieee_quad,
decode_ieee_quad,
2,
1,
113,
113,
-16381,
16384,
127,
127,
true,
true,
true,
true,
false
};
static void encode_vax_f (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_vax_f (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void encode_vax_d (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_vax_d (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void encode_vax_g (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_vax_g (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void
encode_vax_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
const REAL_VALUE_TYPE *r)
{
unsigned long sign, exp, sig, image;
sign = r->sign << 15;
switch (r->cl)
{
case rvc_zero:
image = 0;
break;
case rvc_inf:
case rvc_nan:
image = 0xffff7fff | sign;
break;
case rvc_normal:
sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff;
exp = REAL_EXP (r) + 128;
image = (sig << 16) & 0xffff0000;
image |= sign;
image |= exp << 7;
image |= sig >> 16;
break;
default:
gcc_unreachable ();
}
buf[0] = image;
}
static void
decode_vax_f (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long image = buf[0] & 0xffffffff;
int exp = (image >> 7) & 0xff;
memset (r, 0, sizeof (*r));
if (exp != 0)
{
r->cl = rvc_normal;
r->sign = (image >> 15) & 1;
SET_REAL_EXP (r, exp - 128);
image = ((image & 0x7f) << 16) | ((image >> 16) & 0xffff);
r->sig[SIGSZ-1] = (image << (HOST_BITS_PER_LONG - 24)) | SIG_MSB;
}
}
static void
encode_vax_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
const REAL_VALUE_TYPE *r)
{
unsigned long image0, image1, sign = r->sign << 15;
switch (r->cl)
{
case rvc_zero:
image0 = image1 = 0;
break;
case rvc_inf:
case rvc_nan:
image0 = 0xffff7fff | sign;
image1 = 0xffffffff;
break;
case rvc_normal:
if (HOST_BITS_PER_LONG == 64)
{
image0 = r->sig[SIGSZ-1];
image1 = (image0 >> (64 - 56)) & 0xffffffff;
image0 = (image0 >> (64 - 56 + 1) >> 31) & 0x7fffff;
}
else
{
image0 = r->sig[SIGSZ-1];
image1 = r->sig[SIGSZ-2];
image1 = (image0 << 24) | (image1 >> 8);
image0 = (image0 >> 8) & 0xffffff;
}
image0 = ((image0 << 16) | (image0 >> 16)) & 0xffff007f;
image1 = ((image1 << 16) | (image1 >> 16)) & 0xffffffff;
image0 |= sign;
image0 |= (REAL_EXP (r) + 128) << 7;
break;
default:
gcc_unreachable ();
}
if (FLOAT_WORDS_BIG_ENDIAN)
buf[0] = image1, buf[1] = image0;
else
buf[0] = image0, buf[1] = image1;
}
static void
decode_vax_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long image0, image1;
int exp;
if (FLOAT_WORDS_BIG_ENDIAN)
image1 = buf[0], image0 = buf[1];
else
image0 = buf[0], image1 = buf[1];
image0 &= 0xffffffff;
image1 &= 0xffffffff;
exp = (image0 >> 7) & 0xff;
memset (r, 0, sizeof (*r));
if (exp != 0)
{
r->cl = rvc_normal;
r->sign = (image0 >> 15) & 1;
SET_REAL_EXP (r, exp - 128);
image0 = ((image0 & 0x7f) << 16) | ((image0 >> 16) & 0xffff);
image1 = ((image1 & 0xffff) << 16) | ((image1 >> 16) & 0xffff);
if (HOST_BITS_PER_LONG == 64)
{
image0 = (image0 << 31 << 1) | image1;
image0 <<= 64 - 56;
image0 |= SIG_MSB;
r->sig[SIGSZ-1] = image0;
}
else
{
r->sig[SIGSZ-1] = image0;
r->sig[SIGSZ-2] = image1;
lshift_significand (r, r, 2*HOST_BITS_PER_LONG - 56);
r->sig[SIGSZ-1] |= SIG_MSB;
}
}
}
static void
encode_vax_g (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
const REAL_VALUE_TYPE *r)
{
unsigned long image0, image1, sign = r->sign << 15;
switch (r->cl)
{
case rvc_zero:
image0 = image1 = 0;
break;
case rvc_inf:
case rvc_nan:
image0 = 0xffff7fff | sign;
image1 = 0xffffffff;
break;
case rvc_normal:
if (HOST_BITS_PER_LONG == 64)
{
image0 = r->sig[SIGSZ-1];
image1 = (image0 >> (64 - 53)) & 0xffffffff;
image0 = (image0 >> (64 - 53 + 1) >> 31) & 0xfffff;
}
else
{
image0 = r->sig[SIGSZ-1];
image1 = r->sig[SIGSZ-2];
image1 = (image0 << 21) | (image1 >> 11);
image0 = (image0 >> 11) & 0xfffff;
}
image0 = ((image0 << 16) | (image0 >> 16)) & 0xffff000f;
image1 = ((image1 << 16) | (image1 >> 16)) & 0xffffffff;
image0 |= sign;
image0 |= (REAL_EXP (r) + 1024) << 4;
break;
default:
gcc_unreachable ();
}
if (FLOAT_WORDS_BIG_ENDIAN)
buf[0] = image1, buf[1] = image0;
else
buf[0] = image0, buf[1] = image1;
}
static void
decode_vax_g (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long image0, image1;
int exp;
if (FLOAT_WORDS_BIG_ENDIAN)
image1 = buf[0], image0 = buf[1];
else
image0 = buf[0], image1 = buf[1];
image0 &= 0xffffffff;
image1 &= 0xffffffff;
exp = (image0 >> 4) & 0x7ff;
memset (r, 0, sizeof (*r));
if (exp != 0)
{
r->cl = rvc_normal;
r->sign = (image0 >> 15) & 1;
SET_REAL_EXP (r, exp - 1024);
image0 = ((image0 & 0xf) << 16) | ((image0 >> 16) & 0xffff);
image1 = ((image1 & 0xffff) << 16) | ((image1 >> 16) & 0xffff);
if (HOST_BITS_PER_LONG == 64)
{
image0 = (image0 << 31 << 1) | image1;
image0 <<= 64 - 53;
image0 |= SIG_MSB;
r->sig[SIGSZ-1] = image0;
}
else
{
r->sig[SIGSZ-1] = image0;
r->sig[SIGSZ-2] = image1;
lshift_significand (r, r, 64 - 53);
r->sig[SIGSZ-1] |= SIG_MSB;
}
}
}
const struct real_format vax_f_format =
{
encode_vax_f,
decode_vax_f,
2,
1,
24,
24,
-127,
127,
15,
15,
false,
false,
false,
false,
false
};
const struct real_format vax_d_format =
{
encode_vax_d,
decode_vax_d,
2,
1,
56,
56,
-127,
127,
15,
15,
false,
false,
false,
false,
false
};
const struct real_format vax_g_format =
{
encode_vax_g,
decode_vax_g,
2,
1,
53,
53,
-1023,
1023,
15,
15,
false,
false,
false,
false,
false
};
static void encode_i370_single (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_i370_single (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void encode_i370_double (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_i370_double (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void
encode_i370_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
long *buf, const REAL_VALUE_TYPE *r)
{
unsigned long sign, exp, sig, image;
sign = r->sign << 31;
switch (r->cl)
{
case rvc_zero:
image = 0;
break;
case rvc_inf:
case rvc_nan:
image = 0x7fffffff | sign;
break;
case rvc_normal:
sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0xffffff;
exp = ((REAL_EXP (r) / 4) + 64) << 24;
image = sign | exp | sig;
break;
default:
gcc_unreachable ();
}
buf[0] = image;
}
static void
decode_i370_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long sign, sig, image = buf[0];
int exp;
sign = (image >> 31) & 1;
exp = (image >> 24) & 0x7f;
sig = image & 0xffffff;
memset (r, 0, sizeof (*r));
if (exp || sig)
{
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, (exp - 64) * 4);
r->sig[SIGSZ-1] = sig << (HOST_BITS_PER_LONG - 24);
normalize (r);
}
}
static void
encode_i370_double (const struct real_format *fmt ATTRIBUTE_UNUSED,
long *buf, const REAL_VALUE_TYPE *r)
{
unsigned long sign, exp, image_hi, image_lo;
sign = r->sign << 31;
switch (r->cl)
{
case rvc_zero:
image_hi = image_lo = 0;
break;
case rvc_inf:
case rvc_nan:
image_hi = 0x7fffffff | sign;
image_lo = 0xffffffff;
break;
case rvc_normal:
if (HOST_BITS_PER_LONG == 64)
{
image_hi = r->sig[SIGSZ-1];
image_lo = (image_hi >> (64 - 56)) & 0xffffffff;
image_hi = (image_hi >> (64 - 56 + 1) >> 31) & 0xffffff;
}
else
{
image_hi = r->sig[SIGSZ-1];
image_lo = r->sig[SIGSZ-2];
image_lo = (image_lo >> 8) | (image_hi << 24);
image_hi >>= 8;
}
exp = ((REAL_EXP (r) / 4) + 64) << 24;
image_hi |= sign | exp;
break;
default:
gcc_unreachable ();
}
if (FLOAT_WORDS_BIG_ENDIAN)
buf[0] = image_hi, buf[1] = image_lo;
else
buf[0] = image_lo, buf[1] = image_hi;
}
static void
decode_i370_double (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long sign, image_hi, image_lo;
int exp;
if (FLOAT_WORDS_BIG_ENDIAN)
image_hi = buf[0], image_lo = buf[1];
else
image_lo = buf[0], image_hi = buf[1];
sign = (image_hi >> 31) & 1;
exp = (image_hi >> 24) & 0x7f;
image_hi &= 0xffffff;
image_lo &= 0xffffffff;
memset (r, 0, sizeof (*r));
if (exp || image_hi || image_lo)
{
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, (exp - 64) * 4 + (SIGNIFICAND_BITS - 56));
if (HOST_BITS_PER_LONG == 32)
{
r->sig[0] = image_lo;
r->sig[1] = image_hi;
}
else
r->sig[0] = image_lo | (image_hi << 31 << 1);
normalize (r);
}
}
const struct real_format i370_single_format =
{
encode_i370_single,
decode_i370_single,
16,
4,
6,
6,
-64,
63,
31,
31,
false,
false,
false,
false,
false
};
const struct real_format i370_double_format =
{
encode_i370_double,
decode_i370_double,
16,
4,
14,
14,
-64,
63,
63,
63,
false,
false,
false,
false,
false
};
static void
encode_decimal_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
long *buf ATTRIBUTE_UNUSED,
const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
{
encode_decimal32 (fmt, buf, r);
}
static void
decode_decimal_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED,
const long *buf ATTRIBUTE_UNUSED)
{
decode_decimal32 (fmt, r, buf);
}
static void
encode_decimal_double (const struct real_format *fmt ATTRIBUTE_UNUSED,
long *buf ATTRIBUTE_UNUSED,
const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
{
encode_decimal64 (fmt, buf, r);
}
static void
decode_decimal_double (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED,
const long *buf ATTRIBUTE_UNUSED)
{
decode_decimal64 (fmt, r, buf);
}
static void
encode_decimal_quad (const struct real_format *fmt ATTRIBUTE_UNUSED,
long *buf ATTRIBUTE_UNUSED,
const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
{
encode_decimal128 (fmt, buf, r);
}
static void
decode_decimal_quad (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED,
const long *buf ATTRIBUTE_UNUSED)
{
decode_decimal128 (fmt, r, buf);
}
const struct real_format decimal_single_format =
{
encode_decimal_single,
decode_decimal_single,
10,
1,
7,
7,
-95,
96,
31,
31,
true,
true,
true,
true,
true
};
const struct real_format decimal_double_format =
{
encode_decimal_double,
decode_decimal_double,
10,
1,
16,
16,
-383,
384,
63,
63,
true,
true,
true,
true,
true
};
const struct real_format decimal_quad_format =
{
encode_decimal_quad,
decode_decimal_quad,
10,
1,
34,
34,
-6143,
6144,
127,
127,
true,
true,
true,
true,
true
};
static void encode_c4x_single (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_c4x_single (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void encode_c4x_extended (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_c4x_extended (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void
encode_c4x_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
long *buf, const REAL_VALUE_TYPE *r)
{
unsigned long image, exp, sig;
switch (r->cl)
{
case rvc_zero:
exp = -128;
sig = 0;
break;
case rvc_inf:
case rvc_nan:
exp = 127;
sig = 0x800000 - r->sign;
break;
case rvc_normal:
exp = REAL_EXP (r) - 1;
sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff;
if (r->sign)
{
if (sig)
sig = -sig;
else
exp--;
sig |= 0x800000;
}
break;
default:
gcc_unreachable ();
}
image = ((exp & 0xff) << 24) | (sig & 0xffffff);
buf[0] = image;
}
static void
decode_c4x_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long image = buf[0];
unsigned long sig;
int exp, sf;
exp = (((image >> 24) & 0xff) ^ 0x80) - 0x80;
sf = ((image & 0xffffff) ^ 0x800000) - 0x800000;
memset (r, 0, sizeof (*r));
if (exp != -128)
{
r->cl = rvc_normal;
sig = sf & 0x7fffff;
if (sf < 0)
{
r->sign = 1;
if (sig)
sig = -sig;
else
exp++;
}
sig = (sig << (HOST_BITS_PER_LONG - 24)) | SIG_MSB;
SET_REAL_EXP (r, exp + 1);
r->sig[SIGSZ-1] = sig;
}
}
static void
encode_c4x_extended (const struct real_format *fmt ATTRIBUTE_UNUSED,
long *buf, const REAL_VALUE_TYPE *r)
{
unsigned long exp, sig;
switch (r->cl)
{
case rvc_zero:
exp = -128;
sig = 0;
break;
case rvc_inf:
case rvc_nan:
exp = 127;
sig = 0x80000000 - r->sign;
break;
case rvc_normal:
exp = REAL_EXP (r) - 1;
sig = r->sig[SIGSZ-1];
if (HOST_BITS_PER_LONG == 64)
sig = sig >> 1 >> 31;
sig &= 0x7fffffff;
if (r->sign)
{
if (sig)
sig = -sig;
else
exp--;
sig |= 0x80000000;
}
break;
default:
gcc_unreachable ();
}
exp = (exp & 0xff) << 24;
sig &= 0xffffffff;
if (FLOAT_WORDS_BIG_ENDIAN)
buf[0] = exp, buf[1] = sig;
else
buf[0] = sig, buf[0] = exp;
}
static void
decode_c4x_extended (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long sig;
int exp, sf;
if (FLOAT_WORDS_BIG_ENDIAN)
exp = buf[0], sf = buf[1];
else
sf = buf[0], exp = buf[1];
exp = (((exp >> 24) & 0xff) & 0x80) - 0x80;
sf = ((sf & 0xffffffff) ^ 0x80000000) - 0x80000000;
memset (r, 0, sizeof (*r));
if (exp != -128)
{
r->cl = rvc_normal;
sig = sf & 0x7fffffff;
if (sf < 0)
{
r->sign = 1;
if (sig)
sig = -sig;
else
exp++;
}
if (HOST_BITS_PER_LONG == 64)
sig = sig << 1 << 31;
sig |= SIG_MSB;
SET_REAL_EXP (r, exp + 1);
r->sig[SIGSZ-1] = sig;
}
}
const struct real_format c4x_single_format =
{
encode_c4x_single,
decode_c4x_single,
2,
1,
24,
24,
-126,
128,
23,
-1,
false,
false,
false,
false,
false
};
const struct real_format c4x_extended_format =
{
encode_c4x_extended,
decode_c4x_extended,
2,
1,
32,
32,
-126,
128,
31,
-1,
false,
false,
false,
false,
false
};
static void encode_internal (const struct real_format *fmt,
long *, const REAL_VALUE_TYPE *);
static void decode_internal (const struct real_format *,
REAL_VALUE_TYPE *, const long *);
static void
encode_internal (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
const REAL_VALUE_TYPE *r)
{
memcpy (buf, r, sizeof (*r));
}
static void
decode_internal (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r, const long *buf)
{
memcpy (r, buf, sizeof (*r));
}
const struct real_format real_internal_format =
{
encode_internal,
decode_internal,
2,
1,
SIGNIFICAND_BITS - 2,
SIGNIFICAND_BITS - 2,
-MAX_EXP,
MAX_EXP,
-1,
-1,
true,
true,
false,
true,
true
};
bool
real_sqrt (REAL_VALUE_TYPE *r, enum machine_mode mode,
const REAL_VALUE_TYPE *x)
{
static REAL_VALUE_TYPE halfthree;
static bool init = false;
REAL_VALUE_TYPE h, t, i;
int iter, exp;
if (real_isnegzero (x))
{
*r = *x;
return false;
}
if (real_isneg (x))
{
get_canonical_qnan (r, 0);
return false;
}
if (real_isinf (x) || real_isnan (x))
{
*r = *x;
return false;
}
if (!init)
{
do_add (&halfthree, &dconst1, &dconsthalf, 0);
init = true;
}
exp = real_exponent (x);
real_ldexp (&i, &dconst1, -exp/2);
for (iter = 0; iter < 16; iter++)
{
do_multiply (&t, x, &i);
do_multiply (&h, &t, &i);
do_multiply (&t, &h, &dconsthalf);
do_add (&h, &halfthree, &t, 1);
do_multiply (&t, &i, &h);
if (iter >= 6 && real_identical (&i, &t))
break;
i = t;
}
do_multiply (&t, x, &i);
do_multiply (&h, &t, &i);
do_add (&i, &dconst1, &h, 1);
do_multiply (&h, &t, &i);
do_multiply (&i, &dconsthalf, &h);
do_add (&h, &t, &i, 0);
real_convert (r, mode, &h);
return true;
}
bool
real_powi (REAL_VALUE_TYPE *r, enum machine_mode mode,
const REAL_VALUE_TYPE *x, HOST_WIDE_INT n)
{
unsigned HOST_WIDE_INT bit;
REAL_VALUE_TYPE t;
bool inexact = false;
bool init = false;
bool neg;
int i;
if (n == 0)
{
*r = dconst1;
return false;
}
else if (n < 0)
{
neg = true;
n = -n;
}
else
neg = false;
t = *x;
bit = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1);
for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
{
if (init)
{
inexact |= do_multiply (&t, &t, &t);
if (n & bit)
inexact |= do_multiply (&t, &t, x);
}
else if (n & bit)
init = true;
bit >>= 1;
}
if (neg)
inexact |= do_divide (&t, &dconst1, &t);
real_convert (r, mode, &t);
return inexact;
}
void
real_trunc (REAL_VALUE_TYPE *r, enum machine_mode mode,
const REAL_VALUE_TYPE *x)
{
do_fix_trunc (r, x);
if (mode != VOIDmode)
real_convert (r, mode, r);
}
void
real_floor (REAL_VALUE_TYPE *r, enum machine_mode mode,
const REAL_VALUE_TYPE *x)
{
REAL_VALUE_TYPE t;
do_fix_trunc (&t, x);
if (! real_identical (&t, x) && x->sign)
do_add (&t, &t, &dconstm1, 0);
if (mode != VOIDmode)
real_convert (r, mode, &t);
else
*r = t;
}
void
real_ceil (REAL_VALUE_TYPE *r, enum machine_mode mode,
const REAL_VALUE_TYPE *x)
{
REAL_VALUE_TYPE t;
do_fix_trunc (&t, x);
if (! real_identical (&t, x) && ! x->sign)
do_add (&t, &t, &dconst1, 0);
if (mode != VOIDmode)
real_convert (r, mode, &t);
else
*r = t;
}
void
real_round (REAL_VALUE_TYPE *r, enum machine_mode mode,
const REAL_VALUE_TYPE *x)
{
do_add (r, x, &dconsthalf, x->sign);
do_fix_trunc (r, r);
if (mode != VOIDmode)
real_convert (r, mode, r);
}
void
real_copysign (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *x)
{
r->sign = x->sign;
}