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