sparc64/144900: [patch] SPARC64 Floating point fixes

Peter Jeremy peterjeremy at acm.org
Sat Mar 20 09:20:04 UTC 2010


>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 at 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:


More information about the freebsd-sparc64 mailing list