1 | /* Definitions of libc internal inline math functions implemented |
2 | by the m68881/2. |
3 | Copyright (C) 1991-2024 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 |
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 |
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 | |