Handle rounding of denorms correctly; make fp overflow a warning
authorH. Peter Anvin <hpa@zytor.com>
Tue, 16 Oct 2007 18:32:58 +0000 (11:32 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Tue, 16 Oct 2007 18:32:58 +0000 (11:32 -0700)
- Handle rounding of denorms correctly
- Make fp overflow a warning, not an error (produces Inf)
- Make fp warnings controllable

float.c
nasm.c
nasmlib.h
test/floatx.asm

diff --git a/float.c b/float.c
index 6db5fba..9230781 100644 (file)
--- a/float.c
+++ b/float.c
@@ -149,7 +149,7 @@ static bool ieee_flconvert(const char *string, uint16_t * mant,
                     *p++ = *string - '0';
                 } else {
                     if (!warned) {
-                        error(ERR_WARNING,
+                        error(ERR_WARNING|ERR_WARN_FL_TOOLONG,
                               "floating-point constant significand contains "
                               "more than %i digits", MANT_DIGITS);
                         warned = true;
@@ -639,11 +639,11 @@ static int to_float(const char *str, int sign, uint8_t * result,
             exponent--;
             if (exponent >= 2 - expmax && exponent <= expmax) {
                type = FL_NORMAL;
-            } else if (!daz && exponent < 2 - expmax &&
+            } else if (exponent < 2 - expmax &&
                        exponent >= 2 - expmax - fmt->mantissa) {
                type = FL_DENORMAL;
             } else if (exponent > 0) {
-               error(ERR_NONFATAL,
+               error(ERR_WARNING|ERR_WARN_FL_OVERFLOW,
                      "overflow in floating-point constant");
                type = FL_INFINITY;
            } else {
@@ -658,6 +658,7 @@ static int to_float(const char *str, int sign, uint8_t * result,
 
     switch (type) {
     case FL_ZERO:
+    zero:
        memset(mant, 0, sizeof mant);
        break;
 
@@ -666,15 +667,16 @@ static int to_float(const char *str, int sign, uint8_t * result,
        shift = -(exponent + expmax - 2 - fmt->exponent)
            + fmt->explicit;
        ieee_shr(mant, shift);
-       if (ieee_round(sign, mant, fmt->words)
-           || (shift > 0 && test_bit(mant, shift-1))) {
-           ieee_shr(mant, 1);
-           if (!shift) {
-               /* XXX: We shifted into the normal range? */
-               /* XXX: This is definitely not right... */
-               mant[0] |= 0x8000;
-           }
-           exponent++; /* UNUSED, WTF? */
+       ieee_round(sign, mant, fmt->words);
+       if (mant[one_pos] & one_mask) {
+           /* One's position is set, we rounded up into normal range */
+           exponent = 1;
+           if (!fmt->explicit)
+               mant[one_pos] &= ~one_mask;     /* remove explicit one */
+           mant[0] |= exponent << (15 - fmt->exponent);
+       } else if (daz) {
+           /* Flush denormals to zero */
+           goto zero;
        }
        break;
     }
@@ -687,7 +689,12 @@ static int to_float(const char *str, int sign, uint8_t * result,
        if (test_bit(mant, fmt->exponent+fmt->explicit-1)) {
            ieee_shr(mant, 1);
            exponent++;
-           /* XXX: Handle overflow here */
+           if (exponent >= expmax) {
+               error(ERR_WARNING|ERR_WARN_FL_OVERFLOW,
+                     "overflow in floating-point constant");
+               type = FL_INFINITY;
+               goto overflow;
+           }
        }
        
        if (!fmt->explicit)
@@ -698,6 +705,7 @@ static int to_float(const char *str, int sign, uint8_t * result,
     case FL_INFINITY:
     case FL_QNAN:
     case FL_SNAN:
+    overflow:
        memset(mant, 0, sizeof mant);
        mant[0] = ((1 << fmt->exponent)-1) << (15 - fmt->exponent);
        if (fmt->explicit)
diff --git a/nasm.c b/nasm.c
index fa13460..3045534 100644 (file)
--- a/nasm.c
+++ b/nasm.c
@@ -92,8 +92,8 @@ static enum op_type operating_mode;
  * Which of the suppressible warnings are suppressed. Entry zero
  * doesn't do anything. Initial defaults are given here.
  */
-static char suppressed[1 + ERR_WARN_MAX] = {
-    0, true, true, true, false, true
+static bool suppressed[1 + ERR_WARN_MAX] = {
+    0, true, true, true, false, true, false, true, true, false
 };
 
 /*
@@ -102,8 +102,8 @@ static char suppressed[1 + ERR_WARN_MAX] = {
  */
 static const char *suppressed_names[1 + ERR_WARN_MAX] = {
     NULL, "macro-params", "macro-selfref", "orphan-labels",
-        "number-overflow",
-    "gnu-elf-extensions"
+    "number-overflow", "gnu-elf-extensions", "float-overflow",
+    "float-denorm", "float-underflow", "float-toolong"
 };
 
 /*
@@ -115,8 +115,12 @@ static const char *suppressed_what[1 + ERR_WARN_MAX] = {
     "macro calls with wrong no. of params",
     "cyclic macro self-references",
     "labels alone on lines without trailing `:'",
-    "numeric constants greater than 0xFFFFFFFF",
-    "using 8- or 16-bit relocation in ELF, a GNU extension"
+    "numeric constants do not fit in 32 bits",
+    "using 8- or 16-bit relocation in ELF32, a GNU extension"
+    "floating point overflow",
+    "floating point denormal",
+    "floating point underflow",
+    "too many digits in floating-point number",
 };
 
 /*
index 14b2867..08a68a5 100644 (file)
--- a/nasmlib.h
+++ b/nasmlib.h
@@ -59,15 +59,21 @@ typedef void (*efunc) (int severity, const char *fmt, ...);
  */
 
 #define ERR_WARN_MASK  0x0000FF00      /* the mask for this feature */
-#define ERR_WARN_SHR  8         /* how far to shift right */
+#define ERR_WARN_SHR  8                /* how far to shift right */
 
-#define ERR_WARN_MNP   0x00000100      /* macro-num-parameters warning */
-#define ERR_WARN_MSR   0x00000200      /* macro self-reference */
-#define ERR_WARN_OL    0x00000300      /* orphan label (no colon, and
+#define WARN(x) ((x) << ERR_WARN_SHR)
+
+#define ERR_WARN_MNP           WARN(1) /* macro-num-parameters warning */
+#define ERR_WARN_MSR           WARN(2) /* macro self-reference */
+#define ERR_WARN_OL            WARN(3) /* orphan label (no colon, and
                                          * alone on line) */
-#define ERR_WARN_NOV   0x00000400      /* numeric overflow */
-#define ERR_WARN_GNUELF        0x00000500      /* using GNU ELF extensions */
-#define ERR_WARN_MAX   5       /* the highest numbered one */
+#define ERR_WARN_NOV           WARN(4) /* numeric overflow */
+#define ERR_WARN_GNUELF                WARN(5) /* using GNU ELF extensions */
+#define ERR_WARN_FL_OVERFLOW   WARN(6) /* FP overflow */
+#define ERR_WARN_FL_DENORM     WARN(7) /* FP denormal */
+#define ERR_WARN_FL_UNDERFLOW  WARN(8) /* FP underflow */
+#define ERR_WARN_FL_TOOLONG    WARN(9) /* FP too many digits */
+#define ERR_WARN_MAX   8       /* the highest numbered one */
 
 /*
  * Wrappers around malloc, realloc and free. nasm_malloc will
index 28b805e..dd6f511 100644 (file)
        dw 0x0.0000123456789p-10
        dw 0x1.0p-25            ; Underflow
        dw 0x1.0p-24            ; Smallest denorm
+       dw 0x1.ffffffffffffffffffffffffffffp-16 ; Rounds to denorm
        dw 0x1.0p-15            ; Denorm
+       dw 0x1.ffffffffffffffffffffffffffffp-15 ; Rounds to normal
        dw 0x1.0p-14            ; Smallest non-denorm
        dw 0x1.0p+15            ; Biggest possible exponent
+       dw 0x1.ffffffffffffffffffffffffffffp+15 ; Rounds to infinity
        dw Inf                  ; Infinity
        dw NaN
 
        dd 0x123456789.0p+64
        dd 0x1.0p-150           ; Underflow
        dd 0x1.0p-149           ; Smallest denorm
+       dd 0x1.ffffffffffffffffffffffffffffp-128        ; Rounds to denorm
        dd 0x1.0p-127           ; Denorm
+       dd 0x1.ffffffffffffffffffffffffffffp-127        ; Rounds to normal
        dd 0x1.0p-126           ; Smallest non-denorm
        dd 0x1.0p+127           ; Biggest possible exponent
+       dd 0x1.ffffffffffffffffffffffffffffp+127        ; Rounds to infinity
        dd Inf                  ; Infinity
        dd NaN
 
        dq 0x123456789.0p+300
        dq 0x1.0p-1075          ; Underflow
        dq 0x1.0p-1074          ; Smallest denorm
+       dq 0x1.ffffffffffffffffffffffffffffp-1024       ; Rounds to denorm
        dq 0x1.0p-1023          ; Denorm
+       dq 0x1.ffffffffffffffffffffffffffffp-1023       ; Rounds to normal
        dq 0x1.0p-1022          ; Smallest non-denorm
        dq 0x1.0p+1023          ; Biggest possible exponent
+       dq 0x1.ffffffffffffffffffffffffffffp+1023       ; Rounds to infinity
        dq Inf                  ; Infinity
        dq NaN
 
        dt 0x123456789.0p+1024
        dt 0x1.0p-16446         ; Underflow
        dt 0x1.0p-16445         ; Smallest denorm
+       dt 0x1.ffffffffffffffffffffffffffffp-16384      ; Rounds to denorm
        dt 0x1.0p-16383         ; Denorm
+       dt 0x1.ffffffffffffffffffffffffffffp-16383      ; Rounds to normal
        dt 0x1.0p-16382         ; Smallest non-denorm
        dt 0x1.0p+16383         ; Biggest possible exponent
+       dq 0x1.ffffffffffffffffffffffffffffp+16383      ; Rounds to infinity
        dt Inf                  ; Infinity
        dt NaN
 
        do 0x123456789.0p+1024
        do 0x1.0p-16495         ; Underflow
        do 0x1.0p-16494         ; Smallest denorm
+       do 0x1.ffffffffffffffffffffffffffffffffp-16384  ; Rounds to denorm
        do 0x1.0p-16383         ; Denorm
+       do 0x1.ffffffffffffffffffffffffffffffffp-16383  ; Rounds to normal
        do 0x1.0p-16382         ; Smallest non-denorm
        do 0x1.0p+16383         ; Biggest possible exponent
+       do 0x1.ffffffffffffffffffffffffffffffffp+16383  ; Rounds to infinity
        do Inf                  ; Infinity
        do NaN