xref: /freebsd/contrib/arm-optimized-routines/math/test/ulp_wrappers.h (revision dd21556857e8d40f66bf5ad54754d9d52669ebf7)
1 /*
2  * Function wrappers for ulp.
3  *
4  * Copyright (c) 2022-2024, Arm Limited.
5  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6  */
7 
8 /* clang-format off */
9 
10 #if  __aarch64__ && __linux__
11 #include <arm_neon.h>
12 #endif
13 
14 #include <stdbool.h>
15 
16 /* Wrappers for sincos.  */
17 static float sincosf_sinf(float x) {(void)cosf(x); return sinf(x);}
18 static float sincosf_cosf(float x) {(void)sinf(x); return cosf(x);}
19 static double sincos_sin(double x) {(void)cos(x); return sin(x);}
20 static double sincos_cos(double x) {(void)sin(x); return cos(x);}
21 #if USE_MPFR
22 static int sincos_mpfr_sin(mpfr_t y, const mpfr_t x, mpfr_rnd_t r) { mpfr_cos(y,x,r); return mpfr_sin(y,x,r); }
23 static int sincos_mpfr_cos(mpfr_t y, const mpfr_t x, mpfr_rnd_t r) { mpfr_sin(y,x,r); return mpfr_cos(y,x,r); }
24 static int modf_mpfr_frac(mpfr_t f, const mpfr_t x, mpfr_rnd_t r) { MPFR_DECL_INIT(i, 80); return mpfr_modf(i,f,x,r); }
25 static int modf_mpfr_int(mpfr_t i, const mpfr_t x, mpfr_rnd_t r) { MPFR_DECL_INIT(f, 80); return mpfr_modf(i,f,x,r); }
26 # if MPFR_VERSION < MPFR_VERSION_NUM(4, 2, 0)
27 static int mpfr_tanpi (mpfr_t ret, const mpfr_t arg, mpfr_rnd_t rnd) {
28   MPFR_DECL_INIT (frd, 1080);
29   mpfr_const_pi (frd, GMP_RNDN);
30   mpfr_mul (frd, frd, arg, GMP_RNDN);
31   return mpfr_tan (ret, frd, GMP_RNDN);
32 }
33 static int mpfr_sinpi (mpfr_t ret, const mpfr_t arg, mpfr_rnd_t rnd) {
34   MPFR_DECL_INIT (frd, 1080);
35   mpfr_const_pi (frd, GMP_RNDN);
36   mpfr_mul (frd, frd, arg, GMP_RNDN);
37   return mpfr_sin (ret, frd, GMP_RNDN);
38 }
39 
40 static int mpfr_cospi (mpfr_t ret, const mpfr_t arg, mpfr_rnd_t rnd) {
41   MPFR_DECL_INIT (frd, 1080);
42   mpfr_const_pi (frd, GMP_RNDN);
43   mpfr_mul (frd, frd, arg, GMP_RNDN);
44   return mpfr_cos (ret, frd, GMP_RNDN);
45 }
46 # endif
47 # if WANT_EXPERIMENTAL_MATH
48 static int wrap_mpfr_powi(mpfr_t ret, const mpfr_t x, const mpfr_t y, mpfr_rnd_t rnd) {
49   mpfr_t y2;
50   mpfr_init(y2);
51   mpfr_trunc(y2, y);
52   return mpfr_pow(ret, x, y2, rnd);
53 }
54 # endif
55 #endif
56 
57 float modff_frac(float x) { float i; return modff(x, &i); }
58 float modff_int(float x) { float i; modff(x, &i); return i; }
59 double modf_frac(double x) { double i; return modf(x, &i); }
60 double modf_int(double x) { double i; modf(x, &i); return i; }
61 long double modfl_frac(long double x) { long double i; return modfl(x, &i); }
62 long double modfl_int(long double x) { long double i; modfl(x, &i); return i; }
63 
64 /* Wrappers for vector functions.  */
65 #if __aarch64__ && __linux__
66 static float Z_expf_1u(float x) { return _ZGVnN4v_expf_1u(argf(x))[0]; }
67 static float Z_exp2f_1u(float x) { return _ZGVnN4v_exp2f_1u(argf(x))[0]; }
68 #endif
69 
70 /* clang-format on */
71 
72 /* No wrappers for scalar routines, but TEST_SIG will emit them.  */
73 #define ZSNF1_WRAP(func)
74 #define ZSNF2_WRAP(func)
75 #define ZSND1_WRAP(func)
76 #define ZSND2_WRAP(func)
77 
78 #define ZVNF1_WRAP(func)                                                      \
79   static float Z_##func##f (float x)                                          \
80   {                                                                           \
81     return _ZGVnN4v_##func##f (argf (x))[0];                                  \
82   }
83 #define ZVNF2_WRAP(func)                                                      \
84   static float Z_##func##f (float x, float y)                                 \
85   {                                                                           \
86     return _ZGVnN4vv_##func##f (argf (x), argf (y))[0];                       \
87   }
88 #define ZVND1_WRAP(func)                                                      \
89   static double Z_##func (double x) { return _ZGVnN2v_##func (argd (x))[0]; }
90 #define ZVND2_WRAP(func)                                                      \
91   static double Z_##func (double x, double y)                                 \
92   {                                                                           \
93     return _ZGVnN2vv_##func (argd (x), argd (y))[0];                          \
94   }
95 
96 #if WANT_TRIGPI_TESTS
97 float
98 arm_math_sincospif_sin (float x)
99 {
100   float s, c;
101   arm_math_sincospif (x, &s, &c);
102   return s;
103 }
104 float
105 arm_math_sincospif_cos (float x)
106 {
107   float s, c;
108   arm_math_sincospif (x, &s, &c);
109   return c;
110 }
111 double
112 arm_math_sincospi_sin (double x)
113 {
114   double s, c;
115   arm_math_sincospi (x, &s, &c);
116   return s;
117 }
118 double
119 arm_math_sincospi_cos (double x)
120 {
121   double s, c;
122   arm_math_sincospi (x, &s, &c);
123   return c;
124 }
125 #endif
126 
127 #if  __aarch64__ && __linux__
128 
129 # if WANT_TRIGPI_TESTS
130 ZVNF1_WRAP (cospi)
131 ZVND1_WRAP (cospi)
132 ZVNF1_WRAP (sinpi)
133 ZVND1_WRAP (sinpi)
134 ZVNF1_WRAP (tanpi)
135 ZVND1_WRAP (tanpi)
136 
137 double
138 v_sincospi_sin (double x)
139 {
140   double s[2], c[2];
141   _ZGVnN2vl8l8_sincospi (vdupq_n_f64 (x), s, c);
142   return s[0];
143 }
144 double
145 v_sincospi_cos (double x)
146 {
147   double s[2], c[2];
148   _ZGVnN2vl8l8_sincospi (vdupq_n_f64 (x), s, c);
149   return c[0];
150 }
151 float
152 v_sincospif_sin (float x)
153 {
154   float s[4], c[4];
155   _ZGVnN4vl4l4_sincospif (vdupq_n_f32 (x), s, c);
156   return s[0];
157 }
158 float
159 v_sincospif_cos (float x)
160 {
161   float s[4], c[4];
162   _ZGVnN4vl4l4_sincospif (vdupq_n_f32 (x), s, c);
163   return c[0];
164 }
165 # endif // WANT_TRIGPI_TESTS
166 
167 float
168 v_sincosf_sin (float x)
169 {
170   float s[4], c[4];
171   _ZGVnN4vl4l4_sincosf (vdupq_n_f32 (x), s, c);
172   return s[0];
173 }
174 float
175 v_sincosf_cos (float x)
176 {
177   float s[4], c[4];
178   _ZGVnN4vl4l4_sincosf (vdupq_n_f32 (x), s, c);
179   return c[0];
180 }
181 float
182 v_cexpif_sin (float x)
183 {
184   return _ZGVnN4v_cexpif (vdupq_n_f32 (x)).val[0][0];
185 }
186 float
187 v_cexpif_cos (float x)
188 {
189   return _ZGVnN4v_cexpif (vdupq_n_f32 (x)).val[1][0];
190 }
191 float
192 v_modff_frac (float x)
193 {
194   float y[4];
195   return _ZGVnN4vl4_modff (vdupq_n_f32 (x), y)[0];
196 }
197 float
198 v_modff_int (float x)
199 {
200   float y[4];
201   _ZGVnN4vl4_modff (vdupq_n_f32 (x), y);
202   return y[0];
203 }
204 double
205 v_sincos_sin (double x)
206 {
207   double s[2], c[2];
208   _ZGVnN2vl8l8_sincos (vdupq_n_f64 (x), s, c);
209   return s[0];
210 }
211 double
212 v_sincos_cos (double x)
213 {
214   double s[2], c[2];
215   _ZGVnN2vl8l8_sincos (vdupq_n_f64 (x), s, c);
216   return c[0];
217 }
218 double
219 v_cexpi_sin (double x)
220 {
221   return _ZGVnN2v_cexpi (vdupq_n_f64 (x)).val[0][0];
222 }
223 double
224 v_cexpi_cos (double x)
225 {
226   return _ZGVnN2v_cexpi (vdupq_n_f64 (x)).val[1][0];
227 }
228 double
229 v_modf_frac (double x)
230 {
231   double y[2];
232   return _ZGVnN2vl8_modf (vdupq_n_f64 (x), y)[0];
233 }
234 double
235 v_modf_int (double x)
236 {
237   double y[2];
238   _ZGVnN2vl8_modf (vdupq_n_f64 (x), y);
239   return y[0];
240 }
241 #endif //  __aarch64__ && __linux__
242 
243 #if WANT_SVE_TESTS
244 # define ZSVNF1_WRAP(func)                                                   \
245     static float Z_sv_##func##f (svbool_t pg, float x)                        \
246     {                                                                         \
247       return svretf (_ZGVsMxv_##func##f (svargf (x), pg), pg);                \
248     }
249 # define ZSVNF2_WRAP(func)                                                   \
250     static float Z_sv_##func##f (svbool_t pg, float x, float y)               \
251     {                                                                         \
252       return svretf (_ZGVsMxvv_##func##f (svargf (x), svargf (y), pg), pg);   \
253     }
254 # define ZSVND1_WRAP(func)                                                   \
255     static double Z_sv_##func (svbool_t pg, double x)                         \
256     {                                                                         \
257       return svretd (_ZGVsMxv_##func (svargd (x), pg), pg);                   \
258     }
259 # define ZSVND2_WRAP(func)                                                   \
260     static double Z_sv_##func (svbool_t pg, double x, double y)               \
261     {                                                                         \
262       return svretd (_ZGVsMxvv_##func (svargd (x), svargd (y), pg), pg);      \
263     }
264 
265 # if WANT_TRIGPI_TESTS
266 ZSVNF1_WRAP (cospi)
267 ZSVND1_WRAP (cospi)
268 ZSVNF1_WRAP (sinpi)
269 ZSVND1_WRAP (sinpi)
270 ZSVNF1_WRAP (tanpi)
271 ZSVND1_WRAP (tanpi)
272 double
273 sv_sincospi_sin (svbool_t pg, double x)
274 {
275   double s[svcntd ()], c[svcntd ()];
276   _ZGVsMxvl8l8_sincospi (svdup_f64 (x), s, c, pg);
277   return svretd (svld1 (pg, s), pg);
278 }
279 double
280 sv_sincospi_cos (svbool_t pg, double x)
281 {
282   double s[svcntd ()], c[svcntd ()];
283   _ZGVsMxvl8l8_sincospi (svdup_f64 (x), s, c, pg);
284   return svretd (svld1 (pg, c), pg);
285 }
286 float
287 sv_sincospif_sin (svbool_t pg, float x)
288 {
289   float s[svcntw ()], c[svcntw ()];
290   _ZGVsMxvl4l4_sincospif (svdup_f32 (x), s, c, pg);
291   return svretf (svld1 (pg, s), pg);
292 }
293 float
294 sv_sincospif_cos (svbool_t pg, float x)
295 {
296   float s[svcntw ()], c[svcntw ()];
297   _ZGVsMxvl4l4_sincospif (svdup_f32 (x), s, c, pg);
298   return svretf (svld1 (pg, c), pg);
299 }
300 # endif // WANT_TRIGPI_TESTS
301 
302 float
303 sv_sincosf_sin (svbool_t pg, float x)
304 {
305   float s[svcntw ()], c[svcntw ()];
306   _ZGVsMxvl4l4_sincosf (svdup_f32 (x), s, c, pg);
307   return svretf (svld1 (pg, s), pg);
308 }
309 float
310 sv_sincosf_cos (svbool_t pg, float x)
311 {
312   float s[svcntw ()], c[svcntw ()];
313   _ZGVsMxvl4l4_sincosf (svdup_f32 (x), s, c, pg);
314   return svretf (svld1 (pg, c), pg);
315 }
316 float
317 sv_cexpif_sin (svbool_t pg, float x)
318 {
319   return svretf (svget2 (_ZGVsMxv_cexpif (svdup_f32 (x), pg), 0), pg);
320 }
321 float
322 sv_cexpif_cos (svbool_t pg, float x)
323 {
324   return svretf (svget2 (_ZGVsMxv_cexpif (svdup_f32 (x), pg), 1), pg);
325 }
326 float
327 sv_modff_frac (svbool_t pg, float x)
328 {
329   float i[svcntw ()];
330   return svretf (_ZGVsMxvl4_modff (svdup_f32 (x), i, pg), pg);
331 }
332 float
333 sv_modff_int (svbool_t pg, float x)
334 {
335   float i[svcntw ()];
336   _ZGVsMxvl4_modff (svdup_f32 (x), i, pg);
337   return svretf (svld1 (pg, i), pg);
338 }
339 double
340 sv_sincos_sin (svbool_t pg, double x)
341 {
342   double s[svcntd ()], c[svcntd ()];
343   _ZGVsMxvl8l8_sincos (svdup_f64 (x), s, c, pg);
344   return svretd (svld1 (pg, s), pg);
345 }
346 double
347 sv_sincos_cos (svbool_t pg, double x)
348 {
349   double s[svcntd ()], c[svcntd ()];
350   _ZGVsMxvl8l8_sincos (svdup_f64 (x), s, c, pg);
351   return svretd (svld1 (pg, c), pg);
352 }
353 double
354 sv_cexpi_sin (svbool_t pg, double x)
355 {
356   return svretd (svget2 (_ZGVsMxv_cexpi (svdup_f64 (x), pg), 0), pg);
357 }
358 double
359 sv_cexpi_cos (svbool_t pg, double x)
360 {
361   return svretd (svget2 (_ZGVsMxv_cexpi (svdup_f64 (x), pg), 1), pg);
362 }
363 double
364 sv_modf_frac (svbool_t pg, double x)
365 {
366   double i[svcntd ()];
367   return svretd (_ZGVsMxvl8_modf (svdup_f64 (x), i, pg), pg);
368 }
369 double
370 sv_modf_int (svbool_t pg, double x)
371 {
372   double i[svcntd ()];
373   _ZGVsMxvl8_modf (svdup_f64 (x), i, pg);
374   return svretd (svld1 (pg, i), pg);
375 }
376 
377 # if WANT_EXPERIMENTAL_MATH
378 
379 /* Our implementations of powi/powk are too imprecise to verify
380    against any established pow implementation. Instead we have the
381    following simple implementation, against which it is enough to
382    maintain bitwise reproducibility. Note the test framework expects
383    the reference impl to be of higher precision than the function
384    under test. For instance this means that the reference for
385    double-precision powi will be passed a long double, so to check
386    bitwise reproducibility we have to cast it back down to
387    double. This is fine since a round-trip to higher precision and
388    back down is correctly rounded.  */
389 #  define DECL_POW_INT_REF(NAME, DBL_T, FLT_T, INT_T)                       \
390       static DBL_T __attribute__ ((unused)) NAME (DBL_T in_val, DBL_T y)      \
391       {                                                                       \
392 	INT_T n = (INT_T) round (y);                                          \
393 	FLT_T acc = 1.0;                                                      \
394 	bool want_recip = n < 0;                                              \
395 	n = n < 0 ? -n : n;                                                   \
396                                                                               \
397 	for (FLT_T c = in_val; n; c *= c, n >>= 1)                            \
398 	  {                                                                   \
399 	    if (n & 0x1)                                                      \
400 	      {                                                               \
401 		acc *= c;                                                     \
402 	      }                                                               \
403 	  }                                                                   \
404 	if (want_recip)                                                       \
405 	  {                                                                   \
406 	    acc = 1.0 / acc;                                                  \
407 	  }                                                                   \
408 	return acc;                                                           \
409       }
410 
411 DECL_POW_INT_REF (ref_powif, double, float, int)
412 DECL_POW_INT_REF (ref_powi, long double, double, int)
413 static float
414 Z_sv_powi (svbool_t pg, float x, float y)
415 {
416   return svretf (_ZGVsMxvv_powi (svargf (x), svdup_s32 ((int) round (y)), pg),
417 		 pg);
418 }
419 static double
420 Z_sv_powk (svbool_t pg, double x, double y)
421 {
422   return svretd (_ZGVsMxvv_powk (svargd (x), svdup_s64 ((long) round (y)), pg),
423 		 pg);
424 }
425 
426 # endif // WANT_EXPERIMENTAL_MATH
427 #endif	// WANT_SVE_TESTS
428 
429 #include "test/ulp_wrappers_gen.h"
430