1130142Sdas/*- 2143708Sdas * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> 3130142Sdas * All rights reserved. 4130142Sdas * 5130142Sdas * Redistribution and use in source and binary forms, with or without 6130142Sdas * modification, are permitted provided that the following conditions 7130142Sdas * are met: 8130142Sdas * 1. Redistributions of source code must retain the above copyright 9130142Sdas * notice, this list of conditions and the following disclaimer. 10130142Sdas * 2. Redistributions in binary form must reproduce the above copyright 11130142Sdas * notice, this list of conditions and the following disclaimer in the 12130142Sdas * documentation and/or other materials provided with the distribution. 13130142Sdas * 14130142Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15130142Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16130142Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17130142Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18130142Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19130142Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20130142Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21130142Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22130142Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23130142Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24130142Sdas * SUCH DAMAGE. 25130142Sdas * 26130142Sdas * $FreeBSD$ 27130142Sdas */ 28130142Sdas 29130142Sdas#include <sys/cdefs.h> 30130142Sdas#include <sys/types.h> 31130142Sdas#include <machine/fpu.h> 32226218Sdas 33226218Sdas#define __fenv_static 34226415Sdas#include "fenv.h" 35130142Sdas 36226218Sdas#ifdef __GNUC_GNU_INLINE__ 37226218Sdas#error "This file must be compiled with C99 'inline' semantics" 38226218Sdas#endif 39226218Sdas 40130142Sdasconst fenv_t __fe_dfl_env = { 41130142Sdas { 0xffff0000 | __INITIAL_FPUCW__, 42130142Sdas 0xffff0000, 43130142Sdas 0xffffffff, 44130142Sdas { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45130142Sdas 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff } 46130142Sdas }, 47130142Sdas __INITIAL_MXCSR__ 48130142Sdas}; 49130142Sdas 50226218Sdasextern inline int feclearexcept(int __excepts); 51226218Sdasextern inline int fegetexceptflag(fexcept_t *__flagp, int __excepts); 52226218Sdas 53130142Sdasint 54130142Sdasfesetexceptflag(const fexcept_t *flagp, int excepts) 55130142Sdas{ 56130142Sdas fenv_t env; 57130142Sdas 58130142Sdas __fnstenv(&env.__x87); 59130142Sdas env.__x87.__status &= ~excepts; 60130142Sdas env.__x87.__status |= *flagp & excepts; 61130142Sdas __fldenv(env.__x87); 62130142Sdas 63130142Sdas __stmxcsr(&env.__mxcsr); 64130142Sdas env.__mxcsr &= ~excepts; 65130142Sdas env.__mxcsr |= *flagp & excepts; 66130142Sdas __ldmxcsr(env.__mxcsr); 67130142Sdas 68130142Sdas return (0); 69130142Sdas} 70130142Sdas 71130142Sdasint 72130142Sdasferaiseexcept(int excepts) 73130142Sdas{ 74130142Sdas fexcept_t ex = excepts; 75130142Sdas 76130142Sdas fesetexceptflag(&ex, excepts); 77130142Sdas __fwait(); 78130142Sdas return (0); 79130142Sdas} 80130142Sdas 81226218Sdasextern inline int fetestexcept(int __excepts); 82226218Sdasextern inline int fegetround(void); 83226218Sdasextern inline int fesetround(int __round); 84226218Sdas 85130142Sdasint 86130142Sdasfegetenv(fenv_t *envp) 87130142Sdas{ 88130142Sdas 89165795Sdas __fnstenv(&envp->__x87); 90165795Sdas __stmxcsr(&envp->__mxcsr); 91130142Sdas /* 92165795Sdas * fnstenv masks all exceptions, so we need to restore the 93165795Sdas * control word to avoid this side effect. 94130142Sdas */ 95165795Sdas __fldcw(envp->__x87.__control); 96130142Sdas return (0); 97130142Sdas} 98130142Sdas 99130142Sdasint 100130142Sdasfeholdexcept(fenv_t *envp) 101130142Sdas{ 102203441Skib __uint32_t mxcsr; 103130142Sdas 104130142Sdas __stmxcsr(&mxcsr); 105130142Sdas __fnstenv(&envp->__x87); 106130142Sdas __fnclex(); 107130142Sdas envp->__mxcsr = mxcsr; 108130328Sdas mxcsr &= ~FE_ALL_EXCEPT; 109130142Sdas mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT; 110130142Sdas __ldmxcsr(mxcsr); 111130142Sdas return (0); 112130142Sdas} 113130142Sdas 114226218Sdasextern inline int fesetenv(const fenv_t *__envp); 115226218Sdas 116130142Sdasint 117130142Sdasfeupdateenv(const fenv_t *envp) 118130142Sdas{ 119203441Skib __uint32_t mxcsr; 120203441Skib __uint16_t status; 121130142Sdas 122130142Sdas __fnstsw(&status); 123130142Sdas __stmxcsr(&mxcsr); 124130142Sdas fesetenv(envp); 125130142Sdas feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT); 126130142Sdas return (0); 127130142Sdas} 128130142Sdas 129130142Sdasint 130143708Sdas__feenableexcept(int mask) 131130142Sdas{ 132203441Skib __uint32_t mxcsr, omask; 133203441Skib __uint16_t control; 134130142Sdas 135143708Sdas mask &= FE_ALL_EXCEPT; 136130142Sdas __fnstcw(&control); 137130142Sdas __stmxcsr(&mxcsr); 138226594Sdas omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; 139143708Sdas control &= ~mask; 140130142Sdas __fldcw(control); 141130142Sdas mxcsr &= ~(mask << _SSE_EMASK_SHIFT); 142130142Sdas __ldmxcsr(mxcsr); 143226594Sdas return (omask); 144130142Sdas} 145130142Sdas 146143708Sdasint 147143708Sdas__fedisableexcept(int mask) 148143708Sdas{ 149203441Skib __uint32_t mxcsr, omask; 150203441Skib __uint16_t control; 151143708Sdas 152143708Sdas mask &= FE_ALL_EXCEPT; 153143708Sdas __fnstcw(&control); 154143708Sdas __stmxcsr(&mxcsr); 155226594Sdas omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; 156143708Sdas control |= mask; 157143708Sdas __fldcw(control); 158143708Sdas mxcsr |= mask << _SSE_EMASK_SHIFT; 159143708Sdas __ldmxcsr(mxcsr); 160226594Sdas return (omask); 161143708Sdas} 162143708Sdas 163143708Sdas__weak_reference(__feenableexcept, feenableexcept); 164143708Sdas__weak_reference(__fedisableexcept, fedisableexcept); 165