1 /* 2 * ULP error checking tool for math functions. 3 * 4 * Copyright (c) 2019-2024, Arm Limited. 5 * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception 6 */ 7 8 #if WANT_SVE_TESTS 9 # if __aarch64__ && __linux__ 10 # ifdef __clang__ 11 # pragma clang attribute push(__attribute__((target("sve"))), \ 12 apply_to = any(function)) 13 # else 14 # pragma GCC target("+sve") 15 # endif 16 # else 17 # error "SVE not supported - please disable WANT_SVE_TESTS" 18 # endif 19 #endif 20 21 #define _GNU_SOURCE 22 #include <ctype.h> 23 #include <fenv.h> 24 #include <float.h> 25 #include <math.h> 26 #include <stdint.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include "mathlib.h" 31 32 #include "trigpi_references.h" 33 34 /* Don't depend on mpfr by default. */ 35 #ifndef USE_MPFR 36 # define USE_MPFR 0 37 #endif 38 #if USE_MPFR 39 # include <mpfr.h> 40 #endif 41 42 static uint64_t seed = 0x0123456789abcdef; 43 static uint64_t 44 rand64 (void) 45 { 46 seed = 6364136223846793005ull * seed + 1; 47 return seed ^ (seed >> 32); 48 } 49 50 /* Uniform random in [0,n]. */ 51 static uint64_t 52 randn (uint64_t n) 53 { 54 uint64_t r, m; 55 56 if (n == 0) 57 return 0; 58 n++; 59 if (n == 0) 60 return rand64 (); 61 for (;;) 62 { 63 r = rand64 (); 64 m = r % n; 65 if (r - m <= -n) 66 return m; 67 } 68 } 69 70 struct gen 71 { 72 uint64_t start; 73 uint64_t len; 74 uint64_t start2; 75 uint64_t len2; 76 uint64_t off; 77 uint64_t step; 78 uint64_t cnt; 79 }; 80 81 struct args_f1 82 { 83 float x; 84 }; 85 86 struct args_f2 87 { 88 float x; 89 float x2; 90 }; 91 92 struct args_d1 93 { 94 double x; 95 }; 96 97 struct args_d2 98 { 99 double x; 100 double x2; 101 }; 102 103 /* result = y + tail*2^ulpexp. */ 104 struct ret_f 105 { 106 float y; 107 double tail; 108 int ulpexp; 109 int ex; 110 int ex_may; 111 }; 112 113 struct ret_d 114 { 115 double y; 116 double tail; 117 int ulpexp; 118 int ex; 119 int ex_may; 120 }; 121 122 static inline uint64_t 123 next1 (struct gen *g) 124 { 125 /* For single argument use randomized incremental steps, 126 that produce dense sampling without collisions and allow 127 testing all inputs in a range. */ 128 uint64_t r = g->start + g->off; 129 g->off += g->step + randn (g->step / 2); 130 if (g->off > g->len) 131 g->off -= g->len; /* hack. */ 132 return r; 133 } 134 135 static inline uint64_t 136 next2 (uint64_t *x2, struct gen *g) 137 { 138 /* For two arguments use uniform random sampling. */ 139 uint64_t r = g->start + randn (g->len); 140 *x2 = g->start2 + randn (g->len2); 141 return r; 142 } 143 144 static struct args_f1 145 next_f1 (void *g) 146 { 147 return (struct args_f1){asfloat (next1 (g))}; 148 } 149 150 static struct args_f2 151 next_f2 (void *g) 152 { 153 uint64_t x2; 154 uint64_t x = next2 (&x2, g); 155 return (struct args_f2){asfloat (x), asfloat (x2)}; 156 } 157 158 static struct args_d1 159 next_d1 (void *g) 160 { 161 return (struct args_d1){asdouble (next1 (g))}; 162 } 163 164 static struct args_d2 165 next_d2 (void *g) 166 { 167 uint64_t x2; 168 uint64_t x = next2 (&x2, g); 169 return (struct args_d2){asdouble (x), asdouble (x2)}; 170 } 171 172 /* A bit of a hack: call vector functions twice with the same 173 input in lane 0 but a different value in other lanes: once 174 with an in-range value and then with a special case value. */ 175 static int secondcall; 176 177 /* Wrappers for vector functions. */ 178 #if __aarch64__ && __linux__ 179 /* First element of fv and dv may be changed by -c argument. */ 180 static float fv[2] = {1.0f, -INFINITY}; 181 static double dv[2] = {1.0, -INFINITY}; 182 static inline float32x4_t 183 argf (float x) 184 { 185 return (float32x4_t){ x, x, x, fv[secondcall] }; 186 } 187 static inline float64x2_t 188 argd (double x) 189 { 190 return (float64x2_t){ x, dv[secondcall] }; 191 } 192 #if WANT_SVE_TESTS 193 #include <arm_sve.h> 194 195 static inline svfloat32_t 196 svargf (float x) 197 { 198 int n = svcntw (); 199 float base[n]; 200 for (int i = 0; i < n; i++) 201 base[i] = (float) x; 202 base[n - 1] = (float) fv[secondcall]; 203 return svld1 (svptrue_b32 (), base); 204 } 205 static inline svfloat64_t 206 svargd (double x) 207 { 208 int n = svcntd (); 209 double base[n]; 210 for (int i = 0; i < n; i++) 211 base[i] = x; 212 base[n - 1] = dv[secondcall]; 213 return svld1 (svptrue_b64 (), base); 214 } 215 static inline float 216 svretf (svfloat32_t vec, svbool_t pg) 217 { 218 return svlastb_f32 (svpfirst (pg, svpfalse ()), vec); 219 } 220 static inline double 221 svretd (svfloat64_t vec, svbool_t pg) 222 { 223 return svlastb_f64 (svpfirst (pg, svpfalse ()), vec); 224 } 225 226 static inline svbool_t 227 parse_pg (uint64_t p, int is_single) 228 { 229 if (is_single) 230 { 231 uint32_t tmp[svcntw ()]; 232 for (unsigned i = 0; i < svcntw (); i++) 233 tmp[i] = (p >> i) & 1; 234 return svcmpne (svptrue_b32 (), svld1 (svptrue_b32 (), tmp), 0); 235 } 236 else 237 { 238 uint64_t tmp[svcntd ()]; 239 for (unsigned i = 0; i < svcntd (); i++) 240 tmp[i] = (p >> i) & 1; 241 return svcmpne (svptrue_b64 (), svld1 (svptrue_b64 (), tmp), 0); 242 } 243 } 244 # endif 245 #endif 246 247 struct conf 248 { 249 int r; 250 int rc; 251 int quiet; 252 int mpfr; 253 int fenv; 254 unsigned long long n; 255 double softlim; 256 double errlim; 257 int ignore_zero_sign; 258 #if WANT_SVE_TESTS 259 svbool_t *pg; 260 #endif 261 }; 262 263 #include "test/ulp_wrappers.h" 264 265 struct fun 266 { 267 const char *name; 268 int arity; 269 int singleprec; 270 int twice; 271 int is_predicated; 272 union 273 { 274 float (*f1) (float); 275 float (*f2) (float, float); 276 double (*d1) (double); 277 double (*d2) (double, double); 278 #if WANT_SVE_TESTS 279 float (*f1_pred) (svbool_t, float); 280 float (*f2_pred) (svbool_t, float, float); 281 double (*d1_pred) (svbool_t, double); 282 double (*d2_pred) (svbool_t, double, double); 283 #endif 284 } fun; 285 union 286 { 287 double (*f1) (double); 288 double (*f2) (double, double); 289 long double (*d1) (long double); 290 long double (*d2) (long double, long double); 291 } fun_long; 292 #if USE_MPFR 293 union 294 { 295 int (*f1) (mpfr_t, const mpfr_t, mpfr_rnd_t); 296 int (*f2) (mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t); 297 int (*d1) (mpfr_t, const mpfr_t, mpfr_rnd_t); 298 int (*d2) (mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t); 299 } fun_mpfr; 300 #endif 301 }; 302 303 // clang-format off 304 static const struct fun fun[] = { 305 #if USE_MPFR 306 # define F(x, x_wrap, x_long, x_mpfr, a, s, t, twice) \ 307 { #x, a, s, twice, 0, { .t = x_wrap }, { .t = x_long }, { .t = x_mpfr } }, 308 # define SVF(x, x_wrap, x_long, x_mpfr, a, s, t, twice) \ 309 { #x, a, s, twice, 1, { .t##_pred = x_wrap }, { .t = x_long }, { .t = x_mpfr } }, 310 #else 311 # define F(x, x_wrap, x_long, x_mpfr, a, s, t, twice) \ 312 { #x, a, s, twice, 0, { .t = x_wrap }, { .t = x_long } }, 313 # define SVF(x, x_wrap, x_long, x_mpfr, a, s, t, twice) \ 314 { #x, a, s, twice, 1, { .t##_pred = x_wrap }, { .t = x_long } }, 315 #endif 316 #define F1(x) F (x##f, x##f, x, mpfr_##x, 1, 1, f1, 0) 317 #define F2(x) F (x##f, x##f, x, mpfr_##x, 2, 1, f2, 0) 318 #define D1(x) F (x, x, x##l, mpfr_##x, 1, 0, d1, 0) 319 #define D2(x) F (x, x, x##l, mpfr_##x, 2, 0, d2, 0) 320 /* Neon routines. */ 321 #define ZVNF1(x) F (_ZGVnN4v_##x##f, Z_##x##f, x, mpfr_##x, 1, 1, f1, 0) 322 #define ZVNF2(x) F (_ZGVnN4vv_##x##f, Z_##x##f, x, mpfr_##x, 2, 1, f2, 0) 323 #define ZVND1(x) F (_ZGVnN2v_##x, Z_##x, x##l, mpfr_##x, 1, 0, d1, 0) 324 #define ZVND2(x) F (_ZGVnN2vv_##x, Z_##x, x##l, mpfr_##x, 2, 0, d2, 0) 325 /* SVE routines. */ 326 #define ZSVF1(x) SVF (_ZGVsMxv_##x##f, Z_sv_##x##f, x, mpfr_##x, 1, 1, f1, 0) 327 #define ZSVF2(x) SVF (_ZGVsMxvv_##x##f, Z_sv_##x##f, x, mpfr_##x, 2, 1, f2, 0) 328 #define ZSVD1(x) SVF (_ZGVsMxv_##x, Z_sv_##x, x##l, mpfr_##x, 1, 0, d1, 0) 329 #define ZSVD2(x) SVF (_ZGVsMxvv_##x, Z_sv_##x, x##l, mpfr_##x, 2, 0, d2, 0) 330 331 #include "test/ulp_funcs.h" 332 333 #undef F 334 #undef F1 335 #undef F2 336 #undef D1 337 #undef D2 338 #undef ZSVF1 339 #undef ZSVF2 340 #undef ZSVD1 341 #undef ZSVD2 342 { 0 } 343 }; 344 // clang-format on 345 346 /* Boilerplate for generic calls. */ 347 348 static inline int 349 ulpscale_f (float x) 350 { 351 int e = asuint (x) >> 23 & 0xff; 352 if (!e) 353 e++; 354 return e - 0x7f - 23; 355 } 356 static inline int 357 ulpscale_d (double x) 358 { 359 int e = asuint64 (x) >> 52 & 0x7ff; 360 if (!e) 361 e++; 362 return e - 0x3ff - 52; 363 } 364 static inline float 365 call_f1 (const struct fun *f, struct args_f1 a, const struct conf *conf) 366 { 367 #if WANT_SVE_TESTS 368 if (f->is_predicated) 369 return f->fun.f1_pred (*conf->pg, a.x); 370 #endif 371 return f->fun.f1 (a.x); 372 } 373 static inline float 374 call_f2 (const struct fun *f, struct args_f2 a, const struct conf *conf) 375 { 376 #if WANT_SVE_TESTS 377 if (f->is_predicated) 378 return f->fun.f2_pred (*conf->pg, a.x, a.x2); 379 #endif 380 return f->fun.f2 (a.x, a.x2); 381 } 382 383 static inline double 384 call_d1 (const struct fun *f, struct args_d1 a, const struct conf *conf) 385 { 386 #if WANT_SVE_TESTS 387 if (f->is_predicated) 388 return f->fun.d1_pred (*conf->pg, a.x); 389 #endif 390 return f->fun.d1 (a.x); 391 } 392 static inline double 393 call_d2 (const struct fun *f, struct args_d2 a, const struct conf *conf) 394 { 395 #if WANT_SVE_TESTS 396 if (f->is_predicated) 397 return f->fun.d2_pred (*conf->pg, a.x, a.x2); 398 #endif 399 return f->fun.d2 (a.x, a.x2); 400 } 401 static inline double 402 call_long_f1 (const struct fun *f, struct args_f1 a) 403 { 404 return f->fun_long.f1 (a.x); 405 } 406 static inline double 407 call_long_f2 (const struct fun *f, struct args_f2 a) 408 { 409 return f->fun_long.f2 (a.x, a.x2); 410 } 411 static inline long double 412 call_long_d1 (const struct fun *f, struct args_d1 a) 413 { 414 return f->fun_long.d1 (a.x); 415 } 416 static inline long double 417 call_long_d2 (const struct fun *f, struct args_d2 a) 418 { 419 return f->fun_long.d2 (a.x, a.x2); 420 } 421 static inline void 422 printcall_f1 (const struct fun *f, struct args_f1 a) 423 { 424 printf ("%s(%a)", f->name, a.x); 425 } 426 static inline void 427 printcall_f2 (const struct fun *f, struct args_f2 a) 428 { 429 printf ("%s(%a, %a)", f->name, a.x, a.x2); 430 } 431 static inline void 432 printcall_d1 (const struct fun *f, struct args_d1 a) 433 { 434 printf ("%s(%a)", f->name, a.x); 435 } 436 static inline void 437 printcall_d2 (const struct fun *f, struct args_d2 a) 438 { 439 printf ("%s(%a, %a)", f->name, a.x, a.x2); 440 } 441 static inline void 442 printgen_f1 (const struct fun *f, struct gen *gen) 443 { 444 printf ("%s in [%a;%a]", f->name, asfloat (gen->start), 445 asfloat (gen->start + gen->len)); 446 } 447 static inline void 448 printgen_f2 (const struct fun *f, struct gen *gen) 449 { 450 printf ("%s in [%a;%a] x [%a;%a]", f->name, asfloat (gen->start), 451 asfloat (gen->start + gen->len), asfloat (gen->start2), 452 asfloat (gen->start2 + gen->len2)); 453 } 454 static inline void 455 printgen_d1 (const struct fun *f, struct gen *gen) 456 { 457 printf ("%s in [%a;%a]", f->name, asdouble (gen->start), 458 asdouble (gen->start + gen->len)); 459 } 460 static inline void 461 printgen_d2 (const struct fun *f, struct gen *gen) 462 { 463 printf ("%s in [%a;%a] x [%a;%a]", f->name, asdouble (gen->start), 464 asdouble (gen->start + gen->len), asdouble (gen->start2), 465 asdouble (gen->start2 + gen->len2)); 466 } 467 468 #define reduce_f1(a, f, op) (f (a.x)) 469 #define reduce_f2(a, f, op) (f (a.x) op f (a.x2)) 470 #define reduce_d1(a, f, op) (f (a.x)) 471 #define reduce_d2(a, f, op) (f (a.x) op f (a.x2)) 472 473 #ifndef IEEE_754_2008_SNAN 474 # define IEEE_754_2008_SNAN 1 475 #endif 476 static inline int 477 issignaling_f (float x) 478 { 479 uint32_t ix = asuint (x); 480 if (!IEEE_754_2008_SNAN) 481 return (ix & 0x7fc00000) == 0x7fc00000; 482 return 2 * (ix ^ 0x00400000) > 2u * 0x7fc00000; 483 } 484 static inline int 485 issignaling_d (double x) 486 { 487 uint64_t ix = asuint64 (x); 488 if (!IEEE_754_2008_SNAN) 489 return (ix & 0x7ff8000000000000) == 0x7ff8000000000000; 490 return 2 * (ix ^ 0x0008000000000000) > 2 * 0x7ff8000000000000ULL; 491 } 492 493 #if USE_MPFR 494 static mpfr_rnd_t 495 rmap (int r) 496 { 497 switch (r) 498 { 499 case FE_TONEAREST: 500 return MPFR_RNDN; 501 case FE_TOWARDZERO: 502 return MPFR_RNDZ; 503 case FE_UPWARD: 504 return MPFR_RNDU; 505 case FE_DOWNWARD: 506 return MPFR_RNDD; 507 } 508 return -1; 509 } 510 511 #define prec_mpfr_f 50 512 #define prec_mpfr_d 80 513 #define prec_f 24 514 #define prec_d 53 515 #define emin_f -148 516 #define emin_d -1073 517 #define emax_f 128 518 #define emax_d 1024 519 static inline int 520 call_mpfr_f1 (mpfr_t y, const struct fun *f, struct args_f1 a, mpfr_rnd_t r) 521 { 522 MPFR_DECL_INIT (x, prec_f); 523 mpfr_set_flt (x, a.x, MPFR_RNDN); 524 return f->fun_mpfr.f1 (y, x, r); 525 } 526 static inline int 527 call_mpfr_f2 (mpfr_t y, const struct fun *f, struct args_f2 a, mpfr_rnd_t r) 528 { 529 MPFR_DECL_INIT (x, prec_f); 530 MPFR_DECL_INIT (x2, prec_f); 531 mpfr_set_flt (x, a.x, MPFR_RNDN); 532 mpfr_set_flt (x2, a.x2, MPFR_RNDN); 533 return f->fun_mpfr.f2 (y, x, x2, r); 534 } 535 static inline int 536 call_mpfr_d1 (mpfr_t y, const struct fun *f, struct args_d1 a, mpfr_rnd_t r) 537 { 538 MPFR_DECL_INIT (x, prec_d); 539 mpfr_set_d (x, a.x, MPFR_RNDN); 540 return f->fun_mpfr.d1 (y, x, r); 541 } 542 static inline int 543 call_mpfr_d2 (mpfr_t y, const struct fun *f, struct args_d2 a, mpfr_rnd_t r) 544 { 545 MPFR_DECL_INIT (x, prec_d); 546 MPFR_DECL_INIT (x2, prec_d); 547 mpfr_set_d (x, a.x, MPFR_RNDN); 548 mpfr_set_d (x2, a.x2, MPFR_RNDN); 549 return f->fun_mpfr.d2 (y, x, x2, r); 550 } 551 #endif 552 553 #define float_f float 554 #define double_f double 555 #define copysign_f copysignf 556 #define nextafter_f nextafterf 557 #define fabs_f fabsf 558 #define asuint_f asuint 559 #define asfloat_f asfloat 560 #define scalbn_f scalbnf 561 #define lscalbn_f scalbn 562 #define halfinf_f 0x1p127f 563 #define min_normal_f 0x1p-126f 564 565 #define float_d double 566 #define double_d long double 567 #define copysign_d copysign 568 #define nextafter_d nextafter 569 #define fabs_d fabs 570 #define asuint_d asuint64 571 #define asfloat_d asdouble 572 #define scalbn_d scalbn 573 #define lscalbn_d scalbnl 574 #define halfinf_d 0x1p1023 575 #define min_normal_d 0x1p-1022 576 577 #define NEW_RT 578 #define RT(x) x##_f 579 #define T(x) x##_f1 580 #include "ulp.h" 581 #undef T 582 #define T(x) x##_f2 583 #include "ulp.h" 584 #undef T 585 #undef RT 586 587 #define NEW_RT 588 #define RT(x) x##_d 589 #define T(x) x##_d1 590 #include "ulp.h" 591 #undef T 592 #define T(x) x##_d2 593 #include "ulp.h" 594 #undef T 595 #undef RT 596 597 static void 598 usage (void) 599 { 600 puts ("./ulp [-q] [-m] [-f] [-r {n|u|d|z}] [-l soft-ulplimit] [-e ulplimit] func " 601 "lo [hi [x lo2 hi2] [count]]"); 602 puts ("Compares func against a higher precision implementation in [lo; hi]."); 603 puts ("-q: quiet."); 604 puts ("-m: use mpfr even if faster method is available."); 605 puts ("-f: disable fenv exceptions testing."); 606 #ifdef ___vpcs 607 puts ("-c: neutral 'control value' to test behaviour when one lane can affect another. \n" 608 " This should be different from tested input in other lanes, and non-special \n" 609 " (i.e. should not trigger fenv exceptions). Default is 1."); 610 #endif 611 #if WANT_SVE_TESTS 612 puts ("-p: integer input for controlling predicate passed to SVE function. " 613 "If bit N is set, lane N is activated (bits past the vector length " 614 "are ignored). Default is UINT64_MAX (ptrue)."); 615 #endif 616 puts ("-z: ignore sign of 0."); 617 puts ("Supported func:"); 618 for (const struct fun *f = fun; f->name; f++) 619 printf ("\t%s\n", f->name); 620 exit (1); 621 } 622 623 static int 624 cmp (const struct fun *f, struct gen *gen, const struct conf *conf) 625 { 626 int r = 1; 627 if (f->arity == 1 && f->singleprec) 628 r = cmp_f1 (f, gen, conf); 629 else if (f->arity == 2 && f->singleprec) 630 r = cmp_f2 (f, gen, conf); 631 else if (f->arity == 1 && !f->singleprec) 632 r = cmp_d1 (f, gen, conf); 633 else if (f->arity == 2 && !f->singleprec) 634 r = cmp_d2 (f, gen, conf); 635 else 636 usage (); 637 return r; 638 } 639 640 static uint64_t 641 getnum (const char *s, int singleprec) 642 { 643 // int i; 644 uint64_t sign = 0; 645 // char buf[12]; 646 647 if (s[0] == '+') 648 s++; 649 else if (s[0] == '-') 650 { 651 sign = singleprec ? 1ULL << 31 : 1ULL << 63; 652 s++; 653 } 654 655 /* Sentinel value for failed parse. */ 656 char *should_not_be_s = NULL; 657 658 /* 0xXXXX is treated as bit representation, '-' flips the sign bit. */ 659 if (s[0] == '0' && tolower (s[1]) == 'x' && strchr (s, 'p') == 0) 660 { 661 uint64_t out = sign ^ strtoull (s, &should_not_be_s, 0); 662 if (should_not_be_s == s) 663 { 664 printf ("ERROR: Could not parse '%s'\n", s); 665 exit (1); 666 } 667 return out; 668 } 669 // /* SNaN, QNaN, NaN, Inf. */ 670 // for (i=0; s[i] && i < sizeof buf; i++) 671 // buf[i] = tolower(s[i]); 672 // buf[i] = 0; 673 // if (strcmp(buf, "snan") == 0) 674 // return sign | (singleprec ? 0x7fa00000 : 0x7ff4000000000000); 675 // if (strcmp(buf, "qnan") == 0 || strcmp(buf, "nan") == 0) 676 // return sign | (singleprec ? 0x7fc00000 : 0x7ff8000000000000); 677 // if (strcmp(buf, "inf") == 0 || strcmp(buf, "infinity") == 0) 678 // return sign | (singleprec ? 0x7f800000 : 0x7ff0000000000000); 679 /* Otherwise assume it's a floating-point literal. */ 680 uint64_t out = sign 681 | (singleprec ? asuint (strtof (s, &should_not_be_s)) 682 : asuint64 (strtod (s, &should_not_be_s))); 683 if (should_not_be_s == s) 684 { 685 printf ("ERROR: Could not parse '%s'\n", s); 686 exit (1); 687 } 688 689 return out; 690 } 691 692 static void 693 parsegen (struct gen *g, int argc, char *argv[], const struct fun *f) 694 { 695 int singleprec = f->singleprec; 696 int arity = f->arity; 697 uint64_t a, b, a2, b2, n; 698 if (argc < 1) 699 usage (); 700 b = a = getnum (argv[0], singleprec); 701 n = 0; 702 if (argc > 1 && strcmp (argv[1], "x") == 0) 703 { 704 argc -= 2; 705 argv += 2; 706 } 707 else if (argc > 1) 708 { 709 b = getnum (argv[1], singleprec); 710 if (argc > 2 && strcmp (argv[2], "x") == 0) 711 { 712 argc -= 3; 713 argv += 3; 714 } 715 } 716 b2 = a2 = getnum (argv[0], singleprec); 717 if (argc > 1) 718 b2 = getnum (argv[1], singleprec); 719 if (argc > 2) 720 n = strtoull (argv[2], 0, 0); 721 if (argc > 3) 722 usage (); 723 //printf("ab %lx %lx ab2 %lx %lx n %lu\n", a, b, a2, b2, n); 724 if (arity == 1) 725 { 726 g->start = a; 727 g->len = b - a; 728 if (n - 1 > b - a) 729 n = b - a + 1; 730 g->off = 0; 731 g->step = n ? (g->len + 1) / n : 1; 732 g->start2 = g->len2 = 0; 733 g->cnt = n; 734 } 735 else if (arity == 2) 736 { 737 g->start = a; 738 g->len = b - a; 739 g->off = g->step = 0; 740 g->start2 = a2; 741 g->len2 = b2 - a2; 742 g->cnt = n; 743 } 744 else 745 usage (); 746 } 747 748 int 749 main (int argc, char *argv[]) 750 { 751 const struct fun *f; 752 struct gen gen; 753 struct conf conf; 754 conf.rc = 'n'; 755 conf.quiet = 0; 756 conf.mpfr = 0; 757 conf.fenv = 1; 758 conf.softlim = 0; 759 conf.errlim = INFINITY; 760 conf.ignore_zero_sign = 0; 761 #if WANT_SVE_TESTS 762 uint64_t pg_int = UINT64_MAX; 763 #endif 764 for (;;) 765 { 766 argc--; 767 argv++; 768 if (argc < 1) 769 usage (); 770 if (argv[0][0] != '-') 771 break; 772 switch (argv[0][1]) 773 { 774 case 'e': 775 argc--; 776 argv++; 777 if (argc < 1) 778 usage (); 779 conf.errlim = strtod (argv[0], 0); 780 break; 781 case 'f': 782 conf.fenv = 0; 783 break; 784 case 'l': 785 argc--; 786 argv++; 787 if (argc < 1) 788 usage (); 789 conf.softlim = strtod (argv[0], 0); 790 break; 791 case 'm': 792 conf.mpfr = 1; 793 break; 794 case 'q': 795 conf.quiet = 1; 796 break; 797 case 'r': 798 conf.rc = argv[0][2]; 799 if (!conf.rc) 800 { 801 argc--; 802 argv++; 803 if (argc < 1 || argv[0][1] != '\0') 804 usage (); 805 conf.rc = argv[0][0]; 806 } 807 break; 808 case 'z': 809 conf.ignore_zero_sign = 1; 810 break; 811 #if __aarch64__ && __linux__ 812 case 'c': 813 argc--; 814 argv++; 815 fv[0] = strtof(argv[0], 0); 816 dv[0] = strtod(argv[0], 0); 817 break; 818 #endif 819 #if WANT_SVE_TESTS 820 case 'p': 821 argc--; 822 argv++; 823 pg_int = strtoull (argv[0], 0, 0); 824 break; 825 #endif 826 default: 827 usage (); 828 } 829 } 830 switch (conf.rc) 831 { 832 case 'n': 833 conf.r = FE_TONEAREST; 834 break; 835 case 'u': 836 conf.r = FE_UPWARD; 837 break; 838 case 'd': 839 conf.r = FE_DOWNWARD; 840 break; 841 case 'z': 842 conf.r = FE_TOWARDZERO; 843 break; 844 default: 845 usage (); 846 } 847 for (f = fun; f->name; f++) 848 if (strcmp (argv[0], f->name) == 0) 849 break; 850 if (!f->name) 851 { 852 #ifndef __vpcs 853 /* Ignore vector math functions if vector math is not supported. */ 854 if (strncmp (argv[0], "_ZGVnN", 6) == 0) 855 exit (0); 856 #endif 857 #if !WANT_SVE_TESTS 858 if (strncmp (argv[0], "_ZGVsMxv", 8) == 0) 859 exit (0); 860 #endif 861 printf ("math function %s not supported\n", argv[0]); 862 exit (1); 863 } 864 if (!f->singleprec && LDBL_MANT_DIG == DBL_MANT_DIG) 865 conf.mpfr = 1; /* Use mpfr if long double has no extra precision. */ 866 if (!USE_MPFR && conf.mpfr) 867 { 868 puts ("mpfr is not available."); 869 return 0; 870 } 871 argc--; 872 argv++; 873 parsegen (&gen, argc, argv, f); 874 conf.n = gen.cnt; 875 #if WANT_SVE_TESTS 876 svbool_t pg = parse_pg (pg_int, f->singleprec); 877 conf.pg = &pg; 878 #endif 879 return cmp (f, &gen, &conf); 880 } 881 882 #if __aarch64__ && __linux__ && WANT_SVE_TESTS && defined(__clang__) 883 # pragma clang attribute pop 884 #endif 885