1*0a6a1f1dSLionel Sambuc /* $NetBSD: fenv.c,v 1.2 2015/01/13 11:16:06 martin Exp $ */
2*0a6a1f1dSLionel Sambuc
3*0a6a1f1dSLionel Sambuc /*-
4*0a6a1f1dSLionel Sambuc * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
5*0a6a1f1dSLionel Sambuc * All rights reserved.
6*0a6a1f1dSLionel Sambuc *
7*0a6a1f1dSLionel Sambuc * Redistribution and use in source and binary forms, with or without
8*0a6a1f1dSLionel Sambuc * modification, are permitted provided that the following conditions
9*0a6a1f1dSLionel Sambuc * are met:
10*0a6a1f1dSLionel Sambuc * 1. Redistributions of source code must retain the above copyright
11*0a6a1f1dSLionel Sambuc * notice, this list of conditions and the following disclaimer.
12*0a6a1f1dSLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
13*0a6a1f1dSLionel Sambuc * notice, this list of conditions and the following disclaimer in the
14*0a6a1f1dSLionel Sambuc * documentation and/or other materials provided with the distribution.
15*0a6a1f1dSLionel Sambuc *
16*0a6a1f1dSLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*0a6a1f1dSLionel Sambuc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*0a6a1f1dSLionel Sambuc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*0a6a1f1dSLionel Sambuc * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*0a6a1f1dSLionel Sambuc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*0a6a1f1dSLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*0a6a1f1dSLionel Sambuc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*0a6a1f1dSLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*0a6a1f1dSLionel Sambuc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*0a6a1f1dSLionel Sambuc */
26*0a6a1f1dSLionel Sambuc #include <sys/cdefs.h>
27*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: fenv.c,v 1.2 2015/01/13 11:16:06 martin Exp $");
28*0a6a1f1dSLionel Sambuc
29*0a6a1f1dSLionel Sambuc #include <assert.h>
30*0a6a1f1dSLionel Sambuc #include <fenv.h>
31*0a6a1f1dSLionel Sambuc
32*0a6a1f1dSLionel Sambuc /*
33*0a6a1f1dSLionel Sambuc * Convert from exception flags (__BITS(27,32)) to exception enable bits
34*0a6a1f1dSLionel Sambuc * (__BITS(5,0)) by right-shifting this much:
35*0a6a1f1dSLionel Sambuc */
36*0a6a1f1dSLionel Sambuc #define FE_FLAGS_SHIFT 27
37*0a6a1f1dSLionel Sambuc
38*0a6a1f1dSLionel Sambuc /*
39*0a6a1f1dSLionel Sambuc * Mask all rounding mode bits
40*0a6a1f1dSLionel Sambuc */
41*0a6a1f1dSLionel Sambuc #define FE_ROUND_MASK (FE_TONEAREST | FE_DOWNWARD | \
42*0a6a1f1dSLionel Sambuc FE_UPWARD | FE_TOWARDZERO)
43*0a6a1f1dSLionel Sambuc
44*0a6a1f1dSLionel Sambuc /* Load lower 32 bits from floating-point state register */
45*0a6a1f1dSLionel Sambuc static inline uint32_t
readfpsr(void)46*0a6a1f1dSLionel Sambuc readfpsr(void)
47*0a6a1f1dSLionel Sambuc {
48*0a6a1f1dSLionel Sambuc uint32_t rv;
49*0a6a1f1dSLionel Sambuc
50*0a6a1f1dSLionel Sambuc __asm__ __volatile__ ("fstws %%fr0, %0" : "=m"(rv));
51*0a6a1f1dSLionel Sambuc return rv;
52*0a6a1f1dSLionel Sambuc }
53*0a6a1f1dSLionel Sambuc
54*0a6a1f1dSLionel Sambuc /* Save floating-point state register */
55*0a6a1f1dSLionel Sambuc static inline void
writefpsr(uint32_t val)56*0a6a1f1dSLionel Sambuc writefpsr(uint32_t val)
57*0a6a1f1dSLionel Sambuc {
58*0a6a1f1dSLionel Sambuc __asm__ __volatile__("fldws %0,%%fr0" : : "m"(val));
59*0a6a1f1dSLionel Sambuc }
60*0a6a1f1dSLionel Sambuc
61*0a6a1f1dSLionel Sambuc /*
62*0a6a1f1dSLionel Sambuc * The feclearexcept() function clears the supported floating-point exceptions
63*0a6a1f1dSLionel Sambuc * represented by `excepts'.
64*0a6a1f1dSLionel Sambuc */
65*0a6a1f1dSLionel Sambuc int
feclearexcept(int excepts)66*0a6a1f1dSLionel Sambuc feclearexcept(int excepts)
67*0a6a1f1dSLionel Sambuc {
68*0a6a1f1dSLionel Sambuc fexcept_t r;
69*0a6a1f1dSLionel Sambuc int ex;
70*0a6a1f1dSLionel Sambuc
71*0a6a1f1dSLionel Sambuc _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
72*0a6a1f1dSLionel Sambuc
73*0a6a1f1dSLionel Sambuc ex = (excepts & FE_ALL_EXCEPT) << FE_FLAGS_SHIFT;
74*0a6a1f1dSLionel Sambuc
75*0a6a1f1dSLionel Sambuc r = readfpsr();
76*0a6a1f1dSLionel Sambuc r &= ~ex;
77*0a6a1f1dSLionel Sambuc writefpsr(r);
78*0a6a1f1dSLionel Sambuc
79*0a6a1f1dSLionel Sambuc /* Success */
80*0a6a1f1dSLionel Sambuc return 0;
81*0a6a1f1dSLionel Sambuc }
82*0a6a1f1dSLionel Sambuc
83*0a6a1f1dSLionel Sambuc /*
84*0a6a1f1dSLionel Sambuc * The fegetexceptflag() function stores an implementation-defined
85*0a6a1f1dSLionel Sambuc * representation of the states of the floating-point status flags indicated
86*0a6a1f1dSLionel Sambuc * by the argument excepts in the object pointed to by the argument flagp.
87*0a6a1f1dSLionel Sambuc */
88*0a6a1f1dSLionel Sambuc int
fegetexceptflag(fexcept_t * flagp,int excepts)89*0a6a1f1dSLionel Sambuc fegetexceptflag(fexcept_t *flagp, int excepts)
90*0a6a1f1dSLionel Sambuc {
91*0a6a1f1dSLionel Sambuc fexcept_t r;
92*0a6a1f1dSLionel Sambuc int ex;
93*0a6a1f1dSLionel Sambuc
94*0a6a1f1dSLionel Sambuc _DIAGASSERT(flagp != NULL);
95*0a6a1f1dSLionel Sambuc _DIAGASSERT((excepts & ~_FE_ALL_EXCEPT) == 0);
96*0a6a1f1dSLionel Sambuc
97*0a6a1f1dSLionel Sambuc ex = (excepts & FE_ALL_EXCEPT) << FE_FLAGS_SHIFT;
98*0a6a1f1dSLionel Sambuc
99*0a6a1f1dSLionel Sambuc r = readfpsr();
100*0a6a1f1dSLionel Sambuc *flagp = (r & ex) >> FE_FLAGS_SHIFT;
101*0a6a1f1dSLionel Sambuc
102*0a6a1f1dSLionel Sambuc /* Success */
103*0a6a1f1dSLionel Sambuc return 0;
104*0a6a1f1dSLionel Sambuc }
105*0a6a1f1dSLionel Sambuc
106*0a6a1f1dSLionel Sambuc
107*0a6a1f1dSLionel Sambuc /*
108*0a6a1f1dSLionel Sambuc * This function sets the floating-point status flags indicated by the argument
109*0a6a1f1dSLionel Sambuc * `excepts' to the states stored in the object pointed to by `flagp'. It does
110*0a6a1f1dSLionel Sambuc * NOT raise any floating-point exceptions, but only sets the state of the flags.
111*0a6a1f1dSLionel Sambuc */
112*0a6a1f1dSLionel Sambuc int
fesetexceptflag(const fexcept_t * flagp,int excepts)113*0a6a1f1dSLionel Sambuc fesetexceptflag(const fexcept_t *flagp, int excepts)
114*0a6a1f1dSLionel Sambuc {
115*0a6a1f1dSLionel Sambuc fexcept_t r;
116*0a6a1f1dSLionel Sambuc int ex;
117*0a6a1f1dSLionel Sambuc
118*0a6a1f1dSLionel Sambuc _DIAGASSERT(flagp != NULL);
119*0a6a1f1dSLionel Sambuc _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
120*0a6a1f1dSLionel Sambuc
121*0a6a1f1dSLionel Sambuc ex = (excepts & FE_ALL_EXCEPT) << FE_FLAGS_SHIFT;
122*0a6a1f1dSLionel Sambuc
123*0a6a1f1dSLionel Sambuc r = readfpsr();
124*0a6a1f1dSLionel Sambuc r &= ~ex;
125*0a6a1f1dSLionel Sambuc r |= (*flagp << FE_FLAGS_SHIFT) & ex;
126*0a6a1f1dSLionel Sambuc writefpsr(r);
127*0a6a1f1dSLionel Sambuc
128*0a6a1f1dSLionel Sambuc /* Success */
129*0a6a1f1dSLionel Sambuc return 0;
130*0a6a1f1dSLionel Sambuc }
131*0a6a1f1dSLionel Sambuc
132*0a6a1f1dSLionel Sambuc /*
133*0a6a1f1dSLionel Sambuc * The feraiseexcept() function raises the supported floating-point exceptions
134*0a6a1f1dSLionel Sambuc * represented by the argument `excepts'.
135*0a6a1f1dSLionel Sambuc *
136*0a6a1f1dSLionel Sambuc * The order in which these floating-point exceptions are raised is unspecified
137*0a6a1f1dSLionel Sambuc * (by the standard).
138*0a6a1f1dSLionel Sambuc */
139*0a6a1f1dSLionel Sambuc int
feraiseexcept(int excepts)140*0a6a1f1dSLionel Sambuc feraiseexcept(int excepts)
141*0a6a1f1dSLionel Sambuc {
142*0a6a1f1dSLionel Sambuc volatile double d;
143*0a6a1f1dSLionel Sambuc int ex;
144*0a6a1f1dSLionel Sambuc
145*0a6a1f1dSLionel Sambuc _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
146*0a6a1f1dSLionel Sambuc
147*0a6a1f1dSLionel Sambuc ex = excepts & FE_ALL_EXCEPT;
148*0a6a1f1dSLionel Sambuc
149*0a6a1f1dSLionel Sambuc /*
150*0a6a1f1dSLionel Sambuc * With a compiler that supports the FENV_ACCESS pragma properly, simple
151*0a6a1f1dSLionel Sambuc * expressions like '0.0 / 0.0' should be sufficient to generate traps.
152*0a6a1f1dSLionel Sambuc * Unfortunately, we need to bring a volatile variable into the equation
153*0a6a1f1dSLionel Sambuc * to prevent incorrect optimizations.
154*0a6a1f1dSLionel Sambuc */
155*0a6a1f1dSLionel Sambuc if (ex & FE_INVALID) {
156*0a6a1f1dSLionel Sambuc d = 0.0;
157*0a6a1f1dSLionel Sambuc d = 0.0 / d;
158*0a6a1f1dSLionel Sambuc }
159*0a6a1f1dSLionel Sambuc if (ex & FE_DIVBYZERO) {
160*0a6a1f1dSLionel Sambuc d = 0.0;
161*0a6a1f1dSLionel Sambuc d = 1.0 / d;
162*0a6a1f1dSLionel Sambuc }
163*0a6a1f1dSLionel Sambuc if (ex & FE_OVERFLOW) {
164*0a6a1f1dSLionel Sambuc d = 0x1.ffp1023;
165*0a6a1f1dSLionel Sambuc d *= 2.0;
166*0a6a1f1dSLionel Sambuc }
167*0a6a1f1dSLionel Sambuc if (ex & FE_UNDERFLOW) {
168*0a6a1f1dSLionel Sambuc d = 0x1p-1022;
169*0a6a1f1dSLionel Sambuc d /= 0x1p1023;
170*0a6a1f1dSLionel Sambuc }
171*0a6a1f1dSLionel Sambuc if (ex & FE_INEXACT) {
172*0a6a1f1dSLionel Sambuc d = 0x1p-1022;
173*0a6a1f1dSLionel Sambuc d += 1.0;
174*0a6a1f1dSLionel Sambuc }
175*0a6a1f1dSLionel Sambuc
176*0a6a1f1dSLionel Sambuc /* Success */
177*0a6a1f1dSLionel Sambuc return 0;
178*0a6a1f1dSLionel Sambuc }
179*0a6a1f1dSLionel Sambuc
180*0a6a1f1dSLionel Sambuc /*
181*0a6a1f1dSLionel Sambuc * The fetestexcept() function determines which of a specified subset of the
182*0a6a1f1dSLionel Sambuc * floating-point exception flags are currently set. The `excepts' argument
183*0a6a1f1dSLionel Sambuc * specifies the floating-point status flags to be queried.
184*0a6a1f1dSLionel Sambuc */
185*0a6a1f1dSLionel Sambuc int
fetestexcept(int excepts)186*0a6a1f1dSLionel Sambuc fetestexcept(int excepts)
187*0a6a1f1dSLionel Sambuc {
188*0a6a1f1dSLionel Sambuc fexcept_t r;
189*0a6a1f1dSLionel Sambuc
190*0a6a1f1dSLionel Sambuc _DIAGASSERT((excepts & ~FE_ALL_EXCEPT) == 0);
191*0a6a1f1dSLionel Sambuc
192*0a6a1f1dSLionel Sambuc r = readfpsr();
193*0a6a1f1dSLionel Sambuc
194*0a6a1f1dSLionel Sambuc return (r >> FE_FLAGS_SHIFT) & (excepts & FE_ALL_EXCEPT);
195*0a6a1f1dSLionel Sambuc }
196*0a6a1f1dSLionel Sambuc
197*0a6a1f1dSLionel Sambuc /*
198*0a6a1f1dSLionel Sambuc * The fegetround() function gets the current rounding direction.
199*0a6a1f1dSLionel Sambuc */
200*0a6a1f1dSLionel Sambuc int
fegetround(void)201*0a6a1f1dSLionel Sambuc fegetround(void)
202*0a6a1f1dSLionel Sambuc {
203*0a6a1f1dSLionel Sambuc fenv_t r;
204*0a6a1f1dSLionel Sambuc
205*0a6a1f1dSLionel Sambuc r = readfpsr();
206*0a6a1f1dSLionel Sambuc
207*0a6a1f1dSLionel Sambuc return r & FE_ROUND_MASK;
208*0a6a1f1dSLionel Sambuc }
209*0a6a1f1dSLionel Sambuc
210*0a6a1f1dSLionel Sambuc /*
211*0a6a1f1dSLionel Sambuc * The fesetround() function establishes the rounding direction represented by
212*0a6a1f1dSLionel Sambuc * its argument `round'. If the argument is not equal to the value of a rounding
213*0a6a1f1dSLionel Sambuc * direction macro, the rounding direction is not changed.
214*0a6a1f1dSLionel Sambuc */
215*0a6a1f1dSLionel Sambuc int
fesetround(int round)216*0a6a1f1dSLionel Sambuc fesetround(int round)
217*0a6a1f1dSLionel Sambuc {
218*0a6a1f1dSLionel Sambuc fenv_t r;
219*0a6a1f1dSLionel Sambuc
220*0a6a1f1dSLionel Sambuc _DIAGASSERT((round & ~FE_ROUND_MASK) == 0);
221*0a6a1f1dSLionel Sambuc if (round & ~FE_ROUND_MASK)
222*0a6a1f1dSLionel Sambuc return -1;
223*0a6a1f1dSLionel Sambuc
224*0a6a1f1dSLionel Sambuc r = readfpsr();
225*0a6a1f1dSLionel Sambuc r &= ~FE_ROUND_MASK;
226*0a6a1f1dSLionel Sambuc r |= round;
227*0a6a1f1dSLionel Sambuc writefpsr(r);
228*0a6a1f1dSLionel Sambuc
229*0a6a1f1dSLionel Sambuc /* Success */
230*0a6a1f1dSLionel Sambuc return 0;
231*0a6a1f1dSLionel Sambuc }
232*0a6a1f1dSLionel Sambuc
233*0a6a1f1dSLionel Sambuc /*
234*0a6a1f1dSLionel Sambuc * The fegetenv() function attempts to store the current floating-point
235*0a6a1f1dSLionel Sambuc * environment in the object pointed to by envp.
236*0a6a1f1dSLionel Sambuc */
237*0a6a1f1dSLionel Sambuc int
fegetenv(fenv_t * envp)238*0a6a1f1dSLionel Sambuc fegetenv(fenv_t *envp)
239*0a6a1f1dSLionel Sambuc {
240*0a6a1f1dSLionel Sambuc _DIAGASSERT(envp != NULL);
241*0a6a1f1dSLionel Sambuc
242*0a6a1f1dSLionel Sambuc *envp = readfpsr();
243*0a6a1f1dSLionel Sambuc
244*0a6a1f1dSLionel Sambuc /* Success */
245*0a6a1f1dSLionel Sambuc return 0;
246*0a6a1f1dSLionel Sambuc }
247*0a6a1f1dSLionel Sambuc
248*0a6a1f1dSLionel Sambuc
249*0a6a1f1dSLionel Sambuc /*
250*0a6a1f1dSLionel Sambuc * The feholdexcept() function saves the current floating-point environment
251*0a6a1f1dSLionel Sambuc * in the object pointed to by envp, clears the floating-point status flags, and
252*0a6a1f1dSLionel Sambuc * then installs a non-stop (continue on floating-point exceptions) mode, if
253*0a6a1f1dSLionel Sambuc * available, for all floating-point exceptions.
254*0a6a1f1dSLionel Sambuc */
255*0a6a1f1dSLionel Sambuc int
feholdexcept(fenv_t * envp)256*0a6a1f1dSLionel Sambuc feholdexcept(fenv_t *envp)
257*0a6a1f1dSLionel Sambuc {
258*0a6a1f1dSLionel Sambuc fenv_t r;
259*0a6a1f1dSLionel Sambuc
260*0a6a1f1dSLionel Sambuc _DIAGASSERT(envp != NULL);
261*0a6a1f1dSLionel Sambuc
262*0a6a1f1dSLionel Sambuc r = readfpsr();
263*0a6a1f1dSLionel Sambuc *envp = r;
264*0a6a1f1dSLionel Sambuc r &= ~FE_ALL_EXCEPT;
265*0a6a1f1dSLionel Sambuc writefpsr(r);
266*0a6a1f1dSLionel Sambuc
267*0a6a1f1dSLionel Sambuc /* Success */
268*0a6a1f1dSLionel Sambuc return 0;
269*0a6a1f1dSLionel Sambuc }
270*0a6a1f1dSLionel Sambuc
271*0a6a1f1dSLionel Sambuc /*
272*0a6a1f1dSLionel Sambuc * The fesetenv() function attempts to establish the floating-point environment
273*0a6a1f1dSLionel Sambuc * represented by the object pointed to by envp. The argument `envp' points
274*0a6a1f1dSLionel Sambuc * to an object set by a call to fegetenv() or feholdexcept(), or equal a
275*0a6a1f1dSLionel Sambuc * floating-point environment macro. The fesetenv() function does not raise
276*0a6a1f1dSLionel Sambuc * floating-point exceptions, but only installs the state of the floating-point
277*0a6a1f1dSLionel Sambuc * status flags represented through its argument.
278*0a6a1f1dSLionel Sambuc */
279*0a6a1f1dSLionel Sambuc int
fesetenv(const fenv_t * envp)280*0a6a1f1dSLionel Sambuc fesetenv(const fenv_t *envp)
281*0a6a1f1dSLionel Sambuc {
282*0a6a1f1dSLionel Sambuc _DIAGASSERT(envp != NULL);
283*0a6a1f1dSLionel Sambuc
284*0a6a1f1dSLionel Sambuc writefpsr(*envp);
285*0a6a1f1dSLionel Sambuc
286*0a6a1f1dSLionel Sambuc /* Success */
287*0a6a1f1dSLionel Sambuc return 0;
288*0a6a1f1dSLionel Sambuc }
289*0a6a1f1dSLionel Sambuc
290*0a6a1f1dSLionel Sambuc
291*0a6a1f1dSLionel Sambuc /*
292*0a6a1f1dSLionel Sambuc * The feupdateenv() function saves the currently raised floating-point
293*0a6a1f1dSLionel Sambuc * exceptions in its automatic storage, installs the floating-point environment
294*0a6a1f1dSLionel Sambuc * represented by the object pointed to by `envp', and then raises the saved
295*0a6a1f1dSLionel Sambuc * floating-point exceptions. The argument `envp' shall point to an object set
296*0a6a1f1dSLionel Sambuc * by a call to feholdexcept() or fegetenv(), or equal a floating-point
297*0a6a1f1dSLionel Sambuc * environment macro.
298*0a6a1f1dSLionel Sambuc */
299*0a6a1f1dSLionel Sambuc int
feupdateenv(const fenv_t * envp)300*0a6a1f1dSLionel Sambuc feupdateenv(const fenv_t *envp)
301*0a6a1f1dSLionel Sambuc {
302*0a6a1f1dSLionel Sambuc fexcept_t r;
303*0a6a1f1dSLionel Sambuc
304*0a6a1f1dSLionel Sambuc _DIAGASSERT(envp != NULL);
305*0a6a1f1dSLionel Sambuc
306*0a6a1f1dSLionel Sambuc r = readfpsr();
307*0a6a1f1dSLionel Sambuc writefpsr(*envp);
308*0a6a1f1dSLionel Sambuc
309*0a6a1f1dSLionel Sambuc _DIAGASSERT((r & ~FE_ALL_EXCEPT) == 0);
310*0a6a1f1dSLionel Sambuc feraiseexcept(r & FE_ALL_EXCEPT);
311*0a6a1f1dSLionel Sambuc
312*0a6a1f1dSLionel Sambuc /* Success */
313*0a6a1f1dSLionel Sambuc return 0;
314*0a6a1f1dSLionel Sambuc }
315*0a6a1f1dSLionel Sambuc
316*0a6a1f1dSLionel Sambuc /*
317*0a6a1f1dSLionel Sambuc * The following functions are extentions to the standard
318*0a6a1f1dSLionel Sambuc */
319*0a6a1f1dSLionel Sambuc int
feenableexcept(int mask)320*0a6a1f1dSLionel Sambuc feenableexcept(int mask)
321*0a6a1f1dSLionel Sambuc {
322*0a6a1f1dSLionel Sambuc fenv_t old_r, new_r;
323*0a6a1f1dSLionel Sambuc
324*0a6a1f1dSLionel Sambuc old_r = readfpsr();
325*0a6a1f1dSLionel Sambuc new_r = old_r | (mask & FE_ALL_EXCEPT);
326*0a6a1f1dSLionel Sambuc writefpsr(new_r);
327*0a6a1f1dSLionel Sambuc
328*0a6a1f1dSLionel Sambuc return old_r & FE_ALL_EXCEPT;
329*0a6a1f1dSLionel Sambuc }
330*0a6a1f1dSLionel Sambuc
331*0a6a1f1dSLionel Sambuc int
fedisableexcept(int mask)332*0a6a1f1dSLionel Sambuc fedisableexcept(int mask)
333*0a6a1f1dSLionel Sambuc {
334*0a6a1f1dSLionel Sambuc fenv_t old_r, new_r;
335*0a6a1f1dSLionel Sambuc
336*0a6a1f1dSLionel Sambuc old_r = readfpsr();
337*0a6a1f1dSLionel Sambuc new_r = old_r & ~(mask & FE_ALL_EXCEPT);
338*0a6a1f1dSLionel Sambuc writefpsr(new_r);
339*0a6a1f1dSLionel Sambuc
340*0a6a1f1dSLionel Sambuc return old_r & FE_ALL_EXCEPT;
341*0a6a1f1dSLionel Sambuc }
342*0a6a1f1dSLionel Sambuc
343*0a6a1f1dSLionel Sambuc int
fegetexcept(void)344*0a6a1f1dSLionel Sambuc fegetexcept(void)
345*0a6a1f1dSLionel Sambuc {
346*0a6a1f1dSLionel Sambuc fenv_t r;
347*0a6a1f1dSLionel Sambuc
348*0a6a1f1dSLionel Sambuc r = readfpsr();
349*0a6a1f1dSLionel Sambuc return r & FE_ALL_EXCEPT;
350*0a6a1f1dSLionel Sambuc }
351