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);
+}

Reply via email to