From f48bc6fb485de852c128c5756c77acd0611c2b87 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 18 Sep 2007 21:55:56 -0700 Subject: [PATCH] Support generating NaNs and infinities Support generating NaNs and infinities as part of floating-point constants. --- float.c | 182 ++++++++++++++++++++++++++++++++++++++------------------- insns.h | 4 +- test/float.asm | 30 ++++++++++ tokens.dat | 6 ++ 4 files changed, 160 insertions(+), 62 deletions(-) diff --git a/float.c b/float.c index b87db84..d22aa19 100644 --- a/float.c +++ b/float.c @@ -303,6 +303,12 @@ static int ieee_round(uint16_t *mant, int i) #define put(a,b) ( (*(a)=(b)), ((a)[1]=(b)>>8) ) +/* Set a bit, using *bigendian* bit numbering (0 = MSB) */ +static void set_bit(uint16_t *mant, int bit) +{ + mant[bit >> 4] |= 1 << (~bit & 15); +} + /* Produce standard IEEE formats, with implicit "1" bit; this makes the following assumptions: @@ -333,59 +339,84 @@ static int to_float(char *str, int32_t sign, uint8_t *result, sign = (sign < 0 ? 0x8000L : 0L); - ieee_flconvert(str, mant, &exponent, error); - if (mant[0] & 0x8000) { - /* - * Non-zero. - */ - exponent--; - if (exponent >= 2-expmax && exponent <= expmax) { - /* - * Normalised. - */ - exponent += expmax; - ieee_shr(mant, fmt->exponent); - ieee_round(mant, fmt->words); - /* did we scale up by one? */ - if (mant[0] & (implicit_one << 1)) { - ieee_shr(mant, 1); - exponent++; - } + if (str[0] == '_') { + /* NaN or Infinity */ + int32_t expmask = (1 << fmt->exponent)-1; - mant[0] &= (implicit_one-1); /* remove leading one */ - mant[0] |= exponent << (15 - fmt->exponent); - } else if (exponent < 2-expmax && exponent >= 2-expmax-fmt->mantissa) { - /* - * Denormal. - */ - int shift = -(exponent + expmax-2-fmt->exponent); - int sh = shift % 16, wds = shift / 16; - ieee_shr(mant, sh); - if (ieee_round(mant, fmt->words - wds) - || (sh > 0 && (mant[0] & (0x8000 >> (sh - 1))))) { - ieee_shr(mant, 1); - if (sh == 0) - mant[0] |= 0x8000; - exponent++; - } + memset(mant, 0, sizeof mant); + mant[0] = expmask << (15-fmt->exponent); /* Exponent: all bits one */ - if (wds) { - for (i = fmt->words-1; i >= wds; i--) - mant[i] = mant[i-wds]; - for (; i >= 0; i--) - mant[i] = 0; - } - } else { - if (exponent > 0) { - error(ERR_NONFATAL, "overflow in floating-point constant"); - return 0; + switch (str[2]) { + case 'n': /* __nan__ */ + case 'N': + case 'q': /* __qnan__ */ + case 'Q': + set_bit(mant, fmt->exponent+1); /* Highest bit in mantissa */ + break; + case 's': /* __snan__ */ + case 'S': + set_bit(mant, fmt->exponent+fmt->mantissa); /* Last bit */ + break; + case 'i': /* __infinity__ */ + case 'I': + break; + } + } else { + ieee_flconvert(str, mant, &exponent, error); + if (mant[0] & 0x8000) { + /* + * Non-zero. + */ + exponent--; + if (exponent >= 2-expmax && exponent <= expmax) { + /* + * Normalised. + */ + exponent += expmax; + ieee_shr(mant, fmt->exponent); + ieee_round(mant, fmt->words); + /* did we scale up by one? */ + if (mant[0] & (implicit_one << 1)) { + ieee_shr(mant, 1); + exponent++; + } + + mant[0] &= (implicit_one-1); /* remove leading one */ + mant[0] |= exponent << (15 - fmt->exponent); + } else if (exponent < 2-expmax && + exponent >= 2-expmax-fmt->mantissa) { + /* + * Denormal. + */ + int shift = -(exponent + expmax-2-fmt->exponent); + int sh = shift % 16, wds = shift / 16; + ieee_shr(mant, sh); + if (ieee_round(mant, fmt->words - wds) + || (sh > 0 && (mant[0] & (0x8000 >> (sh - 1))))) { + ieee_shr(mant, 1); + if (sh == 0) + mant[0] |= 0x8000; + exponent++; + } + + if (wds) { + for (i = fmt->words-1; i >= wds; i--) + mant[i] = mant[i-wds]; + for (; i >= 0; i--) + mant[i] = 0; + } } else { - memset(mant, 0, 2*fmt->words); + if (exponent > 0) { + error(ERR_NONFATAL, "overflow in floating-point constant"); + return 0; + } else { + memset(mant, 0, 2*fmt->words); + } } - } - } else { - /* Zero */ - memset(mant, 0, 2*fmt->words); + } else { + /* Zero */ + memset(mant, 0, 2*fmt->words); + } } mant[0] |= sign; @@ -409,6 +440,31 @@ static int to_ldoub(char *str, int32_t sign, uint8_t *result, sign = (sign < 0 ? 0x8000L : 0L); + if (str[0] == '_') { + uint16_t is_snan = 0, is_qnan = 0x8000; + switch (str[2]) { + case 'n': + case 'N': + case 'q': + case 'Q': + is_qnan = 0xc000; + break; + case 's': + case 'S': + is_snan = 1; + break; + case 'i': + case 'I': + break; + } + put(result + 0, is_snan); + put(result + 2, 0); + put(result + 4, 0); + put(result + 6, is_qnan); + put(result + 8, 0x7fff|sign); + return 1; + } + ieee_flconvert(str, mant, &exponent, error); if (mant[0] & 0x8000) { /* @@ -422,11 +478,11 @@ static int to_ldoub(char *str, int32_t sign, uint8_t *result, exponent += 16383; if (ieee_round(mant, 4)) /* did we scale up by one? */ ieee_shr(mant, 1), mant[0] |= 0x8000, exponent++; - put(result + 8, exponent | sign); - put(result + 6, mant[0]); - put(result + 4, mant[1]); - put(result + 2, mant[2]); put(result + 0, mant[3]); + put(result + 2, mant[2]); + put(result + 4, mant[1]); + put(result + 6, mant[0]); + put(result + 8, exponent | sign); } else if (exponent < -16383 && exponent >= -16446) { /* * Denormal. @@ -441,23 +497,29 @@ static int to_ldoub(char *str, int32_t sign, uint8_t *result, mant[0] |= 0x8000; exponent++; } - put(result + 8, sign); - put(result + 6, (wds == 0 ? mant[0] : 0)); - put(result + 4, (wds <= 1 ? mant[1 - wds] : 0)); - put(result + 2, (wds <= 2 ? mant[2 - wds] : 0)); put(result + 0, (wds <= 3 ? mant[3 - wds] : 0)); + put(result + 2, (wds <= 2 ? mant[2 - wds] : 0)); + put(result + 4, (wds <= 1 ? mant[1 - wds] : 0)); + put(result + 6, (wds == 0 ? mant[0] : 0)); + put(result + 8, sign); } else { if (exponent > 0) { error(ERR_NONFATAL, "overflow in floating-point constant"); return 0; - } else - memset(result, 0, 10); + } else { + goto zero; + } } } else { /* * Zero. */ - memset(result, 0, 10); + zero: + put(result + 0, 0); + put(result + 2, 0); + put(result + 4, 0); + put(result + 6, 0); + put(result + 8, sign); } return 1; } diff --git a/insns.h b/insns.h index b025c7a..314737a 100644 --- a/insns.h +++ b/insns.h @@ -12,10 +12,10 @@ #include "nasm.h" /* max length of any instruction, register name etc. */ -#if MAX_INSLEN > 9 /* MAX_INSLEN defined in insnsi.h */ +#if MAX_INSLEN > 12 /* MAX_INSLEN defined in insnsi.h */ #define MAX_KEYWORD MAX_INSLEN #else -#define MAX_KEYWORD 9 +#define MAX_KEYWORD 12 #endif struct itemplate { diff --git a/test/float.asm b/test/float.asm index 30d1f06..bcb2ec2 100644 --- a/test/float.asm +++ b/test/float.asm @@ -21,6 +21,12 @@ dw 1.83203125e-6 ; Denormal! dw +1.83203125e-6 ; Denormal! dw -1.83203125e-6 ; Denormal! + dw __Infinity__ + dw +__Infinity__ + dw -__Infinity__ + dw __NaN__ + dw __QNaN__ + dw __SNaN__ ; 32-bit dd 1.0 @@ -41,6 +47,12 @@ dd 1.83203125e-40 ; Denormal! dd +1.83203125e-40 ; Denormal! dd -1.83203125e-40 ; Denormal! + dd __Infinity__ + dd +__Infinity__ + dd -__Infinity__ + dd __NaN__ + dd __QNaN__ + dd __SNaN__ ; 64-bit dq 1.0 @@ -61,6 +73,12 @@ dq 1.83203125e-320 ; Denormal! dq +1.83203125e-320 ; Denormal! dq -1.83203125e-320 ; Denormal! + dq __Infinity__ + dq +__Infinity__ + dq -__Infinity__ + dq __NaN__ + dq __QNaN__ + dq __SNaN__ ; 80-bit dt 1.0 @@ -81,6 +99,12 @@ dt 1.83203125e-4940 ; Denormal! dt +1.83203125e-4940 ; Denormal! dt -1.83203125e-4940 ; Denormal! + dt __Infinity__ + dt +__Infinity__ + dt -__Infinity__ + dt __NaN__ + dt __QNaN__ + dt __SNaN__ ; 128-bit do 1.0 @@ -101,3 +125,9 @@ do 1.83203125e-4940 ; Denormal! do +1.83203125e-4940 ; Denormal! do -1.83203125e-4940 ; Denormal! + do __Infinity__ + do +__Infinity__ + do -__Infinity__ + do __NaN__ + do __QNaN__ + do __SNaN__ diff --git a/tokens.dat b/tokens.dat index c84b8fb..e7c1cb2 100644 --- a/tokens.dat +++ b/tokens.dat @@ -32,6 +32,12 @@ to tword word +% TOKEN_FLOAT, 0, 0 +__infinity__ +__nan__ +__qnan__ +__snan__ + % TOKEN_*, 0, 0 seg wrt -- 2.7.4