Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
3 : : * All rights reserved.
4 : : *
5 : : * Redistribution and use in source and binary forms, with or without
6 : : * modification, are permitted provided that the following conditions
7 : : * are met:
8 : : * 1. Redistributions of source code must retain the above copyright
9 : : * notice, this list of conditions and the following disclaimer.
10 : : * 2. Redistributions in binary form must reproduce the above copyright
11 : : * notice, this list of conditions and the following disclaimer in the
12 : : * documentation and/or other materials provided with the distribution.
13 : : *
14 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 : : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 : : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 : : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 : : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 : : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 : : * SUCH DAMAGE.
25 : : *
26 : : * $FreeBSD: src/lib/msun/amd64/fenv.c,v 1.8 2011/10/21 06:25:31 das Exp $
27 : : */
28 : :
29 : : #include "bsd_fpu.h"
30 : : #include "math_private.h"
31 : :
32 : : #ifdef _WIN32
33 : : #define __fenv_static OLM_DLLEXPORT
34 : : #endif
35 : : #include <openlibm_fenv.h>
36 : :
37 : : #ifdef __GNUC_GNU_INLINE__
38 : : #error "This file must be compiled with C99 'inline' semantics"
39 : : #endif
40 : :
41 : : const fenv_t __fe_dfl_env = {
42 : : { 0xffff0000 | __INITIAL_FPUCW__,
43 : : 0xffff0000,
44 : : 0xffffffff,
45 : : { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }
47 : : },
48 : : __INITIAL_MXCSR__
49 : : };
50 : :
51 : : extern inline OLM_DLLEXPORT int feclearexcept(int __excepts);
52 : : extern inline OLM_DLLEXPORT int fegetexceptflag(fexcept_t *__flagp, int __excepts);
53 : :
54 : : OLM_DLLEXPORT int
55 : 0 : fesetexceptflag(const fexcept_t *flagp, int excepts)
56 : : {
57 : : fenv_t env;
58 : :
59 : 0 : __fnstenv(&env.__x87);
60 : 0 : env.__x87.__status &= ~excepts;
61 : 0 : env.__x87.__status |= *flagp & excepts;
62 : 0 : __fldenv(env.__x87);
63 : :
64 : 0 : __stmxcsr(&env.__mxcsr);
65 : 0 : env.__mxcsr &= ~excepts;
66 : 0 : env.__mxcsr |= *flagp & excepts;
67 : 0 : __ldmxcsr(env.__mxcsr);
68 : :
69 : 0 : return (0);
70 : : }
71 : :
72 : : OLM_DLLEXPORT int
73 : 0 : feraiseexcept(int excepts)
74 : : {
75 : 0 : fexcept_t ex = excepts;
76 : :
77 : 0 : fesetexceptflag(&ex, excepts);
78 : 0 : __fwait();
79 : 0 : return (0);
80 : : }
81 : :
82 : : extern inline OLM_DLLEXPORT int fetestexcept(int __excepts);
83 : : extern inline OLM_DLLEXPORT int fegetround(void);
84 : : extern inline OLM_DLLEXPORT int fesetround(int __round);
85 : :
86 : : OLM_DLLEXPORT int
87 : 18 : fegetenv(fenv_t *envp)
88 : : {
89 : :
90 : 18 : __fnstenv(&envp->__x87);
91 : 18 : __stmxcsr(&envp->__mxcsr);
92 : : /*
93 : : * fnstenv masks all exceptions, so we need to restore the
94 : : * control word to avoid this side effect.
95 : : */
96 : 18 : __fldcw(envp->__x87.__control);
97 : 18 : return (0);
98 : : }
99 : :
100 : : OLM_DLLEXPORT int
101 : 0 : feholdexcept(fenv_t *envp)
102 : : {
103 : : uint32_t mxcsr;
104 : :
105 : 0 : __stmxcsr(&mxcsr);
106 : 0 : __fnstenv(&envp->__x87);
107 : 0 : __fnclex();
108 : 0 : envp->__mxcsr = mxcsr;
109 : 0 : mxcsr &= ~FE_ALL_EXCEPT;
110 : 0 : mxcsr |= FE_ALL_EXCEPT << _SSE_EMASK_SHIFT;
111 : 0 : __ldmxcsr(mxcsr);
112 : 0 : return (0);
113 : : }
114 : :
115 : : extern inline OLM_DLLEXPORT int fesetenv(const fenv_t *__envp);
116 : :
117 : : OLM_DLLEXPORT int
118 : 0 : feupdateenv(const fenv_t *envp)
119 : : {
120 : : uint32_t mxcsr;
121 : : uint16_t status;
122 : :
123 : 0 : __fnstsw(&status);
124 : 0 : __stmxcsr(&mxcsr);
125 : 0 : fesetenv(envp);
126 : 0 : feraiseexcept((mxcsr | status) & FE_ALL_EXCEPT);
127 : 0 : return (0);
128 : : }
129 : :
130 : : int
131 : 0 : feenableexcept(int mask)
132 : : {
133 : : uint32_t mxcsr, omask;
134 : : uint16_t control;
135 : :
136 : 0 : mask &= FE_ALL_EXCEPT;
137 : 0 : __fnstcw(&control);
138 : 0 : __stmxcsr(&mxcsr);
139 : 0 : omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
140 : 0 : control &= ~mask;
141 : 0 : __fldcw(control);
142 : 0 : mxcsr &= ~(mask << _SSE_EMASK_SHIFT);
143 : 0 : __ldmxcsr(mxcsr);
144 : 0 : return (omask);
145 : : }
146 : :
147 : : int
148 : 0 : fedisableexcept(int mask)
149 : : {
150 : : uint32_t mxcsr, omask;
151 : : uint16_t control;
152 : :
153 : 0 : mask &= FE_ALL_EXCEPT;
154 : 0 : __fnstcw(&control);
155 : 0 : __stmxcsr(&mxcsr);
156 : 0 : omask = ~(control | mxcsr >> _SSE_EMASK_SHIFT) & FE_ALL_EXCEPT;
157 : 0 : control |= mask;
158 : 0 : __fldcw(control);
159 : 0 : mxcsr |= mask << _SSE_EMASK_SHIFT;
160 : 0 : __ldmxcsr(mxcsr);
161 : 0 : return (omask);
162 : : }
|