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. */
sincosf_sinf(float x)17 static float sincosf_sinf(float x) {(void)cosf(x); return sinf(x);}
sincosf_cosf(float x)18 static float sincosf_cosf(float x) {(void)sinf(x); return cosf(x);}
sincos_sin(double x)19 static double sincos_sin(double x) {(void)cos(x); return sin(x);}
sincos_cos(double x)20 static double sincos_cos(double x) {(void)sin(x); return cos(x);}
21 #if USE_MPFR
sincos_mpfr_sin(mpfr_t y,const mpfr_t x,mpfr_rnd_t r)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); }
sincos_mpfr_cos(mpfr_t y,const mpfr_t x,mpfr_rnd_t 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); }
modf_mpfr_frac(mpfr_t f,const mpfr_t x,mpfr_rnd_t 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); }
modf_mpfr_int(mpfr_t i,const mpfr_t x,mpfr_rnd_t 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)
mpfr_tanpi(mpfr_t ret,const mpfr_t arg,mpfr_rnd_t rnd)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 }
mpfr_sinpi(mpfr_t ret,const mpfr_t arg,mpfr_rnd_t rnd)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
mpfr_cospi(mpfr_t ret,const mpfr_t arg,mpfr_rnd_t rnd)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
wrap_mpfr_powi(mpfr_t ret,const mpfr_t x,const mpfr_t y,mpfr_rnd_t rnd)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
modff_frac(float x)57 float modff_frac(float x) { float i; return modff(x, &i); }
modff_int(float x)58 float modff_int(float x) { float i; modff(x, &i); return i; }
modf_frac(double x)59 double modf_frac(double x) { double i; return modf(x, &i); }
modf_int(double x)60 double modf_int(double x) { double i; modf(x, &i); return i; }
modfl_frac(long double x)61 long double modfl_frac(long double x) { long double i; return modfl(x, &i); }
modfl_int(long double x)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__
Z_expf_1u(float x)66 static float Z_expf_1u(float x) { return _ZGVnN4v_expf_1u(argf(x))[0]; }
Z_exp2f_1u(float x)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
arm_math_sincospif_sin(float x)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
arm_math_sincospif_cos(float x)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
arm_math_sincospi_sin(double x)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
arm_math_sincospi_cos(double x)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)
ZVND1_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
v_sincospi_cos(double x)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
v_sincospif_sin(float x)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
v_sincospif_cos(float x)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
v_sincosf_sin(float x)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
v_sincosf_cos(float x)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
v_cexpif_sin(float x)182 v_cexpif_sin (float x)
183 {
184 return _ZGVnN4v_cexpif (vdupq_n_f32 (x)).val[0][0];
185 }
186 float
v_cexpif_cos(float x)187 v_cexpif_cos (float x)
188 {
189 return _ZGVnN4v_cexpif (vdupq_n_f32 (x)).val[1][0];
190 }
191 float
v_modff_frac(float x)192 v_modff_frac (float x)
193 {
194 float y[4];
195 return _ZGVnN4vl4_modff (vdupq_n_f32 (x), y)[0];
196 }
197 float
v_modff_int(float x)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
v_sincos_sin(double x)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
v_sincos_cos(double x)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
v_cexpi_sin(double x)219 v_cexpi_sin (double x)
220 {
221 return _ZGVnN2v_cexpi (vdupq_n_f64 (x)).val[0][0];
222 }
223 double
v_cexpi_cos(double x)224 v_cexpi_cos (double x)
225 {
226 return _ZGVnN2v_cexpi (vdupq_n_f64 (x)).val[1][0];
227 }
228 double
v_modf_frac(double x)229 v_modf_frac (double x)
230 {
231 double y[2];
232 return _ZGVnN2vl8_modf (vdupq_n_f64 (x), y)[0];
233 }
234 double
v_modf_int(double x)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)
ZSVND1_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
sv_sincospi_cos(svbool_t pg,double x)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
sv_sincospif_sin(svbool_t pg,float x)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
sv_sincospif_cos(svbool_t pg,float x)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
sv_sincosf_sin(svbool_t pg,float x)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
sv_sincosf_cos(svbool_t pg,float x)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
sv_cexpif_sin(svbool_t pg,float x)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
sv_cexpif_cos(svbool_t pg,float x)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
sv_modff_frac(svbool_t pg,float x)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
sv_modff_int(svbool_t pg,float x)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
sv_sincos_sin(svbool_t pg,double x)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
sv_sincos_cos(svbool_t pg,double x)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
sv_cexpi_sin(svbool_t pg,double x)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
sv_cexpi_cos(svbool_t pg,double x)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
sv_modf_frac(svbool_t pg,double x)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
sv_modf_int(svbool_t pg,double x)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
DECL_POW_INT_REF(ref_powif,double,float,int)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
Z_sv_powk(svbool_t pg,double x,double y)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