summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2007-09-18 21:55:56 -0700
committerH. Peter Anvin <hpa@zytor.com>2007-09-18 21:55:56 -0700
commitf48bc6fb485de852c128c5756c77acd0611c2b87 (patch)
tree77593f0cba7ae5e24932f05761112a14ff4320ab
parent5107d672a006750a8f20b227d1fe33ead77ddd41 (diff)
downloadnasm-f48bc6fb485de852c128c5756c77acd0611c2b87.tar.gz
Support generating NaNs and infinities
Support generating NaNs and infinities as part of floating-point constants.
-rw-r--r--float.c182
-rw-r--r--insns.h4
-rw-r--r--test/float.asm30
-rw-r--r--tokens.dat6
4 files changed, 160 insertions, 62 deletions
diff --git a/float.c b/float.c
index b87db848..d22aa19c 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 b025c7a5..314737af 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 30d1f062..bcb2ec28 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 c84b8fb3..e7c1cb29 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