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