Home | History | Annotate | Download | only in amd64
      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/amd64/fenv.h,v 1.5 2005/03/16 22:34:14 das Exp $
     27  */
     28 
     29 #ifndef	_FENV_H_
     30 #define	_FENV_H_
     31 
     32 #include <sys/cdefs.h>
     33 #include <sys/_types.h>
     34 
     35 typedef struct {
     36 	struct {
     37 		__uint32_t	__control;
     38 		__uint32_t	__status;
     39 		__uint32_t	__tag;
     40 		char		__other[16];
     41 	} __x87;
     42 	__uint32_t		__mxcsr;
     43 } fenv_t;
     44 
     45 typedef	__uint16_t	fexcept_t;
     46 
     47 /* Exception flags */
     48 #define	FE_INVALID	0x01
     49 #define	FE_DENORMAL	0x02
     50 #define	FE_DIVBYZERO	0x04
     51 #define	FE_OVERFLOW	0x08
     52 #define	FE_UNDERFLOW	0x10
     53 #define	FE_INEXACT	0x20
     54 #define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \
     55 			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
     56 
     57 /* Rounding modes */
     58 #define	FE_TONEAREST	0x0000
     59 #define	FE_DOWNWARD	0x0400
     60 #define	FE_UPWARD	0x0800
     61 #define	FE_TOWARDZERO	0x0c00
     62 #define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
     63 			 FE_UPWARD | FE_TOWARDZERO)
     64 
     65 /*
     66  * As compared to the x87 control word, the SSE unit's control word
     67  * has the rounding control bits offset by 3 and the exception mask
     68  * bits offset by 7.
     69  */
     70 #define	_SSE_ROUND_SHIFT	3
     71 #define	_SSE_EMASK_SHIFT	7
     72 
     73 __BEGIN_DECLS
     74 
     75 /* Default floating-point environment */
     76 extern const fenv_t	__fe_dfl_env;
     77 #define	FE_DFL_ENV	(&__fe_dfl_env)
     78 
     79 #define	__fldcw(__cw)		__asm __volatile("fldcw %0" : : "m" (__cw))
     80 #define	__fldenv(__env)		__asm __volatile("fldenv %0" : : "m" (__env))
     81 #define	__fnclex()		__asm __volatile("fnclex")
     82 #define	__fnstenv(__env)	__asm __volatile("fnstenv %0" : "=m" (*(__env)))
     83 #define	__fnstcw(__cw)		__asm __volatile("fnstcw %0" : "=m" (*(__cw)))
     84 #define	__fnstsw(__sw)		__asm __volatile("fnstsw %0" : "=am" (*(__sw)))
     85 #define	__fwait()		__asm __volatile("fwait")
     86 #define	__ldmxcsr(__csr)	__asm __volatile("ldmxcsr %0" : : "m" (__csr))
     87 #define	__stmxcsr(__csr)	__asm __volatile("stmxcsr %0" : "=m" (*(__csr)))
     88 
     89 static __inline int
     90 feclearexcept(int __excepts)
     91 {
     92 	fenv_t __env;
     93 
     94 	if (__excepts == FE_ALL_EXCEPT) {
     95 		__fnclex();
     96 	} else {
     97 		__fnstenv(&__env.__x87);
     98 		__env.__x87.__status &= ~__excepts;
     99 		__fldenv(__env.__x87);
    100 	}
    101 	__stmxcsr(&__env.__mxcsr);
    102 	__env.__mxcsr &= ~__excepts;
    103 	__ldmxcsr(__env.__mxcsr);
    104 	return (0);
    105 }
    106 
    107 static __inline int
    108 fegetexceptflag(fexcept_t *__flagp, int __excepts)
    109 {
    110 	int __mxcsr, __status;
    111 
    112 	__stmxcsr(&__mxcsr);
    113 	__fnstsw(&__status);
    114 	*__flagp = (__mxcsr | __status) & __excepts;
    115 	return (0);
    116 }
    117 
    118 int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
    119 int feraiseexcept(int __excepts);
    120 
    121 static __inline int
    122 fetestexcept(int __excepts)
    123 {
    124 	int __mxcsr, __status;
    125 
    126 	__stmxcsr(&__mxcsr);
    127 	__fnstsw(&__status);
    128 	return ((__status | __mxcsr) & __excepts);
    129 }
    130 
    131 static __inline int
    132 fegetround(void)
    133 {
    134 	int __control;
    135 
    136 	/*
    137 	 * We assume that the x87 and the SSE unit agree on the
    138 	 * rounding mode.  Reading the control word on the x87 turns
    139 	 * out to be about 5 times faster than reading it on the SSE
    140 	 * unit on an Opteron 244.
    141 	 */
    142 	__fnstcw(&__control);
    143 	return (__control & _ROUND_MASK);
    144 }
    145 
    146 static __inline int
    147 fesetround(int __round)
    148 {
    149 	int __mxcsr, __control;
    150 
    151 	if (__round & ~_ROUND_MASK)
    152 		return (-1);
    153 
    154 	__fnstcw(&__control);
    155 	__control &= ~_ROUND_MASK;
    156 	__control |= __round;
    157 	__fldcw(__control);
    158 
    159 	__stmxcsr(&__mxcsr);
    160 	__mxcsr &= ~(_ROUND_MASK << _SSE_ROUND_SHIFT);
    161 	__mxcsr |= __round << _SSE_ROUND_SHIFT;
    162 	__ldmxcsr(__mxcsr);
    163 
    164 	return (0);
    165 }
    166 
    167 int fegetenv(fenv_t *__envp);
    168 int feholdexcept(fenv_t *__envp);
    169 
    170 static __inline int
    171 fesetenv(const fenv_t *__envp)
    172 {
    173 
    174 	__fldenv(__envp->__x87);
    175 	__ldmxcsr(__envp->__mxcsr);
    176 	return (0);
    177 }
    178 
    179 int feupdateenv(const fenv_t *__envp);
    180 
    181 #if __BSD_VISIBLE
    182 
    183 int feenableexcept(int __mask);
    184 int fedisableexcept(int __mask);
    185 
    186 static __inline int
    187 fegetexcept(void)
    188 {
    189 	int __control;
    190 
    191 	/*
    192 	 * We assume that the masks for the x87 and the SSE unit are
    193 	 * the same.
    194 	 */
    195 	__fnstcw(&__control);
    196 	return (~__control & FE_ALL_EXCEPT);
    197 }
    198 
    199 #endif /* __BSD_VISIBLE */
    200 
    201 __END_DECLS
    202 
    203 #endif	/* !_FENV_H_ */
    204