1230192Sdas/*-
2230192Sdas * Copyright (c) 2004-2011 David Schultz <das@FreeBSD.ORG>
3230192Sdas * All rights reserved.
4230192Sdas *
5230192Sdas * Redistribution and use in source and binary forms, with or without
6230192Sdas * modification, are permitted provided that the following conditions
7230192Sdas * are met:
8230192Sdas * 1. Redistributions of source code must retain the above copyright
9230192Sdas *    notice, this list of conditions and the following disclaimer.
10230192Sdas * 2. Redistributions in binary form must reproduce the above copyright
11230192Sdas *    notice, this list of conditions and the following disclaimer in the
12230192Sdas *    documentation and/or other materials provided with the distribution.
13230192Sdas *
14230192Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15230192Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16230192Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17230192Sdas * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18230192Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19230192Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20230192Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21230192Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22230192Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23230192Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24230192Sdas * SUCH DAMAGE.
25230192Sdas *
26230192Sdas * $FreeBSD$
27230192Sdas */
28230192Sdas
29230192Sdas#ifndef	_FENV_H_
30230192Sdas#error "This file is meant to be included only by <fenv.h>."
31230192Sdas#endif
32230192Sdas
33230192Sdas/*
34230192Sdas * This file implements the functionality of <fenv.h> on platforms that
35230192Sdas * lack an FPU and use softfloat in libc for floating point.  To use it,
36230192Sdas * you must write an <fenv.h> that provides the following:
37230192Sdas *
38230192Sdas *   - a typedef for fenv_t, which may be an integer or struct type
39230192Sdas *   - a typedef for fexcept_t (XXX This file assumes fexcept_t is a
40230192Sdas *     simple integer type containing the exception mask.)
41230192Sdas *   - definitions of FE_* constants for the five exceptions and four
42230192Sdas *     rounding modes in IEEE 754, as described in fenv(3)
43230192Sdas *   - a definition, and the corresponding external symbol, for FE_DFL_ENV
44230192Sdas *   - a macro __set_env(env, flags, mask, rnd), which sets the given fenv_t
45230192Sdas *     from the exception flags, mask, and rounding mode
46230192Sdas *   - macros __env_flags(env), __env_mask(env), and __env_round(env), which
47230192Sdas *     extract fields from an fenv_t
48230192Sdas *   - a definition of __fenv_static
49230192Sdas *
50230192Sdas * If the architecture supports an optional FPU, it's recommended that you
51230192Sdas * define fenv_t and fexcept_t to match the hardware ABI.  Otherwise, it
52230192Sdas * doesn't matter how you define them.
53230192Sdas */
54230192Sdas
55230192Sdasextern int __softfloat_float_exception_flags;
56230192Sdasextern int __softfloat_float_exception_mask;
57230192Sdasextern int __softfloat_float_rounding_mode;
58230192Sdasvoid __softfloat_float_raise(int);
59230192Sdas
60230192Sdas__fenv_static inline int
61230192Sdasfeclearexcept(int __excepts)
62230192Sdas{
63230192Sdas
64230192Sdas	__softfloat_float_exception_flags &= ~__excepts;
65230192Sdas	return (0);
66230192Sdas}
67230192Sdas
68230192Sdas__fenv_static inline int
69230192Sdasfegetexceptflag(fexcept_t *__flagp, int __excepts)
70230192Sdas{
71230192Sdas
72230192Sdas	*__flagp = __softfloat_float_exception_flags & __excepts;
73230192Sdas	return (0);
74230192Sdas}
75230192Sdas
76230192Sdas__fenv_static inline int
77230192Sdasfesetexceptflag(const fexcept_t *__flagp, int __excepts)
78230192Sdas{
79230192Sdas
80230192Sdas	__softfloat_float_exception_flags &= ~__excepts;
81230192Sdas	__softfloat_float_exception_flags |= *__flagp & __excepts;
82230192Sdas	return (0);
83230192Sdas}
84230192Sdas
85230192Sdas__fenv_static inline int
86230192Sdasferaiseexcept(int __excepts)
87230192Sdas{
88230192Sdas
89230192Sdas	__softfloat_float_raise(__excepts);
90230192Sdas	return (0);
91230192Sdas}
92230192Sdas
93230192Sdas__fenv_static inline int
94230192Sdasfetestexcept(int __excepts)
95230192Sdas{
96230192Sdas
97230192Sdas	return (__softfloat_float_exception_flags & __excepts);
98230192Sdas}
99230192Sdas
100230192Sdas__fenv_static inline int
101230192Sdasfegetround(void)
102230192Sdas{
103230192Sdas
104230192Sdas	return (__softfloat_float_rounding_mode);
105230192Sdas}
106230192Sdas
107230192Sdas__fenv_static inline int
108230192Sdasfesetround(int __round)
109230192Sdas{
110230192Sdas
111230192Sdas	__softfloat_float_rounding_mode = __round;
112230192Sdas	return (0);
113230192Sdas}
114230192Sdas
115230192Sdas__fenv_static inline int
116230192Sdasfegetenv(fenv_t *__envp)
117230192Sdas{
118230192Sdas
119230192Sdas	__set_env(*__envp, __softfloat_float_exception_flags,
120230192Sdas	    __softfloat_float_exception_mask, __softfloat_float_rounding_mode);
121230192Sdas	return (0);
122230192Sdas}
123230192Sdas
124230192Sdas__fenv_static inline int
125230192Sdasfeholdexcept(fenv_t *__envp)
126230192Sdas{
127230192Sdas	fenv_t __env;
128230192Sdas
129230192Sdas	fegetenv(__envp);
130230192Sdas	__softfloat_float_exception_flags = 0;
131230192Sdas	__softfloat_float_exception_mask = 0;
132230192Sdas	return (0);
133230192Sdas}
134230192Sdas
135230192Sdas__fenv_static inline int
136230192Sdasfesetenv(const fenv_t *__envp)
137230192Sdas{
138230192Sdas
139230192Sdas	__softfloat_float_exception_flags = __env_flags(*__envp);
140230192Sdas	__softfloat_float_exception_mask = __env_mask(*__envp);
141230192Sdas	__softfloat_float_rounding_mode = __env_round(*__envp);
142230192Sdas	return (0);
143230192Sdas}
144230192Sdas
145230192Sdas__fenv_static inline int
146230192Sdasfeupdateenv(const fenv_t *__envp)
147230192Sdas{
148230192Sdas	int __oflags = __softfloat_float_exception_flags;
149230192Sdas
150230192Sdas	fesetenv(__envp);
151230192Sdas	feraiseexcept(__oflags);
152230192Sdas	return (0);
153230192Sdas}
154230192Sdas
155230192Sdas#if __BSD_VISIBLE
156230192Sdas
157230192Sdas/* We currently provide no external definitions of the functions below. */
158230192Sdas
159266133Sian__fenv_static inline int
160230192Sdasfeenableexcept(int __mask)
161230192Sdas{
162230192Sdas	int __omask = __softfloat_float_exception_mask;
163230192Sdas
164230192Sdas	__softfloat_float_exception_mask |= __mask;
165230192Sdas	return (__omask);
166230192Sdas}
167230192Sdas
168266133Sian__fenv_static inline int
169230192Sdasfedisableexcept(int __mask)
170230192Sdas{
171230192Sdas	int __omask = __softfloat_float_exception_mask;
172230192Sdas
173230192Sdas	__softfloat_float_exception_mask &= ~__mask;
174230192Sdas	return (__omask);
175230192Sdas}
176230192Sdas
177266133Sian__fenv_static inline int
178230192Sdasfegetexcept(void)
179230192Sdas{
180230192Sdas
181230192Sdas	return (__softfloat_float_exception_mask);
182230192Sdas}
183230192Sdas
184230192Sdas#endif /* __BSD_VISIBLE */
185