Date: Sat, 20 Mar 2010 20:11:20 +1100 (EST) From: Peter Jeremy <peterjeremy@acm.org> To: FreeBSD-gnats-submit@FreeBSD.org Subject: sparc64/144900: [patch] SPARC64 Floating point fixes Message-ID: <201003200911.o2K9BK8a093249@server.vk2pj.dyndns.org> Resent-Message-ID: <201003200920.o2K9K3Fs065226@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 144900 >Category: sparc64 >Synopsis: [patch] SPARC64 Floating point fixes >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-sparc64 >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sat Mar 20 09:20:03 UTC 2010 >Closed-Date: >Last-Modified: >Originator: Peter Jeremy >Release: FreeBSD 8.0-STABLE sparc64 >Organization: n/a >Environment: System: FreeBSD sb1500.vk2pj.dyndns.org 8.0-STABLE FreeBSD 8.0-STABLE #0: Sun Feb 14 19:09:44 EST 2010 root@sb1500.vk2pj.dyndns.org:/usr/obj/usr/src/sys/sb1500 sparc64 >Description: The UltraSPARC architecture implements IEEE Std 754-1985 using a combination of hardware and software - specific implementations will typically implement a subset of the standard in hardware and trap on other floating point operations to allow software emulation. In order to meet this requirement, FreeBSD provides a complete (though SPARC-oriented) floating-point emulator. Initial errors reported by one of perl's configuration tools led me to undertake a more rigorous examination of FreeBSD's emulator. Whilst some gross errors were recently corrected in r204974 & r205002, an IEEE test (http://www.jhauser.us/arithmetic/TestFloat.html) reported a significant number of errors. The attached patch comprises patches to the sparc64 userland floating point code, together with a test harness (based on TestFloat above) to verify the correct operation of the floating point code. Whilst the test harness currently only includes sparc64 support, extending it to other architectures should be simple. Explanation of the fixes: - libc/softfloat is used by the test harness code. It defaults to detecting tinyness after rounding whilst the UltraSPARC Architecture document states that the UltraSPARC detects tinyness before rounding. A patch to softfloat-specialize changes this for sparc only. - Parts of the emulator code must be compiled with no-strict-aliasing specified to function correctly. CFLAGS is updated to include the relevant gcc option. (This will add -fno-strict-aliasing to all of libc - which is excessive but I don't believe it's possible to compile only part of libc that way). - When FPU_DEBUG is defined, files using the debugging facilities need stdio defined. - Division should take both argument's signs into account when the dividend is infinity or zero and the divisor is not the same. - Add a note that the emulator code depends on the numeric values of the FTYPE_xxx macros in places. - __fpu_ftox() needs to correctly return overflow in two pieces. - The UltraSPARC architecture defines that tinyness is detected before rounding therefore rounding up to the smallest normalised number should set the underflow flag. - If an infinite result is rounded down, the result should have an exponent 1 less than the value for infinity. >How-To-Repeat: Run the test harness without applying the emulator fixes: cd /usr/src/tools/test/testfloat/sparc64 make obj && make depend && make cd /usr/obj/usr/src/tools/test/testfloat/sparc64 ./testsoftfloat -all 2>/dev/null # Verify that "No errors found" is reported for all tests ./testemufloat -all 2>/dev/null # Verify that a variety of errors are reported ./testsoftfloat -all 2>/dev/null # Verify that a variety of errors are reported (Explanation of the test error output can be found in /usr/src/tools/test/testfloat/testfloat.txt). Apply emulator fixes and rebuild the test harness. If the above tests are rerun, testsoftfloat and testemufloat should report no errors. testfloat will continue to report errors because libc hasn't been rebuilt. Rebuild and re-install libc. Rerun testfloat and it should report no errors. More rigorous testing is possible by adding '-level 2' prior to '-all' but this will take many hours to run. >Fix: [Test harness will be forwarded separately] Index: lib/libc/softfloat/softfloat-specialize =================================================================== RCS file: /usr/ncvs/src/lib/libc/softfloat/softfloat-specialize,v retrieving revision 1.1.22.1 diff -u -r1.1.22.1 softfloat-specialize --- lib/libc/softfloat/softfloat-specialize 3 Aug 2009 08:13:06 -0000 1.1.22.1 +++ lib/libc/softfloat/softfloat-specialize 20 Mar 2010 02:46:33 -0000 @@ -44,7 +44,11 @@ #ifdef SOFTFLOAT_FOR_GCC static #endif +#ifdef __sparc__ +int8 float_detect_tininess = float_tininess_before_rounding; +#else int8 float_detect_tininess = float_tininess_after_rounding; +#endif /* ------------------------------------------------------------------------------- Index: lib/libc/sparc64/fpu/Makefile.inc =================================================================== RCS file: /usr/ncvs/src/lib/libc/sparc64/fpu/Makefile.inc,v retrieving revision 1.5.36.1 diff -u -r1.5.36.1 Makefile.inc --- lib/libc/sparc64/fpu/Makefile.inc 3 Aug 2009 08:13:06 -0000 1.5.36.1 +++ lib/libc/sparc64/fpu/Makefile.inc 16 Mar 2010 07:54:55 -0000 @@ -2,7 +2,7 @@ .PATH: ${.CURDIR}/sparc64/fpu -CFLAGS+= -I${.CURDIR}/sparc64/sys +CFLAGS+= -I${.CURDIR}/sparc64/sys -fno-strict-aliasing SRCS+= fpu.c fpu_add.c fpu_compare.c fpu_div.c fpu_explode.c fpu_implode.c \ fpu_mul.c fpu_qp.c fpu_reg.S fpu_sqrt.c fpu_subr.c Index: lib/libc/sparc64/fpu/fpu.c =================================================================== RCS file: /usr/ncvs/src/lib/libc/sparc64/fpu/fpu.c,v retrieving revision 1.9.10.2 diff -u -r1.9.10.2 fpu.c --- lib/libc/sparc64/fpu/fpu.c 15 Mar 2010 18:32:57 -0000 1.9.10.2 +++ lib/libc/sparc64/fpu/fpu.c 20 Mar 2010 07:29:32 -0000 @@ -74,6 +74,9 @@ #include <stdlib.h> #include "un-namespace.h" #include "libc_private.h" +#ifdef FPU_DEBUG +#include <stdio.h> +#endif #include <machine/fp.h> #include <machine/frame.h> Index: lib/libc/sparc64/fpu/fpu_div.c =================================================================== RCS file: /usr/ncvs/src/lib/libc/sparc64/fpu/fpu_div.c,v retrieving revision 1.4.10.1 diff -u -r1.4.10.1 fpu_div.c --- lib/libc/sparc64/fpu/fpu_div.c 3 Aug 2009 08:13:06 -0000 1.4.10.1 +++ lib/libc/sparc64/fpu/fpu_div.c 15 Mar 2010 18:21:28 -0000 @@ -167,14 +167,16 @@ * return it. Otherwise we have the following cases: * * Inf / Inf = NaN, plus NV exception - * Inf / num = Inf [i.e., return x] - * Inf / 0 = Inf [i.e., return x] - * 0 / Inf = 0 [i.e., return x] - * 0 / num = 0 [i.e., return x] + * Inf / num = Inf [i.e., return x #] + * Inf / 0 = Inf [i.e., return x #] + * 0 / Inf = 0 [i.e., return x #] + * 0 / num = 0 [i.e., return x #] * 0 / 0 = NaN, plus NV exception - * num / Inf = 0 + * num / Inf = 0 # * num / num = num (do the divide) - * num / 0 = Inf, plus DZ exception + * num / 0 = Inf #, plus DZ exception + * + * # Sign of result is xor of operand signs. */ if (ISNAN(x) || ISNAN(y)) { ORDER(x, y); @@ -183,6 +185,7 @@ if (ISINF(x) || ISZERO(x)) { if (x->fp_class == y->fp_class) return (__fpu_newnan(fe)); + x->fp_sign ^= y->fp_sign; return (x); } Index: lib/libc/sparc64/fpu/fpu_emu.h =================================================================== RCS file: /usr/ncvs/src/lib/libc/sparc64/fpu/fpu_emu.h,v retrieving revision 1.6.10.2 diff -u -r1.6.10.2 fpu_emu.h --- lib/libc/sparc64/fpu/fpu_emu.h 15 Mar 2010 18:32:57 -0000 1.6.10.2 +++ lib/libc/sparc64/fpu/fpu_emu.h 20 Mar 2010 07:30:02 -0000 @@ -134,7 +134,8 @@ /* * Floating point operand types. FTYPE_LNG is syntethic (it does not occur in - * instructions). + * instructions). Note that the code relies on the numeric values of these + * constants in some places. */ #define FTYPE_INT INSFP_i #define FTYPE_SNG INSFP_s Index: lib/libc/sparc64/fpu/fpu_explode.c =================================================================== RCS file: /usr/ncvs/src/lib/libc/sparc64/fpu/fpu_explode.c,v retrieving revision 1.8.2.1 diff -u -r1.8.2.1 fpu_explode.c --- lib/libc/sparc64/fpu/fpu_explode.c 3 Aug 2009 08:13:06 -0000 1.8.2.1 +++ lib/libc/sparc64/fpu/fpu_explode.c 15 Mar 2010 18:21:50 -0000 @@ -48,6 +48,9 @@ */ #include <sys/param.h> +#ifdef FPU_DEBUG +#include <stdio.h> +#endif #include <machine/frame.h> #include <machine/fp.h> Index: lib/libc/sparc64/fpu/fpu_implode.c =================================================================== RCS file: /usr/ncvs/src/lib/libc/sparc64/fpu/fpu_implode.c,v retrieving revision 1.8.10.1 diff -u -r1.8.10.1 fpu_implode.c --- lib/libc/sparc64/fpu/fpu_implode.c 3 Aug 2009 08:13:06 -0000 1.8.10.1 +++ lib/libc/sparc64/fpu/fpu_implode.c 15 Mar 2010 18:21:50 -0000 @@ -48,6 +48,9 @@ */ #include <sys/param.h> +#ifdef FPU_DEBUG +#include <stdio.h> +#endif #include <machine/frame.h> #include <machine/fp.h> @@ -283,7 +286,9 @@ } /* overflow: replace any inexact exception with invalid */ fe->fe_cx = (fe->fe_cx & ~FSR_NX) | FSR_NV; - return (0x7fffffffffffffffLL + sign); + i = 0x7fffffffffffffffLL + sign; + res[1] = (int)i; + return (i >> 32); } /* @@ -325,8 +330,9 @@ * right to introduce leading zeroes. Rounding then acts * differently for normals and subnormals: the largest subnormal * may round to the smallest normal (1.0 x 2^minexp), or may - * remain subnormal. In the latter case, signal an underflow - * if the result was inexact or if underflow traps are enabled. + * remain subnormal. A number that is subnormal before rounding + * will signal an underflow if the result is inexact or if underflow + * traps are enabled. * * Rounding a normal, on the other hand, always produces another * normal (although either way the result might be too big for @@ -341,8 +347,10 @@ if ((exp = fp->fp_exp + SNG_EXP_BIAS) <= 0) { /* subnormal */ /* -NG for g,r; -SNG_FRACBITS-exp for fraction */ (void) __fpu_shr(fp, FP_NMANT - FP_NG - SNG_FRACBITS - exp); - if (fpround(fe, fp) && fp->fp_mant[3] == SNG_EXP(1)) + if (fpround(fe, fp) && fp->fp_mant[3] == SNG_EXP(1)) { + fe->fe_cx |= FSR_UF; return (sign | SNG_EXP(1) | 0); + } if ((fe->fe_cx & FSR_NX) || (fe->fe_fsr & (FSR_UF << FSR_TEM_SHIFT))) fe->fe_cx |= FSR_UF; @@ -403,6 +411,7 @@ if ((exp = fp->fp_exp + DBL_EXP_BIAS) <= 0) { (void) __fpu_shr(fp, FP_NMANT - FP_NG - DBL_FRACBITS - exp); if (fpround(fe, fp) && fp->fp_mant[2] == DBL_EXP(1)) { + fe->fe_cx |= FSR_UF; res[1] = 0; return (sign | DBL_EXP(1) | 0); } @@ -422,7 +431,7 @@ return (sign | DBL_EXP(DBL_EXP_INFNAN) | 0); } res[1] = ~0; - return (sign | DBL_EXP(DBL_EXP_INFNAN) | DBL_MASK); + return (sign | DBL_EXP(DBL_EXP_INFNAN - 1) | DBL_MASK); } done: res[1] = fp->fp_mant[3]; @@ -464,6 +473,7 @@ if ((exp = fp->fp_exp + EXT_EXP_BIAS) <= 0) { (void) __fpu_shr(fp, FP_NMANT - FP_NG - EXT_FRACBITS - exp); if (fpround(fe, fp) && fp->fp_mant[0] == EXT_EXP(1)) { + fe->fe_cx |= FSR_UF; res[1] = res[2] = res[3] = 0; return (sign | EXT_EXP(1) | 0); } @@ -483,7 +493,7 @@ return (sign | EXT_EXP(EXT_EXP_INFNAN) | 0); } res[1] = res[2] = res[3] = ~0; - return (sign | EXT_EXP(EXT_EXP_INFNAN) | EXT_MASK); + return (sign | EXT_EXP(EXT_EXP_INFNAN - 1) | EXT_MASK); } done: res[1] = fp->fp_mant[1]; >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201003200911.o2K9BK8a093249>