xref: /freebsd/contrib/arm-optimized-routines/math/test/ulp.c (revision f3087bef11543b42e0d69b708f367097a4118d24)
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