diff options
-rw-r--r-- | gdb/ChangeLog | 15 | ||||
-rw-r--r-- | gdb/doublest.c | 211 |
2 files changed, 146 insertions, 80 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 918ecdd..8357edb 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -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 diff --git a/gdb/doublest.c b/gdb/doublest.c index 82441b6..b36cbd7 100644 --- a/gdb/doublest.c +++ b/gdb/doublest.c @@ -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. - - 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 (fmt->byteorder == floatformat_littlebyte_bigword) - { - static unsigned char *newfrom; - unsigned char *swapin, *swapout; - int longswaps; - - longswaps = fmt->totalsize / FLOATFORMAT_CHAR_BIT; - longswaps >>= 3; + order = floatformat_normalize_byteorder (fmt, ufrom, newfrom); - 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; - } - } + if (order != fmt->byteorder) + ufrom = newfrom; - 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); |