1 /* Internal libc stuff for floating point environment routines.
2    Copyright (C) 1997-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #ifndef _FENV_LIBC_H
20 #define _FENV_LIBC_H	1
21 
22 #include <fenv.h>
23 #include <ldsodefs.h>
24 #include <sysdep.h>
25 
26 extern const fenv_t *__fe_nomask_env_priv (void);
27 
28 extern const fenv_t *__fe_mask_env (void) attribute_hidden;
29 
30 /* If the old env had any enabled exceptions and the new env has no enabled
31    exceptions, then mask SIGFPE in the MSR FE0/FE1 bits.  This may allow the
32    FPU to run faster because it always takes the default action and can not
33    generate SIGFPE.  */
34 #define __TEST_AND_ENTER_NON_STOP(old, new) \
35   do { \
36     if (((old) & FPSCR_ENABLES_MASK) != 0 && ((new) & FPSCR_ENABLES_MASK) == 0) \
37       (void) __fe_mask_env (); \
38   } while (0)
39 
40 /* If the old env has no enabled exceptions and the new env has any enabled
41    exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits.  This will put the
42    hardware into "precise mode" and may cause the FPU to run slower on some
43    hardware.  */
44 #define __TEST_AND_EXIT_NON_STOP(old, new) \
45   do { \
46     if (((old) & FPSCR_ENABLES_MASK) == 0 && ((new) & FPSCR_ENABLES_MASK) != 0) \
47       (void) __fe_nomask_env_priv (); \
48   } while (0)
49 
50 /* The sticky bits in the FPSCR indicating exceptions have occurred.  */
51 #define FPSCR_STICKY_BITS ((FE_ALL_EXCEPT | FE_ALL_INVALID) & ~FE_INVALID)
52 
53 /* Equivalent to fegetenv, but returns a fenv_t instead of taking a
54    pointer.  */
55 #define fegetenv_register() __builtin_mffs()
56 
57 /* Equivalent to fegetenv_register, but only returns bits for
58    status, exception enables, and mode.
59    Nicely, it turns out that the 'mffsl' instruction will decode to
60    'mffs' on architectures older than "power9" because the additional
61    bits set for 'mffsl' are "don't care" for 'mffs'.  'mffs' is a superset
62    of 'mffsl'.  */
63 #define fegetenv_control()					\
64   ({register double __fr;						\
65     __asm__ __volatile__ (						\
66       ".machine push; .machine \"power9\"; mffsl %0; .machine pop"	\
67       : "=f" (__fr));							\
68     __fr;								\
69   })
70 
71 #define __fe_mffscrn(rn)						\
72   ({register fenv_union_t __fr;						\
73     if (__builtin_constant_p (rn))					\
74       __asm__ __volatile__ (						\
75         ".machine push; .machine \"power9\"; mffscrni %0,%1; .machine pop" \
76         : "=f" (__fr.fenv) : "n" (rn));					\
77     else								\
78     {									\
79       __fr.l = (rn);							\
80       __asm__ __volatile__ (						\
81         ".machine push; .machine \"power9\"; mffscrn %0,%1; .machine pop" \
82         : "=f" (__fr.fenv) : "f" (__fr.fenv));				\
83     }									\
84     __fr.fenv;								\
85   })
86 
87 /* Like fegetenv_control, but also sets the rounding mode.  */
88 #ifdef _ARCH_PWR9
89 #define fegetenv_and_set_rn(rn) __fe_mffscrn (rn)
90 #else
91 /* 'mffscrn' will decode to 'mffs' on ARCH < 3_00, which is still necessary
92    but not sufficient, because it does not set the rounding mode.
93    Explicitly set the rounding mode when 'mffscrn' actually doesn't.  */
94 #define fegetenv_and_set_rn(rn)						\
95   ({register fenv_union_t __fr;						\
96     __fr.fenv = __fe_mffscrn (rn);					\
97     if (__glibc_unlikely (!(GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00)))	\
98       __fesetround_inline (rn);						\
99     __fr.fenv;								\
100   })
101 #endif
102 
103 /* Equivalent to fesetenv, but takes a fenv_t instead of a pointer.  */
104 #define fesetenv_register(env) \
105 	do { \
106 	  double d = (env); \
107 	  if(GLRO(dl_hwcap) & PPC_FEATURE_HAS_DFP) \
108 	    asm volatile (".machine push; " \
109 			  ".machine \"power6\"; " \
110 			  "mtfsf 0xff,%0,1,0; " \
111 			  ".machine pop" : : "f" (d)); \
112 	  else \
113 	    __builtin_mtfsf (0xff, d); \
114 	} while(0)
115 
116 /* Set the last 2 nibbles of the FPSCR, which contain the
117    exception enables and the rounding mode.
118    'fegetenv_control' retrieves these bits by reading the FPSCR.  */
119 #define fesetenv_control(env) __builtin_mtfsf (0b00000011, (env));
120 
121 /* This very handy macro:
122    - Sets the rounding mode to 'round to nearest';
123    - Sets the processor into IEEE mode; and
124    - Prevents exceptions from being raised for inexact results.
125    These things happen to be exactly what you need for typical elementary
126    functions.  */
127 #define relax_fenv_state() \
128 	do { \
129 	   if (GLRO(dl_hwcap) & PPC_FEATURE_HAS_DFP) \
130 	     asm volatile (".machine push; .machine \"power6\"; " \
131 		  "mtfsfi 7,0,1; .machine pop"); \
132 	   asm volatile ("mtfsfi 7,0"); \
133 	} while(0)
134 
135 /* Set/clear a particular FPSCR bit (for instance,
136    reset_fpscr_bit(FPSCR_VE);
137    prevents INVALID exceptions from being raised).  */
138 #define set_fpscr_bit(x) asm volatile ("mtfsb1 %0" : : "n"(x))
139 #define reset_fpscr_bit(x) asm volatile ("mtfsb0 %0" : : "n"(x))
140 
141 typedef union
142 {
143   fenv_t fenv;
144   unsigned long long l;
145 } fenv_union_t;
146 
147 
148 static inline int
__fesetround_inline(int round)149 __fesetround_inline (int round)
150 {
151 #ifdef _ARCH_PWR9
152   __fe_mffscrn (round);
153 #else
154   if (__glibc_likely (GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00))
155     __fe_mffscrn (round);
156   else if ((unsigned int) round < 2)
157     {
158        asm volatile ("mtfsb0 30");
159        if ((unsigned int) round == 0)
160          asm volatile ("mtfsb0 31");
161        else
162          asm volatile ("mtfsb1 31");
163     }
164   else
165     {
166        asm volatile ("mtfsb1 30");
167        if ((unsigned int) round == 2)
168          asm volatile ("mtfsb0 31");
169        else
170          asm volatile ("mtfsb1 31");
171     }
172 #endif
173   return 0;
174 }
175 
176 /* Same as __fesetround_inline, however without runtime check to use DFP
177    mtfsfi syntax (as relax_fenv_state) or if round value is valid.  */
178 static inline void
__fesetround_inline_nocheck(const int round)179 __fesetround_inline_nocheck (const int round)
180 {
181 #ifdef _ARCH_PWR9
182   __fe_mffscrn (round);
183 #else
184   if (__glibc_likely (GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00))
185     __fe_mffscrn (round);
186   else
187     asm volatile ("mtfsfi 7,%0" : : "n" (round));
188 #endif
189 }
190 
191 #define FPSCR_MASK(bit) (1 << (31 - (bit)))
192 
193 /* Definitions of all the FPSCR bit numbers */
194 enum {
195   FPSCR_FX = 0,    /* exception summary */
196 #define FPSCR_FX_MASK (FPSCR_MASK (FPSCR_FX))
197   FPSCR_FEX,       /* enabled exception summary */
198 #define FPSCR_FEX_MASK (FPSCR_MASK FPSCR_FEX))
199   FPSCR_VX,        /* invalid operation summary */
200 #define FPSCR_VX_MASK (FPSCR_MASK (FPSCR_VX))
201   FPSCR_OX,        /* overflow */
202 #define FPSCR_OX_MASK (FPSCR_MASK (FPSCR_OX))
203   FPSCR_UX,        /* underflow */
204 #define FPSCR_UX_MASK (FPSCR_MASK (FPSCR_UX))
205   FPSCR_ZX,        /* zero divide */
206 #define FPSCR_ZX_MASK (FPSCR_MASK (FPSCR_ZX))
207   FPSCR_XX,        /* inexact */
208 #define FPSCR_XX_MASK (FPSCR_MASK (FPSCR_XX))
209   FPSCR_VXSNAN,    /* invalid operation for sNaN */
210 #define FPSCR_VXSNAN_MASK (FPSCR_MASK (FPSCR_VXSNAN))
211   FPSCR_VXISI,     /* invalid operation for Inf-Inf */
212 #define FPSCR_VXISI_MASK (FPSCR_MASK (FPSCR_VXISI))
213   FPSCR_VXIDI,     /* invalid operation for Inf/Inf */
214 #define FPSCR_VXIDI_MASK (FPSCR_MASK (FPSCR_VXIDI))
215   FPSCR_VXZDZ,     /* invalid operation for 0/0 */
216 #define FPSCR_VXZDZ_MASK (FPSCR_MASK (FPSCR_VXZDZ))
217   FPSCR_VXIMZ,     /* invalid operation for Inf*0 */
218 #define FPSCR_VXIMZ_MASK (FPSCR_MASK (FPSCR_VXIMZ))
219   FPSCR_VXVC,      /* invalid operation for invalid compare */
220 #define FPSCR_VXVC_MASK (FPSCR_MASK (FPSCR_VXVC))
221   FPSCR_FR,        /* fraction rounded [fraction was incremented by round] */
222 #define FPSCR_FR_MASK (FPSCR_MASK (FPSCR_FR))
223   FPSCR_FI,        /* fraction inexact */
224 #define FPSCR_FI_MASK (FPSCR_MASK (FPSCR_FI))
225   FPSCR_FPRF_C,    /* result class descriptor */
226 #define FPSCR_FPRF_C_MASK (FPSCR_MASK (FPSCR_FPRF_C))
227   FPSCR_FPRF_FL,   /* result less than (usually, less than 0) */
228 #define FPSCR_FPRF_FL_MASK (FPSCR_MASK (FPSCR_FPRF_FL))
229   FPSCR_FPRF_FG,   /* result greater than */
230 #define FPSCR_FPRF_FG_MASK (FPSCR_MASK (FPSCR_FPRF_FG))
231   FPSCR_FPRF_FE,   /* result equal to */
232 #define FPSCR_FPRF_FE_MASK (FPSCR_MASK (FPSCR_FPRF_FE))
233   FPSCR_FPRF_FU,   /* result unordered */
234 #define FPSCR_FPRF_FU_MASK (FPSCR_MASK (FPSCR_FPRF_FU))
235   FPSCR_20,        /* reserved */
236   FPSCR_VXSOFT,    /* invalid operation set by software */
237 #define FPSCR_VXSOFT_MASK (FPSCR_MASK (FPSCR_VXSOFT))
238   FPSCR_VXSQRT,    /* invalid operation for square root */
239 #define FPSCR_VXSQRT_MASK (FPSCR_MASK (FPSCR_VXSQRT))
240   FPSCR_VXCVI,     /* invalid operation for invalid integer convert */
241 #define FPSCR_VXCVI_MASK (FPSCR_MASK (FPSCR_VXCVI))
242   FPSCR_VE,        /* invalid operation exception enable */
243 #define FPSCR_VE_MASK (FPSCR_MASK (FPSCR_VE))
244   FPSCR_OE,        /* overflow exception enable */
245 #define FPSCR_OE_MASK (FPSCR_MASK (FPSCR_OE))
246   FPSCR_UE,        /* underflow exception enable */
247 #define FPSCR_UE_MASK (FPSCR_MASK (FPSCR_UE))
248   FPSCR_ZE,        /* zero divide exception enable */
249 #define FPSCR_ZE_MASK (FPSCR_MASK (FPSCR_ZE))
250   FPSCR_XE,        /* inexact exception enable */
251 #define FPSCR_XE_MASK (FPSCR_MASK (FPSCR_XE))
252 #ifdef _ARCH_PWR6
253   FPSCR_29,        /* Reserved in ISA 2.05  */
254 #define FPSCR_NI_MASK (FPSCR_MASK (FPSCR_29))
255 #else
256   FPSCR_NI,        /* non-IEEE mode (typically, no denormalised numbers) */
257 #define FPSCR_NI_MASK (FPSCR_MASK (FPSCR_NI))
258 #endif /* _ARCH_PWR6 */
259   /* the remaining two least-significant bits keep the rounding mode */
260   FPSCR_RN_hi,
261 #define FPSCR_RN_hi_MASK (FPSCR_MASK (FPSCR_RN_hi))
262   FPSCR_RN_lo
263 #define FPSCR_RN_lo_MASK (FPSCR_MASK (FPSCR_RN_lo))
264 };
265 
266 #define FPSCR_RN_MASK (FPSCR_RN_hi_MASK|FPSCR_RN_lo_MASK)
267 #define FPSCR_ENABLES_MASK \
268   (FPSCR_VE_MASK|FPSCR_OE_MASK|FPSCR_UE_MASK|FPSCR_ZE_MASK|FPSCR_XE_MASK)
269 #define FPSCR_BASIC_EXCEPTIONS_MASK \
270   (FPSCR_VX_MASK|FPSCR_OX_MASK|FPSCR_UX_MASK|FPSCR_ZX_MASK|FPSCR_XX_MASK)
271 #define FPSCR_EXCEPTIONS_MASK (FPSCR_BASIC_EXCEPTIONS_MASK| \
272   FPSCR_VXSNAN_MASK|FPSCR_VXISI_MASK|FPSCR_VXIDI_MASK|FPSCR_VXZDZ_MASK| \
273   FPSCR_VXIMZ_MASK|FPSCR_VXVC_MASK|FPSCR_VXSOFT_MASK|FPSCR_VXSQRT_MASK| \
274   FPSCR_VXCVI_MASK)
275 #define FPSCR_FPRF_MASK \
276   (FPSCR_FPRF_C_MASK|FPSCR_FPRF_FL_MASK|FPSCR_FPRF_FG_MASK| \
277    FPSCR_FPRF_FE_MASK|FPSCR_FPRF_FU_MASK)
278 #define FPSCR_CONTROL_MASK (FPSCR_ENABLES_MASK|FPSCR_NI_MASK|FPSCR_RN_MASK)
279 #define FPSCR_STATUS_MASK (FPSCR_FR_MASK|FPSCR_FI_MASK|FPSCR_FPRF_MASK)
280 
281 /* The bits in the FENV(1) ABI for exceptions correspond one-to-one with bits
282    in the FPSCR, albeit shifted to different but corresponding locations.
283    Similarly, the exception indicator bits in the FPSCR correspond one-to-one
284    with the exception enable bits. It is thus possible to map the FENV(1)
285    exceptions directly to the FPSCR enables with a simple mask and shift,
286    and vice versa. */
287 #define FPSCR_EXCEPT_TO_ENABLE_SHIFT 22
288 
289 static inline int
fenv_reg_to_exceptions(unsigned long long l)290 fenv_reg_to_exceptions (unsigned long long l)
291 {
292   return (((int)l) & FPSCR_ENABLES_MASK) << FPSCR_EXCEPT_TO_ENABLE_SHIFT;
293 }
294 
295 static inline unsigned long long
fenv_exceptions_to_reg(int excepts)296 fenv_exceptions_to_reg (int excepts)
297 {
298   return (unsigned long long)
299     (excepts & FE_ALL_EXCEPT) >> FPSCR_EXCEPT_TO_ENABLE_SHIFT;
300 }
301 
302 #ifdef _ARCH_PWR6
303   /* Not supported in ISA 2.05.  Provided for source compat only.  */
304 # define FPSCR_NI 29
305 #endif /* _ARCH_PWR6 */
306 
307 /* This operation (i) sets the appropriate FPSCR bits for its
308    parameter, (ii) converts sNaN to the corresponding qNaN, and (iii)
309    otherwise passes its parameter through unchanged (in particular, -0
310    and +0 stay as they were).  The `obvious' way to do this is optimised
311    out by gcc.  */
312 #define f_wash(x) \
313    ({ double d; asm volatile ("fmul %0,%1,%2" \
314 			      : "=f"(d) \
315 			      : "f" (x), "f"((float)1.0)); d; })
316 #define f_washf(x) \
317    ({ float f; asm volatile ("fmuls %0,%1,%2" \
318 			     : "=f"(f) \
319 			     : "f" (x), "f"((float)1.0)); f; })
320 
321 #endif /* fenv_libc.h */
322