diff options
author | H. Peter Anvin <hpa@zytor.com> | 2007-10-16 11:32:58 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2007-10-16 11:32:58 -0700 |
commit | 125c878e96b5aeb50ae0c7f68847200262a9340f (patch) | |
tree | 6bce054d902250707e5d7be8cbe0fd0e36327ed6 | |
parent | 630b52013ab1ebd53e043d9c5dec36fca609a95c (diff) | |
download | nasm-125c878e96b5aeb50ae0c7f68847200262a9340f.tar.gz |
Handle rounding of denorms correctly; make fp overflow a warning
- Handle rounding of denorms correctly
- Make fp overflow a warning, not an error (produces Inf)
- Make fp warnings controllable
-rw-r--r-- | float.c | 34 | ||||
-rw-r--r-- | nasm.c | 16 | ||||
-rw-r--r-- | nasmlib.h | 20 | ||||
-rw-r--r-- | test/floatx.asm | 15 |
4 files changed, 59 insertions, 26 deletions
@@ -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) @@ -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", }; /* @@ -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 diff --git a/test/floatx.asm b/test/floatx.asm index 28b805e2..dd6f5118 100644 --- a/test/floatx.asm +++ b/test/floatx.asm @@ -28,9 +28,12 @@ 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 @@ -60,9 +63,12 @@ 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 @@ -92,9 +98,12 @@ 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 @@ -124,9 +133,12 @@ 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 @@ -156,8 +168,11 @@ 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 |