diff options
author | somov <somov@yandex-team.ru> | 2022-02-10 16:45:47 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:47 +0300 |
commit | a5950576e397b1909261050b8c7da16db58f10b1 (patch) | |
tree | 7ba7677f6a4c3e19e2cefab34d16df2c8963b4d4 /contrib/tools/yasm/libyasm/floatnum.c | |
parent | 81eddc8c0b55990194e112b02d127b87d54164a9 (diff) | |
download | ydb-a5950576e397b1909261050b8c7da16db58f10b1.tar.gz |
Restoring authorship annotation for <somov@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/yasm/libyasm/floatnum.c')
-rw-r--r-- | contrib/tools/yasm/libyasm/floatnum.c | 1520 |
1 files changed, 760 insertions, 760 deletions
diff --git a/contrib/tools/yasm/libyasm/floatnum.c b/contrib/tools/yasm/libyasm/floatnum.c index ab67c2b2e4b..98eabeebcf8 100644 --- a/contrib/tools/yasm/libyasm/floatnum.c +++ b/contrib/tools/yasm/libyasm/floatnum.c @@ -1,760 +1,760 @@ -/* - * Floating point number functions. - * - * Copyright (C) 2001-2007 Peter Johnson - * - * Based on public-domain x86 assembly code by Randall Hyde (8/28/91). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include "util.h" - -#include <ctype.h> - -#include "coretype.h" -#include "bitvect.h" -#include "file.h" - -#include "errwarn.h" -#include "floatnum.h" - - -/* 97-bit internal floating point format: - * 0000000s eeeeeeee eeeeeeee m.....................................m - * Sign exponent mantissa (80 bits) - * 79 0 - * - * Only L.O. bit of Sign byte is significant. The rest is zero. - * Exponent is bias 32767. - * Mantissa does NOT have an implied one bit (it's explicit). - */ -struct yasm_floatnum { - /*@only@*/ wordptr mantissa; /* Allocated to MANT_BITS bits */ - unsigned short exponent; - unsigned char sign; - unsigned char flags; -}; - -/* constants describing parameters of internal floating point format */ -#define MANT_BITS 80 -#define MANT_BYTES 10 -#define MANT_SIGDIGITS 24 -#define EXP_BIAS 0x7FFF -#define EXP_INF 0xFFFF -#define EXP_MAX 0xFFFE -#define EXP_MIN 1 -#define EXP_ZERO 0 - -/* Flag settings for flags field */ -#define FLAG_ISZERO 1<<0 - -/* Note this structure integrates the floatnum structure */ -typedef struct POT_Entry_s { - yasm_floatnum f; - int dec_exponent; -} POT_Entry; - -/* "Source" for POT_Entry. */ -typedef struct POT_Entry_Source_s { - unsigned char mantissa[MANT_BYTES]; /* little endian mantissa */ - unsigned short exponent; /* Bias 32767 exponent */ -} POT_Entry_Source; - -/* Power of ten tables used by the floating point I/O routines. - * The POT_Table? arrays are built from the POT_Table?_Source arrays at - * runtime by POT_Table_Init(). - */ - -/* This table contains the powers of ten raised to negative powers of two: - * - * entry[12-n] = 10 ** (-2 ** n) for 0 <= n <= 12. - * entry[13] = 1.0 - */ -static /*@only@*/ POT_Entry *POT_TableN; -static POT_Entry_Source POT_TableN_Source[] = { - {{0xe3,0x2d,0xde,0x9f,0xce,0xd2,0xc8,0x04,0xdd,0xa6},0x4ad8}, /* 1e-4096 */ - {{0x25,0x49,0xe4,0x2d,0x36,0x34,0x4f,0x53,0xae,0xce},0x656b}, /* 1e-2048 */ - {{0xa6,0x87,0xbd,0xc0,0x57,0xda,0xa5,0x82,0xa6,0xa2},0x72b5}, /* 1e-1024 */ - {{0x33,0x71,0x1c,0xd2,0x23,0xdb,0x32,0xee,0x49,0x90},0x795a}, /* 1e-512 */ - {{0x91,0xfa,0x39,0x19,0x7a,0x63,0x25,0x43,0x31,0xc0},0x7cac}, /* 1e-256 */ - {{0x7d,0xac,0xa0,0xe4,0xbc,0x64,0x7c,0x46,0xd0,0xdd},0x7e55}, /* 1e-128 */ - {{0x24,0x3f,0xa5,0xe9,0x39,0xa5,0x27,0xea,0x7f,0xa8},0x7f2a}, /* 1e-64 */ - {{0xde,0x67,0xba,0x94,0x39,0x45,0xad,0x1e,0xb1,0xcf},0x7f94}, /* 1e-32 */ - {{0x2f,0x4c,0x5b,0xe1,0x4d,0xc4,0xbe,0x94,0x95,0xe6},0x7fc9}, /* 1e-16 */ - {{0xc2,0xfd,0xfc,0xce,0x61,0x84,0x11,0x77,0xcc,0xab},0x7fe4}, /* 1e-8 */ - {{0xc3,0xd3,0x2b,0x65,0x19,0xe2,0x58,0x17,0xb7,0xd1},0x7ff1}, /* 1e-4 */ - {{0x71,0x3d,0x0a,0xd7,0xa3,0x70,0x3d,0x0a,0xd7,0xa3},0x7ff8}, /* 1e-2 */ - {{0xcd,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc},0x7ffb}, /* 1e-1 */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},0x7fff}, /* 1e-0 */ -}; - -/* This table contains the powers of ten raised to positive powers of two: - * - * entry[12-n] = 10 ** (2 ** n) for 0 <= n <= 12. - * entry[13] = 1.0 - * entry[-1] = entry[0]; - * - * There is a -1 entry since it is possible for the algorithm to back up - * before the table. This -1 entry is created at runtime by duplicating the - * 0 entry. - */ -static /*@only@*/ POT_Entry *POT_TableP; -static POT_Entry_Source POT_TableP_Source[] = { - {{0x4c,0xc9,0x9a,0x97,0x20,0x8a,0x02,0x52,0x60,0xc4},0xb525}, /* 1e+4096 */ - {{0x4d,0xa7,0xe4,0x5d,0x3d,0xc5,0x5d,0x3b,0x8b,0x9e},0x9a92}, /* 1e+2048 */ - {{0x0d,0x65,0x17,0x0c,0x75,0x81,0x86,0x75,0x76,0xc9},0x8d48}, /* 1e+1024 */ - {{0x65,0xcc,0xc6,0x91,0x0e,0xa6,0xae,0xa0,0x19,0xe3},0x86a3}, /* 1e+512 */ - {{0xbc,0xdd,0x8d,0xde,0xf9,0x9d,0xfb,0xeb,0x7e,0xaa},0x8351}, /* 1e+256 */ - {{0x6f,0xc6,0xdf,0x8c,0xe9,0x80,0xc9,0x47,0xba,0x93},0x81a8}, /* 1e+128 */ - {{0xbf,0x3c,0xd5,0xa6,0xcf,0xff,0x49,0x1f,0x78,0xc2},0x80d3}, /* 1e+64 */ - {{0x20,0xf0,0x9d,0xb5,0x70,0x2b,0xa8,0xad,0xc5,0x9d},0x8069}, /* 1e+32 */ - {{0x00,0x00,0x00,0x00,0x00,0x04,0xbf,0xc9,0x1b,0x8e},0x8034}, /* 1e+16 */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0xbc,0xbe},0x8019}, /* 1e+8 */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x9c},0x800c}, /* 1e+4 */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8},0x8005}, /* 1e+2 */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0},0x8002}, /* 1e+1 */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},0x7fff}, /* 1e+0 */ -}; - - -static void -POT_Table_Init_Entry(/*@out@*/ POT_Entry *e, POT_Entry_Source *s, int dec_exp) -{ - /* Save decimal exponent */ - e->dec_exponent = dec_exp; - - /* Initialize mantissa */ - e->f.mantissa = BitVector_Create(MANT_BITS, FALSE); - BitVector_Block_Store(e->f.mantissa, s->mantissa, MANT_BYTES); - - /* Initialize exponent */ - e->f.exponent = s->exponent; - - /* Set sign to 0 (positive) */ - e->f.sign = 0; - - /* Clear flags */ - e->f.flags = 0; -} - -/*@-compdef@*/ -void -yasm_floatnum_initialize(void) -/*@globals undef POT_TableN, undef POT_TableP, POT_TableP_Source, - POT_TableN_Source @*/ -{ - int dec_exp = 1; - int i; - - /* Allocate space for two POT tables */ - POT_TableN = yasm_xmalloc(14*sizeof(POT_Entry)); - POT_TableP = yasm_xmalloc(15*sizeof(POT_Entry)); /* note 1 extra for -1 */ - - /* Initialize entry[0..12] */ - for (i=12; i>=0; i--) { - POT_Table_Init_Entry(&POT_TableN[i], &POT_TableN_Source[i], 0-dec_exp); - POT_Table_Init_Entry(&POT_TableP[i+1], &POT_TableP_Source[i], dec_exp); - dec_exp *= 2; /* Update decimal exponent */ - } - - /* Initialize entry[13] */ - POT_Table_Init_Entry(&POT_TableN[13], &POT_TableN_Source[13], 0); - POT_Table_Init_Entry(&POT_TableP[14], &POT_TableP_Source[13], 0); - - /* Initialize entry[-1] for POT_TableP */ - POT_Table_Init_Entry(&POT_TableP[0], &POT_TableP_Source[0], 4096); - - /* Offset POT_TableP so that [0] becomes [-1] */ - POT_TableP++; -} -/*@=compdef@*/ - -/*@-globstate@*/ -void -yasm_floatnum_cleanup(void) -{ - int i; - - /* Un-offset POT_TableP */ - POT_TableP--; - - for (i=0; i<14; i++) { - BitVector_Destroy(POT_TableN[i].f.mantissa); - BitVector_Destroy(POT_TableP[i].f.mantissa); - } - BitVector_Destroy(POT_TableP[14].f.mantissa); - - yasm_xfree(POT_TableN); - yasm_xfree(POT_TableP); -} -/*@=globstate@*/ - -static void -floatnum_normalize(yasm_floatnum *flt) -{ - long norm_amt; - - if (BitVector_is_empty(flt->mantissa)) { - flt->exponent = 0; - return; - } - - /* Look for the highest set bit, shift to make it the MSB, and adjust - * exponent. Don't let exponent go negative. */ - norm_amt = (MANT_BITS-1)-Set_Max(flt->mantissa); - if (norm_amt > (long)flt->exponent) - norm_amt = (long)flt->exponent; - BitVector_Move_Left(flt->mantissa, (N_int)norm_amt); - flt->exponent -= (unsigned short)norm_amt; -} - -/* acc *= op */ -static void -floatnum_mul(yasm_floatnum *acc, const yasm_floatnum *op) -{ - long expon; - wordptr product, op1, op2; - long norm_amt; - - /* Compute the new sign */ - acc->sign ^= op->sign; - - /* Check for multiply by 0 */ - if (BitVector_is_empty(acc->mantissa) || BitVector_is_empty(op->mantissa)) { - BitVector_Empty(acc->mantissa); - acc->exponent = EXP_ZERO; - return; - } - - /* Add exponents, checking for overflow/underflow. */ - expon = (((int)acc->exponent)-EXP_BIAS) + (((int)op->exponent)-EXP_BIAS); - expon += EXP_BIAS; - if (expon > EXP_MAX) { - /* Overflow; return infinity. */ - BitVector_Empty(acc->mantissa); - acc->exponent = EXP_INF; - return; - } else if (expon < EXP_MIN) { - /* Underflow; return zero. */ - BitVector_Empty(acc->mantissa); - acc->exponent = EXP_ZERO; - return; - } - - /* Add one to the final exponent, as the multiply shifts one extra time. */ - acc->exponent = (unsigned short)(expon+1); - - /* Allocate space for the multiply result */ - product = BitVector_Create((N_int)((MANT_BITS+1)*2), FALSE); - - /* Allocate 1-bit-longer fields to force the operands to be unsigned */ - op1 = BitVector_Create((N_int)(MANT_BITS+1), FALSE); - op2 = BitVector_Create((N_int)(MANT_BITS+1), FALSE); - - /* Make the operands unsigned after copying from original operands */ - BitVector_Copy(op1, acc->mantissa); - BitVector_MSB(op1, 0); - BitVector_Copy(op2, op->mantissa); - BitVector_MSB(op2, 0); - - /* Compute the product of the mantissas */ - BitVector_Multiply(product, op1, op2); - - /* Normalize the product. Note: we know the product is non-zero because - * both of the original operands were non-zero. - * - * Look for the highest set bit, shift to make it the MSB, and adjust - * exponent. Don't let exponent go negative. - */ - norm_amt = (MANT_BITS*2-1)-Set_Max(product); - if (norm_amt > (long)acc->exponent) - norm_amt = (long)acc->exponent; - BitVector_Move_Left(product, (N_int)norm_amt); - acc->exponent -= (unsigned short)norm_amt; - - /* Store the highest bits of the result */ - BitVector_Interval_Copy(acc->mantissa, product, 0, MANT_BITS, MANT_BITS); - - /* Free allocated variables */ - BitVector_Destroy(product); - BitVector_Destroy(op1); - BitVector_Destroy(op2); -} - -yasm_floatnum * -yasm_floatnum_create(const char *str) -{ - yasm_floatnum *flt; - int dec_exponent, dec_exp_add; /* decimal (powers of 10) exponent */ - int POT_index; - wordptr operand[2]; - int sig_digits; - int decimal_pt; - boolean carry; - - flt = yasm_xmalloc(sizeof(yasm_floatnum)); - - flt->mantissa = BitVector_Create(MANT_BITS, TRUE); - - /* allocate and initialize calculation variables */ - operand[0] = BitVector_Create(MANT_BITS, TRUE); - operand[1] = BitVector_Create(MANT_BITS, TRUE); - dec_exponent = 0; - sig_digits = 0; - decimal_pt = 1; - - /* set initial flags to 0 */ - flt->flags = 0; - - /* check for + or - character and skip */ - if (*str == '-') { - flt->sign = 1; - str++; - } else if (*str == '+') { - flt->sign = 0; - str++; - } else - flt->sign = 0; - - /* eliminate any leading zeros (which do not count as significant digits) */ - while (*str == '0') - str++; - - /* When we reach the end of the leading zeros, first check for a decimal - * point. If the number is of the form "0---0.0000" we need to get rid - * of the zeros after the decimal point and not count them as significant - * digits. - */ - if (*str == '.') { - str++; - while (*str == '0') { - str++; - dec_exponent--; - } - } else { - /* The number is of the form "yyy.xxxx" (where y <> 0). */ - while (isdigit(*str)) { - /* See if we've processed more than the max significant digits: */ - if (sig_digits < MANT_SIGDIGITS) { - /* Multiply mantissa by 10 [x = (x<<1)+(x<<3)] */ - BitVector_shift_left(flt->mantissa, 0); - BitVector_Copy(operand[0], flt->mantissa); - BitVector_Move_Left(flt->mantissa, 2); - carry = 0; - BitVector_add(operand[1], operand[0], flt->mantissa, &carry); - - /* Add in current digit */ - BitVector_Empty(operand[0]); - BitVector_Chunk_Store(operand[0], 4, 0, (N_long)(*str-'0')); - carry = 0; - BitVector_add(flt->mantissa, operand[1], operand[0], &carry); - } else { - /* Can't integrate more digits with mantissa, so instead just - * raise by a power of ten. - */ - dec_exponent++; - } - sig_digits++; - str++; - } - - if (*str == '.') - str++; - else - decimal_pt = 0; - } - - if (decimal_pt) { - /* Process the digits to the right of the decimal point. */ - while (isdigit(*str)) { - /* See if we've processed more than 19 significant digits: */ - if (sig_digits < 19) { - /* Raise by a power of ten */ - dec_exponent--; - - /* Multiply mantissa by 10 [x = (x<<1)+(x<<3)] */ - BitVector_shift_left(flt->mantissa, 0); - BitVector_Copy(operand[0], flt->mantissa); - BitVector_Move_Left(flt->mantissa, 2); - carry = 0; - BitVector_add(operand[1], operand[0], flt->mantissa, &carry); - - /* Add in current digit */ - BitVector_Empty(operand[0]); - BitVector_Chunk_Store(operand[0], 4, 0, (N_long)(*str-'0')); - carry = 0; - BitVector_add(flt->mantissa, operand[1], operand[0], &carry); - } - sig_digits++; - str++; - } - } - - if (*str == 'e' || *str == 'E') { - str++; - /* We just saw the "E" character, now read in the exponent value and - * add it into dec_exponent. - */ - dec_exp_add = 0; - sscanf(str, "%d", &dec_exp_add); - dec_exponent += dec_exp_add; - } - - /* Free calculation variables. */ - BitVector_Destroy(operand[1]); - BitVector_Destroy(operand[0]); - - /* Normalize the number, checking for 0 first. */ - if (BitVector_is_empty(flt->mantissa)) { - /* Mantissa is 0, zero exponent too. */ - flt->exponent = 0; - /* Set zero flag so output functions don't see 0 value as underflow. */ - flt->flags |= FLAG_ISZERO; - /* Return 0 value. */ - return flt; - } - /* Exponent if already norm. */ - flt->exponent = (unsigned short)(0x7FFF+(MANT_BITS-1)); - floatnum_normalize(flt); - - /* The number is normalized. Now multiply by 10 the number of times - * specified in DecExponent. This uses the power of ten tables to speed - * up this operation (and make it more accurate). - */ - if (dec_exponent > 0) { - POT_index = 0; - /* Until we hit 1.0 or finish exponent or overflow */ - while ((POT_index < 14) && (dec_exponent != 0) && - (flt->exponent != EXP_INF)) { - /* Find the first power of ten in the table which is just less than - * the exponent. - */ - while (dec_exponent < POT_TableP[POT_index].dec_exponent) - POT_index++; - - if (POT_index < 14) { - /* Subtract out what we're multiplying in from exponent */ - dec_exponent -= POT_TableP[POT_index].dec_exponent; - - /* Multiply by current power of 10 */ - floatnum_mul(flt, &POT_TableP[POT_index].f); - } - } - } else if (dec_exponent < 0) { - POT_index = 0; - /* Until we hit 1.0 or finish exponent or underflow */ - while ((POT_index < 14) && (dec_exponent != 0) && - (flt->exponent != EXP_ZERO)) { - /* Find the first power of ten in the table which is just less than - * the exponent. - */ - while (dec_exponent > POT_TableN[POT_index].dec_exponent) - POT_index++; - - if (POT_index < 14) { - /* Subtract out what we're multiplying in from exponent */ - dec_exponent -= POT_TableN[POT_index].dec_exponent; - - /* Multiply by current power of 10 */ - floatnum_mul(flt, &POT_TableN[POT_index].f); - } - } - } - - /* Round the result. (Don't round underflow or overflow). Also don't - * increment if this would cause the mantissa to wrap. - */ - if ((flt->exponent != EXP_INF) && (flt->exponent != EXP_ZERO) && - !BitVector_is_full(flt->mantissa)) - BitVector_increment(flt->mantissa); - - return flt; -} - -yasm_floatnum * -yasm_floatnum_copy(const yasm_floatnum *flt) -{ - yasm_floatnum *f = yasm_xmalloc(sizeof(yasm_floatnum)); - - f->mantissa = BitVector_Clone(flt->mantissa); - f->exponent = flt->exponent; - f->sign = flt->sign; - f->flags = flt->flags; - - return f; -} - -void -yasm_floatnum_destroy(yasm_floatnum *flt) -{ - BitVector_Destroy(flt->mantissa); - yasm_xfree(flt); -} - -int -yasm_floatnum_calc(yasm_floatnum *acc, yasm_expr_op op, - /*@unused@*/ yasm_floatnum *operand) -{ - if (op != YASM_EXPR_NEG) { - yasm_error_set(YASM_ERROR_FLOATING_POINT, - N_("Unsupported floating-point arithmetic operation")); - return 1; - } - acc->sign ^= 1; - return 0; -} - -int -yasm_floatnum_get_int(const yasm_floatnum *flt, unsigned long *ret_val) -{ - unsigned char t[4]; - - if (yasm_floatnum_get_sized(flt, t, 4, 32, 0, 0, 0)) { - *ret_val = 0xDEADBEEFUL; /* Obviously incorrect return value */ - return 1; - } - - YASM_LOAD_32_L(*ret_val, &t[0]); - return 0; -} - -/* Function used by conversion routines to actually perform the conversion. - * - * ptr -> the array to return the little-endian floating point value into. - * flt -> the floating point value to convert. - * byte_size -> the size in bytes of the output format. - * mant_bits -> the size in bits of the output mantissa. - * implicit1 -> does the output format have an implicit 1? 1=yes, 0=no. - * exp_bits -> the size in bits of the output exponent. - * - * Returns 0 on success, 1 if overflow, -1 if underflow. - */ -static int -floatnum_get_common(const yasm_floatnum *flt, /*@out@*/ unsigned char *ptr, - N_int byte_size, N_int mant_bits, int implicit1, - N_int exp_bits) -{ - long exponent = (long)flt->exponent; - wordptr output; - charptr buf; - unsigned int len; - unsigned int overflow = 0, underflow = 0; - int retval = 0; - long exp_bias = (1<<(exp_bits-1))-1; - long exp_inf = (1<<exp_bits)-1; - - output = BitVector_Create(byte_size*8, TRUE); - - /* copy mantissa */ - BitVector_Interval_Copy(output, flt->mantissa, 0, - (N_int)((MANT_BITS-implicit1)-mant_bits), - mant_bits); - - /* round mantissa */ - if (BitVector_bit_test(flt->mantissa, (MANT_BITS-implicit1)-(mant_bits+1))) - BitVector_increment(output); - - if (BitVector_bit_test(output, mant_bits)) { - /* overflowed, so zero mantissa (and set explicit bit if necessary) */ - BitVector_Empty(output); - BitVector_Bit_Copy(output, mant_bits-1, !implicit1); - /* and up the exponent (checking for overflow) */ - if (exponent+1 >= EXP_INF) - overflow = 1; - else - exponent++; - } - - /* adjust the exponent to the output bias, checking for overflow */ - exponent -= EXP_BIAS-exp_bias; - if (exponent >= exp_inf) - overflow = 1; - else if (exponent <= 0) - underflow = 1; - - /* underflow and overflow both set!? */ - if (underflow && overflow) - yasm_internal_error(N_("Both underflow and overflow set")); - - /* check for underflow or overflow and set up appropriate output */ - if (underflow) { - BitVector_Empty(output); - exponent = 0; - if (!(flt->flags & FLAG_ISZERO)) - retval = -1; - } else if (overflow) { - BitVector_Empty(output); - exponent = exp_inf; - retval = 1; - } - - /* move exponent into place */ - BitVector_Chunk_Store(output, exp_bits, mant_bits, (N_long)exponent); - - /* merge in sign bit */ - BitVector_Bit_Copy(output, byte_size*8-1, flt->sign); - - /* get little-endian bytes */ - buf = BitVector_Block_Read(output, &len); - if (len < byte_size) - yasm_internal_error( - N_("Byte length of BitVector does not match bit length")); - - /* copy to output */ - memcpy(ptr, buf, byte_size*sizeof(unsigned char)); - - /* free allocated resources */ - yasm_xfree(buf); - - BitVector_Destroy(output); - - return retval; -} - -/* IEEE-754r "half precision" format: - * 16 bits: - * 15 9 Bit 0 - * | | | - * seee eemm mmmm mmmm - * - * e = bias 15 exponent - * s = sign bit - * m = mantissa bits, bit 10 is an implied one bit. - * - * IEEE-754 (Intel) "single precision" format: - * 32 bits: - * Bit 31 Bit 22 Bit 0 - * | | | - * seeeeeee emmmmmmm mmmmmmmm mmmmmmmm - * - * e = bias 127 exponent - * s = sign bit - * m = mantissa bits, bit 23 is an implied one bit. - * - * IEEE-754 (Intel) "double precision" format: - * 64 bits: - * bit 63 bit 51 bit 0 - * | | | - * seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm - * - * e = bias 1023 exponent. - * s = sign bit. - * m = mantissa bits. Bit 52 is an implied one bit. - * - * IEEE-754 (Intel) "extended precision" format: - * 80 bits: - * bit 79 bit 63 bit 0 - * | | | - * seeeeeee eeeeeeee mmmmmmmm m...m m...m m...m m...m m...m - * - * e = bias 16383 exponent - * m = 64 bit mantissa with NO implied bit! - * s = sign (for mantissa) - */ -int -yasm_floatnum_get_sized(const yasm_floatnum *flt, unsigned char *ptr, - size_t destsize, size_t valsize, size_t shift, - int bigendian, int warn) -{ - int retval; - if (destsize*8 != valsize || shift>0 || bigendian) { - /* TODO */ - yasm_internal_error(N_("unsupported floatnum functionality")); - } - switch (destsize) { - case 2: - retval = floatnum_get_common(flt, ptr, 2, 10, 1, 5); - break; - case 4: - retval = floatnum_get_common(flt, ptr, 4, 23, 1, 8); - break; - case 8: - retval = floatnum_get_common(flt, ptr, 8, 52, 1, 11); - break; - case 10: - retval = floatnum_get_common(flt, ptr, 10, 64, 0, 15); - break; - default: - yasm_internal_error(N_("Invalid float conversion size")); - /*@notreached@*/ - return 1; - } - if (warn) { - if (retval < 0) - yasm_warn_set(YASM_WARN_GENERAL, - N_("underflow in floating point expression")); - else if (retval > 0) - yasm_warn_set(YASM_WARN_GENERAL, - N_("overflow in floating point expression")); - } - return retval; -} - -/* 1 if the size is valid, 0 if it isn't */ -int -yasm_floatnum_check_size(/*@unused@*/ const yasm_floatnum *flt, size_t size) -{ - switch (size) { - case 16: - case 32: - case 64: - case 80: - return 1; - default: - return 0; - } -} - -void -yasm_floatnum_print(const yasm_floatnum *flt, FILE *f) -{ - unsigned char out[10]; - unsigned char *str; - int i; - - /* Internal format */ - str = BitVector_to_Hex(flt->mantissa); - fprintf(f, "%c %s *2^%04x\n", flt->sign?'-':'+', (char *)str, - flt->exponent); - yasm_xfree(str); - - /* 32-bit (single precision) format */ - fprintf(f, "32-bit: %d: ", - yasm_floatnum_get_sized(flt, out, 4, 32, 0, 0, 0)); - for (i=0; i<4; i++) - fprintf(f, "%02x ", out[i]); - fprintf(f, "\n"); - - /* 64-bit (double precision) format */ - fprintf(f, "64-bit: %d: ", - yasm_floatnum_get_sized(flt, out, 8, 64, 0, 0, 0)); - for (i=0; i<8; i++) - fprintf(f, "%02x ", out[i]); - fprintf(f, "\n"); - - /* 80-bit (extended precision) format */ - fprintf(f, "80-bit: %d: ", - yasm_floatnum_get_sized(flt, out, 10, 80, 0, 0, 0)); - for (i=0; i<10; i++) - fprintf(f, "%02x ", out[i]); - fprintf(f, "\n"); -} +/* + * Floating point number functions. + * + * Copyright (C) 2001-2007 Peter Johnson + * + * Based on public-domain x86 assembly code by Randall Hyde (8/28/91). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "util.h" + +#include <ctype.h> + +#include "coretype.h" +#include "bitvect.h" +#include "file.h" + +#include "errwarn.h" +#include "floatnum.h" + + +/* 97-bit internal floating point format: + * 0000000s eeeeeeee eeeeeeee m.....................................m + * Sign exponent mantissa (80 bits) + * 79 0 + * + * Only L.O. bit of Sign byte is significant. The rest is zero. + * Exponent is bias 32767. + * Mantissa does NOT have an implied one bit (it's explicit). + */ +struct yasm_floatnum { + /*@only@*/ wordptr mantissa; /* Allocated to MANT_BITS bits */ + unsigned short exponent; + unsigned char sign; + unsigned char flags; +}; + +/* constants describing parameters of internal floating point format */ +#define MANT_BITS 80 +#define MANT_BYTES 10 +#define MANT_SIGDIGITS 24 +#define EXP_BIAS 0x7FFF +#define EXP_INF 0xFFFF +#define EXP_MAX 0xFFFE +#define EXP_MIN 1 +#define EXP_ZERO 0 + +/* Flag settings for flags field */ +#define FLAG_ISZERO 1<<0 + +/* Note this structure integrates the floatnum structure */ +typedef struct POT_Entry_s { + yasm_floatnum f; + int dec_exponent; +} POT_Entry; + +/* "Source" for POT_Entry. */ +typedef struct POT_Entry_Source_s { + unsigned char mantissa[MANT_BYTES]; /* little endian mantissa */ + unsigned short exponent; /* Bias 32767 exponent */ +} POT_Entry_Source; + +/* Power of ten tables used by the floating point I/O routines. + * The POT_Table? arrays are built from the POT_Table?_Source arrays at + * runtime by POT_Table_Init(). + */ + +/* This table contains the powers of ten raised to negative powers of two: + * + * entry[12-n] = 10 ** (-2 ** n) for 0 <= n <= 12. + * entry[13] = 1.0 + */ +static /*@only@*/ POT_Entry *POT_TableN; +static POT_Entry_Source POT_TableN_Source[] = { + {{0xe3,0x2d,0xde,0x9f,0xce,0xd2,0xc8,0x04,0xdd,0xa6},0x4ad8}, /* 1e-4096 */ + {{0x25,0x49,0xe4,0x2d,0x36,0x34,0x4f,0x53,0xae,0xce},0x656b}, /* 1e-2048 */ + {{0xa6,0x87,0xbd,0xc0,0x57,0xda,0xa5,0x82,0xa6,0xa2},0x72b5}, /* 1e-1024 */ + {{0x33,0x71,0x1c,0xd2,0x23,0xdb,0x32,0xee,0x49,0x90},0x795a}, /* 1e-512 */ + {{0x91,0xfa,0x39,0x19,0x7a,0x63,0x25,0x43,0x31,0xc0},0x7cac}, /* 1e-256 */ + {{0x7d,0xac,0xa0,0xe4,0xbc,0x64,0x7c,0x46,0xd0,0xdd},0x7e55}, /* 1e-128 */ + {{0x24,0x3f,0xa5,0xe9,0x39,0xa5,0x27,0xea,0x7f,0xa8},0x7f2a}, /* 1e-64 */ + {{0xde,0x67,0xba,0x94,0x39,0x45,0xad,0x1e,0xb1,0xcf},0x7f94}, /* 1e-32 */ + {{0x2f,0x4c,0x5b,0xe1,0x4d,0xc4,0xbe,0x94,0x95,0xe6},0x7fc9}, /* 1e-16 */ + {{0xc2,0xfd,0xfc,0xce,0x61,0x84,0x11,0x77,0xcc,0xab},0x7fe4}, /* 1e-8 */ + {{0xc3,0xd3,0x2b,0x65,0x19,0xe2,0x58,0x17,0xb7,0xd1},0x7ff1}, /* 1e-4 */ + {{0x71,0x3d,0x0a,0xd7,0xa3,0x70,0x3d,0x0a,0xd7,0xa3},0x7ff8}, /* 1e-2 */ + {{0xcd,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc},0x7ffb}, /* 1e-1 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},0x7fff}, /* 1e-0 */ +}; + +/* This table contains the powers of ten raised to positive powers of two: + * + * entry[12-n] = 10 ** (2 ** n) for 0 <= n <= 12. + * entry[13] = 1.0 + * entry[-1] = entry[0]; + * + * There is a -1 entry since it is possible for the algorithm to back up + * before the table. This -1 entry is created at runtime by duplicating the + * 0 entry. + */ +static /*@only@*/ POT_Entry *POT_TableP; +static POT_Entry_Source POT_TableP_Source[] = { + {{0x4c,0xc9,0x9a,0x97,0x20,0x8a,0x02,0x52,0x60,0xc4},0xb525}, /* 1e+4096 */ + {{0x4d,0xa7,0xe4,0x5d,0x3d,0xc5,0x5d,0x3b,0x8b,0x9e},0x9a92}, /* 1e+2048 */ + {{0x0d,0x65,0x17,0x0c,0x75,0x81,0x86,0x75,0x76,0xc9},0x8d48}, /* 1e+1024 */ + {{0x65,0xcc,0xc6,0x91,0x0e,0xa6,0xae,0xa0,0x19,0xe3},0x86a3}, /* 1e+512 */ + {{0xbc,0xdd,0x8d,0xde,0xf9,0x9d,0xfb,0xeb,0x7e,0xaa},0x8351}, /* 1e+256 */ + {{0x6f,0xc6,0xdf,0x8c,0xe9,0x80,0xc9,0x47,0xba,0x93},0x81a8}, /* 1e+128 */ + {{0xbf,0x3c,0xd5,0xa6,0xcf,0xff,0x49,0x1f,0x78,0xc2},0x80d3}, /* 1e+64 */ + {{0x20,0xf0,0x9d,0xb5,0x70,0x2b,0xa8,0xad,0xc5,0x9d},0x8069}, /* 1e+32 */ + {{0x00,0x00,0x00,0x00,0x00,0x04,0xbf,0xc9,0x1b,0x8e},0x8034}, /* 1e+16 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0xbc,0xbe},0x8019}, /* 1e+8 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x9c},0x800c}, /* 1e+4 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8},0x8005}, /* 1e+2 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0},0x8002}, /* 1e+1 */ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},0x7fff}, /* 1e+0 */ +}; + + +static void +POT_Table_Init_Entry(/*@out@*/ POT_Entry *e, POT_Entry_Source *s, int dec_exp) +{ + /* Save decimal exponent */ + e->dec_exponent = dec_exp; + + /* Initialize mantissa */ + e->f.mantissa = BitVector_Create(MANT_BITS, FALSE); + BitVector_Block_Store(e->f.mantissa, s->mantissa, MANT_BYTES); + + /* Initialize exponent */ + e->f.exponent = s->exponent; + + /* Set sign to 0 (positive) */ + e->f.sign = 0; + + /* Clear flags */ + e->f.flags = 0; +} + +/*@-compdef@*/ +void +yasm_floatnum_initialize(void) +/*@globals undef POT_TableN, undef POT_TableP, POT_TableP_Source, + POT_TableN_Source @*/ +{ + int dec_exp = 1; + int i; + + /* Allocate space for two POT tables */ + POT_TableN = yasm_xmalloc(14*sizeof(POT_Entry)); + POT_TableP = yasm_xmalloc(15*sizeof(POT_Entry)); /* note 1 extra for -1 */ + + /* Initialize entry[0..12] */ + for (i=12; i>=0; i--) { + POT_Table_Init_Entry(&POT_TableN[i], &POT_TableN_Source[i], 0-dec_exp); + POT_Table_Init_Entry(&POT_TableP[i+1], &POT_TableP_Source[i], dec_exp); + dec_exp *= 2; /* Update decimal exponent */ + } + + /* Initialize entry[13] */ + POT_Table_Init_Entry(&POT_TableN[13], &POT_TableN_Source[13], 0); + POT_Table_Init_Entry(&POT_TableP[14], &POT_TableP_Source[13], 0); + + /* Initialize entry[-1] for POT_TableP */ + POT_Table_Init_Entry(&POT_TableP[0], &POT_TableP_Source[0], 4096); + + /* Offset POT_TableP so that [0] becomes [-1] */ + POT_TableP++; +} +/*@=compdef@*/ + +/*@-globstate@*/ +void +yasm_floatnum_cleanup(void) +{ + int i; + + /* Un-offset POT_TableP */ + POT_TableP--; + + for (i=0; i<14; i++) { + BitVector_Destroy(POT_TableN[i].f.mantissa); + BitVector_Destroy(POT_TableP[i].f.mantissa); + } + BitVector_Destroy(POT_TableP[14].f.mantissa); + + yasm_xfree(POT_TableN); + yasm_xfree(POT_TableP); +} +/*@=globstate@*/ + +static void +floatnum_normalize(yasm_floatnum *flt) +{ + long norm_amt; + + if (BitVector_is_empty(flt->mantissa)) { + flt->exponent = 0; + return; + } + + /* Look for the highest set bit, shift to make it the MSB, and adjust + * exponent. Don't let exponent go negative. */ + norm_amt = (MANT_BITS-1)-Set_Max(flt->mantissa); + if (norm_amt > (long)flt->exponent) + norm_amt = (long)flt->exponent; + BitVector_Move_Left(flt->mantissa, (N_int)norm_amt); + flt->exponent -= (unsigned short)norm_amt; +} + +/* acc *= op */ +static void +floatnum_mul(yasm_floatnum *acc, const yasm_floatnum *op) +{ + long expon; + wordptr product, op1, op2; + long norm_amt; + + /* Compute the new sign */ + acc->sign ^= op->sign; + + /* Check for multiply by 0 */ + if (BitVector_is_empty(acc->mantissa) || BitVector_is_empty(op->mantissa)) { + BitVector_Empty(acc->mantissa); + acc->exponent = EXP_ZERO; + return; + } + + /* Add exponents, checking for overflow/underflow. */ + expon = (((int)acc->exponent)-EXP_BIAS) + (((int)op->exponent)-EXP_BIAS); + expon += EXP_BIAS; + if (expon > EXP_MAX) { + /* Overflow; return infinity. */ + BitVector_Empty(acc->mantissa); + acc->exponent = EXP_INF; + return; + } else if (expon < EXP_MIN) { + /* Underflow; return zero. */ + BitVector_Empty(acc->mantissa); + acc->exponent = EXP_ZERO; + return; + } + + /* Add one to the final exponent, as the multiply shifts one extra time. */ + acc->exponent = (unsigned short)(expon+1); + + /* Allocate space for the multiply result */ + product = BitVector_Create((N_int)((MANT_BITS+1)*2), FALSE); + + /* Allocate 1-bit-longer fields to force the operands to be unsigned */ + op1 = BitVector_Create((N_int)(MANT_BITS+1), FALSE); + op2 = BitVector_Create((N_int)(MANT_BITS+1), FALSE); + + /* Make the operands unsigned after copying from original operands */ + BitVector_Copy(op1, acc->mantissa); + BitVector_MSB(op1, 0); + BitVector_Copy(op2, op->mantissa); + BitVector_MSB(op2, 0); + + /* Compute the product of the mantissas */ + BitVector_Multiply(product, op1, op2); + + /* Normalize the product. Note: we know the product is non-zero because + * both of the original operands were non-zero. + * + * Look for the highest set bit, shift to make it the MSB, and adjust + * exponent. Don't let exponent go negative. + */ + norm_amt = (MANT_BITS*2-1)-Set_Max(product); + if (norm_amt > (long)acc->exponent) + norm_amt = (long)acc->exponent; + BitVector_Move_Left(product, (N_int)norm_amt); + acc->exponent -= (unsigned short)norm_amt; + + /* Store the highest bits of the result */ + BitVector_Interval_Copy(acc->mantissa, product, 0, MANT_BITS, MANT_BITS); + + /* Free allocated variables */ + BitVector_Destroy(product); + BitVector_Destroy(op1); + BitVector_Destroy(op2); +} + +yasm_floatnum * +yasm_floatnum_create(const char *str) +{ + yasm_floatnum *flt; + int dec_exponent, dec_exp_add; /* decimal (powers of 10) exponent */ + int POT_index; + wordptr operand[2]; + int sig_digits; + int decimal_pt; + boolean carry; + + flt = yasm_xmalloc(sizeof(yasm_floatnum)); + + flt->mantissa = BitVector_Create(MANT_BITS, TRUE); + + /* allocate and initialize calculation variables */ + operand[0] = BitVector_Create(MANT_BITS, TRUE); + operand[1] = BitVector_Create(MANT_BITS, TRUE); + dec_exponent = 0; + sig_digits = 0; + decimal_pt = 1; + + /* set initial flags to 0 */ + flt->flags = 0; + + /* check for + or - character and skip */ + if (*str == '-') { + flt->sign = 1; + str++; + } else if (*str == '+') { + flt->sign = 0; + str++; + } else + flt->sign = 0; + + /* eliminate any leading zeros (which do not count as significant digits) */ + while (*str == '0') + str++; + + /* When we reach the end of the leading zeros, first check for a decimal + * point. If the number is of the form "0---0.0000" we need to get rid + * of the zeros after the decimal point and not count them as significant + * digits. + */ + if (*str == '.') { + str++; + while (*str == '0') { + str++; + dec_exponent--; + } + } else { + /* The number is of the form "yyy.xxxx" (where y <> 0). */ + while (isdigit(*str)) { + /* See if we've processed more than the max significant digits: */ + if (sig_digits < MANT_SIGDIGITS) { + /* Multiply mantissa by 10 [x = (x<<1)+(x<<3)] */ + BitVector_shift_left(flt->mantissa, 0); + BitVector_Copy(operand[0], flt->mantissa); + BitVector_Move_Left(flt->mantissa, 2); + carry = 0; + BitVector_add(operand[1], operand[0], flt->mantissa, &carry); + + /* Add in current digit */ + BitVector_Empty(operand[0]); + BitVector_Chunk_Store(operand[0], 4, 0, (N_long)(*str-'0')); + carry = 0; + BitVector_add(flt->mantissa, operand[1], operand[0], &carry); + } else { + /* Can't integrate more digits with mantissa, so instead just + * raise by a power of ten. + */ + dec_exponent++; + } + sig_digits++; + str++; + } + + if (*str == '.') + str++; + else + decimal_pt = 0; + } + + if (decimal_pt) { + /* Process the digits to the right of the decimal point. */ + while (isdigit(*str)) { + /* See if we've processed more than 19 significant digits: */ + if (sig_digits < 19) { + /* Raise by a power of ten */ + dec_exponent--; + + /* Multiply mantissa by 10 [x = (x<<1)+(x<<3)] */ + BitVector_shift_left(flt->mantissa, 0); + BitVector_Copy(operand[0], flt->mantissa); + BitVector_Move_Left(flt->mantissa, 2); + carry = 0; + BitVector_add(operand[1], operand[0], flt->mantissa, &carry); + + /* Add in current digit */ + BitVector_Empty(operand[0]); + BitVector_Chunk_Store(operand[0], 4, 0, (N_long)(*str-'0')); + carry = 0; + BitVector_add(flt->mantissa, operand[1], operand[0], &carry); + } + sig_digits++; + str++; + } + } + + if (*str == 'e' || *str == 'E') { + str++; + /* We just saw the "E" character, now read in the exponent value and + * add it into dec_exponent. + */ + dec_exp_add = 0; + sscanf(str, "%d", &dec_exp_add); + dec_exponent += dec_exp_add; + } + + /* Free calculation variables. */ + BitVector_Destroy(operand[1]); + BitVector_Destroy(operand[0]); + + /* Normalize the number, checking for 0 first. */ + if (BitVector_is_empty(flt->mantissa)) { + /* Mantissa is 0, zero exponent too. */ + flt->exponent = 0; + /* Set zero flag so output functions don't see 0 value as underflow. */ + flt->flags |= FLAG_ISZERO; + /* Return 0 value. */ + return flt; + } + /* Exponent if already norm. */ + flt->exponent = (unsigned short)(0x7FFF+(MANT_BITS-1)); + floatnum_normalize(flt); + + /* The number is normalized. Now multiply by 10 the number of times + * specified in DecExponent. This uses the power of ten tables to speed + * up this operation (and make it more accurate). + */ + if (dec_exponent > 0) { + POT_index = 0; + /* Until we hit 1.0 or finish exponent or overflow */ + while ((POT_index < 14) && (dec_exponent != 0) && + (flt->exponent != EXP_INF)) { + /* Find the first power of ten in the table which is just less than + * the exponent. + */ + while (dec_exponent < POT_TableP[POT_index].dec_exponent) + POT_index++; + + if (POT_index < 14) { + /* Subtract out what we're multiplying in from exponent */ + dec_exponent -= POT_TableP[POT_index].dec_exponent; + + /* Multiply by current power of 10 */ + floatnum_mul(flt, &POT_TableP[POT_index].f); + } + } + } else if (dec_exponent < 0) { + POT_index = 0; + /* Until we hit 1.0 or finish exponent or underflow */ + while ((POT_index < 14) && (dec_exponent != 0) && + (flt->exponent != EXP_ZERO)) { + /* Find the first power of ten in the table which is just less than + * the exponent. + */ + while (dec_exponent > POT_TableN[POT_index].dec_exponent) + POT_index++; + + if (POT_index < 14) { + /* Subtract out what we're multiplying in from exponent */ + dec_exponent -= POT_TableN[POT_index].dec_exponent; + + /* Multiply by current power of 10 */ + floatnum_mul(flt, &POT_TableN[POT_index].f); + } + } + } + + /* Round the result. (Don't round underflow or overflow). Also don't + * increment if this would cause the mantissa to wrap. + */ + if ((flt->exponent != EXP_INF) && (flt->exponent != EXP_ZERO) && + !BitVector_is_full(flt->mantissa)) + BitVector_increment(flt->mantissa); + + return flt; +} + +yasm_floatnum * +yasm_floatnum_copy(const yasm_floatnum *flt) +{ + yasm_floatnum *f = yasm_xmalloc(sizeof(yasm_floatnum)); + + f->mantissa = BitVector_Clone(flt->mantissa); + f->exponent = flt->exponent; + f->sign = flt->sign; + f->flags = flt->flags; + + return f; +} + +void +yasm_floatnum_destroy(yasm_floatnum *flt) +{ + BitVector_Destroy(flt->mantissa); + yasm_xfree(flt); +} + +int +yasm_floatnum_calc(yasm_floatnum *acc, yasm_expr_op op, + /*@unused@*/ yasm_floatnum *operand) +{ + if (op != YASM_EXPR_NEG) { + yasm_error_set(YASM_ERROR_FLOATING_POINT, + N_("Unsupported floating-point arithmetic operation")); + return 1; + } + acc->sign ^= 1; + return 0; +} + +int +yasm_floatnum_get_int(const yasm_floatnum *flt, unsigned long *ret_val) +{ + unsigned char t[4]; + + if (yasm_floatnum_get_sized(flt, t, 4, 32, 0, 0, 0)) { + *ret_val = 0xDEADBEEFUL; /* Obviously incorrect return value */ + return 1; + } + + YASM_LOAD_32_L(*ret_val, &t[0]); + return 0; +} + +/* Function used by conversion routines to actually perform the conversion. + * + * ptr -> the array to return the little-endian floating point value into. + * flt -> the floating point value to convert. + * byte_size -> the size in bytes of the output format. + * mant_bits -> the size in bits of the output mantissa. + * implicit1 -> does the output format have an implicit 1? 1=yes, 0=no. + * exp_bits -> the size in bits of the output exponent. + * + * Returns 0 on success, 1 if overflow, -1 if underflow. + */ +static int +floatnum_get_common(const yasm_floatnum *flt, /*@out@*/ unsigned char *ptr, + N_int byte_size, N_int mant_bits, int implicit1, + N_int exp_bits) +{ + long exponent = (long)flt->exponent; + wordptr output; + charptr buf; + unsigned int len; + unsigned int overflow = 0, underflow = 0; + int retval = 0; + long exp_bias = (1<<(exp_bits-1))-1; + long exp_inf = (1<<exp_bits)-1; + + output = BitVector_Create(byte_size*8, TRUE); + + /* copy mantissa */ + BitVector_Interval_Copy(output, flt->mantissa, 0, + (N_int)((MANT_BITS-implicit1)-mant_bits), + mant_bits); + + /* round mantissa */ + if (BitVector_bit_test(flt->mantissa, (MANT_BITS-implicit1)-(mant_bits+1))) + BitVector_increment(output); + + if (BitVector_bit_test(output, mant_bits)) { + /* overflowed, so zero mantissa (and set explicit bit if necessary) */ + BitVector_Empty(output); + BitVector_Bit_Copy(output, mant_bits-1, !implicit1); + /* and up the exponent (checking for overflow) */ + if (exponent+1 >= EXP_INF) + overflow = 1; + else + exponent++; + } + + /* adjust the exponent to the output bias, checking for overflow */ + exponent -= EXP_BIAS-exp_bias; + if (exponent >= exp_inf) + overflow = 1; + else if (exponent <= 0) + underflow = 1; + + /* underflow and overflow both set!? */ + if (underflow && overflow) + yasm_internal_error(N_("Both underflow and overflow set")); + + /* check for underflow or overflow and set up appropriate output */ + if (underflow) { + BitVector_Empty(output); + exponent = 0; + if (!(flt->flags & FLAG_ISZERO)) + retval = -1; + } else if (overflow) { + BitVector_Empty(output); + exponent = exp_inf; + retval = 1; + } + + /* move exponent into place */ + BitVector_Chunk_Store(output, exp_bits, mant_bits, (N_long)exponent); + + /* merge in sign bit */ + BitVector_Bit_Copy(output, byte_size*8-1, flt->sign); + + /* get little-endian bytes */ + buf = BitVector_Block_Read(output, &len); + if (len < byte_size) + yasm_internal_error( + N_("Byte length of BitVector does not match bit length")); + + /* copy to output */ + memcpy(ptr, buf, byte_size*sizeof(unsigned char)); + + /* free allocated resources */ + yasm_xfree(buf); + + BitVector_Destroy(output); + + return retval; +} + +/* IEEE-754r "half precision" format: + * 16 bits: + * 15 9 Bit 0 + * | | | + * seee eemm mmmm mmmm + * + * e = bias 15 exponent + * s = sign bit + * m = mantissa bits, bit 10 is an implied one bit. + * + * IEEE-754 (Intel) "single precision" format: + * 32 bits: + * Bit 31 Bit 22 Bit 0 + * | | | + * seeeeeee emmmmmmm mmmmmmmm mmmmmmmm + * + * e = bias 127 exponent + * s = sign bit + * m = mantissa bits, bit 23 is an implied one bit. + * + * IEEE-754 (Intel) "double precision" format: + * 64 bits: + * bit 63 bit 51 bit 0 + * | | | + * seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm + * + * e = bias 1023 exponent. + * s = sign bit. + * m = mantissa bits. Bit 52 is an implied one bit. + * + * IEEE-754 (Intel) "extended precision" format: + * 80 bits: + * bit 79 bit 63 bit 0 + * | | | + * seeeeeee eeeeeeee mmmmmmmm m...m m...m m...m m...m m...m + * + * e = bias 16383 exponent + * m = 64 bit mantissa with NO implied bit! + * s = sign (for mantissa) + */ +int +yasm_floatnum_get_sized(const yasm_floatnum *flt, unsigned char *ptr, + size_t destsize, size_t valsize, size_t shift, + int bigendian, int warn) +{ + int retval; + if (destsize*8 != valsize || shift>0 || bigendian) { + /* TODO */ + yasm_internal_error(N_("unsupported floatnum functionality")); + } + switch (destsize) { + case 2: + retval = floatnum_get_common(flt, ptr, 2, 10, 1, 5); + break; + case 4: + retval = floatnum_get_common(flt, ptr, 4, 23, 1, 8); + break; + case 8: + retval = floatnum_get_common(flt, ptr, 8, 52, 1, 11); + break; + case 10: + retval = floatnum_get_common(flt, ptr, 10, 64, 0, 15); + break; + default: + yasm_internal_error(N_("Invalid float conversion size")); + /*@notreached@*/ + return 1; + } + if (warn) { + if (retval < 0) + yasm_warn_set(YASM_WARN_GENERAL, + N_("underflow in floating point expression")); + else if (retval > 0) + yasm_warn_set(YASM_WARN_GENERAL, + N_("overflow in floating point expression")); + } + return retval; +} + +/* 1 if the size is valid, 0 if it isn't */ +int +yasm_floatnum_check_size(/*@unused@*/ const yasm_floatnum *flt, size_t size) +{ + switch (size) { + case 16: + case 32: + case 64: + case 80: + return 1; + default: + return 0; + } +} + +void +yasm_floatnum_print(const yasm_floatnum *flt, FILE *f) +{ + unsigned char out[10]; + unsigned char *str; + int i; + + /* Internal format */ + str = BitVector_to_Hex(flt->mantissa); + fprintf(f, "%c %s *2^%04x\n", flt->sign?'-':'+', (char *)str, + flt->exponent); + yasm_xfree(str); + + /* 32-bit (single precision) format */ + fprintf(f, "32-bit: %d: ", + yasm_floatnum_get_sized(flt, out, 4, 32, 0, 0, 0)); + for (i=0; i<4; i++) + fprintf(f, "%02x ", out[i]); + fprintf(f, "\n"); + + /* 64-bit (double precision) format */ + fprintf(f, "64-bit: %d: ", + yasm_floatnum_get_sized(flt, out, 8, 64, 0, 0, 0)); + for (i=0; i<8; i++) + fprintf(f, "%02x ", out[i]); + fprintf(f, "\n"); + + /* 80-bit (extended precision) format */ + fprintf(f, "80-bit: %d: ", + yasm_floatnum_get_sized(flt, out, 10, 80, 0, 0, 0)); + for (i=0; i<10; i++) + fprintf(f, "%02x ", out[i]); + fprintf(f, "\n"); +} |