Subject: Setting FP precision: fpgetprec() and fpsetprec()
To: None <tech-userlevel@netbsd.org>
From: Jason Thorpe <thorpej@wasabisystems.com>
List: tech-userlevel
Date: 06/23/2003 18:58:21
--Apple-Mail-4-803290029
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed

Folks...

Some platforms have a way to set the precision of FP operations 
(singe-, double-, or extended-precision) in the FP control register 
(the x86 and m68k FPUs fall into this category).  However, we have no 
interface to control this.  I encountered this while tracking down GCC 
testsuite failures on NetBSD; one particular test depends on 
extended-precision mode on x86 platforms (the default in Linux; BSD 
defaults to double-precision).

FreeBSD has an fp{get,set}prec() interface to control this on x86, so I 
borrowed the API and have provided implementations for i386 and m68k.  
An amd64 implementation should be trivial to copy from the i386.

Unfortunately, this setting isn't meaningful on many platforms; most 
only have single- and double-precision, and don't have an FP control 
setting to set it.

So, what I did is have the <machine/ieeefp.h> of platforms that support 
the new API define __HAVE_FP_PREC, so that source code can test for its 
presence.

I've discussed this change with Frank van der Linden, and he thought it 
was a reasonable thing to add, but that conversation predated the 
__HAVE_FP_PREC part of my patch.

Now, before anyone flames me for not just implementing C99 <fenv.h>, 
I'll point out that C99 doesn't have a standard interface for setting 
the precision.

Comments on this?  I'd like to check it in soon so I can feed back the 
patch to GCC that quashes 5 testsuite failures :-)

         -- Jason R. Thorpe <thorpej@wasabisystems.com>

--Apple-Mail-4-803290029
Content-Disposition: attachment;
	filename=fp_prec-patch
Content-Transfer-Encoding: 7bit
Content-Type: application/octet-stream;
	x-unix-mode=0644;
	name="fp_prec-patch"

Index: lib/libc/arch/i386/gen/Makefile.inc
===================================================================
RCS file: /cvsroot/src/lib/libc/arch/i386/gen/Makefile.inc,v
retrieving revision 1.15
diff -c -r1.15 Makefile.inc
*** lib/libc/arch/i386/gen/Makefile.inc	2003/05/17 15:05:53	1.15
--- lib/libc/arch/i386/gen/Makefile.inc	2003/06/24 01:35:13
***************
*** 2,9 ****
  
  # objects built from assembler sources (need lint stubs)
  SRCS+=	alloca.S byte_swap_2.S byte_swap_4.S fabs.S modf.S \
! 	flt_rounds.S fpgetmask.S fpgetround.S fpgetsticky.S \
! 	fpsetmask.S fpsetround.S fpsetsticky.S 
  
  SRCS+=	setjmp.S __setjmp14.S
  SRCS+=	_setjmp.S
--- 2,9 ----
  
  # objects built from assembler sources (need lint stubs)
  SRCS+=	alloca.S byte_swap_2.S byte_swap_4.S fabs.S modf.S \
! 	flt_rounds.S fpgetmask.S fpgetprec.S fpgetround.S fpgetsticky.S \
! 	fpsetmask.S fpsetprec.S fpsetround.S fpsetsticky.S 
  
  SRCS+=	setjmp.S __setjmp14.S
  SRCS+=	_setjmp.S
Index: lib/libc/arch/i386/gen/fpgetprec.S
===================================================================
RCS file: fpgetprec.S
diff -N fpgetprec.S
*** /dev/null	Tue Jun 24 01:34:46 2003
--- fpgetprec.S	Tue Jun 24 01:35:13 2003
***************
*** 0 ****
--- 1,23 ----
+ /*	$NetBSD$	*/
+ 
+ /*
+  * Written by J.T. Conklin, Apr 4, 1995
+  * Modified by Jason R. Thorpe, June 22, 2003
+  * Public domain.
+  */
+ 
+ #include <machine/asm.h>
+ 
+ #ifdef WEAK_ALIAS
+ WEAK_ALIAS(fpgetprec, _fpgetprec)
+ ENTRY(_fpgetprec)
+ #else
+ ENTRY(fpgetprec)
+ #endif
+ 	subl $4,%esp
+ 	fnstcw (%esp)
+ 	movl (%esp),%eax
+ 	rorl $8,%eax
+ 	andl $3,%eax
+ 	addl $4,%esp
+ 	ret
Index: lib/libc/arch/i386/gen/fpsetprec.S
===================================================================
RCS file: fpsetprec.S
diff -N fpsetprec.S
*** /dev/null	Tue Jun 24 01:34:46 2003
--- fpsetprec.S	Tue Jun 24 01:35:13 2003
***************
*** 0 ****
--- 1,35 ----
+ /*	$NetBSD$	*/
+ 
+ /*
+  * Written by Charles M. Hannum, Apr 9, 1995
+  * Modified by Jason R. Thorpe, June 22, 2003
+  * Public domain.
+  */
+ 
+ #include <machine/asm.h>
+ 
+ #ifdef WEAK_ALIAS
+ WEAK_ALIAS(fpsetprec, _fpsetprec)
+ ENTRY(_fpsetprec)
+ #else
+ ENTRY(fpsetprec)
+ #endif
+ 	subl $4,%esp
+ 
+ 	fnstcw (%esp)
+ 	movl (%esp),%eax
+ 
+ 	rorl $8,%eax
+ 	movl %eax,%edx
+ 	andl $3,%eax
+ 
+ 	subl %eax,%edx
+ 	movl 8(%esp),%ecx
+ 	andl $3,%ecx
+ 	orl %ecx,%edx
+ 	roll $8,%edx
+ 	movl %edx,(%esp)
+ 	fldcw (%esp)
+ 
+ 	addl $4,%esp
+ 	ret
Index: lib/libc/arch/m68k/gen/Makefile.inc
===================================================================
RCS file: /cvsroot/src/lib/libc/arch/m68k/gen/Makefile.inc,v
retrieving revision 1.17
diff -c -r1.17 Makefile.inc
*** lib/libc/arch/m68k/gen/Makefile.inc	2003/05/17 15:05:53	1.17
--- lib/libc/arch/m68k/gen/Makefile.inc	2003/06/24 01:35:13
***************
*** 21,28 ****
  SRCS+=	flt_rounds_softfloat.S
  .else
  SRCS+=	modf.S
! SRCS+=	flt_rounds.S fpgetmask.S fpgetround.S fpgetsticky.S fpsetmask.S \
! 	fpsetround.S fpsetsticky.S
  SRCS+=	adddf3.S addsf3.S cmpdf2.S cmpsf2.S divdf3.S \
  	divsf3.S divsi3.S extendsfdf2.S fixdfsi.S fixunsdfsi.S \
  	floatsidf.S modsi3.S muldf3.S mulsf3.S mulsi3.S \
--- 21,28 ----
  SRCS+=	flt_rounds_softfloat.S
  .else
  SRCS+=	modf.S
! SRCS+=	flt_rounds.S fpgetmask.S fpgetprec.S fpgetround.S fpgetsticky.S 
! SRCS+=	fpsetmask.S fpsetprec.S fpsetround.S fpsetsticky.S
  SRCS+=	adddf3.S addsf3.S cmpdf2.S cmpsf2.S divdf3.S \
  	divsf3.S divsi3.S extendsfdf2.S fixdfsi.S fixunsdfsi.S \
  	floatsidf.S modsi3.S muldf3.S mulsf3.S mulsi3.S \
Index: lib/libc/arch/m68k/gen/fpgetprec.S
===================================================================
RCS file: fpgetprec.S
diff -N fpgetprec.S
*** /dev/null	Tue Jun 24 01:34:46 2003
--- fpgetprec.S	Tue Jun 24 01:35:13 2003
***************
*** 0 ****
--- 1,19 ----
+ /*	$NetBSD$	*/
+ 
+ /*
+  * Written by J.T. Conklin, Apr 6, 1995
+  * Modified by Jason R. Thorpe, June 22, 2003
+  * Public domain.
+  */
+ 
+ #include <machine/asm.h>
+ 
+ #ifdef WEAK_ALIAS
+ WEAK_ALIAS(fpgetprec, _fpgetprec)
+ ENTRY(_fpgetprec)
+ #else
+ ENTRY(fpgetprec)
+ #endif
+ 	fmovel %fpcr,%d0
+ 	bfextu %d0{#24:#2},%d0
+ 	rts
Index: lib/libc/arch/m68k/gen/fpsetprec.S
===================================================================
RCS file: fpsetprec.S
diff -N fpsetprec.S
*** /dev/null	Tue Jun 24 01:34:46 2003
--- fpsetprec.S	Tue Jun 24 01:35:14 2003
***************
*** 0 ****
--- 1,24 ----
+ /*	$NetBSD$	*/
+ 
+ /*
+  * Written by J.T. Conklin, Apr 6, 1995
+  * Modified by Jason R. Thorpe, June 22, 2003
+  * Public Domain.
+  */
+ 
+ #include <machine/asm.h>
+ 
+ #ifdef WEAK_ALIAS
+ WEAK_ALIAS(fpsetprec, _fpsetprec)
+ ENTRY(_fpsetprec)
+ #else
+ ENTRY(fpsetprec)
+ #endif
+ 	movel %d2,%sp@-
+ 	fmovel %fpcr,%d1
+ 	movel %sp@(8),%d2
+ 	bfextu %d1{#24,#2},%d0
+ 	bfins %d2,%d1{#24:#2}
+ 	movel %sp@+,%d2
+ 	fmovel %d1,%fpcr
+ 	rts
Index: lib/libc/gen/fpgetmask.3
===================================================================
RCS file: /cvsroot/src/lib/libc/gen/fpgetmask.3,v
retrieving revision 1.7
diff -c -r1.7 fpgetmask.3
*** lib/libc/gen/fpgetmask.3	2003/04/16 13:34:36	1.7
--- lib/libc/gen/fpgetmask.3	2003/06/24 01:35:16
***************
*** 1,10 ****
  .\"	$NetBSD: fpgetmask.3,v 1.7 2003/04/16 13:34:36 wiz Exp $
  .\"
! .\" Copyright (c) 1999 The NetBSD Foundation, Inc.
  .\" All rights reserved.
  .\"
  .\" This code is derived from software contributed to The NetBSD Foundation
! .\" by Ross Harvey.
  .\"
  .\" Redistribution and use in source and binary forms, with or without
  .\" modification, are permitted provided that the following conditions
--- 1,10 ----
  .\"	$NetBSD: fpgetmask.3,v 1.7 2003/04/16 13:34:36 wiz Exp $
  .\"
! .\" Copyright (c) 1999, 2003 The NetBSD Foundation, Inc.
  .\" All rights reserved.
  .\"
  .\" This code is derived from software contributed to The NetBSD Foundation
! .\" by Ross Harvey, and by Jason R. Thorpe.
  .\"
  .\" Redistribution and use in source and binary forms, with or without
  .\" modification, are permitted provided that the following conditions
***************
*** 34,47 ****
  .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  .\" POSSIBILITY OF SUCH DAMAGE.
  .\"
! .Dd April 29, 1999
  .Dt FPGETMASK 3
  .Os
  .Sh NAME
  .Nm fpgetmask ,
  .Nm fpgetround ,
  .Nm fpgetsticky ,
  .Nm fpsetmask ,
  .Nm fpsetround ,
  .Nm fpsetsticky
  .Nd IEEE FP mode control
--- 34,49 ----
  .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  .\" POSSIBILITY OF SUCH DAMAGE.
  .\"
! .Dd June 22, 2003
  .Dt FPGETMASK 3
  .Os
  .Sh NAME
  .Nm fpgetmask ,
+ .Nm fpgetprec ,
  .Nm fpgetround ,
  .Nm fpgetsticky ,
  .Nm fpsetmask ,
+ .Nm fpsetprec ,
  .Nm fpsetround ,
  .Nm fpsetsticky
  .Nd IEEE FP mode control
***************
*** 51,62 ****
--- 53,68 ----
  .In ieeefp.h
  .Ft fp_except
  .Fn fpgetmask void
+ .Ft fp_prec
+ .Fn fpgetprec void
  .Ft fp_rnd
  .Fn fpgetround void
  .Ft fp_except
  .Fn fpgetsticky void
  .Ft fp_except
  .Fn fpsetmask fp_except\ mask
+ .Ft fp_prec
+ .Fn fpsetprec fp_prec\ precision
  .Ft fp_rnd
  .Fn fpsetround fp_rnd\ rnd_dir
  .Ft fp_except
***************
*** 75,80 ****
--- 81,106 ----
  up.
  The default mode is
  .Dv FP_RN .
+ .Pp
+ Precision settings are available if the C preprocessor macro
+ .Dv __HAVE_FP_PREC
+ is defined.
+ A precision setting is one of
+ .Dv FP_PS , FP_PD ,
+ or
+ .Dv FP_PE ,
+ for single-precision
+ .Pq 24-bit ,
+ double-precision
+ .Pq 53-bit ,
+ and extended-precision
+ .Pq 64-bit .
+ The default precision setting is platform-dependent:
+ .Bl -column -offset indent x86_64xx
+ .It i386 Ta Dv FP_PD
+ .It m68k Ta Dv FP_PE
+ .It x86_64 Ta Dv FP_PD
+ .El
  .Pp
  An
  .Ft fp_except
Index: sys/arch/x86/include/ieeefp.h
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/include/ieeefp.h,v
retrieving revision 1.1
diff -c -r1.1 ieeefp.h
*** sys/arch/x86/include/ieeefp.h	2003/02/26 21:26:10	1.1
--- sys/arch/x86/include/ieeefp.h	2003/06/24 01:35:25
***************
*** 2,7 ****
--- 2,8 ----
  
  /* 
   * Written by J.T. Conklin, Apr 6, 1995
+  * Modified by Jason R. Thorpe, June 22, 2003
   * Public domain.
   */
  
***************
*** 22,26 ****
--- 23,35 ----
      FP_RP=2,			/* round toward positive infinity */
      FP_RZ=3			/* round to zero (truncate) */
  } fp_rnd;
+ 
+ typedef enum {
+     FP_PS=0,			/* single-precision (24-bit) */
+     FP_PD=2,			/* double-precision (53-bit) */
+     FP_PE=3			/* extended-precision (64-bit) */
+ } fp_prec;
+ 
+ #define	__HAVE_FP_PREC
  
  #endif /* _X86_IEEEFP_H_ */
Index: sys/arch/m68k/include/ieeefp.h
===================================================================
RCS file: /cvsroot/src/sys/arch/m68k/include/ieeefp.h,v
retrieving revision 1.3
diff -c -r1.3 ieeefp.h
*** sys/arch/m68k/include/ieeefp.h	1998/01/05 07:02:59	1.3
--- sys/arch/m68k/include/ieeefp.h	2003/06/24 01:35:25
***************
*** 2,7 ****
--- 2,8 ----
  
  /* 
   * Written by J.T. Conklin, Apr 6, 1995
+  * Modified by Jason R. Thorpe, June 22, 2003
   * Public domain.
   */
  
***************
*** 21,25 ****
--- 22,34 ----
      FP_RM=2,			/* round toward negative infinity */
      FP_RP=3			/* round toward positive infinity */
  } fp_rnd;
+ 
+ typedef enum {
+     FP_PE=0,			/* extended-precision (64-bit) */
+     FP_PS=1,			/* single-precision (24-bit) */
+     FP_PD=2			/* double-precision (53-bit) */
+ } fp_prec;
+ 
+ #define	__HAVE_FP_PREC
  
  #endif /* _M68K_IEEEFP_H_ */

--Apple-Mail-4-803290029--