1 /* Definitions of libc internal inline math functions implemented
2 by the m68881/2.
3 Copyright (C) 1991-2022 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library. If not, see
18 <https://www.gnu.org/licenses/>. */
19
20 #ifndef _MATHIMPL_H
21 #define _MATHIMPL_H
22
23 /* This file contains the definitions of the inline math functions that
24 are only used internally inside libm, not visible to the user. */
25
26 #define __MATH_INLINE __extern_inline
27
28 /* This is used when defining the functions themselves. Define them with
29 __ names, and with `static inline' instead of `extern inline' so the
30 bodies will always be used, never an external function call.
31 Note: GCC 6 objects to __attribute__ ((__leaf__)) on static functions. */
32 #define __m81_u(x) __CONCAT(__,x)
33 #define __m81_inline static __inline
34 #define __m81_nth(fn) __NTH (fn)
35
36 /* Define a math function. */
37 #define __m81_defun(rettype, func, args, attrs) \
38 __m81_inline rettype attrs \
39 __m81_nth (__m81_u(func) args)
40
41 /* Define the three variants of a math function that has a direct
42 implementation in the m68k fpu. FUNC is the name for C (which will be
43 suffixed with f and l for the float and long double version, resp). OP
44 is the name of the fpu operation (without leading f). */
45
46 # define __inline_mathop(func, op, attrs) \
47 __inline_mathop1(double, func, op, attrs) \
48 __inline_mathop1(float, __CONCAT(func,f), op, attrs) \
49 __inline_mathop1(long double, __CONCAT(func,l), op, attrs)
50
51 #define __inline_mathop1(float_type,func, op, attrs) \
52 __m81_defun (float_type, func, (float_type __mathop_x), attrs) \
53 { \
54 float_type __result; \
55 __asm __volatile__ ("f" __STRING(op) "%.x %1, %0" \
56 : "=f" (__result) : "f" (__mathop_x)); \
57 return __result; \
58 }
59
60 __inline_mathop(__atan, atan,)
61 __inline_mathop(__cos, cos,)
62 __inline_mathop(__sin, sin,)
63 __inline_mathop(__tan, tan,)
64 __inline_mathop(__tanh, tanh,)
65 __inline_mathop(__fabs, abs, __attribute__ ((__const__)))
66
67 __inline_mathop(__rint, int,)
68 __inline_mathop(__expm1, etoxm1,)
69 __inline_mathop(__log1p, lognp1,)
70
71 __inline_mathop(__significand, getman,)
72
73 __inline_mathop(__trunc, intrz, __attribute__ ((__const__)))
74
75
76 /* This macro contains the definition for the rest of the inline
77 functions, using FLOAT_TYPE as the domain type and M as a macro
78 that adds the suffix for the function names. */
79
80 #define __inline_functions(float_type, m) \
81 __m81_defun (float_type, m(__floor), (float_type __x), \
82 __attribute__ ((__const__))) \
83 { \
84 float_type __result; \
85 unsigned long int __ctrl_reg; \
86 __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg)); \
87 /* Set rounding towards negative infinity. */ \
88 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
89 : "dmi" ((__ctrl_reg & ~0x10) | 0x20)); \
90 /* Convert X to an integer, using -Inf rounding. */ \
91 __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x)); \
92 /* Restore the previous rounding mode. */ \
93 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
94 : "dmi" (__ctrl_reg)); \
95 return __result; \
96 } \
97 \
98 __m81_defun (float_type, m(__ceil), (float_type __x), \
99 __attribute__ ((__const__))) \
100 { \
101 float_type __result; \
102 unsigned long int __ctrl_reg; \
103 __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg)); \
104 /* Set rounding towards positive infinity. */ \
105 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
106 : "dmi" (__ctrl_reg | 0x30)); \
107 /* Convert X to an integer, using +Inf rounding. */ \
108 __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x)); \
109 /* Restore the previous rounding mode. */ \
110 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
111 : "dmi" (__ctrl_reg)); \
112 return __result; \
113 }
114
115 #define __CONCAT_d(arg) arg
116 #define __CONCAT_f(arg) arg ## f
117 #define __CONCAT_l(arg) arg ## l
__inline_functions(double,__CONCAT_d)118 __inline_functions(double, __CONCAT_d)
119 __inline_functions(float, __CONCAT_f)
120 __inline_functions(long double, __CONCAT_l)
121 #undef __inline_functions
122
123 # define __inline_functions(float_type, m) \
124 __m81_defun (int, m(__isinf), (float_type __value), \
125 __attribute__ ((__const__))) \
126 { \
127 /* There is no branch-condition for infinity, \
128 so we must extract and examine the condition codes manually. */ \
129 unsigned long int __fpsr; \
130 __asm ("ftst%.x %1\n" \
131 "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value)); \
132 return (__fpsr & (2 << 24)) ? (__fpsr & (8 << 24) ? -1 : 1) : 0; \
133 } \
134 \
135 __m81_defun (int, m(__finite), (float_type __value), \
136 __attribute__ ((__const__))) \
137 { \
138 /* There is no branch-condition for infinity, so we must extract and \
139 examine the condition codes manually. */ \
140 unsigned long int __fpsr; \
141 __asm ("ftst%.x %1\n" \
142 "fmove%.l %/fpsr, %0" : "=dm" (__fpsr) : "f" (__value)); \
143 return (__fpsr & (3 << 24)) == 0; \
144 } \
145 \
146 __m81_defun (float_type, m(__scalbn), \
147 (float_type __x, int __n),) \
148 { \
149 float_type __result; \
150 __asm __volatile__ ("fscale%.l %1, %0" : "=f" (__result) \
151 : "dmi" (__n), "0" (__x)); \
152 return __result; \
153 }
154
155 __inline_functions(double, __CONCAT_d)
156 __inline_functions(float, __CONCAT_f)
157 __inline_functions(long double, __CONCAT_l)
158 #undef __inline_functions
159
160 # define __inline_functions(float_type, m) \
161 __m81_defun (int, m(__isnan), (float_type __value), \
162 __attribute__ ((__const__))) \
163 { \
164 char __result; \
165 __asm ("ftst%.x %1\n" \
166 "fsun %0" : "=dm" (__result) : "f" (__value)); \
167 return __result; \
168 }
169
170 __inline_functions(double, __CONCAT_d)
171 __inline_functions(float, __CONCAT_f)
172 __inline_functions(long double, __CONCAT_l)
173 #undef __inline_functions
174
175 # define __inline_functions(float_type, m) \
176 __m81_defun (float_type, m(__scalbln), \
177 (float_type __x, long int __n),) \
178 { \
179 return m(__scalbn) (__x, __n); \
180 } \
181 \
182 __m81_defun (float_type, m(__nearbyint), (float_type __x),) \
183 { \
184 float_type __result; \
185 unsigned long int __ctrl_reg; \
186 __asm __volatile__ ("fmove%.l %!, %0" : "=dm" (__ctrl_reg)); \
187 /* Temporarily disable the inexact exception. */ \
188 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
189 : "dmi" (__ctrl_reg & ~0x200)); \
190 __asm __volatile__ ("fint%.x %1, %0" : "=f" (__result) : "f" (__x)); \
191 __asm __volatile__ ("fmove%.l %0, %!" : /* No outputs. */ \
192 : "dmi" (__ctrl_reg)); \
193 return __result; \
194 } \
195 \
196 __m81_defun (long int, m(__lrint), (float_type __x),) \
197 { \
198 long int __result; \
199 __asm __volatile__ ("fmove%.l %1, %0" : "=dm" (__result) : "f" (__x)); \
200 return __result; \
201 }
202
203 __inline_functions (double, __CONCAT_d)
204 __inline_functions (float, __CONCAT_f)
205 __inline_functions (long double, __CONCAT_l)
206 #undef __inline_functions
207
208 #define __inline_functions(float_type, m) \
209 __m81_inline void \
210 __m81_nth (__m81_u(m(__sincos)) \
211 (float_type __x, float_type *__sinx, float_type *__cosx)) \
212 { \
213 __asm __volatile__ ("fsincos%.x %2,%1:%0" \
214 : "=f" (*__sinx), "=f" (*__cosx) : "f" (__x)); \
215 }
216
217 __inline_functions (double, __CONCAT_d)
218 __inline_functions (float, __CONCAT_f)
219 __inline_functions (long double, __CONCAT_l)
220 #undef __inline_functions
221
222 #undef __CONCAT_d
223 #undef __CONCAT_f
224 #undef __CONCAT_l
225
226 /* Define the three variants of a math function that has a direct
227 implementation in the m68k fpu. FUNC is the name for C (which will be
228 suffixed with f and l for the float and long double version, resp). OP
229 is the name of the fpu operation (without leading f). */
230
231 #define __inline_mathop(func, op, attrs) \
232 __inline_mathop1(double, func, op, attrs) \
233 __inline_mathop1(float, __CONCAT(func,f), op, attrs) \
234 __inline_mathop1(long double, __CONCAT(func,l), op, attrs)
235
236 #define __inline_mathop1(float_type,func, op, attrs) \
237 __m81_defun (float_type, func, (float_type __mathop_x), attrs) \
238 { \
239 float_type __result; \
240 __asm __volatile__ ("f" __STRING(op) "%.x %1, %0" \
241 : "=f" (__result) : "f" (__mathop_x)); \
242 return __result; \
243 }
244
245 __inline_mathop (__ieee754_acos, acos,)
246 __inline_mathop (__ieee754_asin, asin,)
247 __inline_mathop (__ieee754_cosh, cosh,)
248 __inline_mathop (__ieee754_sinh, sinh,)
249 __inline_mathop (__ieee754_exp, etox,)
250 __inline_mathop (__ieee754_exp2, twotox,)
251 __inline_mathop (__ieee754_exp10, tentox,)
252 __inline_mathop (__ieee754_log10, log10,)
253 __inline_mathop (__ieee754_log2, log2,)
254 __inline_mathop (__ieee754_log, logn,)
255 __inline_mathop (__ieee754_sqrt, sqrt,)
256 __inline_mathop (__ieee754_atanh, atanh,)
257
258 __m81_defun (double, __ieee754_remainder, (double __x, double __y),)
259 {
260 double __result;
261 __asm ("frem%.x %1, %0" : "=f" (__result) : "f" (__y), "0" (__x));
262 return __result;
263 }
264
265 __m81_defun (float, __ieee754_remainderf, (float __x, float __y),)
266 {
267 float __result;
268 __asm ("frem%.x %1, %0" : "=f" (__result) : "f" (__y), "0" (__x));
269 return __result;
270 }
271
272 __m81_defun (long double,
273 __ieee754_remainderl, (long double __x, long double __y),)
274 {
275 long double __result;
276 __asm ("frem%.x %1, %0" : "=f" (__result) : "f" (__y), "0" (__x));
277 return __result;
278 }
279
280 __m81_defun (double, __ieee754_fmod, (double __x, double __y),)
281 {
282 double __result;
283 __asm ("fmod%.x %1, %0" : "=f" (__result) : "f" (__y), "0" (__x));
284 return __result;
285 }
286
287 __m81_defun (float, __ieee754_fmodf, (float __x, float __y),)
288 {
289 float __result;
290 __asm ("fmod%.x %1, %0" : "=f" (__result) : "f" (__y), "0" (__x));
291 return __result;
292 }
293
294 __m81_defun (long double,
295 __ieee754_fmodl, (long double __x, long double __y),)
296 {
297 long double __result;
298 __asm ("fmod%.x %1, %0" : "=f" (__result) : "f" (__y), "0" (__x));
299 return __result;
300 }
301
302 /* Get the m68881 condition codes, to quickly check multiple conditions. */
303 static __inline__ unsigned long
__m81_test(long double __val)304 __m81_test (long double __val)
305 {
306 unsigned long __fpsr;
307 __asm ("ftst%.x %1; fmove%.l %/fpsr,%0" : "=dm" (__fpsr) : "f" (__val));
308 return __fpsr;
309 }
310
311 /* Bit values returned by __m81_test. */
312 #define __M81_COND_NAN (1 << 24)
313 #define __M81_COND_INF (2 << 24)
314 #define __M81_COND_ZERO (4 << 24)
315 #define __M81_COND_NEG (8 << 24)
316
317 #endif /* _MATHIMPL_H */
318