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#ifndef _FENV_H_ 30130142Sdas#define _FENV_H_ 31130142Sdas 32130142Sdas#include <sys/cdefs.h> 33130142Sdas#include <sys/_types.h> 34130142Sdas 35130142Sdastypedef struct { 36130142Sdas struct { 37130142Sdas __uint32_t __control; 38130142Sdas __uint32_t __status; 39130142Sdas __uint32_t __tag; 40130142Sdas char __other[16]; 41130142Sdas } __x87; 42130142Sdas __uint32_t __mxcsr; 43130142Sdas} fenv_t; 44130142Sdas 45130142Sdastypedef __uint16_t fexcept_t; 46130142Sdas 47130142Sdas/* Exception flags */ 48130142Sdas#define FE_INVALID 0x01 49130142Sdas#define FE_DENORMAL 0x02 50130142Sdas#define FE_DIVBYZERO 0x04 51130142Sdas#define FE_OVERFLOW 0x08 52130142Sdas#define FE_UNDERFLOW 0x10 53130142Sdas#define FE_INEXACT 0x20 54130142Sdas#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \ 55130142Sdas FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) 56130142Sdas 57130142Sdas/* Rounding modes */ 58130142Sdas#define FE_TONEAREST 0x0000 59130142Sdas#define FE_DOWNWARD 0x0400 60130142Sdas#define FE_UPWARD 0x0800 61130142Sdas#define FE_TOWARDZERO 0x0c00 62130142Sdas#define _ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \ 63130142Sdas FE_UPWARD | FE_TOWARDZERO) 64130142Sdas 65130142Sdas/* 66130142Sdas * As compared to the x87 control word, the SSE unit's control word 67130142Sdas * has the rounding control bits offset by 3 and the exception mask 68130142Sdas * bits offset by 7. 69130142Sdas */ 70130142Sdas#define _SSE_ROUND_SHIFT 3 71130142Sdas#define _SSE_EMASK_SHIFT 7 72130142Sdas 73130142Sdas__BEGIN_DECLS 74130142Sdas 75130142Sdas/* Default floating-point environment */ 76130142Sdasextern const fenv_t __fe_dfl_env; 77130142Sdas#define FE_DFL_ENV (&__fe_dfl_env) 78130142Sdas 79130142Sdas#define __fldcw(__cw) __asm __volatile("fldcw %0" : : "m" (__cw)) 80130142Sdas#define __fldenv(__env) __asm __volatile("fldenv %0" : : "m" (__env)) 81165841Sdas#define __fldenvx(__env) __asm __volatile("fldenv %0" : : "m" (__env) \ 82165841Sdas : "st", "st(1)", "st(2)", "st(3)", "st(4)", \ 83165841Sdas "st(5)", "st(6)", "st(7)") 84130142Sdas#define __fnclex() __asm __volatile("fnclex") 85140219Sdas#define __fnstenv(__env) __asm __volatile("fnstenv %0" : "=m" (*(__env))) 86140219Sdas#define __fnstcw(__cw) __asm __volatile("fnstcw %0" : "=m" (*(__cw))) 87140219Sdas#define __fnstsw(__sw) __asm __volatile("fnstsw %0" : "=am" (*(__sw))) 88130142Sdas#define __fwait() __asm __volatile("fwait") 89130142Sdas#define __ldmxcsr(__csr) __asm __volatile("ldmxcsr %0" : : "m" (__csr)) 90140085Sdas#define __stmxcsr(__csr) __asm __volatile("stmxcsr %0" : "=m" (*(__csr))) 91130142Sdas 92130142Sdasstatic __inline int 93130142Sdasfeclearexcept(int __excepts) 94130142Sdas{ 95130142Sdas fenv_t __env; 96130142Sdas 97130142Sdas if (__excepts == FE_ALL_EXCEPT) { 98130142Sdas __fnclex(); 99130142Sdas } else { 100130142Sdas __fnstenv(&__env.__x87); 101130142Sdas __env.__x87.__status &= ~__excepts; 102130142Sdas __fldenv(__env.__x87); 103130142Sdas } 104130142Sdas __stmxcsr(&__env.__mxcsr); 105130142Sdas __env.__mxcsr &= ~__excepts; 106130142Sdas __ldmxcsr(__env.__mxcsr); 107130142Sdas return (0); 108130142Sdas} 109130142Sdas 110130142Sdasstatic __inline int 111130142Sdasfegetexceptflag(fexcept_t *__flagp, int __excepts) 112130142Sdas{ 113203441Skib __uint32_t __mxcsr; 114203441Skib __uint16_t __status; 115130142Sdas 116130142Sdas __stmxcsr(&__mxcsr); 117130142Sdas __fnstsw(&__status); 118130142Sdas *__flagp = (__mxcsr | __status) & __excepts; 119130142Sdas return (0); 120130142Sdas} 121130142Sdas 122130142Sdasint fesetexceptflag(const fexcept_t *__flagp, int __excepts); 123130142Sdasint feraiseexcept(int __excepts); 124130142Sdas 125130142Sdasstatic __inline int 126130142Sdasfetestexcept(int __excepts) 127130142Sdas{ 128203441Skib __uint32_t __mxcsr; 129203441Skib __uint16_t __status; 130130142Sdas 131130142Sdas __stmxcsr(&__mxcsr); 132130142Sdas __fnstsw(&__status); 133130142Sdas return ((__status | __mxcsr) & __excepts); 134130142Sdas} 135130142Sdas 136130142Sdasstatic __inline int 137130142Sdasfegetround(void) 138130142Sdas{ 139203441Skib __uint16_t __control; 140130142Sdas 141130142Sdas /* 142130142Sdas * We assume that the x87 and the SSE unit agree on the 143130142Sdas * rounding mode. Reading the control word on the x87 turns 144130142Sdas * out to be about 5 times faster than reading it on the SSE 145130142Sdas * unit on an Opteron 244. 146130142Sdas */ 147130142Sdas __fnstcw(&__control); 148130142Sdas return (__control & _ROUND_MASK); 149130142Sdas} 150130142Sdas 151130142Sdasstatic __inline int 152130142Sdasfesetround(int __round) 153130142Sdas{ 154203441Skib __uint32_t __mxcsr; 155203441Skib __uint16_t __control; 156130142Sdas 157130142Sdas if (__round & ~_ROUND_MASK) 158130142Sdas return (-1); 159130142Sdas 160130142Sdas __fnstcw(&__control); 161130142Sdas __control &= ~_ROUND_MASK; 162130142Sdas __control |= __round; 163130142Sdas __fldcw(__control); 164130142Sdas 165130142Sdas __stmxcsr(&__mxcsr); 166130142Sdas __mxcsr &= ~(_ROUND_MASK << _SSE_ROUND_SHIFT); 167130142Sdas __mxcsr |= __round << _SSE_ROUND_SHIFT; 168130142Sdas __ldmxcsr(__mxcsr); 169130142Sdas 170130142Sdas return (0); 171130142Sdas} 172130142Sdas 173130142Sdasint fegetenv(fenv_t *__envp); 174130142Sdasint feholdexcept(fenv_t *__envp); 175130142Sdas 176130142Sdasstatic __inline int 177130142Sdasfesetenv(const fenv_t *__envp) 178130142Sdas{ 179130142Sdas 180165841Sdas /* 181165841Sdas * XXX Using fldenvx() instead of fldenv() tells the compiler that this 182165841Sdas * instruction clobbers the i387 register stack. This happens because 183165841Sdas * we restore the tag word from the saved environment. Normally, this 184165841Sdas * would happen anyway and we wouldn't care, because the ABI allows 185165841Sdas * function calls to clobber the i387 regs. However, fesetenv() is 186165841Sdas * inlined, so we need to be more careful. 187165841Sdas */ 188165841Sdas __fldenvx(__envp->__x87); 189130142Sdas __ldmxcsr(__envp->__mxcsr); 190130142Sdas return (0); 191130142Sdas} 192130142Sdas 193130142Sdasint feupdateenv(const fenv_t *__envp); 194130142Sdas 195130142Sdas#if __BSD_VISIBLE 196130142Sdas 197143708Sdasint feenableexcept(int __mask); 198143722Sdasint fedisableexcept(int __mask); 199130142Sdas 200130142Sdasstatic __inline int 201143708Sdasfegetexcept(void) 202130142Sdas{ 203203441Skib __uint16_t __control; 204130142Sdas 205130142Sdas /* 206130142Sdas * We assume that the masks for the x87 and the SSE unit are 207130142Sdas * the same. 208130142Sdas */ 209130142Sdas __fnstcw(&__control); 210130142Sdas return (~__control & FE_ALL_EXCEPT); 211130142Sdas} 212130142Sdas 213130142Sdas#endif /* __BSD_VISIBLE */ 214130142Sdas 215130142Sdas__END_DECLS 216130142Sdas 217130142Sdas#endif /* !_FENV_H_ */ 218