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