this repo has no description
1/*
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*******************************************************************************
23* *
24* File: fenv.c *
25* *
26* Contains: C source code for PowerPC implementations of floating-point *
27* environmental functions defined in C99. *
28* *
29* Copyright � 1992-2001 Apple Computer, Inc. All rights reserved. *
30* *
31* Written by Jon Okada, started on November 1992. *
32* Modified by A. sazegari (ali) for MathLib v3. *
33* Modified and ported by Robert A. Murley (ram) for Mac OS X. *
34* *
35* A MathLib v4 file. *
36* *
37* Change History (most recent first): *
38* *
39* 06 Nov 01 ram commented out warning about Intel architectures. *
40* 08 Oct 01 ram removed <CoreServices/CoreServices.h>. *
41* changed compiler errors to warnings. *
42* 18 Sep 01 ali added <CoreServices/CoreServices.h> to get <fenv.h>. *
43* 10 Sep 01 ali added macros to detect PowerPC and correct compiler. *
44* 09 Sep 01 ali added more comments. *
45* 05 Sep 01 ram added #ifdef __ppc__. *
46* 16 Jul 01 ram Moved exception flag symbols to fenv_private.h. *
47* Replaced __setflm with FEGETENVD and FESETENVD. *
48* 29 Sep 94 ali use __setflm for generating INEXACT, INVALID and *
49* DIVBYZERO in feraiseexecpt. *
50* 28 Sep 94 PAF Modified to use __setflm *
51* 07 Oct 93 ali corrected a mistake in setting flags for underflow *
52* and overflow in the feraiseexcept *
53* 07 Apr 93 ali included fenv.h and deleted the unnecessary macros *
54* 03 Feb 93 JPO Reflecting changes in NCEG specification, changed *
55* the following functions from type int to void: *
56* feclearexcept, fegetexceptflag, feraiseexcept, and *
57* fesetexceptflag. Changed the functionality of *
58* fesetexceptflag to match interpretation of the author *
59* of the NCEG spec. *
60* 21 Jan 93 JPO Added default environment _FE_DFL_ENV. *
61* 10 Dec 92 JPO Put underscore in names of low level routines *
62* (_getFPSCR and _setFPSCR). *
63* 30 Nov 92 JPO First created. *
64* *
65* W A R N I N G: *
66* These routines require a 64-bit double precision IEEE-754 model. *
67* They are written for PowerPC only and are expecting the compiler *
68* to generate the correct sequence of multiply-add fused instructions. *
69* *
70* These routines are not intended for 32-bit Intel architectures. *
71* *
72* A version of gcc higher than 932 is required. *
73* *
74* GCC compiler options: *
75* optimization level 3 (-O3) *
76* -fschedule-insns -finline-functions -funroll-all-loops *
77* *
78*******************************************************************************/
79
80#include "fp_private.h"
81#include "fenv_private.h"
82
83/******************************************************************************
84* Implementations of functions which provide access to the exception flags. *
85* The "int" input argument is constructed by bitwise ORs of the exception *
86* macros defined in fenv.h: for example, FE_OVERFLOW | FE_INEXACT. *
87******************************************************************************/
88
89static int _fegetexceptflag ( fexcept_t *flagp, int excepts )
90{
91 hexdouble temp;
92 fenv_t excstate;
93 uint32_t mask;
94
95 mask = excepts & FE_ALL_EXCEPT;
96 FEGETENVD_GRP( temp.d );
97 excstate = temp.i.lo & FE_ALL_FLAGS;
98 mask &= excstate;
99 if (mask == 0)
100 *flagp = 0;
101 else {
102 if ( (mask & FE_INVALID) == 0 ) excstate &= FE_NO_INVALID;
103 mask |= FE_NO_EXCEPT;
104 *flagp = excstate & mask;
105 }
106
107 return 0;
108}
109
110static int _fesetexceptflag ( const fexcept_t *flagp, int excepts )
111{
112 hexdouble ifpscr;
113 uint32_t mask;
114
115 mask = excepts & FE_ALL_EXCEPT;
116 if (mask != 0) { // take action if mask != 0
117 FEGETENVD_GRP( ifpscr.d ); // read current environment
118 if (excepts & FE_INVALID) // special case: INVALID
119 ifpscr.i.lo = (ifpscr.i.lo & FE_NO_INVALID) | (*flagp & FE_ALL_INVALID);
120 ifpscr.i.lo = (ifpscr.i.lo & (~mask)) | (*flagp & mask);
121 if (ifpscr.i.lo & FE_ALL_EXCEPT)
122 ifpscr.i.lo |= FE_SET_FX;
123 else
124 ifpscr.i.lo &= FE_CLR_FX;
125 FESETENVD_GRP( ifpscr.d );
126 }
127
128 return 0;
129}
130
131#if defined(BUILDING_FOR_CARBONCORE_LEGACY)
132
133/* default environment object */
134const fenv_t _FE_DFL_ENV = (const fenv_t) 0L;
135
136/****************************************************************************
137 the "feclearexcept" function clears the exceptions represented by its
138 argument.
139****************************************************************************/
140
141int feclearexcept ( int excepts )
142{
143 hexdouble ifpscr;
144 uint32_t mask;
145
146 mask = excepts & FE_ALL_EXCEPT;
147 if (( excepts & FE_INVALID) != 0 ) mask |= FE_ALL_INVALID;
148 FEGETENVD_GRP( ifpscr.d );
149 mask = ~mask;
150 //if (( excepts & FE_INVALID) != 0 ) mask &= FE_NO_INVALID;
151 ifpscr.i.lo &= mask;
152 if (( ifpscr.i.lo & FE_ALL_EXCEPT ) == 0)
153 ifpscr.i.lo &= FE_CLR_FX;
154 FESETENVD_GRP( ifpscr.d );
155 return 0;
156}
157
158/****************************************************************************
159 the "feraiseexcept" function raises the exceptions represented by its
160 argument.
161****************************************************************************/
162
163int feraiseexcept ( int excepts )
164{
165 uint32_t mask;
166 hexdouble ifpscr;
167
168 mask = excepts & FE_ALL_EXCEPT;
169
170 FEGETENVD_GRP( ifpscr.d );
171
172 if ((mask & FE_INVALID) != 0)
173 {
174 ifpscr.i.lo |= SET_INVALID;
175 mask &= ~FE_INVALID;
176 }
177
178 if (( mask & ( FE_OVERFLOW | FE_UNDERFLOW | FE_DIVBYZERO | FE_INEXACT )) != 0)
179 ifpscr.i.lo |= mask;
180
181 FESETENVD_GRP( ifpscr.d );
182 return 0;
183}
184
185/****************************************************************************
186 The function "fetestexcept" determines which of the specified subset of
187 the exception flags are currently set. It returns the bitwise OR of a
188 subset of the exception macros included in "excepts".
189****************************************************************************/
190
191int fetestexcept ( int excepts )
192{
193 hexdouble temp;
194
195 FEGETENVD_GRP( temp.d );
196 return (int) ((excepts & FE_ALL_EXCEPT) & temp.i.lo);
197}
198
199
200/* The following functions provide control of rounding direction modes. */
201
202/****************************************************************************
203 The function "fegetround" returns the value of the rounding direction
204 macro which represents the current rounding direction.
205****************************************************************************/
206
207int fegetround ( void )
208{
209 hexdouble temp;
210
211 FEGETENVD_GRP( temp.d );
212 return (int) (temp.i.lo & FE_ALL_RND);
213}
214
215
216/****************************************************************************
217 The function "fesetround" establishes the rounding direction
218 represented by its argument. It returns zero if and only if
219 the argument matches a rounding direction macro. If not, the
220 rounding direction is not changed.
221****************************************************************************/
222
223int fesetround ( int round )
224{
225 if ((round & FE_NO_RND))
226 return 1;
227 else
228 {
229 hexdouble temp;
230
231 FEGETENVD_GRP( temp.d );
232 temp.i.lo = (temp.i.lo & FE_NO_RND) | round;
233 FESETENVD_GRP( temp.d );
234 return 0;
235 }
236}
237
238
239/* The following functions manage the floating-point environment---
240 exception flags and dynamic modes---as one entity. */
241
242/****************************************************************************
243 The function "fgetenv" stores the current environment in the
244 object pointed to by its pointer argument "envp".
245****************************************************************************/
246
247int fegetenv ( fenv_t *envp )
248{
249 hexdouble temp;
250
251 FEGETENVD_GRP( temp.d );
252 *envp = temp.i.lo;
253 return 0;
254}
255
256
257/****************************************************************************
258 The function "feholdexcept" saves the current environment in
259 the object pointed to by its argument "envp" and clears the
260 exception flags. It returns zero. This function supersedes
261 the SANE function "procentry".
262****************************************************************************/
263
264int feholdexcept ( fenv_t *envp )
265{
266 hexdouble ifpscr;
267
268 FEGETENVD_GRP( ifpscr.d );
269 *envp = ifpscr.i.lo;
270 ifpscr.i.lo &= (FE_NO_FLAGS & FE_NO_ENABLES);
271 FESETENVD_GRP( ifpscr.d );
272 return 0;
273}
274
275
276/****************************************************************************
277 The function "fesetenv" establishes the floating-point environment
278 represented by the object pointed to by its argument "envp". The
279 value of "*env_p" must be set by a call to "fegetenv" or
280 "feholdexcept", by the macro "FE_DFL_ENV", or by an implementation-
281 defined macro of type "fenv_t".
282****************************************************************************/
283
284int fesetenv ( const fenv_t *envp )
285{
286 hexdouble temp;
287
288 temp.i.lo = *envp;
289 FESETENVD_GRP( temp.d );
290
291 return 0;
292}
293
294
295/****************************************************************************
296 The function "feupdateenv" saves the current exceptions in its
297 automatic storage, installs the environment pointed to by its
298 pointer argument "envp", and then re-raises the saved exceptions.
299 This function, which supersedes the SANE function "procexit", can
300 be used in conjunction with "feholdexcept" to write routines which
301 hide spurious exceptions from their callers.
302****************************************************************************/
303
304int feupdateenv ( const fenv_t *envp )
305{
306 int newexc;
307 hexdouble temp;
308
309 FEGETENVD_GRP( temp.d );
310 newexc = temp.i.lo & FE_ALL_EXCEPT;
311 temp.i.lo = *envp;
312 FESETENVD_GRP( temp.d );
313 feraiseexcept(newexc);
314 return 0;
315}
316
317/* Legacy entry point */
318void fegetexcept ( fexcept_t *flagp, int excepts )
319{
320 _fegetexceptflag (flagp, excepts );
321}
322
323/* Legacy entry point */
324void fesetexcept ( fexcept_t *flagp, int excepts )
325{
326 _fesetexceptflag ( flagp, excepts );
327}
328
329#else /* !BUILDING_FOR_CARBONCORE_LEGACY */
330
331/****************************************************************************
332 "fegetexceptflag" stores a representation of the exception flags indicated by
333 the argument "excepts" through the pointer argument "flagp".
334****************************************************************************/
335
336int fegetexceptflag ( fexcept_t *flagp, int excepts )
337{
338 return _fegetexceptflag (flagp, excepts );
339}
340
341
342/****************************************************************************
343 "fesetexceptflag" sets the exception flags indicated by the argument "excepts",
344 to the corresponding state represented in the object pointed to by "flagp".
345 This function does not raise exceptions, but only sets the state of the
346 flags.
347****************************************************************************/
348
349int fesetexceptflag ( const fexcept_t *flagp, int excepts )
350{
351 return _fesetexceptflag ( flagp, excepts );
352}
353
354/****************************************************************************
355 The float.h macro FLT_ROUNDS has a value derived from fegetround() --
356 Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown
357****************************************************************************/
358
359int __fegetfltrounds( void )
360{
361 switch ( fegetround() )
362 {
363 case FE_TONEAREST:
364 return 1;
365 case FE_TOWARDZERO:
366 return 0;
367 case FE_UPWARD:
368 return 2;
369 case FE_DOWNWARD:
370 return 3;
371 default:
372 return -1;
373 }
374}
375
376#endif /* !BUILDING_FOR_CARBONCORE_LEGACY */