xref: /freebsd-src/contrib/arm-optimized-routines/math/test/ulp.c (revision f3087bef11543b42e0d69b708f367097a4118d24)
131914882SAlex Richardson /*
231914882SAlex Richardson  * ULP error checking tool for math functions.
331914882SAlex Richardson  *
4*f3087befSAndrew Turner  * Copyright (c) 2019-2024, Arm Limited.
5072a4ba8SAndrew Turner  * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
631914882SAlex Richardson  */
731914882SAlex Richardson 
8*f3087befSAndrew Turner #if WANT_SVE_TESTS
9*f3087befSAndrew Turner #  if __aarch64__ && __linux__
10*f3087befSAndrew Turner #    ifdef __clang__
11*f3087befSAndrew Turner #      pragma clang attribute push(__attribute__((target("sve"))),            \
12*f3087befSAndrew Turner 				   apply_to = any(function))
13*f3087befSAndrew Turner #    else
14*f3087befSAndrew Turner #      pragma GCC target("+sve")
15*f3087befSAndrew Turner #    endif
16*f3087befSAndrew Turner #  else
17*f3087befSAndrew Turner #    error "SVE not supported - please disable WANT_SVE_TESTS"
18*f3087befSAndrew Turner #  endif
19*f3087befSAndrew Turner #endif
20*f3087befSAndrew Turner 
215a02ffc3SAndrew Turner #define _GNU_SOURCE
2231914882SAlex Richardson #include <ctype.h>
2331914882SAlex Richardson #include <fenv.h>
2431914882SAlex Richardson #include <float.h>
2531914882SAlex Richardson #include <math.h>
2631914882SAlex Richardson #include <stdint.h>
2731914882SAlex Richardson #include <stdio.h>
2831914882SAlex Richardson #include <stdlib.h>
2931914882SAlex Richardson #include <string.h>
3031914882SAlex Richardson #include "mathlib.h"
3131914882SAlex Richardson 
32*f3087befSAndrew Turner #include "trigpi_references.h"
33*f3087befSAndrew Turner 
3431914882SAlex Richardson /* Don't depend on mpfr by default.  */
3531914882SAlex Richardson #ifndef USE_MPFR
3631914882SAlex Richardson # define USE_MPFR 0
3731914882SAlex Richardson #endif
3831914882SAlex Richardson #if USE_MPFR
3931914882SAlex Richardson # include <mpfr.h>
4031914882SAlex Richardson #endif
4131914882SAlex Richardson 
4231914882SAlex Richardson static uint64_t seed = 0x0123456789abcdef;
4331914882SAlex Richardson static uint64_t
4431914882SAlex Richardson rand64 (void)
4531914882SAlex Richardson {
4631914882SAlex Richardson   seed = 6364136223846793005ull * seed + 1;
4731914882SAlex Richardson   return seed ^ (seed >> 32);
4831914882SAlex Richardson }
4931914882SAlex Richardson 
5031914882SAlex Richardson /* Uniform random in [0,n].  */
5131914882SAlex Richardson static uint64_t
5231914882SAlex Richardson randn (uint64_t n)
5331914882SAlex Richardson {
5431914882SAlex Richardson   uint64_t r, m;
5531914882SAlex Richardson 
5631914882SAlex Richardson   if (n == 0)
5731914882SAlex Richardson     return 0;
5831914882SAlex Richardson   n++;
5931914882SAlex Richardson   if (n == 0)
6031914882SAlex Richardson     return rand64 ();
6131914882SAlex Richardson   for (;;)
6231914882SAlex Richardson     {
6331914882SAlex Richardson       r = rand64 ();
6431914882SAlex Richardson       m = r % n;
6531914882SAlex Richardson       if (r - m <= -n)
6631914882SAlex Richardson 	return m;
6731914882SAlex Richardson     }
6831914882SAlex Richardson }
6931914882SAlex Richardson 
7031914882SAlex Richardson struct gen
7131914882SAlex Richardson {
7231914882SAlex Richardson   uint64_t start;
7331914882SAlex Richardson   uint64_t len;
7431914882SAlex Richardson   uint64_t start2;
7531914882SAlex Richardson   uint64_t len2;
7631914882SAlex Richardson   uint64_t off;
7731914882SAlex Richardson   uint64_t step;
7831914882SAlex Richardson   uint64_t cnt;
7931914882SAlex Richardson };
8031914882SAlex Richardson 
8131914882SAlex Richardson struct args_f1
8231914882SAlex Richardson {
8331914882SAlex Richardson   float x;
8431914882SAlex Richardson };
8531914882SAlex Richardson 
8631914882SAlex Richardson struct args_f2
8731914882SAlex Richardson {
8831914882SAlex Richardson   float x;
8931914882SAlex Richardson   float x2;
9031914882SAlex Richardson };
9131914882SAlex Richardson 
9231914882SAlex Richardson struct args_d1
9331914882SAlex Richardson {
9431914882SAlex Richardson   double x;
9531914882SAlex Richardson };
9631914882SAlex Richardson 
9731914882SAlex Richardson struct args_d2
9831914882SAlex Richardson {
9931914882SAlex Richardson   double x;
10031914882SAlex Richardson   double x2;
10131914882SAlex Richardson };
10231914882SAlex Richardson 
10331914882SAlex Richardson /* result = y + tail*2^ulpexp.  */
10431914882SAlex Richardson struct ret_f
10531914882SAlex Richardson {
10631914882SAlex Richardson   float y;
10731914882SAlex Richardson   double tail;
10831914882SAlex Richardson   int ulpexp;
10931914882SAlex Richardson   int ex;
11031914882SAlex Richardson   int ex_may;
11131914882SAlex Richardson };
11231914882SAlex Richardson 
11331914882SAlex Richardson struct ret_d
11431914882SAlex Richardson {
11531914882SAlex Richardson   double y;
11631914882SAlex Richardson   double tail;
11731914882SAlex Richardson   int ulpexp;
11831914882SAlex Richardson   int ex;
11931914882SAlex Richardson   int ex_may;
12031914882SAlex Richardson };
12131914882SAlex Richardson 
12231914882SAlex Richardson static inline uint64_t
12331914882SAlex Richardson next1 (struct gen *g)
12431914882SAlex Richardson {
12531914882SAlex Richardson   /* For single argument use randomized incremental steps,
12631914882SAlex Richardson      that produce dense sampling without collisions and allow
12731914882SAlex Richardson      testing all inputs in a range.  */
12831914882SAlex Richardson   uint64_t r = g->start + g->off;
12931914882SAlex Richardson   g->off += g->step + randn (g->step / 2);
13031914882SAlex Richardson   if (g->off > g->len)
13131914882SAlex Richardson     g->off -= g->len; /* hack.  */
13231914882SAlex Richardson   return r;
13331914882SAlex Richardson }
13431914882SAlex Richardson 
13531914882SAlex Richardson static inline uint64_t
13631914882SAlex Richardson next2 (uint64_t *x2, struct gen *g)
13731914882SAlex Richardson {
13831914882SAlex Richardson   /* For two arguments use uniform random sampling.  */
13931914882SAlex Richardson   uint64_t r = g->start + randn (g->len);
14031914882SAlex Richardson   *x2 = g->start2 + randn (g->len2);
14131914882SAlex Richardson   return r;
14231914882SAlex Richardson }
14331914882SAlex Richardson 
14431914882SAlex Richardson static struct args_f1
14531914882SAlex Richardson next_f1 (void *g)
14631914882SAlex Richardson {
14731914882SAlex Richardson   return (struct args_f1){asfloat (next1 (g))};
14831914882SAlex Richardson }
14931914882SAlex Richardson 
15031914882SAlex Richardson static struct args_f2
15131914882SAlex Richardson next_f2 (void *g)
15231914882SAlex Richardson {
15331914882SAlex Richardson   uint64_t x2;
15431914882SAlex Richardson   uint64_t x = next2 (&x2, g);
15531914882SAlex Richardson   return (struct args_f2){asfloat (x), asfloat (x2)};
15631914882SAlex Richardson }
15731914882SAlex Richardson 
15831914882SAlex Richardson static struct args_d1
15931914882SAlex Richardson next_d1 (void *g)
16031914882SAlex Richardson {
16131914882SAlex Richardson   return (struct args_d1){asdouble (next1 (g))};
16231914882SAlex Richardson }
16331914882SAlex Richardson 
16431914882SAlex Richardson static struct args_d2
16531914882SAlex Richardson next_d2 (void *g)
16631914882SAlex Richardson {
16731914882SAlex Richardson   uint64_t x2;
16831914882SAlex Richardson   uint64_t x = next2 (&x2, g);
16931914882SAlex Richardson   return (struct args_d2){asdouble (x), asdouble (x2)};
17031914882SAlex Richardson }
17131914882SAlex Richardson 
172*f3087befSAndrew Turner /* A bit of a hack: call vector functions twice with the same
173*f3087befSAndrew Turner    input in lane 0 but a different value in other lanes: once
174*f3087befSAndrew Turner    with an in-range value and then with a special case value.  */
175*f3087befSAndrew Turner static int secondcall;
176*f3087befSAndrew Turner 
177*f3087befSAndrew Turner /* Wrappers for vector functions.  */
178*f3087befSAndrew Turner #if __aarch64__ && __linux__
179*f3087befSAndrew Turner /* First element of fv and dv may be changed by -c argument.  */
180*f3087befSAndrew Turner static float fv[2] = {1.0f, -INFINITY};
181*f3087befSAndrew Turner static double dv[2] = {1.0, -INFINITY};
182*f3087befSAndrew Turner static inline float32x4_t
183*f3087befSAndrew Turner argf (float x)
184*f3087befSAndrew Turner {
185*f3087befSAndrew Turner   return (float32x4_t){ x, x, x, fv[secondcall] };
186*f3087befSAndrew Turner }
187*f3087befSAndrew Turner static inline float64x2_t
188*f3087befSAndrew Turner argd (double x)
189*f3087befSAndrew Turner {
190*f3087befSAndrew Turner   return (float64x2_t){ x, dv[secondcall] };
191*f3087befSAndrew Turner }
192*f3087befSAndrew Turner #if WANT_SVE_TESTS
193*f3087befSAndrew Turner #include <arm_sve.h>
194*f3087befSAndrew Turner 
195*f3087befSAndrew Turner static inline svfloat32_t
196*f3087befSAndrew Turner svargf (float x)
197*f3087befSAndrew Turner {
198*f3087befSAndrew Turner   int n = svcntw ();
199*f3087befSAndrew Turner   float base[n];
200*f3087befSAndrew Turner   for (int i = 0; i < n; i++)
201*f3087befSAndrew Turner     base[i] = (float) x;
202*f3087befSAndrew Turner   base[n - 1] = (float) fv[secondcall];
203*f3087befSAndrew Turner   return svld1 (svptrue_b32 (), base);
204*f3087befSAndrew Turner }
205*f3087befSAndrew Turner static inline svfloat64_t
206*f3087befSAndrew Turner svargd (double x)
207*f3087befSAndrew Turner {
208*f3087befSAndrew Turner   int n = svcntd ();
209*f3087befSAndrew Turner   double base[n];
210*f3087befSAndrew Turner   for (int i = 0; i < n; i++)
211*f3087befSAndrew Turner     base[i] = x;
212*f3087befSAndrew Turner   base[n - 1] = dv[secondcall];
213*f3087befSAndrew Turner   return svld1 (svptrue_b64 (), base);
214*f3087befSAndrew Turner }
215*f3087befSAndrew Turner static inline float
216*f3087befSAndrew Turner svretf (svfloat32_t vec, svbool_t pg)
217*f3087befSAndrew Turner {
218*f3087befSAndrew Turner   return svlastb_f32 (svpfirst (pg, svpfalse ()), vec);
219*f3087befSAndrew Turner }
220*f3087befSAndrew Turner static inline double
221*f3087befSAndrew Turner svretd (svfloat64_t vec, svbool_t pg)
222*f3087befSAndrew Turner {
223*f3087befSAndrew Turner   return svlastb_f64 (svpfirst (pg, svpfalse ()), vec);
224*f3087befSAndrew Turner }
225*f3087befSAndrew Turner 
226*f3087befSAndrew Turner static inline svbool_t
227*f3087befSAndrew Turner parse_pg (uint64_t p, int is_single)
228*f3087befSAndrew Turner {
229*f3087befSAndrew Turner   if (is_single)
230*f3087befSAndrew Turner     {
231*f3087befSAndrew Turner       uint32_t tmp[svcntw ()];
232*f3087befSAndrew Turner       for (unsigned i = 0; i < svcntw (); i++)
233*f3087befSAndrew Turner 	tmp[i] = (p >> i) & 1;
234*f3087befSAndrew Turner       return svcmpne (svptrue_b32 (), svld1 (svptrue_b32 (), tmp), 0);
235*f3087befSAndrew Turner     }
236*f3087befSAndrew Turner   else
237*f3087befSAndrew Turner     {
238*f3087befSAndrew Turner       uint64_t tmp[svcntd ()];
239*f3087befSAndrew Turner       for (unsigned i = 0; i < svcntd (); i++)
240*f3087befSAndrew Turner 	tmp[i] = (p >> i) & 1;
241*f3087befSAndrew Turner       return svcmpne (svptrue_b64 (), svld1 (svptrue_b64 (), tmp), 0);
242*f3087befSAndrew Turner     }
243*f3087befSAndrew Turner }
244*f3087befSAndrew Turner # endif
245*f3087befSAndrew Turner #endif
246*f3087befSAndrew Turner 
24731914882SAlex Richardson struct conf
24831914882SAlex Richardson {
24931914882SAlex Richardson   int r;
25031914882SAlex Richardson   int rc;
25131914882SAlex Richardson   int quiet;
25231914882SAlex Richardson   int mpfr;
25331914882SAlex Richardson   int fenv;
25431914882SAlex Richardson   unsigned long long n;
25531914882SAlex Richardson   double softlim;
25631914882SAlex Richardson   double errlim;
2575a02ffc3SAndrew Turner   int ignore_zero_sign;
258*f3087befSAndrew Turner #if WANT_SVE_TESTS
259*f3087befSAndrew Turner   svbool_t *pg;
260*f3087befSAndrew Turner #endif
26131914882SAlex Richardson };
26231914882SAlex Richardson 
263072a4ba8SAndrew Turner #include "test/ulp_wrappers.h"
264072a4ba8SAndrew Turner 
26531914882SAlex Richardson struct fun
26631914882SAlex Richardson {
26731914882SAlex Richardson   const char *name;
26831914882SAlex Richardson   int arity;
26931914882SAlex Richardson   int singleprec;
27031914882SAlex Richardson   int twice;
271*f3087befSAndrew Turner   int is_predicated;
27231914882SAlex Richardson   union
27331914882SAlex Richardson   {
27431914882SAlex Richardson     float (*f1) (float);
27531914882SAlex Richardson     float (*f2) (float, float);
27631914882SAlex Richardson     double (*d1) (double);
27731914882SAlex Richardson     double (*d2) (double, double);
278*f3087befSAndrew Turner #if WANT_SVE_TESTS
279*f3087befSAndrew Turner     float (*f1_pred) (svbool_t, float);
280*f3087befSAndrew Turner     float (*f2_pred) (svbool_t, float, float);
281*f3087befSAndrew Turner     double (*d1_pred) (svbool_t, double);
282*f3087befSAndrew Turner     double (*d2_pred) (svbool_t, double, double);
283*f3087befSAndrew Turner #endif
28431914882SAlex Richardson   } fun;
28531914882SAlex Richardson   union
28631914882SAlex Richardson   {
28731914882SAlex Richardson     double (*f1) (double);
28831914882SAlex Richardson     double (*f2) (double, double);
28931914882SAlex Richardson     long double (*d1) (long double);
29031914882SAlex Richardson     long double (*d2) (long double, long double);
29131914882SAlex Richardson   } fun_long;
29231914882SAlex Richardson #if USE_MPFR
29331914882SAlex Richardson   union
29431914882SAlex Richardson   {
29531914882SAlex Richardson     int (*f1) (mpfr_t, const mpfr_t, mpfr_rnd_t);
29631914882SAlex Richardson     int (*f2) (mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t);
29731914882SAlex Richardson     int (*d1) (mpfr_t, const mpfr_t, mpfr_rnd_t);
29831914882SAlex Richardson     int (*d2) (mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t);
29931914882SAlex Richardson   } fun_mpfr;
30031914882SAlex Richardson #endif
30131914882SAlex Richardson };
30231914882SAlex Richardson 
303*f3087befSAndrew Turner // clang-format off
30431914882SAlex Richardson static const struct fun fun[] = {
30531914882SAlex Richardson #if USE_MPFR
30631914882SAlex Richardson #  define F(x, x_wrap, x_long, x_mpfr, a, s, t, twice)                        \
307*f3087befSAndrew Turner     { #x, a, s, twice, 0, { .t = x_wrap }, { .t = x_long }, { .t = x_mpfr } },
308*f3087befSAndrew Turner #  define SVF(x, x_wrap, x_long, x_mpfr, a, s, t, twice)                      \
309*f3087befSAndrew Turner     { #x, a, s, twice, 1, { .t##_pred = x_wrap }, { .t = x_long }, { .t = x_mpfr } },
31031914882SAlex Richardson #else
31131914882SAlex Richardson #  define F(x, x_wrap, x_long, x_mpfr, a, s, t, twice)                        \
312*f3087befSAndrew Turner     { #x, a, s, twice, 0, { .t = x_wrap }, { .t = x_long } },
313*f3087befSAndrew Turner #  define SVF(x, x_wrap, x_long, x_mpfr, a, s, t, twice)                      \
314*f3087befSAndrew Turner     { #x, a, s, twice, 1, { .t##_pred = x_wrap }, { .t = x_long } },
31531914882SAlex Richardson #endif
31631914882SAlex Richardson #define F1(x) F (x##f, x##f, x, mpfr_##x, 1, 1, f1, 0)
31731914882SAlex Richardson #define F2(x) F (x##f, x##f, x, mpfr_##x, 2, 1, f2, 0)
31831914882SAlex Richardson #define D1(x) F (x, x, x##l, mpfr_##x, 1, 0, d1, 0)
31931914882SAlex Richardson #define D2(x) F (x, x, x##l, mpfr_##x, 2, 0, d2, 0)
320072a4ba8SAndrew Turner /* Neon routines.  */
321*f3087befSAndrew Turner #define ZVNF1(x) F (_ZGVnN4v_##x##f, Z_##x##f, x, mpfr_##x, 1, 1, f1, 0)
322*f3087befSAndrew Turner #define ZVNF2(x) F (_ZGVnN4vv_##x##f, Z_##x##f, x, mpfr_##x, 2, 1, f2, 0)
323*f3087befSAndrew Turner #define ZVND1(x) F (_ZGVnN2v_##x, Z_##x, x##l, mpfr_##x, 1, 0, d1, 0)
324*f3087befSAndrew Turner #define ZVND2(x) F (_ZGVnN2vv_##x, Z_##x, x##l, mpfr_##x, 2, 0, d2, 0)
325072a4ba8SAndrew Turner /* SVE routines.  */
326*f3087befSAndrew Turner #define ZSVF1(x) SVF (_ZGVsMxv_##x##f, Z_sv_##x##f, x, mpfr_##x, 1, 1, f1, 0)
327*f3087befSAndrew Turner #define ZSVF2(x) SVF (_ZGVsMxvv_##x##f, Z_sv_##x##f, x, mpfr_##x, 2, 1, f2, 0)
328*f3087befSAndrew Turner #define ZSVD1(x) SVF (_ZGVsMxv_##x, Z_sv_##x, x##l, mpfr_##x, 1, 0, d1, 0)
329*f3087befSAndrew Turner #define ZSVD2(x) SVF (_ZGVsMxvv_##x, Z_sv_##x, x##l, mpfr_##x, 2, 0, d2, 0)
330072a4ba8SAndrew Turner 
331072a4ba8SAndrew Turner #include "test/ulp_funcs.h"
332072a4ba8SAndrew Turner 
33331914882SAlex Richardson #undef F
33431914882SAlex Richardson #undef F1
33531914882SAlex Richardson #undef F2
33631914882SAlex Richardson #undef D1
33731914882SAlex Richardson #undef D2
338*f3087befSAndrew Turner #undef ZSVF1
339*f3087befSAndrew Turner #undef ZSVF2
340*f3087befSAndrew Turner #undef ZSVD1
341*f3087befSAndrew Turner #undef ZSVD2
342*f3087befSAndrew Turner   { 0 }
343*f3087befSAndrew Turner };
344*f3087befSAndrew Turner // clang-format on
34531914882SAlex Richardson 
34631914882SAlex Richardson /* Boilerplate for generic calls.  */
34731914882SAlex Richardson 
34831914882SAlex Richardson static inline int
34931914882SAlex Richardson ulpscale_f (float x)
35031914882SAlex Richardson {
35131914882SAlex Richardson   int e = asuint (x) >> 23 & 0xff;
35231914882SAlex Richardson   if (!e)
35331914882SAlex Richardson     e++;
35431914882SAlex Richardson   return e - 0x7f - 23;
35531914882SAlex Richardson }
35631914882SAlex Richardson static inline int
35731914882SAlex Richardson ulpscale_d (double x)
35831914882SAlex Richardson {
35931914882SAlex Richardson   int e = asuint64 (x) >> 52 & 0x7ff;
36031914882SAlex Richardson   if (!e)
36131914882SAlex Richardson     e++;
36231914882SAlex Richardson   return e - 0x3ff - 52;
36331914882SAlex Richardson }
36431914882SAlex Richardson static inline float
365*f3087befSAndrew Turner call_f1 (const struct fun *f, struct args_f1 a, const struct conf *conf)
36631914882SAlex Richardson {
367*f3087befSAndrew Turner #if WANT_SVE_TESTS
368*f3087befSAndrew Turner   if (f->is_predicated)
369*f3087befSAndrew Turner     return f->fun.f1_pred (*conf->pg, a.x);
370*f3087befSAndrew Turner #endif
37131914882SAlex Richardson   return f->fun.f1 (a.x);
37231914882SAlex Richardson }
37331914882SAlex Richardson static inline float
374*f3087befSAndrew Turner call_f2 (const struct fun *f, struct args_f2 a, const struct conf *conf)
37531914882SAlex Richardson {
376*f3087befSAndrew Turner #if WANT_SVE_TESTS
377*f3087befSAndrew Turner   if (f->is_predicated)
378*f3087befSAndrew Turner     return f->fun.f2_pred (*conf->pg, a.x, a.x2);
379*f3087befSAndrew Turner #endif
38031914882SAlex Richardson   return f->fun.f2 (a.x, a.x2);
38131914882SAlex Richardson }
38231914882SAlex Richardson 
38331914882SAlex Richardson static inline double
384*f3087befSAndrew Turner call_d1 (const struct fun *f, struct args_d1 a, const struct conf *conf)
38531914882SAlex Richardson {
386*f3087befSAndrew Turner #if WANT_SVE_TESTS
387*f3087befSAndrew Turner   if (f->is_predicated)
388*f3087befSAndrew Turner     return f->fun.d1_pred (*conf->pg, a.x);
389*f3087befSAndrew Turner #endif
39031914882SAlex Richardson   return f->fun.d1 (a.x);
39131914882SAlex Richardson }
39231914882SAlex Richardson static inline double
393*f3087befSAndrew Turner call_d2 (const struct fun *f, struct args_d2 a, const struct conf *conf)
39431914882SAlex Richardson {
395*f3087befSAndrew Turner #if WANT_SVE_TESTS
396*f3087befSAndrew Turner   if (f->is_predicated)
397*f3087befSAndrew Turner     return f->fun.d2_pred (*conf->pg, a.x, a.x2);
398*f3087befSAndrew Turner #endif
39931914882SAlex Richardson   return f->fun.d2 (a.x, a.x2);
40031914882SAlex Richardson }
40131914882SAlex Richardson static inline double
40231914882SAlex Richardson call_long_f1 (const struct fun *f, struct args_f1 a)
40331914882SAlex Richardson {
40431914882SAlex Richardson   return f->fun_long.f1 (a.x);
40531914882SAlex Richardson }
40631914882SAlex Richardson static inline double
40731914882SAlex Richardson call_long_f2 (const struct fun *f, struct args_f2 a)
40831914882SAlex Richardson {
40931914882SAlex Richardson   return f->fun_long.f2 (a.x, a.x2);
41031914882SAlex Richardson }
41131914882SAlex Richardson static inline long double
41231914882SAlex Richardson call_long_d1 (const struct fun *f, struct args_d1 a)
41331914882SAlex Richardson {
41431914882SAlex Richardson   return f->fun_long.d1 (a.x);
41531914882SAlex Richardson }
41631914882SAlex Richardson static inline long double
41731914882SAlex Richardson call_long_d2 (const struct fun *f, struct args_d2 a)
41831914882SAlex Richardson {
41931914882SAlex Richardson   return f->fun_long.d2 (a.x, a.x2);
42031914882SAlex Richardson }
42131914882SAlex Richardson static inline void
42231914882SAlex Richardson printcall_f1 (const struct fun *f, struct args_f1 a)
42331914882SAlex Richardson {
42431914882SAlex Richardson   printf ("%s(%a)", f->name, a.x);
42531914882SAlex Richardson }
42631914882SAlex Richardson static inline void
42731914882SAlex Richardson printcall_f2 (const struct fun *f, struct args_f2 a)
42831914882SAlex Richardson {
42931914882SAlex Richardson   printf ("%s(%a, %a)", f->name, a.x, a.x2);
43031914882SAlex Richardson }
43131914882SAlex Richardson static inline void
43231914882SAlex Richardson printcall_d1 (const struct fun *f, struct args_d1 a)
43331914882SAlex Richardson {
43431914882SAlex Richardson   printf ("%s(%a)", f->name, a.x);
43531914882SAlex Richardson }
43631914882SAlex Richardson static inline void
43731914882SAlex Richardson printcall_d2 (const struct fun *f, struct args_d2 a)
43831914882SAlex Richardson {
43931914882SAlex Richardson   printf ("%s(%a, %a)", f->name, a.x, a.x2);
44031914882SAlex Richardson }
44131914882SAlex Richardson static inline void
44231914882SAlex Richardson printgen_f1 (const struct fun *f, struct gen *gen)
44331914882SAlex Richardson {
44431914882SAlex Richardson   printf ("%s in [%a;%a]", f->name, asfloat (gen->start),
44531914882SAlex Richardson 	  asfloat (gen->start + gen->len));
44631914882SAlex Richardson }
44731914882SAlex Richardson static inline void
44831914882SAlex Richardson printgen_f2 (const struct fun *f, struct gen *gen)
44931914882SAlex Richardson {
45031914882SAlex Richardson   printf ("%s in [%a;%a] x [%a;%a]", f->name, asfloat (gen->start),
45131914882SAlex Richardson 	  asfloat (gen->start + gen->len), asfloat (gen->start2),
45231914882SAlex Richardson 	  asfloat (gen->start2 + gen->len2));
45331914882SAlex Richardson }
45431914882SAlex Richardson static inline void
45531914882SAlex Richardson printgen_d1 (const struct fun *f, struct gen *gen)
45631914882SAlex Richardson {
45731914882SAlex Richardson   printf ("%s in [%a;%a]", f->name, asdouble (gen->start),
45831914882SAlex Richardson 	  asdouble (gen->start + gen->len));
45931914882SAlex Richardson }
46031914882SAlex Richardson static inline void
46131914882SAlex Richardson printgen_d2 (const struct fun *f, struct gen *gen)
46231914882SAlex Richardson {
46331914882SAlex Richardson   printf ("%s in [%a;%a] x [%a;%a]", f->name, asdouble (gen->start),
46431914882SAlex Richardson 	  asdouble (gen->start + gen->len), asdouble (gen->start2),
46531914882SAlex Richardson 	  asdouble (gen->start2 + gen->len2));
46631914882SAlex Richardson }
46731914882SAlex Richardson 
46831914882SAlex Richardson #define reduce_f1(a, f, op) (f (a.x))
46931914882SAlex Richardson #define reduce_f2(a, f, op) (f (a.x) op f (a.x2))
47031914882SAlex Richardson #define reduce_d1(a, f, op) (f (a.x))
47131914882SAlex Richardson #define reduce_d2(a, f, op) (f (a.x) op f (a.x2))
47231914882SAlex Richardson 
47331914882SAlex Richardson #ifndef IEEE_754_2008_SNAN
47431914882SAlex Richardson # define IEEE_754_2008_SNAN 1
47531914882SAlex Richardson #endif
47631914882SAlex Richardson static inline int
47731914882SAlex Richardson issignaling_f (float x)
47831914882SAlex Richardson {
47931914882SAlex Richardson   uint32_t ix = asuint (x);
48031914882SAlex Richardson   if (!IEEE_754_2008_SNAN)
48131914882SAlex Richardson     return (ix & 0x7fc00000) == 0x7fc00000;
48231914882SAlex Richardson   return 2 * (ix ^ 0x00400000) > 2u * 0x7fc00000;
48331914882SAlex Richardson }
48431914882SAlex Richardson static inline int
48531914882SAlex Richardson issignaling_d (double x)
48631914882SAlex Richardson {
48731914882SAlex Richardson   uint64_t ix = asuint64 (x);
48831914882SAlex Richardson   if (!IEEE_754_2008_SNAN)
48931914882SAlex Richardson     return (ix & 0x7ff8000000000000) == 0x7ff8000000000000;
49031914882SAlex Richardson   return 2 * (ix ^ 0x0008000000000000) > 2 * 0x7ff8000000000000ULL;
49131914882SAlex Richardson }
49231914882SAlex Richardson 
49331914882SAlex Richardson #if USE_MPFR
49431914882SAlex Richardson static mpfr_rnd_t
49531914882SAlex Richardson rmap (int r)
49631914882SAlex Richardson {
49731914882SAlex Richardson   switch (r)
49831914882SAlex Richardson     {
49931914882SAlex Richardson     case FE_TONEAREST:
50031914882SAlex Richardson       return MPFR_RNDN;
50131914882SAlex Richardson     case FE_TOWARDZERO:
50231914882SAlex Richardson       return MPFR_RNDZ;
50331914882SAlex Richardson     case FE_UPWARD:
50431914882SAlex Richardson       return MPFR_RNDU;
50531914882SAlex Richardson     case FE_DOWNWARD:
50631914882SAlex Richardson       return MPFR_RNDD;
50731914882SAlex Richardson     }
50831914882SAlex Richardson   return -1;
50931914882SAlex Richardson }
51031914882SAlex Richardson 
51131914882SAlex Richardson #define prec_mpfr_f 50
51231914882SAlex Richardson #define prec_mpfr_d 80
51331914882SAlex Richardson #define prec_f 24
51431914882SAlex Richardson #define prec_d 53
51531914882SAlex Richardson #define emin_f -148
51631914882SAlex Richardson #define emin_d -1073
51731914882SAlex Richardson #define emax_f 128
51831914882SAlex Richardson #define emax_d 1024
51931914882SAlex Richardson static inline int
52031914882SAlex Richardson call_mpfr_f1 (mpfr_t y, const struct fun *f, struct args_f1 a, mpfr_rnd_t r)
52131914882SAlex Richardson {
52231914882SAlex Richardson   MPFR_DECL_INIT (x, prec_f);
52331914882SAlex Richardson   mpfr_set_flt (x, a.x, MPFR_RNDN);
52431914882SAlex Richardson   return f->fun_mpfr.f1 (y, x, r);
52531914882SAlex Richardson }
52631914882SAlex Richardson static inline int
52731914882SAlex Richardson call_mpfr_f2 (mpfr_t y, const struct fun *f, struct args_f2 a, mpfr_rnd_t r)
52831914882SAlex Richardson {
52931914882SAlex Richardson   MPFR_DECL_INIT (x, prec_f);
53031914882SAlex Richardson   MPFR_DECL_INIT (x2, prec_f);
53131914882SAlex Richardson   mpfr_set_flt (x, a.x, MPFR_RNDN);
53231914882SAlex Richardson   mpfr_set_flt (x2, a.x2, MPFR_RNDN);
53331914882SAlex Richardson   return f->fun_mpfr.f2 (y, x, x2, r);
53431914882SAlex Richardson }
53531914882SAlex Richardson static inline int
53631914882SAlex Richardson call_mpfr_d1 (mpfr_t y, const struct fun *f, struct args_d1 a, mpfr_rnd_t r)
53731914882SAlex Richardson {
53831914882SAlex Richardson   MPFR_DECL_INIT (x, prec_d);
53931914882SAlex Richardson   mpfr_set_d (x, a.x, MPFR_RNDN);
54031914882SAlex Richardson   return f->fun_mpfr.d1 (y, x, r);
54131914882SAlex Richardson }
54231914882SAlex Richardson static inline int
54331914882SAlex Richardson call_mpfr_d2 (mpfr_t y, const struct fun *f, struct args_d2 a, mpfr_rnd_t r)
54431914882SAlex Richardson {
54531914882SAlex Richardson   MPFR_DECL_INIT (x, prec_d);
54631914882SAlex Richardson   MPFR_DECL_INIT (x2, prec_d);
54731914882SAlex Richardson   mpfr_set_d (x, a.x, MPFR_RNDN);
54831914882SAlex Richardson   mpfr_set_d (x2, a.x2, MPFR_RNDN);
54931914882SAlex Richardson   return f->fun_mpfr.d2 (y, x, x2, r);
55031914882SAlex Richardson }
55131914882SAlex Richardson #endif
55231914882SAlex Richardson 
55331914882SAlex Richardson #define float_f float
55431914882SAlex Richardson #define double_f double
55531914882SAlex Richardson #define copysign_f copysignf
55631914882SAlex Richardson #define nextafter_f nextafterf
55731914882SAlex Richardson #define fabs_f fabsf
55831914882SAlex Richardson #define asuint_f asuint
55931914882SAlex Richardson #define asfloat_f asfloat
56031914882SAlex Richardson #define scalbn_f scalbnf
56131914882SAlex Richardson #define lscalbn_f scalbn
56231914882SAlex Richardson #define halfinf_f 0x1p127f
56331914882SAlex Richardson #define min_normal_f 0x1p-126f
56431914882SAlex Richardson 
56531914882SAlex Richardson #define float_d double
56631914882SAlex Richardson #define double_d long double
56731914882SAlex Richardson #define copysign_d copysign
56831914882SAlex Richardson #define nextafter_d nextafter
56931914882SAlex Richardson #define fabs_d fabs
57031914882SAlex Richardson #define asuint_d asuint64
57131914882SAlex Richardson #define asfloat_d asdouble
57231914882SAlex Richardson #define scalbn_d scalbn
57331914882SAlex Richardson #define lscalbn_d scalbnl
57431914882SAlex Richardson #define halfinf_d 0x1p1023
57531914882SAlex Richardson #define min_normal_d 0x1p-1022
57631914882SAlex Richardson 
57731914882SAlex Richardson #define NEW_RT
57831914882SAlex Richardson #define RT(x) x##_f
57931914882SAlex Richardson #define T(x) x##_f1
58031914882SAlex Richardson #include "ulp.h"
58131914882SAlex Richardson #undef T
58231914882SAlex Richardson #define T(x) x##_f2
58331914882SAlex Richardson #include "ulp.h"
58431914882SAlex Richardson #undef T
58531914882SAlex Richardson #undef RT
58631914882SAlex Richardson 
58731914882SAlex Richardson #define NEW_RT
58831914882SAlex Richardson #define RT(x) x##_d
58931914882SAlex Richardson #define T(x) x##_d1
59031914882SAlex Richardson #include "ulp.h"
59131914882SAlex Richardson #undef T
59231914882SAlex Richardson #define T(x) x##_d2
59331914882SAlex Richardson #include "ulp.h"
59431914882SAlex Richardson #undef T
59531914882SAlex Richardson #undef RT
59631914882SAlex Richardson 
59731914882SAlex Richardson static void
59831914882SAlex Richardson usage (void)
59931914882SAlex Richardson {
6005a02ffc3SAndrew Turner   puts ("./ulp [-q] [-m] [-f] [-r {n|u|d|z}] [-l soft-ulplimit] [-e ulplimit] func "
60131914882SAlex Richardson 	"lo [hi [x lo2 hi2] [count]]");
60231914882SAlex Richardson   puts ("Compares func against a higher precision implementation in [lo; hi].");
60331914882SAlex Richardson   puts ("-q: quiet.");
60431914882SAlex Richardson   puts ("-m: use mpfr even if faster method is available.");
6055a02ffc3SAndrew Turner   puts ("-f: disable fenv exceptions testing.");
6065a02ffc3SAndrew Turner #ifdef ___vpcs
607072a4ba8SAndrew Turner   puts ("-c: neutral 'control value' to test behaviour when one lane can affect another. \n"
608072a4ba8SAndrew Turner 	"    This should be different from tested input in other lanes, and non-special \n"
609072a4ba8SAndrew Turner 	"    (i.e. should not trigger fenv exceptions). Default is 1.");
610072a4ba8SAndrew Turner #endif
611*f3087befSAndrew Turner #if WANT_SVE_TESTS
612*f3087befSAndrew Turner   puts ("-p: integer input for controlling predicate passed to SVE function. "
613*f3087befSAndrew Turner 	"If bit N is set, lane N is activated (bits past the vector length "
614*f3087befSAndrew Turner 	"are ignored). Default is UINT64_MAX (ptrue).");
615*f3087befSAndrew Turner #endif
6165a02ffc3SAndrew Turner   puts ("-z: ignore sign of 0.");
61731914882SAlex Richardson   puts ("Supported func:");
61831914882SAlex Richardson   for (const struct fun *f = fun; f->name; f++)
61931914882SAlex Richardson     printf ("\t%s\n", f->name);
62031914882SAlex Richardson   exit (1);
62131914882SAlex Richardson }
62231914882SAlex Richardson 
62331914882SAlex Richardson static int
62431914882SAlex Richardson cmp (const struct fun *f, struct gen *gen, const struct conf *conf)
62531914882SAlex Richardson {
62631914882SAlex Richardson   int r = 1;
62731914882SAlex Richardson   if (f->arity == 1 && f->singleprec)
62831914882SAlex Richardson     r = cmp_f1 (f, gen, conf);
62931914882SAlex Richardson   else if (f->arity == 2 && f->singleprec)
63031914882SAlex Richardson     r = cmp_f2 (f, gen, conf);
63131914882SAlex Richardson   else if (f->arity == 1 && !f->singleprec)
63231914882SAlex Richardson     r = cmp_d1 (f, gen, conf);
63331914882SAlex Richardson   else if (f->arity == 2 && !f->singleprec)
63431914882SAlex Richardson     r = cmp_d2 (f, gen, conf);
63531914882SAlex Richardson   else
63631914882SAlex Richardson     usage ();
63731914882SAlex Richardson   return r;
63831914882SAlex Richardson }
63931914882SAlex Richardson 
64031914882SAlex Richardson static uint64_t
64131914882SAlex Richardson getnum (const char *s, int singleprec)
64231914882SAlex Richardson {
64331914882SAlex Richardson   //	int i;
64431914882SAlex Richardson   uint64_t sign = 0;
64531914882SAlex Richardson   //	char buf[12];
64631914882SAlex Richardson 
64731914882SAlex Richardson   if (s[0] == '+')
64831914882SAlex Richardson     s++;
64931914882SAlex Richardson   else if (s[0] == '-')
65031914882SAlex Richardson     {
65131914882SAlex Richardson       sign = singleprec ? 1ULL << 31 : 1ULL << 63;
65231914882SAlex Richardson       s++;
65331914882SAlex Richardson     }
654*f3087befSAndrew Turner 
655*f3087befSAndrew Turner   /* Sentinel value for failed parse.  */
656*f3087befSAndrew Turner   char *should_not_be_s = NULL;
657*f3087befSAndrew Turner 
65831914882SAlex Richardson   /* 0xXXXX is treated as bit representation, '-' flips the sign bit.  */
65931914882SAlex Richardson   if (s[0] == '0' && tolower (s[1]) == 'x' && strchr (s, 'p') == 0)
660*f3087befSAndrew Turner     {
661*f3087befSAndrew Turner       uint64_t out = sign ^ strtoull (s, &should_not_be_s, 0);
662*f3087befSAndrew Turner       if (should_not_be_s == s)
663*f3087befSAndrew Turner 	{
664*f3087befSAndrew Turner 	  printf ("ERROR: Could not parse '%s'\n", s);
665*f3087befSAndrew Turner 	  exit (1);
666*f3087befSAndrew Turner 	}
667*f3087befSAndrew Turner       return out;
668*f3087befSAndrew Turner     }
66931914882SAlex Richardson   //	/* SNaN, QNaN, NaN, Inf.  */
67031914882SAlex Richardson   //	for (i=0; s[i] && i < sizeof buf; i++)
67131914882SAlex Richardson   //		buf[i] = tolower(s[i]);
67231914882SAlex Richardson   //	buf[i] = 0;
67331914882SAlex Richardson   //	if (strcmp(buf, "snan") == 0)
67431914882SAlex Richardson   //		return sign | (singleprec ? 0x7fa00000 : 0x7ff4000000000000);
67531914882SAlex Richardson   //	if (strcmp(buf, "qnan") == 0 || strcmp(buf, "nan") == 0)
67631914882SAlex Richardson   //		return sign | (singleprec ? 0x7fc00000 : 0x7ff8000000000000);
67731914882SAlex Richardson   //	if (strcmp(buf, "inf") == 0 || strcmp(buf, "infinity") == 0)
67831914882SAlex Richardson   //		return sign | (singleprec ? 0x7f800000 : 0x7ff0000000000000);
67931914882SAlex Richardson   /* Otherwise assume it's a floating-point literal.  */
680*f3087befSAndrew Turner   uint64_t out = sign
681*f3087befSAndrew Turner 		 | (singleprec ? asuint (strtof (s, &should_not_be_s))
682*f3087befSAndrew Turner 			       : asuint64 (strtod (s, &should_not_be_s)));
683*f3087befSAndrew Turner   if (should_not_be_s == s)
684*f3087befSAndrew Turner     {
685*f3087befSAndrew Turner       printf ("ERROR: Could not parse '%s'\n", s);
686*f3087befSAndrew Turner       exit (1);
687*f3087befSAndrew Turner     }
688*f3087befSAndrew Turner 
689*f3087befSAndrew Turner   return out;
69031914882SAlex Richardson }
69131914882SAlex Richardson 
69231914882SAlex Richardson static void
69331914882SAlex Richardson parsegen (struct gen *g, int argc, char *argv[], const struct fun *f)
69431914882SAlex Richardson {
69531914882SAlex Richardson   int singleprec = f->singleprec;
69631914882SAlex Richardson   int arity = f->arity;
69731914882SAlex Richardson   uint64_t a, b, a2, b2, n;
69831914882SAlex Richardson   if (argc < 1)
69931914882SAlex Richardson     usage ();
70031914882SAlex Richardson   b = a = getnum (argv[0], singleprec);
70131914882SAlex Richardson   n = 0;
70231914882SAlex Richardson   if (argc > 1 && strcmp (argv[1], "x") == 0)
70331914882SAlex Richardson     {
70431914882SAlex Richardson       argc -= 2;
70531914882SAlex Richardson       argv += 2;
70631914882SAlex Richardson     }
70731914882SAlex Richardson   else if (argc > 1)
70831914882SAlex Richardson     {
70931914882SAlex Richardson       b = getnum (argv[1], singleprec);
71031914882SAlex Richardson       if (argc > 2 && strcmp (argv[2], "x") == 0)
71131914882SAlex Richardson 	{
71231914882SAlex Richardson 	  argc -= 3;
71331914882SAlex Richardson 	  argv += 3;
71431914882SAlex Richardson 	}
71531914882SAlex Richardson     }
71631914882SAlex Richardson   b2 = a2 = getnum (argv[0], singleprec);
71731914882SAlex Richardson   if (argc > 1)
71831914882SAlex Richardson     b2 = getnum (argv[1], singleprec);
71931914882SAlex Richardson   if (argc > 2)
72031914882SAlex Richardson     n = strtoull (argv[2], 0, 0);
72131914882SAlex Richardson   if (argc > 3)
72231914882SAlex Richardson     usage ();
72331914882SAlex Richardson   //printf("ab %lx %lx ab2 %lx %lx n %lu\n", a, b, a2, b2, n);
72431914882SAlex Richardson   if (arity == 1)
72531914882SAlex Richardson     {
72631914882SAlex Richardson       g->start = a;
72731914882SAlex Richardson       g->len = b - a;
72831914882SAlex Richardson       if (n - 1 > b - a)
72931914882SAlex Richardson 	n = b - a + 1;
73031914882SAlex Richardson       g->off = 0;
73131914882SAlex Richardson       g->step = n ? (g->len + 1) / n : 1;
73231914882SAlex Richardson       g->start2 = g->len2 = 0;
73331914882SAlex Richardson       g->cnt = n;
73431914882SAlex Richardson     }
73531914882SAlex Richardson   else if (arity == 2)
73631914882SAlex Richardson     {
73731914882SAlex Richardson       g->start = a;
73831914882SAlex Richardson       g->len = b - a;
73931914882SAlex Richardson       g->off = g->step = 0;
74031914882SAlex Richardson       g->start2 = a2;
74131914882SAlex Richardson       g->len2 = b2 - a2;
74231914882SAlex Richardson       g->cnt = n;
74331914882SAlex Richardson     }
74431914882SAlex Richardson   else
74531914882SAlex Richardson     usage ();
74631914882SAlex Richardson }
74731914882SAlex Richardson 
74831914882SAlex Richardson int
74931914882SAlex Richardson main (int argc, char *argv[])
75031914882SAlex Richardson {
75131914882SAlex Richardson   const struct fun *f;
75231914882SAlex Richardson   struct gen gen;
75331914882SAlex Richardson   struct conf conf;
75431914882SAlex Richardson   conf.rc = 'n';
75531914882SAlex Richardson   conf.quiet = 0;
75631914882SAlex Richardson   conf.mpfr = 0;
75731914882SAlex Richardson   conf.fenv = 1;
75831914882SAlex Richardson   conf.softlim = 0;
75931914882SAlex Richardson   conf.errlim = INFINITY;
7605a02ffc3SAndrew Turner   conf.ignore_zero_sign = 0;
761*f3087befSAndrew Turner #if WANT_SVE_TESTS
762*f3087befSAndrew Turner   uint64_t pg_int = UINT64_MAX;
763*f3087befSAndrew Turner #endif
76431914882SAlex Richardson   for (;;)
76531914882SAlex Richardson     {
76631914882SAlex Richardson       argc--;
76731914882SAlex Richardson       argv++;
76831914882SAlex Richardson       if (argc < 1)
76931914882SAlex Richardson 	usage ();
77031914882SAlex Richardson       if (argv[0][0] != '-')
77131914882SAlex Richardson 	break;
77231914882SAlex Richardson       switch (argv[0][1])
77331914882SAlex Richardson 	{
77431914882SAlex Richardson 	case 'e':
77531914882SAlex Richardson 	  argc--;
77631914882SAlex Richardson 	  argv++;
77731914882SAlex Richardson 	  if (argc < 1)
77831914882SAlex Richardson 	    usage ();
77931914882SAlex Richardson 	  conf.errlim = strtod (argv[0], 0);
78031914882SAlex Richardson 	  break;
78131914882SAlex Richardson 	case 'f':
78231914882SAlex Richardson 	  conf.fenv = 0;
78331914882SAlex Richardson 	  break;
78431914882SAlex Richardson 	case 'l':
78531914882SAlex Richardson 	  argc--;
78631914882SAlex Richardson 	  argv++;
78731914882SAlex Richardson 	  if (argc < 1)
78831914882SAlex Richardson 	    usage ();
78931914882SAlex Richardson 	  conf.softlim = strtod (argv[0], 0);
79031914882SAlex Richardson 	  break;
79131914882SAlex Richardson 	case 'm':
79231914882SAlex Richardson 	  conf.mpfr = 1;
79331914882SAlex Richardson 	  break;
79431914882SAlex Richardson 	case 'q':
79531914882SAlex Richardson 	  conf.quiet = 1;
79631914882SAlex Richardson 	  break;
79731914882SAlex Richardson 	case 'r':
79831914882SAlex Richardson 	  conf.rc = argv[0][2];
79931914882SAlex Richardson 	  if (!conf.rc)
80031914882SAlex Richardson 	    {
80131914882SAlex Richardson 	      argc--;
80231914882SAlex Richardson 	      argv++;
8035a02ffc3SAndrew Turner 	      if (argc < 1 || argv[0][1] != '\0')
80431914882SAlex Richardson 		usage ();
80531914882SAlex Richardson 	      conf.rc = argv[0][0];
80631914882SAlex Richardson 	    }
80731914882SAlex Richardson 	  break;
8085a02ffc3SAndrew Turner 	case 'z':
8095a02ffc3SAndrew Turner 	  conf.ignore_zero_sign = 1;
8105a02ffc3SAndrew Turner 	  break;
811*f3087befSAndrew Turner #if  __aarch64__ && __linux__
812072a4ba8SAndrew Turner 	case 'c':
813072a4ba8SAndrew Turner 	  argc--;
814072a4ba8SAndrew Turner 	  argv++;
815072a4ba8SAndrew Turner 	  fv[0] = strtof(argv[0], 0);
816072a4ba8SAndrew Turner 	  dv[0] = strtod(argv[0], 0);
817072a4ba8SAndrew Turner 	  break;
818072a4ba8SAndrew Turner #endif
819*f3087befSAndrew Turner #if WANT_SVE_TESTS
820*f3087befSAndrew Turner 	case 'p':
821*f3087befSAndrew Turner 	  argc--;
822*f3087befSAndrew Turner 	  argv++;
823*f3087befSAndrew Turner 	  pg_int = strtoull (argv[0], 0, 0);
824*f3087befSAndrew Turner 	  break;
825*f3087befSAndrew Turner #endif
82631914882SAlex Richardson 	default:
82731914882SAlex Richardson 	  usage ();
82831914882SAlex Richardson 	}
82931914882SAlex Richardson     }
83031914882SAlex Richardson   switch (conf.rc)
83131914882SAlex Richardson     {
83231914882SAlex Richardson     case 'n':
83331914882SAlex Richardson       conf.r = FE_TONEAREST;
83431914882SAlex Richardson       break;
83531914882SAlex Richardson     case 'u':
83631914882SAlex Richardson       conf.r = FE_UPWARD;
83731914882SAlex Richardson       break;
83831914882SAlex Richardson     case 'd':
83931914882SAlex Richardson       conf.r = FE_DOWNWARD;
84031914882SAlex Richardson       break;
84131914882SAlex Richardson     case 'z':
84231914882SAlex Richardson       conf.r = FE_TOWARDZERO;
84331914882SAlex Richardson       break;
84431914882SAlex Richardson     default:
84531914882SAlex Richardson       usage ();
84631914882SAlex Richardson     }
84731914882SAlex Richardson   for (f = fun; f->name; f++)
84831914882SAlex Richardson     if (strcmp (argv[0], f->name) == 0)
84931914882SAlex Richardson       break;
85031914882SAlex Richardson   if (!f->name)
8515a02ffc3SAndrew Turner     {
8525a02ffc3SAndrew Turner #ifndef __vpcs
8535a02ffc3SAndrew Turner       /* Ignore vector math functions if vector math is not supported.  */
8545a02ffc3SAndrew Turner       if (strncmp (argv[0], "_ZGVnN", 6) == 0)
8555a02ffc3SAndrew Turner 	exit (0);
8565a02ffc3SAndrew Turner #endif
857*f3087befSAndrew Turner #if !WANT_SVE_TESTS
8585a02ffc3SAndrew Turner       if (strncmp (argv[0], "_ZGVsMxv", 8) == 0)
8595a02ffc3SAndrew Turner 	exit (0);
8605a02ffc3SAndrew Turner #endif
8615a02ffc3SAndrew Turner       printf ("math function %s not supported\n", argv[0]);
8625a02ffc3SAndrew Turner       exit (1);
8635a02ffc3SAndrew Turner     }
86431914882SAlex Richardson   if (!f->singleprec && LDBL_MANT_DIG == DBL_MANT_DIG)
86531914882SAlex Richardson     conf.mpfr = 1; /* Use mpfr if long double has no extra precision.  */
86631914882SAlex Richardson   if (!USE_MPFR && conf.mpfr)
86731914882SAlex Richardson     {
86831914882SAlex Richardson       puts ("mpfr is not available.");
86931914882SAlex Richardson       return 0;
87031914882SAlex Richardson     }
87131914882SAlex Richardson   argc--;
87231914882SAlex Richardson   argv++;
87331914882SAlex Richardson   parsegen (&gen, argc, argv, f);
87431914882SAlex Richardson   conf.n = gen.cnt;
875*f3087befSAndrew Turner #if WANT_SVE_TESTS
876*f3087befSAndrew Turner   svbool_t pg = parse_pg (pg_int, f->singleprec);
877*f3087befSAndrew Turner   conf.pg = &pg;
878*f3087befSAndrew Turner #endif
87931914882SAlex Richardson   return cmp (f, &gen, &conf);
88031914882SAlex Richardson }
881*f3087befSAndrew Turner 
882*f3087befSAndrew Turner #if __aarch64__ && __linux__ && WANT_SVE_TESTS && defined(__clang__)
883*f3087befSAndrew Turner #  pragma clang attribute pop
884*f3087befSAndrew Turner #endif
885