Hi, I've taken a look at the amd64 part of the diff. Comments inline.
I'm in the progress of implementing support for the remaining architectures, if anyone could provide me with remote access that would speed up the process. > Delivered-To: [email protected] > Received: by 10.231.207.5 with SMTP id fw5cs37718ibb; > Tue, 8 Mar 2011 12:50:47 -0800 (PST) > Received: by 10.43.51.65 with SMTP id vh1mr6985314icb.435.1299617447631; > Tue, 08 Mar 2011 12:50:47 -0800 (PST) > Return-Path: <[email protected]> > Received: from shear.ucar.edu (lists.openbsd.org [192.43.244.163]) > by mx.google.com with ESMTP id e15si2866420icb.3.2011.03.08.12.50.46; > Tue, 08 Mar 2011 12:50:46 -0800 (PST) > Received-SPF: pass (google.com: manual fallback record for domain of > [email protected] designates 192.43.244.163 as permitted sender) > client-ip=192.43.244.163; > Authentication-Results: mx.google.com; spf=pass (google.com: manual fallback > record for domain of [email protected] designates 192.43.244.163 > as permitted sender) [email protected] > Received: from openbsd.org (localhost.ucar.edu [127.0.0.1]) > by shear.ucar.edu (8.14.3/8.14.3) with ESMTP id p28Knngv024012; > Tue, 8 Mar 2011 13:49:49 -0700 (MST) > Received: from mail-fx0-f49.google.com (mail-fx0-f49.google.com > [209.85.161.49]) > by shear.ucar.edu (8.14.3/8.14.3) with ESMTP id p28KlIUF020626 > for <[email protected]>; Tue, 8 Mar 2011 13:47:20 -0700 (MST) > Received: by fxm16 with SMTP id 16so5702993fxm.8 > for <[email protected]>; Tue, 08 Mar 2011 12:47:18 -0800 (PST) > Received: by 10.223.148.83 with SMTP id o19mr1047530fav.52.1299613854399; > Tue, 08 Mar 2011 11:50:54 -0800 (PST) > Received: from mdempsky.mtv.corp.google.com (mdempsky.mtv.corp.google.com > [172.17.81.82]) > by mx.google.com with ESMTPS id n15sm530297fam.36.2011.03.08.11.50.51 > (version=SSLv3 cipher=OTHER); Tue, 08 Mar 2011 11:50:53 -0800 (PST) > Date: Tue, 8 Mar 2011 11:50:48 -0800 > From: Matthew Dempsky <[email protected]> > To: [email protected] > Subject: fenv.h support for libm > Message-ID: <[email protected]> > MIME-Version: 1.0 > Content-Type: text/plain; charset=us-ascii > List-Help: <mailto:[email protected]?body=help> > List-Owner: <mailto:[email protected]> > List-Post: <mailto:[email protected]> > List-Subscribe: <mailto:[email protected]?body=sub%20tech> > List-Unsubscribe: <mailto:[email protected]?body=unsub%20tech> > X-Loop: [email protected] > Precedence: list > Sender: [email protected] > > The diff below adds support for C99's <fenv.h> to libm. It's based on > NetBSD's implementation with minimal changes to work on OpenBSD. I'm not sure how this got into the NetBSD tree, but as far as I can tell there are some serious problems with it; at least fesetexceptflag, and fegetexcept are broken, default floating-point environment is wrong, fetestexcept could be written in a better fashion. And I've only looked at the amd64 implementation so far. > Currently, the diff only supports amd64, i386, and sparc64 (the only > arches that NetBSD supports fenv.h on), but I've only tested on amd64 > so far. Using this diff, I was able to successfully build and run > OpenSCAD. > > I'd appreciate some feedback on what still needs to be done before > committing this. I'm unsure what to do about NetBSD's _DIAGASSERTs, I'd say remove them. > and I suspect the man pages might need some cleanups, but maybe those > can be further fixed up in tree? I'm omitting manual page changes, this part of code is already complicated enough; man pages can be worked on in-tree. > Thoughts? I'd particularly appreciate test reports on i386 and > sparc64. I agree with what Brad and Philip said. Further comments inline (from the top of my head). I'm attaching final amd64 diff--hopefully Gmail doesn't mangle it, otherwise you can find it on cvs:~martynas/fenv_amd64.diff. > Index: lib/libm/Makefile > =================================================================== > RCS file: /cvs/src/lib/libm/Makefile,v > retrieving revision 1.76 > diff -u -p lib/libm/Makefile > --- lib/libm/Makefile 19 Jul 2010 12:48:23 -0000 1.76 > +++ lib/libm/Makefile 23 Feb 2011 02:20:57 -0000 > @@ -27,6 +27,7 @@ ARCH_SRCS = s_copysign.S s_copysignf.S > ARCH_SRCS = e_acos.S e_asin.S e_atan2.S e_exp.S e_fmod.S e_log.S e_log10.S \ > e_remainder.S e_remainderf.S e_scalb.S e_sqrt.S e_sqrtf.S \ > e_sqrtl.S \ > + fenv.c \ > invtrig.c \ > s_atan.S s_atanf.S s_ceil.S s_ceilf.S s_copysign.S s_copysignf.S \ > s_cos.S s_cosf.S s_floor.S s_floorf.S \ > @@ -40,6 +41,7 @@ CPPFLAGS+=-I${.CURDIR}/arch/amd64 > ARCH_SRCS = e_acos.S e_asin.S e_atan2.S e_exp.S e_fmod.S e_log.S e_log10.S \ > e_remainder.S e_remainderf.S e_scalb.S e_sqrt.S e_sqrtf.S \ > e_sqrtl.S \ > + fenv.c \ > invtrig.c \ > s_atan.S s_atanf.S s_ceil.S s_ceilf.S s_copysign.S s_copysignf.S \ > s_cos.S s_cosf.S s_floor.S s_floorf.S \ > @@ -61,6 +63,8 @@ ARCH_SRCS = e_sqrt.c e_sqrtf.c e_remainder.c e_remaind > .elif (${MACHINE_ARCH} == "sh") > .PATH: ${.CURDIR}/arch/sh > ARCH_SRCS = e_sqrt.c e_sqrtf.c s_fabsf.c > +.elif (${MARCHINE_ARCH} == "sparc64") > +ARCH_SRCS = fenv.c > .elif (${MACHINE_ARCH} == "vax") > .PATH: ${.CURDIR}/arch/vax > NOIEEE_ARCH = n_argred.S n_infnan.S n_sqrt.S > @@ -150,6 +154,10 @@ CPPFLAGS+= -I${.CURDIR}/src -I${.CURDIR}/src/ld128 > SRCS+= ${LONG_SRCS} > .endif > .endif > +.if (${MACHINE_ARCH} == "amd64") || (${MACHINE_ARCH} == "i386") || \ > + (${MACHINE_ARCH} == "sparc64") > +SRCS+= fenv.c > +.endif I'd put those in COMMON_SRCS. > # Substitute common sources with any arch specific sources > .for i in ${ARCH_SRCS} > @@ -169,6 +177,19 @@ MAN+= acos.3 acosh.3 asin.3 asinh.3 atan.3 atan2.3 ata > logb.3 j0.3 lgamma.3 lrint.3 lround.3 math.3 nan.3 remainder.3 \ > rint.3 round.3 sin.3 sinh.3 sqrt.3 tan.3 tanh.3 trunc.3 \ > copysign.3 ilogb.3 nextafter.3 scalbn.3 cimag.3 conj.3 cproj.3 > + > +# fenv.h interface > +MAN+= feclearexcept.3 feenableexcept.3 fegetenv.3 fegetround.3 fenv.3 > +MLINKS+=feclearexcept.3 fegetexceptflag.3 \ > + feclearexcept.3 feraiseexcept.3 \ > + feclearexcept.3 fesetexceptflag.3 \ > + feclearexcept.3 fetestexcept.3 > +MLINKS+=feenableexcept.3 fedisableexcept.3 \ > + feenableexcept.3 fegetexcept.3 > +MLINKS+=fegetenv.3 feholdexcept.3 \ > + fegetenv.3 fesetenv.3 \ > + fegetenv.3 feupdateenv.3 > +MLINKS+=fegetround.3 fesetround.3 > > MLINKS+=erf.3 erfc.3 > MLINKS+=exp.3 exp2.3 exp.3 expm1.3 exp.3 log.3 exp.3 log2.3 \ > --- /dev/null Tue Feb 22 18:22:29 2011 > +++ include/fenv.h Tue Feb 22 14:06:50 2011 > @@ -0,0 +1,63 @@ > +/* $OpenBSD$ */ > +/* $NetBSD: fenv.h,v 1.2.4.1 2011/02/08 16:18:55 bouyer Exp $ */ > +/* > + * Copyright (c) 2010 The NetBSD Foundation, Inc. > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS > + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > LIMITED > + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS > + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#if !defined(__i386__) && !defined(__amd64__) && !defined(__sparc__) > +#error "fenv.h is currently not supported for this architecture" > +#endif Removed. > + > +#ifndef _FENV_H_ > +#define _FENV_H_ > + > +#include <machine/fenv.h> > + > +__BEGIN_DECLS > + > +/* Function prototypes */ > +int feclearexcept(int); > +int fegetexceptflag(fexcept_t *, int); > +int feraiseexcept(int); > +int fesetexceptflag(const fexcept_t *, int); > +int fetestexcept(int); > +int fegetround(void); > +int fesetround(int); > +int fegetenv(fenv_t *); > +int feholdexcept(fenv_t *); > +int fesetenv(const fenv_t *); > +int feupdateenv(const fenv_t *); > + > +#if defined(_NETBSD_SOURCE) || defined(_GNU_SOURCE) > + > +int feenableexcept(int mask); > +int fedisableexcept(int mask); > +int fegetexcept(void); > + > +#endif /* _NETBSD_SOURCE || _GNU_SOURCE */ > + > +__END_DECLS > + > +#endif /* ! _FENV_H_ */ > --- /dev/null Tue Feb 22 18:22:29 2011 > +++ sys/arch/amd64/include/fenv.h Tue Feb 22 16:50:57 2011 > @@ -0,0 +1,108 @@ > +/* $OpenBSD$ */ > +/* $NetBSD: fenv.h,v 1.1 2010/07/31 21:47:54 joerg Exp $ */ > +/*- > + * Copyright (c) 2004-2005 David Schultz <das (at) FreeBSD.ORG> > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#ifndef _AMD64_FENV_H_ > +#define _AMD64_FENV_H_ > + > +#include <sys/stdint.h> > +#include <machine/fpu.h> Removed. > + > +/* > + * Each symbol representing a floating point exception expands to an integer > + * constant expression with values, such that bitwise-inclusive ORs of _all > + * combinations_ of the constants result in distinct values. > + * > + * We use such values that allow direct bitwise operations on FPU/SSE > registers. > + */ > +#define FE_INVALID 0x01 /* 000000000001 */ > +#define FE_DENORMAL 0x02 /* 000000000010 */ > +#define FE_DIVBYZERO 0x04 /* 000000000100 */ > +#define FE_OVERFLOW 0x08 /* 000000001000 */ > +#define FE_UNDERFLOW 0x10 /* 000000010000 */ > +#define FE_INEXACT 0x20 /* 000000100000 */ > + > +/* > + * The following symbol is simply the bitwise-inclusive OR of all > floating-point > + * exception constants defined above > + */ > +#define FE_ALL_EXCEPT \ > + (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) > + > +/* > + * Each symbol representing the rounding direction, expands to an integer > + * constant expression whose value is distinct non-negative value. > + * > + * We use such values that allow direct bitwise operations on FPU/SSE > registers. > + */ > +#define FE_TONEAREST 0x000 /* 000000000000 */ > +#define FE_DOWNWARD 0x400 /* 010000000000 */ > +#define FE_UPWARD 0x800 /* 100000000000 */ > +#define FE_TOWARDZERO 0xC00 /* 110000000000 */ > + > +/* > + * As compared to the x87 control word, the SSE unit's control word > + * has the rounding control bits offset by 3 and the exception mask > + * bits offset by 7. > + */ > +#define _X87_ROUNDING_MASK 0xC00 /* 110000000000 */ > +#define _SSE_ROUNDING_MASK (0xC00 << 3) > +#define _SSE_ROUND_SHIFT 3 > +#define _SSE_EMASK_SHIFT 7 > + > +/* > + * fenv_t represents the entire floating-point environment > + */ > +typedef struct { > + struct { > + uint32_t control; /* Control word register */ > + uint32_t status; /* Status word register */ > + uint32_t tag; /* Tag word register */ > + uint32_t others[4]; /* EIP, Pointer Selector, etc */ Moved to implementation namespace. > + } x87; > + > + uint32_t mxcsr; /* Control and status register */ > +} fenv_t; > + > +extern fenv_t __fe_dfl_env; > +#define FE_DFL_ENV ((const fenv_t *) &__fe_dfl_env) > + > +/* > + * fexcept_t represents the floating-point status flags collectively, > including > + * any status the implementation associates with the flags. > + * > + * A floating-point status flag is a system variable whose value is set (but > + * never cleared) when a floating-point exception is raised, which occurs as > a > + * side effect of exceptional floating-point arithmetic to provide auxiliary > + * information. > + * > + * A floating-point control mode is a system variable whose value may be set > by > + * the user to affect the subsequent behavior of floating-point arithmetic. > + */ > +typedef uint32_t fexcept_t; > + > +#endif /* ! _AMD64_FENV_H_ */ [snipped i386 and sparc64 parts] > --- /dev/null Tue Feb 22 18:22:29 2011 > +++ lib/libm/arch/amd64/fenv.c Tue Feb 22 14:25:12 2011 > @@ -0,0 +1,526 @@ > +/* $OpenBSD$ */ > +/* $NetBSD: fenv.c,v 1.1 2010/07/31 21:47:53 joerg Exp $ */ > + > +/*- > + * Copyright (c) 2004-2005 David Schultz <das (at) FreeBSD.ORG> > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#include <sys/cdefs.h> > + > +#include <assert.h> > +#include <fenv.h> > +#include <stddef.h> > +#include <string.h> > + > +#define _DIAGASSERT(x) ((void) 0) /* XXX */ > + > +/* Load x87 Control Word */ > +#define __fldcw(__cw) __asm__ __volatile__ \ > + ("fldcw %0" : : "m" (__cw)) > + > +/* No-Wait Store Control Word */ > +#define __fnstcw(__cw) __asm__ __volatile__ \ > + ("fnstcw %0" : "=m" (*(__cw))) > + > +/* No-Wait Store Status Word */ > +#define __fnstsw(__sw) __asm__ __volatile__ \ > + ("fnstsw %0" : "=am" (*(__sw))) > + > +/* No-Wait Clear Exception Flags */ > +#define __fnclex() __asm__ __volatile__ \ > + ("fnclex") > + > +/* Load x87 Environment */ > +#define __fldenv(__env) __asm__ __volatile__ \ > + ("fldenv %0" : : "m" (__env)) > + > +/* No-Wait Store x87 environment */ > +#define __fnstenv(__env) __asm__ __volatile__ \ > + ("fnstenv %0" : "=m" (*(__env))) > + > +/* Load the MXCSR register */ > +#define __ldmxcsr(__mxcsr) __asm__ __volatile__ \ > + ("ldmxcsr %0" : : "m" (__mxcsr)) > + > +/* Store the MXCSR register state */ > +#define __stmxcsr(__mxcsr) __asm__ __volatile__ \ > + ("stmxcsr %0" : "=m" (*(__mxcsr))) I'd remove those. > + > +/* > + * The following constant represents the default floating-point environment > + * (that is, the one installed at program startup) and has type pointer to > + * const-qualified fenv_t. > + * > + * It can be used as an argument to the functions within the <fenv.h> header > + * that manage the floating-point environment, namely fesetenv() and > + * feupdateenv(). > + * > + * x87 fpu registers are 16bit wide. The upper bits, 31-16, are marked as > + * RESERVED. We provide a partial floating-point environment, where we > + * define only the lower bits. The reserved bits are extracted and set by > + * the consumers of FE_DFL_ENV, during runtime. > + */ > +fenv_t __fe_dfl_env = { > + { > + __INITIAL_NPXCW__, /* Control word register */ > + 0x00000000, /* Status word register */ > + 0x0000ffff, /* Tag word register */ > + { > + 0x00000000, > + 0x00000000, > + 0x00000000, > + 0x00000000, > + }, > + }, > + __INITIAL_MXCSR__ /* MXCSR register */ > +}; The default environment should look like this: fenv_t __fe_dfl_env = { { 0xffff0000 | __INITIAL_NPXCW__, /* Control word register */ 0xffff0000, /* Status word register */ 0xffffffff, /* Tag word register */ { 0x00000000, 0x00000000, 0x00000000, 0xffff0000, }, }, __INITIAL_MXCSR__ /* MXCSR register */ }; > +#define FE_DFL_ENV ((const fenv_t *) &__fe_dfl_env) This shouldn't be here; it's a redef of fenv.h. > + > + > +/* > + * The feclearexcept() function clears the supported floating-point > exceptions > + * represented by `excepts'. > + */ > +int > +feclearexcept(int excepts) > +{ > + fenv_t fenv; > + int ex; > + > + _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); > + > + ex = excepts & FE_ALL_EXCEPT; > + > + /* Store the current x87 floating-point environment */ > + __fnstenv(&fenv); > + > + /* Clear the requested floating-point exceptions */ > + fenv.x87.status &= ~ex; > + > + /* Load the x87 floating-point environent */ > + __fldenv(fenv); > + > + /* Same for SSE environment */ > + __stmxcsr(&fenv.mxcsr); > + fenv.mxcsr &= ~ex; > + __ldmxcsr(fenv.mxcsr); > + > + /* Success */ > + return (0); > +} > + > +/* > + * The fegetexceptflag() function stores an implementation-defined > + * representation of the states of the floating-point status flags indicated > by > + * the argument excepts in the object pointed to by the argument flagp. > + */ > +int > +fegetexceptflag(fexcept_t *flagp, int excepts) > +{ > + uint32_t mxcsr; > + uint16_t x87_status; > + int ex; > + > + _DIAGASSERT(flagp != NULL); > + _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); > + > + ex = excepts & FE_ALL_EXCEPT; > + > + /* Store the current x87 status register */ > + __fnstsw(&x87_status); > + > + /* Store the MXCSR register */ > + __stmxcsr(&mxcsr); > + > + /* Store the results in flagp */ > + *flagp = (x87_status | mxcsr) & ex; > + > + /* Success */ > + return (0); > +} > + > +/* > + * The feraiseexcept() function raises the supported floating-point > exceptions > + * represented by the argument `excepts'. > + * > + * The standard explicitly allows us to execute an instruction that has the > + * exception as a side effect, but we choose to manipulate the status > register > + * directly. > + * > + * The validation of input is being deferred to fesetexceptflag(). > + */ > +int > +feraiseexcept(int excepts) > +{ > + int ex; > + > + _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); > + > + ex = excepts & FE_ALL_EXCEPT; > + fesetexceptflag((unsigned int *)&excepts, excepts); Might want to fwait here to raise the exception. > + > + /* Success */ > + return (0); > +} > + > +/* > + * This function sets the floating-point status flags indicated by the > argument > + * `excepts' to the states stored in the object pointed to by `flagp'. It > does > + * NOT raise any floating-point exceptions, but only sets the state of the > flags. > + */ > +int > +fesetexceptflag(const fexcept_t *flagp, int excepts) > +{ > + fenv_t fenv; > + int ex; > + > + _DIAGASSERT(flagp != NULL); > + _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); > + > + ex = excepts & FE_ALL_EXCEPT; > + > + /* Store the current x87 floating-point environment */ > + __fnstenv(&fenv); > + > + /* Set the requested status flags */ > + fenv.x87.status |= *flagp & ex; The status bits are not being cleared for excepts, so this is broken. > + > + /* Load the x87 floating-point environent */ > + __fldenv(fenv); > + > + /* Same for SSE environment */ > + __stmxcsr(&fenv.mxcsr); > + fenv.mxcsr |= *flagp & ex; Ditto. > + __ldmxcsr(fenv.mxcsr); > + > + /* Success */ > + return (0); > +} > + > +/* > + * The fetestexcept() function determines which of a specified subset of the > + * floating-point exception flags are currently set. The `excepts' argument > + * specifies the floating-point status flags to be queried. > + */ > +int > +fetestexcept(int excepts) > +{ > + fenv_t fenv; > + uint32_t mxcsr; > + uint16_t status; > + int ex; > + > + _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0); > + > + ex = excepts & FE_ALL_EXCEPT; > + > + /* Store the current x87 floating-point environment */ > + memset(&fenv, 0, sizeof(fenv)); > + > + __fnstenv(&fenv); No need to store the environment, we can use status and mxcsr instead. > + __fnstsw(&status); Doesn't appear to be used. > + /* Store the MXCSR register state */ > + __stmxcsr(&fenv.mxcsr); > + __stmxcsr(&mxcsr); Doesn't appear to be used. > + return ((fenv.x87.status | fenv.mxcsr) & ex); > +} > + > +/* > + * The fegetround() function gets the current rounding direction. > + */ > +int > +fegetround(void) > +{ > + uint32_t mxcsr; > + uint16_t control; > + > + /* > + * We check both the x87 floating-point unit _and_ the SSE unit. > + * Normally, those two must agree with respect to each other. If they > + * don't, it's not our fault and the result is non-determinable, in > + * which case POSIX says that a negative value should be returned. > + */ > + __fnstcw(&control); > + __stmxcsr(&mxcsr); > + > + if ((control & _X87_ROUNDING_MASK) > + != ((mxcsr & _SSE_ROUNDING_MASK) >> 3)) { > + return (-1); > + } > + > + return (control & _X87_ROUNDING_MASK); > +} > + > +/* > + * The fesetround() function establishes the rounding direction represented > by > + * its argument `round'. If the argument is not equal to the value of a > rounding > + * direction macro, the rounding direction is not changed. > + */ > +int > +fesetround(int round) > +{ > + uint32_t mxcsr; > + uint16_t control; > + > + /* Check whether requested rounding direction is supported */ > + if (round & (~_X87_ROUNDING_MASK)) > + return (-1); > + > + /* Store the current x87 control word register */ > + __fnstcw(&control); > + > + /* > + * Set the rounding direction > + * Rounding Control is bits 10-11, so shift appropriately > + */ > + control &= ~_X87_ROUNDING_MASK; > + control |= round; > + > + /* Load the x87 control word register */ > + __fldcw(control); > + > + /* > + * Same for the SSE environment > + * Rounding Control is bits 13-14, so shift appropriately > + */ > + __stmxcsr(&mxcsr); > + mxcsr &= ~_SSE_ROUNDING_MASK; > + mxcsr |= (round << _SSE_ROUND_SHIFT); > + __ldmxcsr(mxcsr); > + > + /* Success */ > + return (0); > +} > + > +/* > + * The fegetenv() function attempts to store the current floating-point > + * environment in the object pointed to by envp. > + */ > +int > +fegetenv(fenv_t *envp) > +{ > + _DIAGASSERT(envp != NULL); > + > + /* Store the current x87 floating-point environment */ > + __fnstenv(envp); > + > + /* Store the MXCSR register state */ > + __stmxcsr(&envp->mxcsr); > + > + /* > + * When an FNSTENV instruction is executed, all pending exceptions are > + * essentially lost (either the x87 FPU status register is cleared or > all > + * exceptions are masked). > + * > + * 8.6 X87 FPU EXCEPTION SYNCHRONIZATION - > + * Intel(R) 64 and IA-32 Architectures Softare Developer's Manual - Vol > 1 > + * > + */ > + __fldcw(envp->x87.control); > + > + /* Success */ > + return (0); > +} > + > +/* > + * The feholdexcept() function saves the current floating-point environment > + * in the object pointed to by envp, clears the floating-point status flags, > and > + * then installs a non-stop (continue on floating-point exceptions) mode, if > + * available, for all floating-point exceptions. > + */ > +int > +feholdexcept(fenv_t *envp) > +{ > + uint32_t mxcsr; > + > + _DIAGASSERT(envp != NULL); > + > + /* Store the current x87 floating-point environment */ > + __fnstenv(envp); > + > + /* Clear all exception flags in FPU */ > + __fnclex(); > + > + /* Store the MXCSR register state */ > + __stmxcsr(&envp->mxcsr); > + > + /* Clear exception flags in MXCSR XXX */ > + mxcsr = envp->mxcsr; > + mxcsr &= ~FE_ALL_EXCEPT; > + > + /* Mask all exceptions */ > + mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT; > + > + __ldmxcsr(mxcsr); > + > + /* Success */ > + return (0); > +} > + > +/* > + * The fesetenv() function attempts to establish the floating-point > environment > + * represented by the object pointed to by envp. The argument `envp' points > + * to an object set by a call to fegetenv() or feholdexcept(), or equal a > + * floating-point environment macro. The fesetenv() function does not raise > + * floating-point exceptions, but only installs the state of the > floating-point > + * status flags represented through its argument. > + */ > +int > +fesetenv(const fenv_t *envp) > +{ > + fenv_t fenv; > + > + _DIAGASSERT(envp != NULL); > + > + /* Store the x87 floating-point environment */ > + memset(&fenv, 0, sizeof fenv); > + __fnstenv(&fenv); > + > + __fe_dfl_env.x87.control = (fenv.x87.control & 0xffff0000) > + | (__fe_dfl_env.x87.control & 0x0000ffff); > + __fe_dfl_env.x87.status = (fenv.x87.status & 0xffff0000) > + | (__fe_dfl_env.x87.status & 0x0000ffff); > + __fe_dfl_env.x87.tag = (fenv.x87.tag & 0xffff0000) > + | (__fe_dfl_env.x87.tag & 0x0000ffff); > + __fe_dfl_env.x87.others[3] = (fenv.x87.others[3] & 0xffff0000) > + | (__fe_dfl_env.x87.others[3] & 0x0000ffff); > + __fldenv(*envp); > + > + /* Store the MXCSR register */ > + __ldmxcsr(envp->mxcsr); > + > + /* Success */ > + return (0); > +} > + > +/* > + * The feupdateenv() function saves the currently raised floating-point > + * exceptions in its automatic storage, installs the floating-point > environment > + * represented by the object pointed to by `envp', and then raises the saved > + * floating-point exceptions. The argument `envp' shall point to an object > set > + * by a call to feholdexcept() or fegetenv(), or equal a floating-point > + * environment macro. > + */ > +int > +feupdateenv(const fenv_t *envp) > +{ > + fenv_t fenv; > + uint32_t mxcsr; > + uint16_t sw; > + > + _DIAGASSERT(envp != NULL); > + > + /* Store the x87 floating-point environment */ > + memset(&fenv, 0, sizeof(fenv)); > + __fnstenv(&fenv); > + > + __fe_dfl_env.x87.control = (fenv.x87.control & 0xffff0000) > + | (__fe_dfl_env.x87.control & 0x0000ffff); > + __fe_dfl_env.x87.status = (fenv.x87.status & 0xffff0000) > + | (__fe_dfl_env.x87.status & 0x0000ffff); > + __fe_dfl_env.x87.tag = (fenv.x87.tag & 0xffff0000) > + | (__fe_dfl_env.x87.tag & 0x0000ffff); > + __fe_dfl_env.x87.others[3] = (fenv.x87.others[3] & 0xffff0000) > + | (__fe_dfl_env.x87.others[3] & 0x0000ffff); > + > + /* Store the x87 status register */ > + __fnstsw(&sw); > + > + /* Store the MXCSR register */ > + __stmxcsr(&mxcsr); > + > + /* Install new floating-point environment */ > + fesetenv(envp); > + > + /* Raise any previously accumulated exceptions */ > + feraiseexcept((sw | mxcsr) & FE_ALL_EXCEPT); > + > + /* Success */ > + return (0); > +} > + > +/* > + * The following functions are extentions to the standard > + */ > +int > +feenableexcept(int mask) > +{ > + uint32_t mxcsr, omask; > + uint16_t control; > + > + _DIAGASSERT((mask & ~FE_ALL_EXCEPT) == 0); > + mask &= FE_ALL_EXCEPT; > + > + __fnstcw(&control); > + __stmxcsr(&mxcsr); > + > + omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; > + control &= ~mask; > + __fldcw(control); > + > + mxcsr &= ~(mask << _SSE_EMASK_SHIFT); > + __ldmxcsr(mxcsr); > + > + return (~omask); > + > +} > + > +int > +fedisableexcept(int mask) > +{ > + uint32_t mxcsr, omask; > + uint16_t control; > + > + _DIAGASSERT((mask & ~FE_ALL_EXCEPT) == 0); > + > + __fnstcw(&control); > + __stmxcsr(&mxcsr); > + > + omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; > + control |= mask; > + __fldcw(control); > + > + mxcsr |= mask << _SSE_EMASK_SHIFT; > + __ldmxcsr(mxcsr); > + > + return (~omask); > +} > + > +int > +fegetexcept(void) > +{ > + uint16_t control; > + > + /* > + * We assume that the masks for the x87 and the SSE unit are > + * the same. > + */ > + __fnstcw(&control); > + > + return (control & FE_ALL_EXCEPT); This returns inverse of the result; the function is supposed to return "the set of all currently enabled exceptions". > +} > + [snipped i386 and sparc64 parts] Index: include/Makefile =================================================================== RCS file: /cvs/src/include/Makefile,v retrieving revision 1.157 diff -u -r1.157 Makefile --- include/Makefile 28 Oct 2010 08:34:37 -0000 1.157 +++ include/Makefile 18 Mar 2011 17:20:42 -0000 @@ -12,8 +12,8 @@ # Missing: mp.h FILES= a.out.h ar.h assert.h bitstring.h blf.h bm.h bsd_auth.h \ complex.h cpio.h ctype.h curses.h db.h dbm.h des.h dirent.h disktab.h \ - dlfcn.h elf_abi.h err.h errno.h fnmatch.h fstab.h fts.h ftw.h getopt.h \ - glob.h grp.h ifaddrs.h inttypes.h iso646.h kvm.h langinfo.h \ + dlfcn.h elf_abi.h err.h errno.h fenv.h fnmatch.h fstab.h fts.h ftw.h \ + getopt.h glob.h grp.h ifaddrs.h inttypes.h iso646.h kvm.h langinfo.h \ libgen.h limits.h locale.h login_cap.h malloc.h math.h md4.h \ md5.h memory.h mpool.h ndbm.h netdb.h netgroup.h nlist.h nl_types.h \ ohash.h paths.h poll.h pwd.h ranlib.h re_comp.h \ Index: include/fenv.h =================================================================== RCS file: include/fenv.h diff -N include/fenv.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/fenv.h 18 Mar 2011 20:38:10 -0000 @@ -0,0 +1,59 @@ +/* $OpenBSD$ */ +/* $NetBSD: fenv.h,v 1.2.4.1 2011/02/08 16:18:55 bouyer Exp $ */ + +/* + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FENV_H_ +#define _FENV_H_ + +#include <sys/cdefs.h> +#include <machine/fenv.h> + +__BEGIN_DECLS + +int feclearexcept(int); +int fegetexceptflag(fexcept_t *, int); +int feraiseexcept(int); +int fesetexceptflag(const fexcept_t *, int); +int fetestexcept(int); + +int fegetround(void); +int fesetround(int); +int fegetenv(fenv_t *); +int feholdexcept(fenv_t *); +int fesetenv(const fenv_t *); +int feupdateenv(const fenv_t *); + +#if __BSD_VISIBLE || defined(_GNU_SOURCE) +int feenableexcept(int mask); +int fedisableexcept(int mask); +int fegetexcept(void); +#endif /* __BSD_VISIBLE || defined(_GNU_SOURCE) */ + +__END_DECLS + +#endif /* ! _FENV_H_ */ Index: sys/arch/amd64/include/fenv.h =================================================================== RCS file: sys/arch/amd64/include/fenv.h diff -N sys/arch/amd64/include/fenv.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/amd64/include/fenv.h 18 Mar 2011 20:37:58 -0000 @@ -0,0 +1,105 @@ +/* $OpenBSD$ */ +/* $NetBSD: fenv.h,v 1.1 2010/07/31 21:47:54 joerg Exp $ */ + +/*- + * Copyright (c) 2004-2005 David Schultz <das (at) FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AMD64_FENV_H_ +#define _AMD64_FENV_H_ + +/* + * Each symbol representing a floating point exception expands to an integer + * constant expression with values, such that bitwise-inclusive ORs of _all + * combinations_ of the constants result in distinct values. + * + * We use such values that allow direct bitwise operations on FPU/SSE registers. + */ +#define FE_INVALID 0x01 +#define FE_DENORMAL 0x02 +#define FE_DIVBYZERO 0x04 +#define FE_OVERFLOW 0x08 +#define FE_UNDERFLOW 0x10 +#define FE_INEXACT 0x20 + +/* + * The following symbol is simply the bitwise-inclusive OR of all floating-point + * exception constants defined above. + */ +#define FE_ALL_EXCEPT \ + (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +/* + * Each symbol representing the rounding direction, expands to an integer + * constant expression whose value is distinct non-negative value. + * + * We use such values that allow direct bitwise operations on FPU/SSE registers. + */ +#define FE_TONEAREST 0x000 +#define FE_DOWNWARD 0x400 +#define FE_UPWARD 0x800 +#define FE_TOWARDZERO 0xC00 + +/* + * As compared to the x87 control word, the SSE unit's control word + * has the rounding control bits offset by 3 and the exception mask + * bits offset by 7. + */ +#define _X87_ROUNDING_MASK 0xC00 +#define _SSE_ROUNDING_MASK (0xC00 << 3) +#define _SSE_ROUND_SHIFT 3 +#define _SSE_EMASK_SHIFT 7 + +/* + * fenv_t represents the entire floating-point environment + */ +typedef struct { + struct { + unsigned int __control; /* Control word register */ + unsigned int __status; /* Status word register */ + unsigned int __tag; /* Tag word register */ + unsigned int __others[4]; /* EIP, Pointer Selector, etc */ + } x87; + unsigned int __mxcsr; /* Control, status register */ +} fenv_t; + +extern fenv_t __fe_dfl_env; +#define FE_DFL_ENV ((const fenv_t *) &__fe_dfl_env) + +/* + * fexcept_t represents the floating-point status flags collectively, including + * any status the implementation associates with the flags. + * + * A floating-point status flag is a system variable whose value is set (but + * never cleared) when a floating-point exception is raised, which occurs as a + * side effect of exceptional floating-point arithmetic to provide auxiliary + * information. + * + * A floating-point control mode is a system variable whose value may be set by + * the user to affect the subsequent behavior of floating-point arithmetic. + */ +typedef unsigned int fexcept_t; + +#endif /* ! _AMD64_FENV_H_ */ Index: lib/libm/Makefile =================================================================== RCS file: /cvs/src/lib/libm/Makefile,v retrieving revision 1.76 diff -u -r1.76 Makefile --- lib/libm/Makefile 19 Jul 2010 12:48:23 -0000 1.76 +++ lib/libm/Makefile 20 Mar 2011 00:43:57 -0000 @@ -82,6 +82,7 @@ e_rem_pio2.c \ e_rem_pio2f.c e_remainder.c e_remainderf.c e_scalb.c e_scalbf.c \ e_sinh.c e_sinhf.c e_sqrt.c e_sqrtf.c \ + fenv.c \ k_cos.c k_cosf.c k_rem_pio2.c k_rem_pio2f.c k_sin.c k_sinf.c \ k_tan.c k_tanf.c \ s_lround.c s_lroundf.c s_llround.c s_llroundf.c \ Index: lib/libm/shlib_version =================================================================== RCS file: /cvs/src/lib/libm/shlib_version,v retrieving revision 1.12 diff -u -r1.12 shlib_version @@ -1,2 +1,2 @@ major=5 -minor=2 +minor=3 Index: lib/libm/arch/amd64/fenv.c =================================================================== RCS file: lib/libm/arch/amd64/fenv.c diff -N lib/libm/arch/amd64/fenv.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lib/libm/arch/amd64/fenv.c 19 Mar 2011 21:35:30 -0000 @@ -0,0 +1,451 @@ +/* $OpenBSD$ */ +/* $NetBSD: fenv.c,v 1.1 2010/07/31 21:47:53 joerg Exp $ */ + +/*- + * Copyright (c) 2004-2005 David Schultz <das (at) FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include <machine/fpu.h> + +#include <fenv.h> +#include <string.h> + +/* + * The following constant represents the default floating-point environment + * (that is, the one installed at program startup) and has type pointer to + * const-qualified fenv_t. + * + * It can be used as an argument to the functions within the <fenv.h> header + * that manage the floating-point environment, namely fesetenv() and + * feupdateenv(). + * + * x87 fpu registers are 16bit wide. The upper bits, 31-16, are marked as + * RESERVED. We provide a partial floating-point environment, where we + * define only the lower bits. The reserved bits are extracted and set by + * the consumers of FE_DFL_ENV, during runtime. + */ +fenv_t __fe_dfl_env = { + { + 0xffff0000 | __INITIAL_NPXCW__, /* Control word register */ + 0xffff0000, /* Status word register */ + 0xffffffff, /* Tag word register */ + { + 0x00000000, + 0x00000000, + 0x00000000, + 0xffff0000, + }, + }, + __INITIAL_MXCSR__ /* MXCSR register */ +}; + + +/* + * The feclearexcept() function clears the supported floating-point exceptions + * represented by `excepts'. + */ +int +feclearexcept(int excepts) +{ + fenv_t fenv; + unsigned int mxcsr; + + excepts &= FE_ALL_EXCEPT; + + /* Store the current x87 floating-point environment */ + __asm__ __volatile__ ("fnstenv %0" : "=m" (*&fenv)); + + /* Clear the requested floating-point exceptions */ + fenv.x87.__status &= ~excepts; + + /* Load the x87 floating-point environent */ + __asm__ __volatile__ ("fldenv %0" : : "m" (fenv)); + + /* Same for SSE environment */ + __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); + mxcsr &= ~excepts; + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (mxcsr)); + + return (0); +} + +/* + * The fegetexceptflag() function stores an implementation-defined + * representation of the states of the floating-point status flags indicated by + * the argument excepts in the object pointed to by the argument flagp. + */ +int +fegetexceptflag(fexcept_t *flagp, int excepts) +{ + unsigned short x87_status; + unsigned int mxcsr; + + excepts &= FE_ALL_EXCEPT; + + /* Store the current x87 status register */ + __asm__ __volatile__ ("fnstsw %0" : "=am" (*&x87_status)); + + /* Store the MXCSR register */ + __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); + + /* Store the results in flagp */ + *flagp = (x87_status | mxcsr) & excepts; + + return (0); +} + +/* + * The feraiseexcept() function raises the supported floating-point exceptions + * represented by the argument `excepts'. + * + * The standard explicitly allows us to execute an instruction that has the + * exception as a side effect, but we choose to manipulate the status register + * directly. + * + * The validation of input is being deferred to fesetexceptflag(). + */ +int +feraiseexcept(int excepts) +{ + excepts &= FE_ALL_EXCEPT; + + fesetexceptflag((unsigned int *)&excepts, excepts); + __asm__ __volatile__ ("fwait"); + + return (0); +} + +/* + * This function sets the floating-point status flags indicated by the argument + * `excepts' to the states stored in the object pointed to by `flagp'. It does + * NOT raise any floating-point exceptions, but only sets the state of the flags. + */ +int +fesetexceptflag(const fexcept_t *flagp, int excepts) +{ + fenv_t fenv; + unsigned int mxcsr; + + excepts &= FE_ALL_EXCEPT; + + /* Store the current x87 floating-point environment */ + __asm__ __volatile__ ("fnstenv %0" : "=m" (*&fenv)); + + /* Set the requested status flags */ + fenv.x87.__status &= ~excepts; + fenv.x87.__status |= *flagp & excepts; + + /* Load the x87 floating-point environent */ + __asm__ __volatile__ ("fldenv %0" : : "m" (fenv)); + + /* Same for SSE environment */ + __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); + mxcsr &= ~excepts; + mxcsr |= *flagp & excepts; + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (mxcsr)); + + return (0); +} + +/* + * The fetestexcept() function determines which of a specified subset of the + * floating-point exception flags are currently set. The `excepts' argument + * specifies the floating-point status flags to be queried. + */ +int +fetestexcept(int excepts) +{ + unsigned short x87_status; + unsigned int mxcsr; + + excepts &= FE_ALL_EXCEPT; + + /* Store the current x87 status register */ + __asm__ __volatile__ ("fnstsw %0" : "=am" (*&x87_status)); + + /* Store the MXCSR register state */ + __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); + + return ((x87_status | mxcsr) & excepts); +} + +/* + * The fegetround() function gets the current rounding direction. + */ +int +fegetround(void) +{ + unsigned short control; + unsigned int mxcsr; + + /* + * We check both the x87 floating-point unit _and_ the SSE unit. + * Normally, those two must agree with respect to each other. If they + * don't, it's not our fault and the result is non-determinable, in + * which case POSIX says that a negative value should be returned. + */ + __asm__ __volatile__ ("fnstcw %0" : "=m" (*&control)); + __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); + + if ((control & _X87_ROUNDING_MASK) + != ((mxcsr & _SSE_ROUNDING_MASK) >> 3)) { + return (-1); + } + + return (control & _X87_ROUNDING_MASK); +} + +/* + * The fesetround() function establishes the rounding direction represented by + * its argument `round'. If the argument is not equal to the value of a rounding + * direction macro, the rounding direction is not changed. + */ +int +fesetround(int round) +{ + unsigned short control; + unsigned int mxcsr; + + /* Check whether requested rounding direction is supported */ + if (round & (~_X87_ROUNDING_MASK)) + return (-1); + + /* Store the current x87 control word register */ + __asm__ __volatile__ ("fnstcw %0" : "=m" (*&control)); + + /* + * Set the rounding direction + * Rounding Control is bits 10-11, so shift appropriately + */ + control &= ~_X87_ROUNDING_MASK; + control |= round; + + /* Load the x87 control word register */ + __asm__ __volatile__ ("fldcw %0" : : "m" (control)); + + /* + * Same for the SSE environment + * Rounding Control is bits 13-14, so shift appropriately + */ + __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); + mxcsr &= ~_SSE_ROUNDING_MASK; + mxcsr |= (round << _SSE_ROUND_SHIFT); + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (mxcsr)); + + return (0); +} + +/* + * The fegetenv() function attempts to store the current floating-point + * environment in the object pointed to by envp. + */ +int +fegetenv(fenv_t *envp) +{ + /* Store the current x87 floating-point environment */ + __asm__ __volatile__ ("fnstenv %0" : "=m" (*envp)); + + /* Store the MXCSR register state */ + __asm__ __volatile__ ("stmxcsr %0" : "=m" (envp->__mxcsr)); + + /* + * When an FNSTENV instruction is executed, all pending exceptions are + * essentially lost (either the x87 FPU status register is cleared or all + * exceptions are masked). + * + * 8.6 X87 FPU EXCEPTION SYNCHRONIZATION - + * Intel(R) 64 and IA-32 Architectures Softare Developer's Manual - Vol 1 + */ + __asm__ __volatile__ ("fldcw %0" : : "m" (envp->x87.__control)); + + return (0); +} + +/* + * The feholdexcept() function saves the current floating-point environment + * in the object pointed to by envp, clears the floating-point status flags, and + * then installs a non-stop (continue on floating-point exceptions) mode, if + * available, for all floating-point exceptions. + */ +int +feholdexcept(fenv_t *envp) +{ + unsigned int mxcsr; + + /* Store the current x87 floating-point environment */ + __asm__ __volatile__ ("fnstenv %0" : "=m" (*(envp))); + + /* Clear all exception flags in FPU */ + __asm__ __volatile__ ("fnclex"); + + /* Store the MXCSR register state */ + __asm__ __volatile__ ("stmxcsr %0" : "=m" (envp->__mxcsr)); + + /* Clear exception flags in MXCSR XXX */ + mxcsr = envp->__mxcsr; + mxcsr &= ~FE_ALL_EXCEPT; + + /* Mask all exceptions */ + mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT; + + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (mxcsr)); + + return (0); +} + +/* + * The fesetenv() function attempts to establish the floating-point environment + * represented by the object pointed to by envp. The argument `envp' points + * to an object set by a call to fegetenv() or feholdexcept(), or equal a + * floating-point environment macro. The fesetenv() function does not raise + * floating-point exceptions, but only installs the state of the floating-point + * status flags represented through its argument. + */ +int +fesetenv(const fenv_t *envp) +{ + fenv_t fenv; + + /* Store the x87 floating-point environment */ + memset(&fenv, 0, sizeof fenv); + __asm__ __volatile__ ("fnstenv %0" : "=m" (*&fenv)); + + __fe_dfl_env.x87.__control = (fenv.x87.__control & 0xffff0000) + | (__fe_dfl_env.x87.__control & 0x0000ffff); + __fe_dfl_env.x87.__status = (fenv.x87.__status & 0xffff0000) + | (__fe_dfl_env.x87.__status & 0x0000ffff); + __fe_dfl_env.x87.__tag = (fenv.x87.__tag & 0xffff0000) + | (__fe_dfl_env.x87.__tag & 0x0000ffff); + __fe_dfl_env.x87.__others[3] = (fenv.x87.__others[3] & 0xffff0000) + | (__fe_dfl_env.x87.__others[3] & 0x0000ffff); + __asm__ __volatile__ ("fldenv %0" : : "m" (*envp)); + + /* Store the MXCSR register */ + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (envp->__mxcsr)); + + return (0); +} + +/* + * The feupdateenv() function saves the currently raised floating-point + * exceptions in its automatic storage, installs the floating-point environment + * represented by the object pointed to by `envp', and then raises the saved + * floating-point exceptions. The argument `envp' shall point to an object set + * by a call to feholdexcept() or fegetenv(), or equal a floating-point + * environment macro. + */ +int +feupdateenv(const fenv_t *envp) +{ + fenv_t fenv; + unsigned short x87_status; + unsigned int mxcsr; + + /* Store the x87 floating-point environment */ + memset(&fenv, 0, sizeof(fenv)); + __asm__ __volatile__ ("fnstenv %0" : "=m" (*(&fenv))); + + __fe_dfl_env.x87.__control = (fenv.x87.__control & 0xffff0000) + | (__fe_dfl_env.x87.__control & 0x0000ffff); + __fe_dfl_env.x87.__status = (fenv.x87.__status & 0xffff0000) + | (__fe_dfl_env.x87.__status & 0x0000ffff); + __fe_dfl_env.x87.__tag = (fenv.x87.__tag & 0xffff0000) + | (__fe_dfl_env.x87.__tag & 0x0000ffff); + __fe_dfl_env.x87.__others[3] = (fenv.x87.__others[3] & 0xffff0000) + | (__fe_dfl_env.x87.__others[3] & 0x0000ffff); + + /* Store the x87 status register */ + __asm__ __volatile__ ("fnstsw %0" : "=am" (*&x87_status)); + + /* Store the MXCSR register */ + __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); + + /* Install new floating-point environment */ + fesetenv(envp); + + /* Raise any previously accumulated exceptions */ + feraiseexcept(x87_status | mxcsr); + + return (0); +} + +/* + * The following functions are extentions to the standard + */ +int +feenableexcept(int mask) +{ + unsigned int mxcsr, omask; + unsigned short control; + + mask &= FE_ALL_EXCEPT; + + __asm__ __volatile__ ("fnstcw %0" : "=m" (*&control)); + __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); + + omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; + control &= ~mask; + __asm__ __volatile__ ("fldcw %0" : : "m" (control)); + + mxcsr &= ~(mask << _SSE_EMASK_SHIFT); + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (mxcsr)); + + return (~omask); + +} + +int +fedisableexcept(int mask) +{ + unsigned int mxcsr, omask; + unsigned short control; + + __asm__ __volatile__ ("fnstcw %0" : "=m" (*&control)); + __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); + + omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; + control |= mask; + __asm__ __volatile__ ("fldcw %0" : : "m" (control)); + + mxcsr |= mask << _SSE_EMASK_SHIFT; + __asm__ __volatile__ ("ldmxcsr %0" : : "m" (mxcsr)); + + return (~omask); +} + +int +fegetexcept(void) +{ + unsigned short control; + + /* + * We assume that the masks for the x87 and the SSE unit are + * the same. + */ + __asm__ __volatile__ ("fnstcw %0" : "=m" (*&control)); + + return (~control & FE_ALL_EXCEPT); +}
