Home | History | Annotate | Download | only in sparc64
      1 /*-
      2  * Copyright (c) 2004-2005 David Schultz <das (at) 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/sparc64/fenv.h,v 1.3 2005/03/16 19:03:46 das Exp $
     27  */
     28 
     29 #ifndef	_FENV_H_
     30 #define	_FENV_H_
     31 
     32 #include <sys/_types.h>
     33 
     34 typedef	__uint64_t	fenv_t;
     35 typedef	__uint64_t	fexcept_t;
     36 
     37 /* Exception flags */
     38 #define	FE_INVALID	0x00000200
     39 #define	FE_DIVBYZERO	0x00000040
     40 #define	FE_OVERFLOW	0x00000100
     41 #define	FE_UNDERFLOW	0x00000080
     42 #define	FE_INEXACT	0x00000020
     43 #define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
     44 			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
     45 
     46 /*
     47  * Rounding modes
     48  *
     49  * We can't just use the hardware bit values here, because that would
     50  * make FE_UPWARD and FE_DOWNWARD negative, which is not allowed.
     51  */
     52 #define	FE_TONEAREST	0x0
     53 #define	FE_TOWARDZERO	0x1
     54 #define	FE_UPWARD	0x2
     55 #define	FE_DOWNWARD	0x3
     56 #define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
     57 			 FE_UPWARD | FE_TOWARDZERO)
     58 #define	_ROUND_SHIFT	30
     59 
     60 __BEGIN_DECLS
     61 
     62 /* Default floating-point environment */
     63 extern const fenv_t	__fe_dfl_env;
     64 #define	FE_DFL_ENV	(&__fe_dfl_env)
     65 
     66 /* We need to be able to map status flag positions to mask flag positions */
     67 #define _FPUSW_SHIFT	18
     68 #define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
     69 
     70 #define	__ldxfsr(__r)	__asm __volatile("ldx %0, %%fsr" : : "m" (__r))
     71 #define	__stxfsr(__r)	__asm __volatile("stx %%fsr, %0" : "=m" (*(__r)))
     72 
     73 static __inline int
     74 feclearexcept(int __excepts)
     75 {
     76 	fexcept_t __r;
     77 
     78 	__stxfsr(&__r);
     79 	__r &= ~__excepts;
     80 	__ldxfsr(__r);
     81 	return (0);
     82 }
     83 
     84 static __inline int
     85 fegetexceptflag(fexcept_t *__flagp, int __excepts)
     86 {
     87 	fexcept_t __r;
     88 
     89 	__stxfsr(&__r);
     90 	*__flagp = __r & __excepts;
     91 	return (0);
     92 }
     93 
     94 static __inline int
     95 fesetexceptflag(const fexcept_t *__flagp, int __excepts)
     96 {
     97 	fexcept_t __r;
     98 
     99 	__stxfsr(&__r);
    100 	__r &= ~__excepts;
    101 	__r |= *__flagp & __excepts;
    102 	__ldxfsr(__r);
    103 	return (0);
    104 }
    105 
    106 /*
    107  * In contrast with the ia64 platform, it seems to be worthwhile to
    108  * inline this function on sparc64 even when the arguments are not
    109  * compile-time constants.  Perhaps this depends on the register window.
    110  */
    111 static __inline int
    112 feraiseexcept(int __excepts)
    113 {
    114 	volatile double d;
    115 
    116 	/*
    117 	 * With a compiler that supports the FENV_ACCESS pragma
    118 	 * properly, simple expressions like '0.0 / 0.0' should
    119 	 * be sufficient to generate traps.  Unfortunately, we
    120 	 * need to bring a volatile variable into the equation
    121 	 * to prevent incorrect optimizations.
    122 	 */
    123 	if (__excepts & FE_INVALID) {
    124 		d = 0.0;
    125 		d = 0.0 / d;
    126 	}
    127 	if (__excepts & FE_DIVBYZERO) {
    128 		d = 0.0;
    129 		d = 1.0 / d;
    130 	}
    131 	if (__excepts & FE_OVERFLOW) {
    132 		d = 0x1.ffp1023;
    133 		d *= 2.0;
    134 	}
    135 	if (__excepts & FE_UNDERFLOW) {
    136 		d = 0x1p-1022;
    137 		d /= 0x1p1023;
    138 	}
    139 	if (__excepts & FE_INEXACT) {
    140 		d = 0x1p-1022;
    141 		d += 1.0;
    142 	}
    143 	return (0);
    144 }
    145 
    146 static __inline int
    147 fetestexcept(int __excepts)
    148 {
    149 	fexcept_t __r;
    150 
    151 	__stxfsr(&__r);
    152 	return (__r & __excepts);
    153 }
    154 
    155 static __inline int
    156 fegetround(void)
    157 {
    158 	fenv_t __r;
    159 
    160 	__stxfsr(&__r);
    161 	return ((__r >> _ROUND_SHIFT) & _ROUND_MASK);
    162 }
    163 
    164 static __inline int
    165 fesetround(int __round)
    166 {
    167 	fenv_t __r;
    168 
    169 	if (__round & ~_ROUND_MASK)
    170 		return (-1);
    171 	__stxfsr(&__r);
    172 	__r &= ~(_ROUND_MASK << _ROUND_SHIFT);
    173 	__r |= __round << _ROUND_SHIFT;
    174 	__ldxfsr(__r);
    175 	return (0);
    176 }
    177 
    178 static __inline int
    179 fegetenv(fenv_t *__envp)
    180 {
    181 
    182 	__stxfsr(__envp);
    183 	return (0);
    184 }
    185 
    186 static __inline int
    187 feholdexcept(fenv_t *__envp)
    188 {
    189 	fenv_t __r;
    190 
    191 	__stxfsr(&__r);
    192 	*__envp = __r;
    193 	__r &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
    194 	__ldxfsr(__r);
    195 	return (0);
    196 }
    197 
    198 static __inline int
    199 fesetenv(const fenv_t *__envp)
    200 {
    201 
    202 	__ldxfsr(*__envp);
    203 	return (0);
    204 }
    205 
    206 static __inline int
    207 feupdateenv(const fenv_t *__envp)
    208 {
    209 	fexcept_t __r;
    210 
    211 	__stxfsr(&__r);
    212 	__ldxfsr(*__envp);
    213 	feraiseexcept(__r & FE_ALL_EXCEPT);
    214 	return (0);
    215 }
    216 
    217 #if __BSD_VISIBLE
    218 
    219 static __inline int
    220 feenableexcept(int __mask)
    221 {
    222 	fenv_t __old_r, __new_r;
    223 
    224 	__stxfsr(&__old_r);
    225 	__new_r = __old_r | ((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
    226 	__ldxfsr(__new_r);
    227 	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
    228 }
    229 
    230 static __inline int
    231 fedisableexcept(int __mask)
    232 {
    233 	fenv_t __old_r, __new_r;
    234 
    235 	__stxfsr(&__old_r);
    236 	__new_r = __old_r & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
    237 	__ldxfsr(__new_r);
    238 	return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
    239 }
    240 
    241 static __inline int
    242 fegetexcept(void)
    243 {
    244 	fenv_t __r;
    245 
    246 	__stxfsr(&__r);
    247 	return ((__r & _ENABLE_MASK) >> _FPUSW_SHIFT);
    248 }
    249 
    250 #endif /* __BSD_VISIBLE */
    251 
    252 __END_DECLS
    253 
    254 #endif	/* !_FENV_H_ */
    255