1259698Sdim/*- 2259698Sdim * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> 3259698Sdim * All rights reserved. 4259698Sdim * 5259698Sdim * Redistribution and use in source and binary forms, with or without 6259698Sdim * modification, are permitted provided that the following conditions 7259698Sdim * are met: 8259698Sdim * 1. Redistributions of source code must retain the above copyright 9259698Sdim * notice, this list of conditions and the following disclaimer. 10259698Sdim * 2. Redistributions in binary form must reproduce the above copyright 11259698Sdim * notice, this list of conditions and the following disclaimer in the 12259698Sdim * documentation and/or other materials provided with the distribution. 13259698Sdim * 14259698Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15259698Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16259698Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17259698Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18259698Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19259698Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20259698Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21259698Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22259698Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23259698Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24259698Sdim * SUCH DAMAGE. 25259698Sdim * 26259698Sdim * $FreeBSD$ 27259698Sdim */ 28259698Sdim 29259698Sdim#include <sys/cdefs.h> 30259698Sdim#include <sys/types.h> 31259698Sdim#include <machine/fpu.h> 32259698Sdim 33259698Sdim#define __fenv_static 34259698Sdim#include "fenv.h" 35259698Sdim 36259698Sdim#ifdef __GNUC_GNU_INLINE__ 37259698Sdim#error "This file must be compiled with C99 'inline' semantics" 38259698Sdim#endif 39259698Sdim 40259698Sdimconst fenv_t __fe_dfl_env = { 41259698Sdim { 0xffff0000 | __INITIAL_FPUCW__, 42259698Sdim 0xffff0000, 43259698Sdim 0xffffffff, 44259698Sdim { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45259698Sdim 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff } 46259698Sdim }, 47259698Sdim __INITIAL_MXCSR__ 48259698Sdim}; 49259698Sdim 50259698Sdimextern inline int feclearexcept(int __excepts); 51259698Sdimextern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); 52259698Sdim 53259698Sdimint 54259698Sdimfesetexceptflag(const fexcept_t *flagp, int excepts) 55259698Sdim{ 56259698Sdim fenv_t env; 57259698Sdim 58259698Sdim __fnstenv(&env.__x87); 59259698Sdim env.__x87.__status &= ~excepts; 60259698Sdim env.__x87.__status |= *flagp & excepts; 61259698Sdim __fldenv(env.__x87); 62259698Sdim 63259698Sdim __stmxcsr(&env.__mxcsr); 64259698Sdim env.__mxcsr &= ~excepts; 65259698Sdim env.__mxcsr |= *flagp & excepts; 66259698Sdim __ldmxcsr(env.__mxcsr); 67259698Sdim 68259698Sdim return (0); 69259698Sdim} 70259698Sdim 71259698Sdimint 72259698Sdimferaiseexcept(int excepts) 73259698Sdim{ 74259698Sdim fexcept_t ex = excepts; 75259698Sdim 76259698Sdim fesetexceptflag(&ex, excepts); 77259698Sdim __fwait(); 78259698Sdim return (0); 79259698Sdim} 80259698Sdim 81259698Sdimextern inline int fetestexcept(int __excepts); 82259698Sdimextern inline int fegetround(void); 83259698Sdimextern inline int fesetround(int __round); 84259698Sdim 85259698Sdimint 86259698Sdimfegetenv(fenv_t *envp) 87259698Sdim{ 88259698Sdim 89259698Sdim __fnstenv(&envp->__x87); 90259698Sdim __stmxcsr(&envp->__mxcsr); 91259698Sdim /* 92259698Sdim * fnstenv masks all exceptions, so we need to restore the 93259698Sdim * control word to avoid this side effect. 94259698Sdim */ 95259698Sdim __fldcw(envp->__x87.__control); 96259698Sdim return (0); 97259698Sdim} 98259698Sdim 99259698Sdimint 100259698Sdimfeholdexcept(fenv_t *envp) 101259698Sdim{ 102259698Sdim __uint32_t mxcsr; 103259698Sdim 104259698Sdim __stmxcsr(&mxcsr); 105259698Sdim __fnstenv(&envp->__x87); 106259698Sdim __fnclex(); 107259698Sdim envp->__mxcsr = mxcsr; 108259698Sdim mxcsr &= ~FE_ALL_EXCEPT; 109259698Sdim mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT; 110259698Sdim __ldmxcsr(mxcsr); 111 return (0); 112} 113 114extern inline int fesetenv(const fenv_t *__envp); 115 116int 117feupdateenv(const fenv_t *envp) 118{ 119 __uint32_t mxcsr; 120 __uint16_t status; 121 122 __fnstsw(&status); 123 __stmxcsr(&mxcsr); 124 fesetenv(envp); 125 feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT); 126 return (0); 127} 128 129int 130__feenableexcept(int mask) 131{ 132 __uint32_t mxcsr, omask; 133 __uint16_t control; 134 135 mask &= FE_ALL_EXCEPT; 136 __fnstcw(&control); 137 __stmxcsr(&mxcsr); 138 omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; 139 control &= ~mask; 140 __fldcw(control); 141 mxcsr &= ~(mask << _SSE_EMASK_SHIFT); 142 __ldmxcsr(mxcsr); 143 return (omask); 144} 145 146int 147__fedisableexcept(int mask) 148{ 149 __uint32_t mxcsr, omask; 150 __uint16_t control; 151 152 mask &= FE_ALL_EXCEPT; 153 __fnstcw(&control); 154 __stmxcsr(&mxcsr); 155 omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; 156 control |= mask; 157 __fldcw(control); 158 mxcsr |= mask << _SSE_EMASK_SHIFT; 159 __ldmxcsr(mxcsr); 160 return (omask); 161} 162 163__weak_reference(__feenableexcept, feenableexcept); 164__weak_reference(__fedisableexcept, fedisableexcept); 165