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
rand64(void)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
randn(uint64_t n)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
next1(struct gen * g)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
next2(uint64_t * x2,struct gen * g)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
next_f1(void * g)145 next_f1 (void *g)
146 {
147 return (struct args_f1){asfloat (next1 (g))};
148 }
149
150 static struct args_f2
next_f2(void * g)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
next_d1(void * g)159 next_d1 (void *g)
160 {
161 return (struct args_d1){asdouble (next1 (g))};
162 }
163
164 static struct args_d2
next_d2(void * g)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
argf(float x)183 argf (float x)
184 {
185 return (float32x4_t){ x, x, x, fv[secondcall] };
186 }
187 static inline float64x2_t
argd(double x)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
svargf(float x)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
svargd(double x)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
svretf(svfloat32_t vec,svbool_t pg)216 svretf (svfloat32_t vec, svbool_t pg)
217 {
218 return svlastb_f32 (svpfirst (pg, svpfalse ()), vec);
219 }
220 static inline double
svretd(svfloat64_t vec,svbool_t pg)221 svretd (svfloat64_t vec, svbool_t pg)
222 {
223 return svlastb_f64 (svpfirst (pg, svpfalse ()), vec);
224 }
225
226 static inline svbool_t
parse_pg(uint64_t p,int is_single)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
ulpscale_f(float x)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
ulpscale_d(double x)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
call_f1(const struct fun * f,struct args_f1 a,const struct conf * conf)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
call_f2(const struct fun * f,struct args_f2 a,const struct conf * conf)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
call_d1(const struct fun * f,struct args_d1 a,const struct conf * conf)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
call_d2(const struct fun * f,struct args_d2 a,const struct conf * conf)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
call_long_f1(const struct fun * f,struct args_f1 a)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
call_long_f2(const struct fun * f,struct args_f2 a)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
call_long_d1(const struct fun * f,struct args_d1 a)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
call_long_d2(const struct fun * f,struct args_d2 a)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
printcall_f1(const struct fun * f,struct args_f1 a)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
printcall_f2(const struct fun * f,struct args_f2 a)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
printcall_d1(const struct fun * f,struct args_d1 a)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
printcall_d2(const struct fun * f,struct args_d2 a)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
printgen_f1(const struct fun * f,struct gen * gen)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
printgen_f2(const struct fun * f,struct gen * gen)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
printgen_d1(const struct fun * f,struct gen * gen)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
printgen_d2(const struct fun * f,struct gen * gen)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
issignaling_f(float x)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
issignaling_d(double x)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
rmap(int r)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
call_mpfr_f1(mpfr_t y,const struct fun * f,struct args_f1 a,mpfr_rnd_t r)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
call_mpfr_f2(mpfr_t y,const struct fun * f,struct args_f2 a,mpfr_rnd_t r)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
call_mpfr_d1(mpfr_t y,const struct fun * f,struct args_d1 a,mpfr_rnd_t r)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
call_mpfr_d2(mpfr_t y,const struct fun * f,struct args_d2 a,mpfr_rnd_t r)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
usage(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
cmp(const struct fun * f,struct gen * gen,const struct conf * conf)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
getnum(const char * s,int singleprec)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
parsegen(struct gen * g,int argc,char * argv[],const struct fun * f)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
main(int argc,char * argv[])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