* doublest.c (FLOATFORMAT_LARGEST_BYTES): New define.

(get_field, put_field): Assert that the format is one we can handle.
Simplify logic accordingly.
(floatformat_normalize_byteorder): New function.
(convert_floatformat_to_doublest): Use floatformat_normalize_byteorder
to normalize and select modified byte order. Pass modified byte order
to get_field.
(floatformat_is_negative, floatformat_is_nan, floatformat_mantissa):
Likewise.
(convert_doublest_to_floatformat): Select an appropriate intermediate
byte order if necessary.  Always convert to the final format before
returning.
This commit is contained in:
Richard Earnshaw
2004-12-05 15:17:34 +00:00
parent 0e1200e593
commit fcab3fb53b
2 changed files with 146 additions and 80 deletions

View File

@ -1,3 +1,18 @@
2004-12-05 Richard Earnshaw <rearnsha@arm.com>
* doublest.c (FLOATFORMAT_LARGEST_BYTES): New define.
(get_field, put_field): Assert that the format is one we can handle.
Simplify logic accordingly.
(floatformat_normalize_byteorder): New function.
(convert_floatformat_to_doublest): Use floatformat_normalize_byteorder
to normalize and select modified byte order. Pass modified byte order
to get_field.
(floatformat_is_negative, floatformat_is_nan, floatformat_mantissa):
Likewise.
(convert_doublest_to_floatformat): Select an appropriate intermediate
byte order if necessary. Always convert to the final format before
returning.
2004-12-04 Daniel Jacobowitz <dan@debian.org>
PR tui/1703

View File

@ -40,6 +40,10 @@
a system header, what we do if not, etc. */
#define FLOATFORMAT_CHAR_BIT 8
/* The number of bytes that the largest floating-point type that we
can convert to doublest will need. */
#define FLOATFORMAT_LARGEST_BYTES 16
static unsigned long get_field (unsigned char *,
enum floatformat_byteorders,
unsigned int, unsigned int, unsigned int);
@ -54,8 +58,11 @@ get_field (unsigned char *data, enum floatformat_byteorders order,
unsigned int cur_byte;
int cur_bitshift;
/* Caller must byte-swap words before calling this routine. */
gdb_assert (order == floatformat_little || order == floatformat_big);
/* Start at the least significant part of the field. */
if (order == floatformat_little || order == floatformat_littlebyte_bigword)
if (order == floatformat_little)
{
/* We start counting from the other end (i.e, from the high bytes
rather than the low bytes). As such, we need to be concerned
@ -81,7 +88,7 @@ get_field (unsigned char *data, enum floatformat_byteorders order,
else
result = 0;
cur_bitshift += FLOATFORMAT_CHAR_BIT;
if (order == floatformat_little || order == floatformat_littlebyte_bigword)
if (order == floatformat_little)
++cur_byte;
else
--cur_byte;
@ -99,8 +106,6 @@ get_field (unsigned char *data, enum floatformat_byteorders order,
case floatformat_big:
--cur_byte;
break;
case floatformat_littlebyte_bigword:
break;
}
}
if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT)
@ -109,6 +114,40 @@ get_field (unsigned char *data, enum floatformat_byteorders order,
return result;
}
/* Normalize the byte order of FROM into TO. If no normalization is needed
then FMT->byteorder is returned and TO is not changed; otherwise the format
of the normalized form in TO is returned. */
static enum floatformat_byteorders
floatformat_normalize_byteorder (const struct floatformat *fmt,
const void *from, void *to)
{
const unsigned char *swapin;
unsigned char *swapout;
int words;
if (fmt->byteorder == floatformat_little
|| fmt->byteorder == floatformat_big)
return fmt->byteorder;
gdb_assert (fmt->byteorder == floatformat_littlebyte_bigword);
words = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
words >>= 2;
swapout = (unsigned char *)to;
swapin = (const unsigned char *)from;
while (words-- > 0)
{
*swapout++ = swapin[3];
*swapout++ = swapin[2];
*swapout++ = swapin[1];
*swapout++ = swapin[0];
swapin += 4;
}
return floatformat_big;
}
/* Convert from FMT to a DOUBLEST.
FROM is the address of the extended float.
Store the DOUBLEST in *TO. */
@ -125,51 +164,19 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
unsigned int mant_bits, mant_off;
int mant_bits_left;
int special_exponent; /* It's a NaN, denorm or zero */
enum floatformat_byteorders order;
unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
gdb_assert (fmt->totalsize
<= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
/* If the mantissa bits are not contiguous from one end of the
mantissa to the other, we need to make a private copy of the
source bytes that is in the right order since the unpacking
algorithm assumes that the bits are contiguous.
order = floatformat_normalize_byteorder (fmt, ufrom, newfrom);
Swap the bytes individually rather than accessing them through
"long *" since we have no guarantee that they start on a long
alignment, and also sizeof(long) for the host could be different
than sizeof(long) for the target. FIXME: Assumes sizeof(long)
for the target is 4. */
if (order != fmt->byteorder)
ufrom = newfrom;
if (fmt->byteorder == floatformat_littlebyte_bigword)
{
static unsigned char *newfrom;
unsigned char *swapin, *swapout;
int longswaps;
longswaps = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
longswaps >>= 3;
if (newfrom == NULL)
{
newfrom = (unsigned char *) xmalloc (fmt->totalsize);
}
swapout = newfrom;
swapin = ufrom;
ufrom = newfrom;
while (longswaps-- > 0)
{
/* This is ugly, but efficient */
*swapout++ = swapin[4];
*swapout++ = swapin[5];
*swapout++ = swapin[6];
*swapout++ = swapin[7];
*swapout++ = swapin[0];
*swapout++ = swapin[1];
*swapout++ = swapin[2];
*swapout++ = swapin[3];
swapin += 8;
}
}
exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
fmt->exp_start, fmt->exp_len);
exponent = get_field (ufrom, order, fmt->totalsize, fmt->exp_start,
fmt->exp_len);
/* Note that if exponent indicates a NaN, we can't really do anything useful
(not knowing if the host has NaN's, or how to build one). So it will
end up as an infinity or something close; that is OK. */
@ -207,8 +214,7 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
{
mant_bits = min (mant_bits_left, 32);
mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
mant_off, mant_bits);
mant = get_field (ufrom, order, fmt->totalsize, mant_off, mant_bits);
dto += ldexp ((double) mant, exponent - mant_bits);
exponent -= mant_bits;
@ -217,7 +223,7 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
}
/* Negate it if negative. */
if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
if (get_field (ufrom, order, fmt->totalsize, fmt->sign_start, 1))
dto = -dto;
*to = dto;
}
@ -236,8 +242,11 @@ put_field (unsigned char *data, enum floatformat_byteorders order,
unsigned int cur_byte;
int cur_bitshift;
/* Caller must byte-swap words before calling this routine. */
gdb_assert (order == floatformat_little || order == floatformat_big);
/* Start at the least significant part of the field. */
if (order == floatformat_little || order == floatformat_littlebyte_bigword)
if (order == floatformat_little)
{
int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
cur_byte = (total_len / FLOATFORMAT_CHAR_BIT)
@ -260,7 +269,7 @@ put_field (unsigned char *data, enum floatformat_byteorders order,
(stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
}
cur_bitshift += FLOATFORMAT_CHAR_BIT;
if (order == floatformat_little || order == floatformat_littlebyte_bigword)
if (order == floatformat_little)
++cur_byte;
else
--cur_byte;
@ -279,7 +288,7 @@ put_field (unsigned char *data, enum floatformat_byteorders order,
*(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
& ((1 << FLOATFORMAT_CHAR_BIT) - 1));
cur_bitshift += FLOATFORMAT_CHAR_BIT;
if (order == floatformat_little || order == floatformat_littlebyte_bigword)
if (order == floatformat_little)
++cur_byte;
else
--cur_byte;
@ -347,6 +356,10 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
unsigned int mant_bits, mant_off;
int mant_bits_left;
unsigned char *uto = (unsigned char *) to;
enum floatformat_byteorders order = fmt->byteorder;
if (order == floatformat_littlebyte_bigword)
order = floatformat_big;
memcpy (&dfrom, from, sizeof (dfrom));
memset (uto, 0, (fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1)
@ -356,30 +369,30 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
if (dfrom != dfrom) /* Result is NaN */
{
/* From is NaN */
put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
put_field (uto, order, fmt->totalsize, fmt->exp_start,
fmt->exp_len, fmt->exp_nan);
/* Be sure it's not infinity, but NaN value is irrel */
put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
put_field (uto, order, fmt->totalsize, fmt->man_start,
32, 1);
return;
goto finalize_byteorder;
}
/* If negative, set the sign bit. */
if (dfrom < 0)
{
put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
put_field (uto, order, fmt->totalsize, fmt->sign_start, 1, 1);
dfrom = -dfrom;
}
if (dfrom + dfrom == dfrom && dfrom != 0.0) /* Result is Infinity */
{
/* Infinity exponent is same as NaN's. */
put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
put_field (uto, order, fmt->totalsize, fmt->exp_start,
fmt->exp_len, fmt->exp_nan);
/* Infinity mantissa is all zeroes. */
put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
put_field (uto, order, fmt->totalsize, fmt->man_start,
fmt->man_len, 0);
return;
goto finalize_byteorder;
}
#ifdef HAVE_LONG_DOUBLE
@ -388,7 +401,7 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
mant = frexp (dfrom, &exponent);
#endif
put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len,
put_field (uto, order, fmt->totalsize, fmt->exp_start, fmt->exp_len,
exponent + fmt->exp_bias - 1);
mant_bits_left = fmt->man_len;
@ -429,23 +442,31 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
mant_long >>= 32 - mant_bits;
}
put_field (uto, fmt->byteorder, fmt->totalsize,
put_field (uto, order, fmt->totalsize,
mant_off, mant_bits, mant_long);
mant_off += mant_bits;
mant_bits_left -= mant_bits;
}
if (fmt->byteorder == floatformat_littlebyte_bigword)
finalize_byteorder:
/* Do we need to byte-swap the words in the result? */
if (order != fmt->byteorder)
{
int count;
unsigned char *swaplow = uto;
unsigned char *swaphigh = uto + 4;
int words;
unsigned char *curword = uto;
unsigned char tmp;
for (count = 0; count < 4; count++)
words = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
words >>= 2;
while (words-- > 0)
{
tmp = *swaplow;
*swaplow++ = *swaphigh;
*swaphigh++ = tmp;
tmp = curword[0];
curword[0] = curword[3];
curword[3] = tmp;
tmp = curword[1];
curword[1] = curword[2];
curword[2] = tmp;
curword += 4;
}
}
}
@ -457,8 +478,19 @@ int
floatformat_is_negative (const struct floatformat *fmt, char *val)
{
unsigned char *uval = (unsigned char *) val;
enum floatformat_byteorders order;
unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
gdb_assert (fmt != NULL);
return get_field (uval, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1);
gdb_assert (fmt->totalsize
<= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
order = floatformat_normalize_byteorder (fmt, uval, newfrom);
if (order != fmt->byteorder)
uval = newfrom;
return get_field (uval, order, fmt->totalsize, fmt->sign_start, 1);
}
/* Check if VAL is "not a number" (NaN) for FMT. */
@ -471,14 +503,23 @@ floatformat_is_nan (const struct floatformat *fmt, char *val)
unsigned long mant;
unsigned int mant_bits, mant_off;
int mant_bits_left;
enum floatformat_byteorders order;
unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
gdb_assert (fmt != NULL);
gdb_assert (fmt->totalsize
<= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
order = floatformat_normalize_byteorder (fmt, uval, newfrom);
if (order != fmt->byteorder)
uval = newfrom;
if (! fmt->exp_nan)
return 0;
exponent = get_field (uval, fmt->byteorder, fmt->totalsize,
fmt->exp_start, fmt->exp_len);
exponent = get_field (uval, order, fmt->totalsize, fmt->exp_start,
fmt->exp_len);
if (exponent != fmt->exp_nan)
return 0;
@ -490,8 +531,7 @@ floatformat_is_nan (const struct floatformat *fmt, char *val)
{
mant_bits = min (mant_bits_left, 32);
mant = get_field (uval, fmt->byteorder, fmt->totalsize,
mant_off, mant_bits);
mant = get_field (uval, order, fmt->totalsize, mant_off, mant_bits);
/* If there is an explicit integer bit, mask it off. */
if (mant_off == fmt->man_start
@ -521,17 +561,29 @@ floatformat_mantissa (const struct floatformat *fmt, char *val)
int mant_bits_left;
static char res[50];
char buf[9];
enum floatformat_byteorders order;
unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
gdb_assert (fmt != NULL);
gdb_assert (fmt->totalsize
<= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
order = floatformat_normalize_byteorder (fmt, uval, newfrom);
if (order != fmt->byteorder)
uval = newfrom;
if (! fmt->exp_nan)
return 0;
/* Make sure we have enough room to store the mantissa. */
gdb_assert (fmt != NULL);
gdb_assert (sizeof res > ((fmt->man_len + 7) / 8) * 2);
mant_off = fmt->man_start;
mant_bits_left = fmt->man_len;
mant_bits = (mant_bits_left % 32) > 0 ? mant_bits_left % 32 : 32;
mant = get_field (uval, fmt->byteorder, fmt->totalsize,
mant_off, mant_bits);
mant = get_field (uval, order, fmt->totalsize, mant_off, mant_bits);
sprintf (res, "%lx", mant);
@ -540,8 +592,7 @@ floatformat_mantissa (const struct floatformat *fmt, char *val)
while (mant_bits_left > 0)
{
mant = get_field (uval, fmt->byteorder, fmt->totalsize,
mant_off, 32);
mant = get_field (uval, order, fmt->totalsize, mant_off, 32);
sprintf (buf, "%08lx", mant);
strcat (res, buf);