diff options
author | dim <dim@FreeBSD.org> | 2010-11-01 19:35:33 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2010-11-01 19:35:33 +0000 |
commit | 3f5c947f4453c6016a2a6a9636367ee3f48fc6fc (patch) | |
tree | 461aafc934d462eb9b9221308f8e25238c0ada62 /contrib/binutils/libiberty/floatformat.c | |
parent | e6be3e7867eb43d220575baee2ce5662fb03e46c (diff) | |
parent | d0f678fa0ff3f08a4eca29daf4d1ac39797b6326 (diff) | |
download | FreeBSD-src-3f5c947f4453c6016a2a6a9636367ee3f48fc6fc.zip FreeBSD-src-3f5c947f4453c6016a2a6a9636367ee3f48fc6fc.tar.gz |
Merge ^/vendor/binutils/dist@214571 into contrib/binutils, which brings
us up to version 2.17.50.20070703, at the last GPLv2 commit.
Amongst others, this added upstream support for some FreeBSD-specific
things that we previously had to manually hack in, such as the OSABI
label support, and so on.
There are also quite a number of new files, some for cpu's (e.g. SPU)
that we may or may not be interested in, but those can be cleaned up
later on, if needed.
Diffstat (limited to 'contrib/binutils/libiberty/floatformat.c')
-rw-r--r-- | contrib/binutils/libiberty/floatformat.c | 111 |
1 files changed, 50 insertions, 61 deletions
diff --git a/contrib/binutils/libiberty/floatformat.c b/contrib/binutils/libiberty/floatformat.c index bd31efa..c5abbb1 100644 --- a/contrib/binutils/libiberty/floatformat.c +++ b/contrib/binutils/libiberty/floatformat.c @@ -249,53 +249,51 @@ const struct floatformat floatformat_ia64_quad_little = floatformat_always_valid }; + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + /* Extract a field which starts at START and is LEN bits long. DATA and TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ static unsigned long get_field (const unsigned char *data, enum floatformat_byteorders order, unsigned int total_len, unsigned int start, unsigned int len) { - unsigned long result; + unsigned long result = 0; unsigned int cur_byte; - int cur_bitshift; + int lo_bit, hi_bit, cur_bitshift = 0; + int nextbyte = (order == floatformat_little) ? 1 : -1; + + /* Start is in big-endian bit order! Fix that first. */ + start = total_len - (start + len); /* Start at the least significant part of the field. */ - cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; if (order == floatformat_little) - cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; - cur_bitshift = - ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; - result = *(data + cur_byte) >> (-cur_bitshift); - cur_bitshift += FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little) - ++cur_byte; + cur_byte = start / FLOATFORMAT_CHAR_BIT; else - --cur_byte; + cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT; - /* Move towards the most significant part of the field. */ - while ((unsigned int) cur_bitshift < len) + lo_bit = start % FLOATFORMAT_CHAR_BIT; + hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT); + + do { - if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) - /* This is the last byte; zero out the bits which are not part of - this field. */ - result |= - (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1)) - << cur_bitshift; - else - result |= *(data + cur_byte) << cur_bitshift; - cur_bitshift += FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little) - ++cur_byte; - else - --cur_byte; + unsigned int shifted = *(data + cur_byte) >> lo_bit; + unsigned int bits = hi_bit - lo_bit; + unsigned int mask = (1 << bits) - 1; + result |= (shifted & mask) << cur_bitshift; + len -= bits; + cur_bitshift += bits; + cur_byte += nextbyte; + lo_bit = 0; + hi_bit = min (len, FLOATFORMAT_CHAR_BIT); } + while (len != 0); + return result; } -#ifndef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#endif - /* Convert from FMT to a double. FROM is the address of the extended float. Store the double in *TO. */ @@ -394,7 +392,7 @@ floatformat_to_double (const struct floatformat *fmt, /* Handle denormalized numbers. FIXME: What should we do for non-IEEE formats? */ - if (exponent == 0 && mant != 0) + if (special_exponent && exponent == 0 && mant != 0) dto += ldexp ((double)mant, (- fmt->exp_bias - mant_bits @@ -428,43 +426,34 @@ put_field (unsigned char *data, enum floatformat_byteorders order, unsigned long stuff_to_put) { unsigned int cur_byte; - int cur_bitshift; + int lo_bit, hi_bit; + int nextbyte = (order == floatformat_little) ? 1 : -1; + + /* Start is in big-endian bit order! Fix that first. */ + start = total_len - (start + len); /* Start at the least significant part of the field. */ - cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little) - cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; - cur_bitshift = - ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; - *(data + cur_byte) &= - ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift)); - *(data + cur_byte) |= - (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift); - cur_bitshift += FLOATFORMAT_CHAR_BIT; if (order == floatformat_little) - ++cur_byte; + cur_byte = start / FLOATFORMAT_CHAR_BIT; else - --cur_byte; + cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT; - /* Move towards the most significant part of the field. */ - while ((unsigned int) cur_bitshift < len) + lo_bit = start % FLOATFORMAT_CHAR_BIT; + hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT); + + do { - if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) - { - /* This is the last byte. */ - *(data + cur_byte) &= - ~((1 << (len - cur_bitshift)) - 1); - *(data + cur_byte) |= (stuff_to_put >> cur_bitshift); - } - else - *(data + cur_byte) = ((stuff_to_put >> cur_bitshift) - & ((1 << FLOATFORMAT_CHAR_BIT) - 1)); - cur_bitshift += FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little) - ++cur_byte; - else - --cur_byte; + unsigned char *byte_ptr = data + cur_byte; + unsigned int bits = hi_bit - lo_bit; + unsigned int mask = ((1 << bits) - 1) << lo_bit; + *byte_ptr = (*byte_ptr & ~mask) | ((stuff_to_put << lo_bit) & mask); + stuff_to_put >>= bits; + len -= bits; + cur_byte += nextbyte; + lo_bit = 0; + hi_bit = min (len, FLOATFORMAT_CHAR_BIT); } + while (len != 0); } /* The converse: convert the double *FROM to an extended float |