fenv.c revision 165795
1254885Sdumbbell/*- 2254885Sdumbbell * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG> 3254885Sdumbbell * All rights reserved. 4254885Sdumbbell * 5254885Sdumbbell * Redistribution and use in source and binary forms, with or without 6254885Sdumbbell * modification, are permitted provided that the following conditions 7254885Sdumbbell * are met: 8254885Sdumbbell * 1. Redistributions of source code must retain the above copyright 9254885Sdumbbell * notice, this list of conditions and the following disclaimer. 10254885Sdumbbell * 2. Redistributions in binary form must reproduce the above copyright 11254885Sdumbbell * notice, this list of conditions and the following disclaimer in the 12254885Sdumbbell * documentation and/or other materials provided with the distribution. 13254885Sdumbbell * 14254885Sdumbbell * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15254885Sdumbbell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16254885Sdumbbell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17254885Sdumbbell * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18254885Sdumbbell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19254885Sdumbbell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20254885Sdumbbell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21254885Sdumbbell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22254885Sdumbbell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23254885Sdumbbell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24254885Sdumbbell * SUCH DAMAGE. 25254885Sdumbbell * 26254885Sdumbbell * $FreeBSD: head/lib/msun/amd64/fenv.c 165795 2007-01-05 07:15:26Z das $ 27254885Sdumbbell */ 28254885Sdumbbell 29254885Sdumbbell#include <sys/cdefs.h> 30254885Sdumbbell#include <sys/types.h> 31254885Sdumbbell#include <machine/fpu.h> 32254885Sdumbbell#include <fenv.h> 33254885Sdumbbell 34254885Sdumbbellconst fenv_t __fe_dfl_env = { 35254885Sdumbbell { 0xffff0000 | __INITIAL_FPUCW__, 36254885Sdumbbell 0xffff0000, 37254885Sdumbbell 0xffffffff, 38254885Sdumbbell { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39254885Sdumbbell 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff } 40254885Sdumbbell }, 41254885Sdumbbell __INITIAL_MXCSR__ 42254885Sdumbbell}; 43254885Sdumbbell 44254885Sdumbbellint 45254885Sdumbbellfesetexceptflag(const fexcept_t *flagp, int excepts) 46254885Sdumbbell{ 47254885Sdumbbell fenv_t env; 48254885Sdumbbell 49254885Sdumbbell __fnstenv(&env.__x87); 50254885Sdumbbell env.__x87.__status &= ~excepts; 51254885Sdumbbell env.__x87.__status |= *flagp & excepts; 52254885Sdumbbell __fldenv(env.__x87); 53254885Sdumbbell 54254885Sdumbbell __stmxcsr(&env.__mxcsr); 55254885Sdumbbell env.__mxcsr &= ~excepts; 56254885Sdumbbell env.__mxcsr |= *flagp & excepts; 57254885Sdumbbell __ldmxcsr(env.__mxcsr); 58254885Sdumbbell 59254885Sdumbbell return (0); 60254885Sdumbbell} 61254885Sdumbbell 62254885Sdumbbellint 63254885Sdumbbellferaiseexcept(int excepts) 64254885Sdumbbell{ 65254885Sdumbbell fexcept_t ex = excepts; 66254885Sdumbbell 67254885Sdumbbell fesetexceptflag(&ex, excepts); 68254885Sdumbbell __fwait(); 69254885Sdumbbell return (0); 70254885Sdumbbell} 71254885Sdumbbell 72254885Sdumbbellint 73254885Sdumbbellfegetenv(fenv_t *envp) 74254885Sdumbbell{ 75254885Sdumbbell 76254885Sdumbbell __fnstenv(&envp->__x87); 77254885Sdumbbell __stmxcsr(&envp->__mxcsr); 78254885Sdumbbell /* 79254885Sdumbbell * fnstenv masks all exceptions, so we need to restore the 80254885Sdumbbell * control word to avoid this side effect. 81254885Sdumbbell */ 82254885Sdumbbell __fldcw(envp->__x87.__control); 83254885Sdumbbell return (0); 84254885Sdumbbell} 85254885Sdumbbell 86254885Sdumbbellint 87254885Sdumbbellfeholdexcept(fenv_t *envp) 88254885Sdumbbell{ 89254885Sdumbbell int mxcsr; 90254885Sdumbbell 91254885Sdumbbell __stmxcsr(&mxcsr); 92254885Sdumbbell __fnstenv(&envp->__x87); 93254885Sdumbbell __fnclex(); 94254885Sdumbbell envp->__mxcsr = mxcsr; 95254885Sdumbbell mxcsr &= ~FE_ALL_EXCEPT; 96254885Sdumbbell mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT; 97254885Sdumbbell __ldmxcsr(mxcsr); 98254885Sdumbbell return (0); 99254885Sdumbbell} 100254885Sdumbbell 101254885Sdumbbellint 102254885Sdumbbellfeupdateenv(const fenv_t *envp) 103254885Sdumbbell{ 104254885Sdumbbell int mxcsr, status; 105254885Sdumbbell 106254885Sdumbbell __fnstsw(&status); 107254885Sdumbbell __stmxcsr(&mxcsr); 108254885Sdumbbell fesetenv(envp); 109254885Sdumbbell feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT); 110254885Sdumbbell return (0); 111254885Sdumbbell} 112254885Sdumbbell 113254885Sdumbbellint 114254885Sdumbbell__feenableexcept(int mask) 115254885Sdumbbell{ 116254885Sdumbbell int mxcsr, control, omask; 117254885Sdumbbell 118254885Sdumbbell mask &= FE_ALL_EXCEPT; 119254885Sdumbbell __fnstcw(&control); 120254885Sdumbbell __stmxcsr(&mxcsr); 121254885Sdumbbell omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; 122254885Sdumbbell control &= ~mask; 123254885Sdumbbell __fldcw(control); 124254885Sdumbbell mxcsr &= ~(mask << _SSE_EMASK_SHIFT); 125254885Sdumbbell __ldmxcsr(mxcsr); 126254885Sdumbbell return (~omask); 127254885Sdumbbell} 128254885Sdumbbell 129254885Sdumbbellint 130254885Sdumbbell__fedisableexcept(int mask) 131254885Sdumbbell{ 132254885Sdumbbell int mxcsr, control, omask; 133254885Sdumbbell 134254885Sdumbbell mask &= FE_ALL_EXCEPT; 135254885Sdumbbell __fnstcw(&control); 136254885Sdumbbell __stmxcsr(&mxcsr); 137254885Sdumbbell omask = (control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT; 138254885Sdumbbell control |= mask; 139254885Sdumbbell __fldcw(control); 140254885Sdumbbell mxcsr |= mask << _SSE_EMASK_SHIFT; 141254885Sdumbbell __ldmxcsr(mxcsr); 142254885Sdumbbell return (~omask); 143254885Sdumbbell} 144254885Sdumbbell 145254885Sdumbbell__weak_reference(__feenableexcept, feenableexcept); 146254885Sdumbbell__weak_reference(__fedisableexcept, fedisableexcept); 147254885Sdumbbell