1*0928368fSKristof Beyls /*
2*0928368fSKristof Beyls * mathtest.c - test rig for mathlib
3*0928368fSKristof Beyls *
4*0928368fSKristof Beyls * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*0928368fSKristof Beyls * See https://llvm.org/LICENSE.txt for license information.
6*0928368fSKristof Beyls * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*0928368fSKristof Beyls */
8*0928368fSKristof Beyls
9*0928368fSKristof Beyls #include <assert.h>
10*0928368fSKristof Beyls #include <stdio.h>
11*0928368fSKristof Beyls #include <stdlib.h>
12*0928368fSKristof Beyls #include <string.h>
13*0928368fSKristof Beyls #include <setjmp.h>
14*0928368fSKristof Beyls #include <ctype.h>
15*0928368fSKristof Beyls #include <math.h>
16*0928368fSKristof Beyls #include <errno.h>
17*0928368fSKristof Beyls #include <limits.h>
18*0928368fSKristof Beyls #include <fenv.h>
19*0928368fSKristof Beyls #include "mathlib.h"
20*0928368fSKristof Beyls
21*0928368fSKristof Beyls #ifndef math_errhandling
22*0928368fSKristof Beyls # define math_errhandling 0
23*0928368fSKristof Beyls #endif
24*0928368fSKristof Beyls
25*0928368fSKristof Beyls #ifdef __cplusplus
26*0928368fSKristof Beyls #define EXTERN_C extern "C"
27*0928368fSKristof Beyls #else
28*0928368fSKristof Beyls #define EXTERN_C extern
29*0928368fSKristof Beyls #endif
30*0928368fSKristof Beyls
31*0928368fSKristof Beyls #ifndef TRUE
32*0928368fSKristof Beyls #define TRUE 1
33*0928368fSKristof Beyls #endif
34*0928368fSKristof Beyls #ifndef FALSE
35*0928368fSKristof Beyls #define FALSE 0
36*0928368fSKristof Beyls #endif
37*0928368fSKristof Beyls
38*0928368fSKristof Beyls #ifdef IMPORT_SYMBOL
39*0928368fSKristof Beyls #define STR2(x) #x
40*0928368fSKristof Beyls #define STR(x) STR2(x)
41*0928368fSKristof Beyls _Pragma(STR(import IMPORT_SYMBOL))
42*0928368fSKristof Beyls #endif
43*0928368fSKristof Beyls
44*0928368fSKristof Beyls int dmsd, dlsd;
45*0928368fSKristof Beyls int quiet = 0;
46*0928368fSKristof Beyls int doround = 0;
47*0928368fSKristof Beyls unsigned statusmask = FE_ALL_EXCEPT;
48*0928368fSKristof Beyls
49*0928368fSKristof Beyls #define EXTRABITS (12)
50*0928368fSKristof Beyls #define ULPUNIT (1<<EXTRABITS)
51*0928368fSKristof Beyls
52*0928368fSKristof Beyls typedef int (*test) (void);
53*0928368fSKristof Beyls
54*0928368fSKristof Beyls /*
55*0928368fSKristof Beyls struct to hold info about a function (which could actually be a macro)
56*0928368fSKristof Beyls */
57*0928368fSKristof Beyls typedef struct {
58*0928368fSKristof Beyls enum {
59*0928368fSKristof Beyls t_func, t_macro
60*0928368fSKristof Beyls } type;
61*0928368fSKristof Beyls enum {
62*0928368fSKristof Beyls at_d, at_s, /* double or single precision float */
63*0928368fSKristof Beyls at_d2, at_s2, /* same, but taking two args */
64*0928368fSKristof Beyls at_di, at_si, /* double/single and an int */
65*0928368fSKristof Beyls at_dip, at_sip, /* double/single and an int ptr */
66*0928368fSKristof Beyls at_ddp, at_ssp, /* d/s and a d/s ptr */
67*0928368fSKristof Beyls at_dc, at_sc, /* double or single precision complex */
68*0928368fSKristof Beyls at_dc2, at_sc2 /* same, but taking two args */
69*0928368fSKristof Beyls } argtype;
70*0928368fSKristof Beyls enum {
71*0928368fSKristof Beyls rt_d, rt_s, rt_i, /* double, single, int */
72*0928368fSKristof Beyls rt_dc, rt_sc, /* double, single precision complex */
73*0928368fSKristof Beyls rt_d2, rt_s2 /* also use res2 */
74*0928368fSKristof Beyls } rettype;
75*0928368fSKristof Beyls union {
76*0928368fSKristof Beyls void* ptr;
77*0928368fSKristof Beyls double (*d_d_ptr)(double);
78*0928368fSKristof Beyls float (*s_s_ptr)(float);
79*0928368fSKristof Beyls int (*d_i_ptr)(double);
80*0928368fSKristof Beyls int (*s_i_ptr)(float);
81*0928368fSKristof Beyls double (*d2_d_ptr)(double, double);
82*0928368fSKristof Beyls float (*s2_s_ptr)(float, float);
83*0928368fSKristof Beyls double (*di_d_ptr)(double,int);
84*0928368fSKristof Beyls float (*si_s_ptr)(float,int);
85*0928368fSKristof Beyls double (*dip_d_ptr)(double,int*);
86*0928368fSKristof Beyls float (*sip_s_ptr)(float,int*);
87*0928368fSKristof Beyls double (*ddp_d_ptr)(double,double*);
88*0928368fSKristof Beyls float (*ssp_s_ptr)(float,float*);
89*0928368fSKristof Beyls } func;
90*0928368fSKristof Beyls enum {
91*0928368fSKristof Beyls m_none,
92*0928368fSKristof Beyls m_isfinite, m_isfinitef,
93*0928368fSKristof Beyls m_isgreater, m_isgreaterequal,
94*0928368fSKristof Beyls m_isgreaterequalf, m_isgreaterf,
95*0928368fSKristof Beyls m_isinf, m_isinff,
96*0928368fSKristof Beyls m_isless, m_islessequal,
97*0928368fSKristof Beyls m_islessequalf, m_islessf,
98*0928368fSKristof Beyls m_islessgreater, m_islessgreaterf,
99*0928368fSKristof Beyls m_isnan, m_isnanf,
100*0928368fSKristof Beyls m_isnormal, m_isnormalf,
101*0928368fSKristof Beyls m_isunordered, m_isunorderedf,
102*0928368fSKristof Beyls m_fpclassify, m_fpclassifyf,
103*0928368fSKristof Beyls m_signbit, m_signbitf,
104*0928368fSKristof Beyls /* not actually a macro, but makes things easier */
105*0928368fSKristof Beyls m_rred, m_rredf,
106*0928368fSKristof Beyls m_cadd, m_csub, m_cmul, m_cdiv,
107*0928368fSKristof Beyls m_caddf, m_csubf, m_cmulf, m_cdivf
108*0928368fSKristof Beyls } macro_name; /* only used if a macro/something that can't be done using func */
109*0928368fSKristof Beyls long long tolerance;
110*0928368fSKristof Beyls const char* name;
111*0928368fSKristof Beyls } test_func;
112*0928368fSKristof Beyls
113*0928368fSKristof Beyls /* used in qsort */
compare_tfuncs(const void * a,const void * b)114*0928368fSKristof Beyls int compare_tfuncs(const void* a, const void* b) {
115*0928368fSKristof Beyls return strcmp(((test_func*)a)->name, ((test_func*)b)->name);
116*0928368fSKristof Beyls }
117*0928368fSKristof Beyls
is_double_argtype(int argtype)118*0928368fSKristof Beyls int is_double_argtype(int argtype) {
119*0928368fSKristof Beyls switch(argtype) {
120*0928368fSKristof Beyls case at_d:
121*0928368fSKristof Beyls case at_d2:
122*0928368fSKristof Beyls case at_dc:
123*0928368fSKristof Beyls case at_dc2:
124*0928368fSKristof Beyls return 1;
125*0928368fSKristof Beyls default:
126*0928368fSKristof Beyls return 0;
127*0928368fSKristof Beyls }
128*0928368fSKristof Beyls }
129*0928368fSKristof Beyls
is_single_argtype(int argtype)130*0928368fSKristof Beyls int is_single_argtype(int argtype) {
131*0928368fSKristof Beyls switch(argtype) {
132*0928368fSKristof Beyls case at_s:
133*0928368fSKristof Beyls case at_s2:
134*0928368fSKristof Beyls case at_sc:
135*0928368fSKristof Beyls case at_sc2:
136*0928368fSKristof Beyls return 1;
137*0928368fSKristof Beyls default:
138*0928368fSKristof Beyls return 0;
139*0928368fSKristof Beyls }
140*0928368fSKristof Beyls }
141*0928368fSKristof Beyls
is_double_rettype(int rettype)142*0928368fSKristof Beyls int is_double_rettype(int rettype) {
143*0928368fSKristof Beyls switch(rettype) {
144*0928368fSKristof Beyls case rt_d:
145*0928368fSKristof Beyls case rt_dc:
146*0928368fSKristof Beyls case rt_d2:
147*0928368fSKristof Beyls return 1;
148*0928368fSKristof Beyls default:
149*0928368fSKristof Beyls return 0;
150*0928368fSKristof Beyls }
151*0928368fSKristof Beyls }
152*0928368fSKristof Beyls
is_single_rettype(int rettype)153*0928368fSKristof Beyls int is_single_rettype(int rettype) {
154*0928368fSKristof Beyls switch(rettype) {
155*0928368fSKristof Beyls case rt_s:
156*0928368fSKristof Beyls case rt_sc:
157*0928368fSKristof Beyls case rt_s2:
158*0928368fSKristof Beyls return 1;
159*0928368fSKristof Beyls default:
160*0928368fSKristof Beyls return 0;
161*0928368fSKristof Beyls }
162*0928368fSKristof Beyls }
163*0928368fSKristof Beyls
is_complex_argtype(int argtype)164*0928368fSKristof Beyls int is_complex_argtype(int argtype) {
165*0928368fSKristof Beyls switch(argtype) {
166*0928368fSKristof Beyls case at_dc:
167*0928368fSKristof Beyls case at_sc:
168*0928368fSKristof Beyls case at_dc2:
169*0928368fSKristof Beyls case at_sc2:
170*0928368fSKristof Beyls return 1;
171*0928368fSKristof Beyls default:
172*0928368fSKristof Beyls return 0;
173*0928368fSKristof Beyls }
174*0928368fSKristof Beyls }
175*0928368fSKristof Beyls
is_complex_rettype(int rettype)176*0928368fSKristof Beyls int is_complex_rettype(int rettype) {
177*0928368fSKristof Beyls switch(rettype) {
178*0928368fSKristof Beyls case rt_dc:
179*0928368fSKristof Beyls case rt_sc:
180*0928368fSKristof Beyls return 1;
181*0928368fSKristof Beyls default:
182*0928368fSKristof Beyls return 0;
183*0928368fSKristof Beyls }
184*0928368fSKristof Beyls }
185*0928368fSKristof Beyls
186*0928368fSKristof Beyls /*
187*0928368fSKristof Beyls * Special-case flags indicating that some functions' error
188*0928368fSKristof Beyls * tolerance handling is more complicated than a fixed relative
189*0928368fSKristof Beyls * error bound.
190*0928368fSKristof Beyls */
191*0928368fSKristof Beyls #define ABSLOWERBOUND 0x4000000000000000LL
192*0928368fSKristof Beyls #define PLUSMINUSPIO2 0x1000000000000000LL
193*0928368fSKristof Beyls
194*0928368fSKristof Beyls #define ARM_PREFIX(x) x
195*0928368fSKristof Beyls
196*0928368fSKristof Beyls #define TFUNC(arg,ret,name,tolerance) { t_func, arg, ret, (void*)&name, m_none, tolerance, #name }
197*0928368fSKristof Beyls #define TFUNCARM(arg,ret,name,tolerance) { t_func, arg, ret, (void*)& ARM_PREFIX(name), m_none, tolerance, #name }
198*0928368fSKristof Beyls #define MFUNC(arg,ret,name,tolerance) { t_macro, arg, ret, NULL, m_##name, tolerance, #name }
199*0928368fSKristof Beyls
200*0928368fSKristof Beyls /* sincosf wrappers for easier testing. */
sincosf_sinf(float x)201*0928368fSKristof Beyls static float sincosf_sinf(float x) { float s,c; sincosf(x, &s, &c); return s; }
sincosf_cosf(float x)202*0928368fSKristof Beyls static float sincosf_cosf(float x) { float s,c; sincosf(x, &s, &c); return c; }
203*0928368fSKristof Beyls
204*0928368fSKristof Beyls test_func tfuncs[] = {
205*0928368fSKristof Beyls /* trigonometric */
206*0928368fSKristof Beyls TFUNC(at_d,rt_d, acos, 4*ULPUNIT),
207*0928368fSKristof Beyls TFUNC(at_d,rt_d, asin, 4*ULPUNIT),
208*0928368fSKristof Beyls TFUNC(at_d,rt_d, atan, 4*ULPUNIT),
209*0928368fSKristof Beyls TFUNC(at_d2,rt_d, atan2, 4*ULPUNIT),
210*0928368fSKristof Beyls
211*0928368fSKristof Beyls TFUNC(at_d,rt_d, tan, 2*ULPUNIT),
212*0928368fSKristof Beyls TFUNC(at_d,rt_d, sin, 2*ULPUNIT),
213*0928368fSKristof Beyls TFUNC(at_d,rt_d, cos, 2*ULPUNIT),
214*0928368fSKristof Beyls
215*0928368fSKristof Beyls TFUNC(at_s,rt_s, acosf, 4*ULPUNIT),
216*0928368fSKristof Beyls TFUNC(at_s,rt_s, asinf, 4*ULPUNIT),
217*0928368fSKristof Beyls TFUNC(at_s,rt_s, atanf, 4*ULPUNIT),
218*0928368fSKristof Beyls TFUNC(at_s2,rt_s, atan2f, 4*ULPUNIT),
219*0928368fSKristof Beyls TFUNCARM(at_s,rt_s, tanf, 4*ULPUNIT),
220*0928368fSKristof Beyls TFUNCARM(at_s,rt_s, sinf, 3*ULPUNIT/4),
221*0928368fSKristof Beyls TFUNCARM(at_s,rt_s, cosf, 3*ULPUNIT/4),
222*0928368fSKristof Beyls TFUNCARM(at_s,rt_s, sincosf_sinf, 3*ULPUNIT/4),
223*0928368fSKristof Beyls TFUNCARM(at_s,rt_s, sincosf_cosf, 3*ULPUNIT/4),
224*0928368fSKristof Beyls
225*0928368fSKristof Beyls /* hyperbolic */
226*0928368fSKristof Beyls TFUNC(at_d, rt_d, atanh, 4*ULPUNIT),
227*0928368fSKristof Beyls TFUNC(at_d, rt_d, asinh, 4*ULPUNIT),
228*0928368fSKristof Beyls TFUNC(at_d, rt_d, acosh, 4*ULPUNIT),
229*0928368fSKristof Beyls TFUNC(at_d,rt_d, tanh, 4*ULPUNIT),
230*0928368fSKristof Beyls TFUNC(at_d,rt_d, sinh, 4*ULPUNIT),
231*0928368fSKristof Beyls TFUNC(at_d,rt_d, cosh, 4*ULPUNIT),
232*0928368fSKristof Beyls
233*0928368fSKristof Beyls TFUNC(at_s, rt_s, atanhf, 4*ULPUNIT),
234*0928368fSKristof Beyls TFUNC(at_s, rt_s, asinhf, 4*ULPUNIT),
235*0928368fSKristof Beyls TFUNC(at_s, rt_s, acoshf, 4*ULPUNIT),
236*0928368fSKristof Beyls TFUNC(at_s,rt_s, tanhf, 4*ULPUNIT),
237*0928368fSKristof Beyls TFUNC(at_s,rt_s, sinhf, 4*ULPUNIT),
238*0928368fSKristof Beyls TFUNC(at_s,rt_s, coshf, 4*ULPUNIT),
239*0928368fSKristof Beyls
240*0928368fSKristof Beyls /* exponential and logarithmic */
241*0928368fSKristof Beyls TFUNC(at_d,rt_d, log, 3*ULPUNIT/4),
242*0928368fSKristof Beyls TFUNC(at_d,rt_d, log10, 3*ULPUNIT),
243*0928368fSKristof Beyls TFUNC(at_d,rt_d, log2, 3*ULPUNIT/4),
244*0928368fSKristof Beyls TFUNC(at_d,rt_d, log1p, 2*ULPUNIT),
245*0928368fSKristof Beyls TFUNC(at_d,rt_d, exp, 3*ULPUNIT/4),
246*0928368fSKristof Beyls TFUNC(at_d,rt_d, exp2, 3*ULPUNIT/4),
247*0928368fSKristof Beyls TFUNC(at_d,rt_d, expm1, ULPUNIT),
248*0928368fSKristof Beyls TFUNCARM(at_s,rt_s, logf, ULPUNIT),
249*0928368fSKristof Beyls TFUNC(at_s,rt_s, log10f, 3*ULPUNIT),
250*0928368fSKristof Beyls TFUNCARM(at_s,rt_s, log2f, ULPUNIT),
251*0928368fSKristof Beyls TFUNC(at_s,rt_s, log1pf, 2*ULPUNIT),
252*0928368fSKristof Beyls TFUNCARM(at_s,rt_s, expf, 3*ULPUNIT/4),
253*0928368fSKristof Beyls TFUNCARM(at_s,rt_s, exp2f, 3*ULPUNIT/4),
254*0928368fSKristof Beyls TFUNC(at_s,rt_s, expm1f, ULPUNIT),
255*0928368fSKristof Beyls
256*0928368fSKristof Beyls /* power */
257*0928368fSKristof Beyls TFUNC(at_d2,rt_d, pow, 3*ULPUNIT/4),
258*0928368fSKristof Beyls TFUNC(at_d,rt_d, sqrt, ULPUNIT/2),
259*0928368fSKristof Beyls TFUNC(at_d,rt_d, cbrt, 2*ULPUNIT),
260*0928368fSKristof Beyls TFUNC(at_d2, rt_d, hypot, 4*ULPUNIT),
261*0928368fSKristof Beyls
262*0928368fSKristof Beyls TFUNCARM(at_s2,rt_s, powf, ULPUNIT),
263*0928368fSKristof Beyls TFUNC(at_s,rt_s, sqrtf, ULPUNIT/2),
264*0928368fSKristof Beyls TFUNC(at_s,rt_s, cbrtf, 2*ULPUNIT),
265*0928368fSKristof Beyls TFUNC(at_s2, rt_s, hypotf, 4*ULPUNIT),
266*0928368fSKristof Beyls
267*0928368fSKristof Beyls /* error function */
268*0928368fSKristof Beyls TFUNC(at_d,rt_d, erf, 16*ULPUNIT),
269*0928368fSKristof Beyls TFUNC(at_s,rt_s, erff, 16*ULPUNIT),
270*0928368fSKristof Beyls TFUNC(at_d,rt_d, erfc, 16*ULPUNIT),
271*0928368fSKristof Beyls TFUNC(at_s,rt_s, erfcf, 16*ULPUNIT),
272*0928368fSKristof Beyls
273*0928368fSKristof Beyls /* gamma functions */
274*0928368fSKristof Beyls TFUNC(at_d,rt_d, tgamma, 16*ULPUNIT),
275*0928368fSKristof Beyls TFUNC(at_s,rt_s, tgammaf, 16*ULPUNIT),
276*0928368fSKristof Beyls TFUNC(at_d,rt_d, lgamma, 16*ULPUNIT | ABSLOWERBOUND),
277*0928368fSKristof Beyls TFUNC(at_s,rt_s, lgammaf, 16*ULPUNIT | ABSLOWERBOUND),
278*0928368fSKristof Beyls
279*0928368fSKristof Beyls TFUNC(at_d,rt_d, ceil, 0),
280*0928368fSKristof Beyls TFUNC(at_s,rt_s, ceilf, 0),
281*0928368fSKristof Beyls TFUNC(at_d2,rt_d, copysign, 0),
282*0928368fSKristof Beyls TFUNC(at_s2,rt_s, copysignf, 0),
283*0928368fSKristof Beyls TFUNC(at_d,rt_d, floor, 0),
284*0928368fSKristof Beyls TFUNC(at_s,rt_s, floorf, 0),
285*0928368fSKristof Beyls TFUNC(at_d2,rt_d, fmax, 0),
286*0928368fSKristof Beyls TFUNC(at_s2,rt_s, fmaxf, 0),
287*0928368fSKristof Beyls TFUNC(at_d2,rt_d, fmin, 0),
288*0928368fSKristof Beyls TFUNC(at_s2,rt_s, fminf, 0),
289*0928368fSKristof Beyls TFUNC(at_d2,rt_d, fmod, 0),
290*0928368fSKristof Beyls TFUNC(at_s2,rt_s, fmodf, 0),
291*0928368fSKristof Beyls MFUNC(at_d, rt_i, fpclassify, 0),
292*0928368fSKristof Beyls MFUNC(at_s, rt_i, fpclassifyf, 0),
293*0928368fSKristof Beyls TFUNC(at_dip,rt_d, frexp, 0),
294*0928368fSKristof Beyls TFUNC(at_sip,rt_s, frexpf, 0),
295*0928368fSKristof Beyls MFUNC(at_d, rt_i, isfinite, 0),
296*0928368fSKristof Beyls MFUNC(at_s, rt_i, isfinitef, 0),
297*0928368fSKristof Beyls MFUNC(at_d, rt_i, isgreater, 0),
298*0928368fSKristof Beyls MFUNC(at_d, rt_i, isgreaterequal, 0),
299*0928368fSKristof Beyls MFUNC(at_s, rt_i, isgreaterequalf, 0),
300*0928368fSKristof Beyls MFUNC(at_s, rt_i, isgreaterf, 0),
301*0928368fSKristof Beyls MFUNC(at_d, rt_i, isinf, 0),
302*0928368fSKristof Beyls MFUNC(at_s, rt_i, isinff, 0),
303*0928368fSKristof Beyls MFUNC(at_d, rt_i, isless, 0),
304*0928368fSKristof Beyls MFUNC(at_d, rt_i, islessequal, 0),
305*0928368fSKristof Beyls MFUNC(at_s, rt_i, islessequalf, 0),
306*0928368fSKristof Beyls MFUNC(at_s, rt_i, islessf, 0),
307*0928368fSKristof Beyls MFUNC(at_d, rt_i, islessgreater, 0),
308*0928368fSKristof Beyls MFUNC(at_s, rt_i, islessgreaterf, 0),
309*0928368fSKristof Beyls MFUNC(at_d, rt_i, isnan, 0),
310*0928368fSKristof Beyls MFUNC(at_s, rt_i, isnanf, 0),
311*0928368fSKristof Beyls MFUNC(at_d, rt_i, isnormal, 0),
312*0928368fSKristof Beyls MFUNC(at_s, rt_i, isnormalf, 0),
313*0928368fSKristof Beyls MFUNC(at_d, rt_i, isunordered, 0),
314*0928368fSKristof Beyls MFUNC(at_s, rt_i, isunorderedf, 0),
315*0928368fSKristof Beyls TFUNC(at_di,rt_d, ldexp, 0),
316*0928368fSKristof Beyls TFUNC(at_si,rt_s, ldexpf, 0),
317*0928368fSKristof Beyls TFUNC(at_ddp,rt_d2, modf, 0),
318*0928368fSKristof Beyls TFUNC(at_ssp,rt_s2, modff, 0),
319*0928368fSKristof Beyls #ifndef BIGRANGERED
320*0928368fSKristof Beyls MFUNC(at_d, rt_d, rred, 2*ULPUNIT),
321*0928368fSKristof Beyls #else
322*0928368fSKristof Beyls MFUNC(at_d, rt_d, m_rred, ULPUNIT),
323*0928368fSKristof Beyls #endif
324*0928368fSKristof Beyls MFUNC(at_d, rt_i, signbit, 0),
325*0928368fSKristof Beyls MFUNC(at_s, rt_i, signbitf, 0),
326*0928368fSKristof Beyls };
327*0928368fSKristof Beyls
328*0928368fSKristof Beyls /*
329*0928368fSKristof Beyls * keywords are: func size op1 op2 result res2 errno op1r op1i op2r op2i resultr resulti
330*0928368fSKristof Beyls * also we ignore: wrongresult wrongres2 wrongerrno
331*0928368fSKristof Beyls * op1 equivalent to op1r, same with op2 and result
332*0928368fSKristof Beyls */
333*0928368fSKristof Beyls
334*0928368fSKristof Beyls typedef struct {
335*0928368fSKristof Beyls test_func *func;
336*0928368fSKristof Beyls unsigned op1r[2]; /* real part, also used for non-complex numbers */
337*0928368fSKristof Beyls unsigned op1i[2]; /* imaginary part */
338*0928368fSKristof Beyls unsigned op2r[2];
339*0928368fSKristof Beyls unsigned op2i[2];
340*0928368fSKristof Beyls unsigned resultr[3];
341*0928368fSKristof Beyls unsigned resulti[3];
342*0928368fSKristof Beyls enum {
343*0928368fSKristof Beyls rc_none, rc_zero, rc_infinity, rc_nan, rc_finite
344*0928368fSKristof Beyls } resultc; /* special complex results, rc_none means use resultr and resulti as normal */
345*0928368fSKristof Beyls unsigned res2[2];
346*0928368fSKristof Beyls unsigned status; /* IEEE status return, if any */
347*0928368fSKristof Beyls unsigned maybestatus; /* for optional status, or allowance for spurious */
348*0928368fSKristof Beyls int nresult; /* number of result words */
349*0928368fSKristof Beyls int in_err, in_err_limit;
350*0928368fSKristof Beyls int err;
351*0928368fSKristof Beyls int maybeerr;
352*0928368fSKristof Beyls int valid;
353*0928368fSKristof Beyls int comment;
354*0928368fSKristof Beyls int random;
355*0928368fSKristof Beyls } testdetail;
356*0928368fSKristof Beyls
357*0928368fSKristof Beyls enum { /* keywords */
358*0928368fSKristof Beyls k_errno, k_errno_in, k_error, k_func, k_maybeerror, k_maybestatus, k_op1, k_op1i, k_op1r, k_op2, k_op2i, k_op2r,
359*0928368fSKristof Beyls k_random, k_res2, k_result, k_resultc, k_resulti, k_resultr, k_status,
360*0928368fSKristof Beyls k_wrongres2, k_wrongresult, k_wrongstatus, k_wrongerrno
361*0928368fSKristof Beyls };
362*0928368fSKristof Beyls char *keywords[] = {
363*0928368fSKristof Beyls "errno", "errno_in", "error", "func", "maybeerror", "maybestatus", "op1", "op1i", "op1r", "op2", "op2i", "op2r",
364*0928368fSKristof Beyls "random", "res2", "result", "resultc", "resulti", "resultr", "status",
365*0928368fSKristof Beyls "wrongres2", "wrongresult", "wrongstatus", "wrongerrno"
366*0928368fSKristof Beyls };
367*0928368fSKristof Beyls
368*0928368fSKristof Beyls enum {
369*0928368fSKristof Beyls e_0, e_EDOM, e_ERANGE,
370*0928368fSKristof Beyls
371*0928368fSKristof Beyls /*
372*0928368fSKristof Beyls * This enum makes sure that we have the right number of errnos in the
373*0928368fSKristof Beyls * errno[] array
374*0928368fSKristof Beyls */
375*0928368fSKristof Beyls e_number_of_errnos
376*0928368fSKristof Beyls };
377*0928368fSKristof Beyls char *errnos[] = {
378*0928368fSKristof Beyls "0", "EDOM", "ERANGE"
379*0928368fSKristof Beyls };
380*0928368fSKristof Beyls
381*0928368fSKristof Beyls enum {
382*0928368fSKristof Beyls e_none, e_divbyzero, e_domain, e_overflow, e_underflow
383*0928368fSKristof Beyls };
384*0928368fSKristof Beyls char *errors[] = {
385*0928368fSKristof Beyls "0", "divbyzero", "domain", "overflow", "underflow"
386*0928368fSKristof Beyls };
387*0928368fSKristof Beyls
388*0928368fSKristof Beyls static int verbose, fo, strict;
389*0928368fSKristof Beyls
390*0928368fSKristof Beyls /* state toggled by random=on / random=off */
391*0928368fSKristof Beyls static int randomstate;
392*0928368fSKristof Beyls
393*0928368fSKristof Beyls /* Canonify a double NaN: SNaNs all become 7FF00000.00000001 and QNaNs
394*0928368fSKristof Beyls * all become 7FF80000.00000001 */
canon_dNaN(unsigned a[2])395*0928368fSKristof Beyls void canon_dNaN(unsigned a[2]) {
396*0928368fSKristof Beyls if ((a[0] & 0x7FF00000) != 0x7FF00000)
397*0928368fSKristof Beyls return; /* not Inf or NaN */
398*0928368fSKristof Beyls if (!(a[0] & 0xFFFFF) && !a[1])
399*0928368fSKristof Beyls return; /* Inf */
400*0928368fSKristof Beyls a[0] &= 0x7FF80000; /* canonify top word */
401*0928368fSKristof Beyls a[1] = 0x00000001; /* canonify bottom word */
402*0928368fSKristof Beyls }
403*0928368fSKristof Beyls
404*0928368fSKristof Beyls /* Canonify a single NaN: SNaNs all become 7F800001 and QNaNs
405*0928368fSKristof Beyls * all become 7FC00001. Returns classification of the NaN. */
canon_sNaN(unsigned a[1])406*0928368fSKristof Beyls void canon_sNaN(unsigned a[1]) {
407*0928368fSKristof Beyls if ((a[0] & 0x7F800000) != 0x7F800000)
408*0928368fSKristof Beyls return; /* not Inf or NaN */
409*0928368fSKristof Beyls if (!(a[0] & 0x7FFFFF))
410*0928368fSKristof Beyls return; /* Inf */
411*0928368fSKristof Beyls a[0] &= 0x7FC00000; /* canonify most bits */
412*0928368fSKristof Beyls a[0] |= 0x00000001; /* canonify bottom bit */
413*0928368fSKristof Beyls }
414*0928368fSKristof Beyls
415*0928368fSKristof Beyls /*
416*0928368fSKristof Beyls * Detect difficult operands for FO mode.
417*0928368fSKristof Beyls */
is_dhard(unsigned a[2])418*0928368fSKristof Beyls int is_dhard(unsigned a[2])
419*0928368fSKristof Beyls {
420*0928368fSKristof Beyls if ((a[0] & 0x7FF00000) == 0x7FF00000)
421*0928368fSKristof Beyls return TRUE; /* inf or NaN */
422*0928368fSKristof Beyls if ((a[0] & 0x7FF00000) == 0 &&
423*0928368fSKristof Beyls ((a[0] & 0x7FFFFFFF) | a[1]) != 0)
424*0928368fSKristof Beyls return TRUE; /* denormal */
425*0928368fSKristof Beyls return FALSE;
426*0928368fSKristof Beyls }
is_shard(unsigned a[1])427*0928368fSKristof Beyls int is_shard(unsigned a[1])
428*0928368fSKristof Beyls {
429*0928368fSKristof Beyls if ((a[0] & 0x7F800000) == 0x7F800000)
430*0928368fSKristof Beyls return TRUE; /* inf or NaN */
431*0928368fSKristof Beyls if ((a[0] & 0x7F800000) == 0 &&
432*0928368fSKristof Beyls (a[0] & 0x7FFFFFFF) != 0)
433*0928368fSKristof Beyls return TRUE; /* denormal */
434*0928368fSKristof Beyls return FALSE;
435*0928368fSKristof Beyls }
436*0928368fSKristof Beyls
437*0928368fSKristof Beyls /*
438*0928368fSKristof Beyls * Normalise all zeroes into +0, for FO mode.
439*0928368fSKristof Beyls */
dnormzero(unsigned a[2])440*0928368fSKristof Beyls void dnormzero(unsigned a[2])
441*0928368fSKristof Beyls {
442*0928368fSKristof Beyls if (a[0] == 0x80000000 && a[1] == 0)
443*0928368fSKristof Beyls a[0] = 0;
444*0928368fSKristof Beyls }
snormzero(unsigned a[1])445*0928368fSKristof Beyls void snormzero(unsigned a[1])
446*0928368fSKristof Beyls {
447*0928368fSKristof Beyls if (a[0] == 0x80000000)
448*0928368fSKristof Beyls a[0] = 0;
449*0928368fSKristof Beyls }
450*0928368fSKristof Beyls
find(char * word,char ** array,int asize)451*0928368fSKristof Beyls static int find(char *word, char **array, int asize) {
452*0928368fSKristof Beyls int i, j;
453*0928368fSKristof Beyls
454*0928368fSKristof Beyls asize /= sizeof(char *);
455*0928368fSKristof Beyls
456*0928368fSKristof Beyls i = -1; j = asize; /* strictly between i and j */
457*0928368fSKristof Beyls while (j-i > 1) {
458*0928368fSKristof Beyls int k = (i+j) / 2;
459*0928368fSKristof Beyls int c = strcmp(word, array[k]);
460*0928368fSKristof Beyls if (c > 0)
461*0928368fSKristof Beyls i = k;
462*0928368fSKristof Beyls else if (c < 0)
463*0928368fSKristof Beyls j = k;
464*0928368fSKristof Beyls else /* found it! */
465*0928368fSKristof Beyls return k;
466*0928368fSKristof Beyls }
467*0928368fSKristof Beyls return -1; /* not found */
468*0928368fSKristof Beyls }
469*0928368fSKristof Beyls
find_testfunc(char * word)470*0928368fSKristof Beyls static test_func* find_testfunc(char *word) {
471*0928368fSKristof Beyls int i, j, asize;
472*0928368fSKristof Beyls
473*0928368fSKristof Beyls asize = sizeof(tfuncs)/sizeof(test_func);
474*0928368fSKristof Beyls
475*0928368fSKristof Beyls i = -1; j = asize; /* strictly between i and j */
476*0928368fSKristof Beyls while (j-i > 1) {
477*0928368fSKristof Beyls int k = (i+j) / 2;
478*0928368fSKristof Beyls int c = strcmp(word, tfuncs[k].name);
479*0928368fSKristof Beyls if (c > 0)
480*0928368fSKristof Beyls i = k;
481*0928368fSKristof Beyls else if (c < 0)
482*0928368fSKristof Beyls j = k;
483*0928368fSKristof Beyls else /* found it! */
484*0928368fSKristof Beyls return tfuncs + k;
485*0928368fSKristof Beyls }
486*0928368fSKristof Beyls return NULL; /* not found */
487*0928368fSKristof Beyls }
488*0928368fSKristof Beyls
calc_error(unsigned a[2],unsigned b[3],int shift,int rettype)489*0928368fSKristof Beyls static long long calc_error(unsigned a[2], unsigned b[3], int shift, int rettype) {
490*0928368fSKristof Beyls unsigned r0, r1, r2;
491*0928368fSKristof Beyls int sign, carry;
492*0928368fSKristof Beyls long long result;
493*0928368fSKristof Beyls
494*0928368fSKristof Beyls /*
495*0928368fSKristof Beyls * If either number is infinite, require exact equality. If
496*0928368fSKristof Beyls * either number is NaN, require that both are NaN. If either
497*0928368fSKristof Beyls * of these requirements is broken, return INT_MAX.
498*0928368fSKristof Beyls */
499*0928368fSKristof Beyls if (is_double_rettype(rettype)) {
500*0928368fSKristof Beyls if ((a[0] & 0x7FF00000) == 0x7FF00000 ||
501*0928368fSKristof Beyls (b[0] & 0x7FF00000) == 0x7FF00000) {
502*0928368fSKristof Beyls if (((a[0] & 0x800FFFFF) || a[1]) &&
503*0928368fSKristof Beyls ((b[0] & 0x800FFFFF) || b[1]) &&
504*0928368fSKristof Beyls (a[0] & 0x7FF00000) == 0x7FF00000 &&
505*0928368fSKristof Beyls (b[0] & 0x7FF00000) == 0x7FF00000)
506*0928368fSKristof Beyls return 0; /* both NaN - OK */
507*0928368fSKristof Beyls if (!((a[0] & 0xFFFFF) || a[1]) &&
508*0928368fSKristof Beyls !((b[0] & 0xFFFFF) || b[1]) &&
509*0928368fSKristof Beyls a[0] == b[0])
510*0928368fSKristof Beyls return 0; /* both same sign of Inf - OK */
511*0928368fSKristof Beyls return LLONG_MAX;
512*0928368fSKristof Beyls }
513*0928368fSKristof Beyls } else {
514*0928368fSKristof Beyls if ((a[0] & 0x7F800000) == 0x7F800000 ||
515*0928368fSKristof Beyls (b[0] & 0x7F800000) == 0x7F800000) {
516*0928368fSKristof Beyls if ((a[0] & 0x807FFFFF) &&
517*0928368fSKristof Beyls (b[0] & 0x807FFFFF) &&
518*0928368fSKristof Beyls (a[0] & 0x7F800000) == 0x7F800000 &&
519*0928368fSKristof Beyls (b[0] & 0x7F800000) == 0x7F800000)
520*0928368fSKristof Beyls return 0; /* both NaN - OK */
521*0928368fSKristof Beyls if (!(a[0] & 0x7FFFFF) &&
522*0928368fSKristof Beyls !(b[0] & 0x7FFFFF) &&
523*0928368fSKristof Beyls a[0] == b[0])
524*0928368fSKristof Beyls return 0; /* both same sign of Inf - OK */
525*0928368fSKristof Beyls return LLONG_MAX;
526*0928368fSKristof Beyls }
527*0928368fSKristof Beyls }
528*0928368fSKristof Beyls
529*0928368fSKristof Beyls /*
530*0928368fSKristof Beyls * Both finite. Return INT_MAX if the signs differ.
531*0928368fSKristof Beyls */
532*0928368fSKristof Beyls if ((a[0] ^ b[0]) & 0x80000000)
533*0928368fSKristof Beyls return LLONG_MAX;
534*0928368fSKristof Beyls
535*0928368fSKristof Beyls /*
536*0928368fSKristof Beyls * Now it's just straight multiple-word subtraction.
537*0928368fSKristof Beyls */
538*0928368fSKristof Beyls if (is_double_rettype(rettype)) {
539*0928368fSKristof Beyls r2 = -b[2]; carry = (r2 == 0);
540*0928368fSKristof Beyls r1 = a[1] + ~b[1] + carry; carry = (r1 < a[1] || (carry && r1 == a[1]));
541*0928368fSKristof Beyls r0 = a[0] + ~b[0] + carry;
542*0928368fSKristof Beyls } else {
543*0928368fSKristof Beyls r2 = -b[1]; carry = (r2 == 0);
544*0928368fSKristof Beyls r1 = a[0] + ~b[0] + carry; carry = (r1 < a[0] || (carry && r1 == a[0]));
545*0928368fSKristof Beyls r0 = ~0 + carry;
546*0928368fSKristof Beyls }
547*0928368fSKristof Beyls
548*0928368fSKristof Beyls /*
549*0928368fSKristof Beyls * Forgive larger errors in specialised cases.
550*0928368fSKristof Beyls */
551*0928368fSKristof Beyls if (shift > 0) {
552*0928368fSKristof Beyls if (shift > 32*3)
553*0928368fSKristof Beyls return 0; /* all errors are forgiven! */
554*0928368fSKristof Beyls while (shift >= 32) {
555*0928368fSKristof Beyls r2 = r1;
556*0928368fSKristof Beyls r1 = r0;
557*0928368fSKristof Beyls r0 = -(r0 >> 31);
558*0928368fSKristof Beyls shift -= 32;
559*0928368fSKristof Beyls }
560*0928368fSKristof Beyls
561*0928368fSKristof Beyls if (shift > 0) {
562*0928368fSKristof Beyls r2 = (r2 >> shift) | (r1 << (32-shift));
563*0928368fSKristof Beyls r1 = (r1 >> shift) | (r0 << (32-shift));
564*0928368fSKristof Beyls r0 = (r0 >> shift) | ((-(r0 >> 31)) << (32-shift));
565*0928368fSKristof Beyls }
566*0928368fSKristof Beyls }
567*0928368fSKristof Beyls
568*0928368fSKristof Beyls if (r0 & 0x80000000) {
569*0928368fSKristof Beyls sign = 1;
570*0928368fSKristof Beyls r2 = ~r2; carry = (r2 == 0);
571*0928368fSKristof Beyls r1 = 0 + ~r1 + carry; carry = (carry && (r2 == 0));
572*0928368fSKristof Beyls r0 = 0 + ~r0 + carry;
573*0928368fSKristof Beyls } else {
574*0928368fSKristof Beyls sign = 0;
575*0928368fSKristof Beyls }
576*0928368fSKristof Beyls
577*0928368fSKristof Beyls if (r0 >= (1LL<<(31-EXTRABITS)))
578*0928368fSKristof Beyls return LLONG_MAX; /* many ulps out */
579*0928368fSKristof Beyls
580*0928368fSKristof Beyls result = (r2 >> (32-EXTRABITS)) & (ULPUNIT-1);
581*0928368fSKristof Beyls result |= r1 << EXTRABITS;
582*0928368fSKristof Beyls result |= (long long)r0 << (32+EXTRABITS);
583*0928368fSKristof Beyls if (sign)
584*0928368fSKristof Beyls result = -result;
585*0928368fSKristof Beyls return result;
586*0928368fSKristof Beyls }
587*0928368fSKristof Beyls
588*0928368fSKristof Beyls /* special named operands */
589*0928368fSKristof Beyls
590*0928368fSKristof Beyls typedef struct {
591*0928368fSKristof Beyls unsigned op1, op2;
592*0928368fSKristof Beyls char* name;
593*0928368fSKristof Beyls } special_op;
594*0928368fSKristof Beyls
595*0928368fSKristof Beyls static special_op special_ops_double[] = {
596*0928368fSKristof Beyls {0x00000000,0x00000000,"0"},
597*0928368fSKristof Beyls {0x3FF00000,0x00000000,"1"},
598*0928368fSKristof Beyls {0x7FF00000,0x00000000,"inf"},
599*0928368fSKristof Beyls {0x7FF80000,0x00000001,"qnan"},
600*0928368fSKristof Beyls {0x7FF00000,0x00000001,"snan"},
601*0928368fSKristof Beyls {0x3ff921fb,0x54442d18,"pi2"},
602*0928368fSKristof Beyls {0x400921fb,0x54442d18,"pi"},
603*0928368fSKristof Beyls {0x3fe921fb,0x54442d18,"pi4"},
604*0928368fSKristof Beyls {0x4002d97c,0x7f3321d2,"3pi4"},
605*0928368fSKristof Beyls };
606*0928368fSKristof Beyls
607*0928368fSKristof Beyls static special_op special_ops_float[] = {
608*0928368fSKristof Beyls {0x00000000,0,"0"},
609*0928368fSKristof Beyls {0x3f800000,0,"1"},
610*0928368fSKristof Beyls {0x7f800000,0,"inf"},
611*0928368fSKristof Beyls {0x7fc00000,0,"qnan"},
612*0928368fSKristof Beyls {0x7f800001,0,"snan"},
613*0928368fSKristof Beyls {0x3fc90fdb,0,"pi2"},
614*0928368fSKristof Beyls {0x40490fdb,0,"pi"},
615*0928368fSKristof Beyls {0x3f490fdb,0,"pi4"},
616*0928368fSKristof Beyls {0x4016cbe4,0,"3pi4"},
617*0928368fSKristof Beyls };
618*0928368fSKristof Beyls
619*0928368fSKristof Beyls /*
620*0928368fSKristof Beyls This is what is returned by the below functions.
621*0928368fSKristof Beyls We need it to handle the sign of the number
622*0928368fSKristof Beyls */
623*0928368fSKristof Beyls static special_op tmp_op = {0,0,0};
624*0928368fSKristof Beyls
find_special_op_from_op(unsigned op1,unsigned op2,int is_double)625*0928368fSKristof Beyls special_op* find_special_op_from_op(unsigned op1, unsigned op2, int is_double) {
626*0928368fSKristof Beyls int i;
627*0928368fSKristof Beyls special_op* sop;
628*0928368fSKristof Beyls if(is_double) {
629*0928368fSKristof Beyls sop = special_ops_double;
630*0928368fSKristof Beyls } else {
631*0928368fSKristof Beyls sop = special_ops_float;
632*0928368fSKristof Beyls }
633*0928368fSKristof Beyls for(i = 0; i < sizeof(special_ops_double)/sizeof(special_op); i++) {
634*0928368fSKristof Beyls if(sop->op1 == (op1&0x7fffffff) && sop->op2 == op2) {
635*0928368fSKristof Beyls if(tmp_op.name) free(tmp_op.name);
636*0928368fSKristof Beyls tmp_op.name = malloc(strlen(sop->name)+2);
637*0928368fSKristof Beyls if(op1>>31) {
638*0928368fSKristof Beyls sprintf(tmp_op.name,"-%s",sop->name);
639*0928368fSKristof Beyls } else {
640*0928368fSKristof Beyls strcpy(tmp_op.name,sop->name);
641*0928368fSKristof Beyls }
642*0928368fSKristof Beyls return &tmp_op;
643*0928368fSKristof Beyls }
644*0928368fSKristof Beyls sop++;
645*0928368fSKristof Beyls }
646*0928368fSKristof Beyls return NULL;
647*0928368fSKristof Beyls }
648*0928368fSKristof Beyls
find_special_op_from_name(const char * name,int is_double)649*0928368fSKristof Beyls special_op* find_special_op_from_name(const char* name, int is_double) {
650*0928368fSKristof Beyls int i, neg=0;
651*0928368fSKristof Beyls special_op* sop;
652*0928368fSKristof Beyls if(is_double) {
653*0928368fSKristof Beyls sop = special_ops_double;
654*0928368fSKristof Beyls } else {
655*0928368fSKristof Beyls sop = special_ops_float;
656*0928368fSKristof Beyls }
657*0928368fSKristof Beyls if(*name=='-') {
658*0928368fSKristof Beyls neg=1;
659*0928368fSKristof Beyls name++;
660*0928368fSKristof Beyls } else if(*name=='+') {
661*0928368fSKristof Beyls name++;
662*0928368fSKristof Beyls }
663*0928368fSKristof Beyls for(i = 0; i < sizeof(special_ops_double)/sizeof(special_op); i++) {
664*0928368fSKristof Beyls if(0 == strcmp(name,sop->name)) {
665*0928368fSKristof Beyls tmp_op.op1 = sop->op1;
666*0928368fSKristof Beyls if(neg) {
667*0928368fSKristof Beyls tmp_op.op1 |= 0x80000000;
668*0928368fSKristof Beyls }
669*0928368fSKristof Beyls tmp_op.op2 = sop->op2;
670*0928368fSKristof Beyls return &tmp_op;
671*0928368fSKristof Beyls }
672*0928368fSKristof Beyls sop++;
673*0928368fSKristof Beyls }
674*0928368fSKristof Beyls return NULL;
675*0928368fSKristof Beyls }
676*0928368fSKristof Beyls
677*0928368fSKristof Beyls /*
678*0928368fSKristof Beyls helper function for the below
679*0928368fSKristof Beyls type=0 for single, 1 for double, 2 for no sop
680*0928368fSKristof Beyls */
do_op(char * q,unsigned * op,const char * name,int num,int sop_type)681*0928368fSKristof Beyls int do_op(char* q, unsigned* op, const char* name, int num, int sop_type) {
682*0928368fSKristof Beyls int i;
683*0928368fSKristof Beyls int n=num;
684*0928368fSKristof Beyls special_op* sop = NULL;
685*0928368fSKristof Beyls for(i = 0; i < num; i++) {
686*0928368fSKristof Beyls op[i] = 0;
687*0928368fSKristof Beyls }
688*0928368fSKristof Beyls if(sop_type<2) {
689*0928368fSKristof Beyls sop = find_special_op_from_name(q,sop_type);
690*0928368fSKristof Beyls }
691*0928368fSKristof Beyls if(sop != NULL) {
692*0928368fSKristof Beyls op[0] = sop->op1;
693*0928368fSKristof Beyls op[1] = sop->op2;
694*0928368fSKristof Beyls } else {
695*0928368fSKristof Beyls switch(num) {
696*0928368fSKristof Beyls case 1: n = sscanf(q, "%x", &op[0]); break;
697*0928368fSKristof Beyls case 2: n = sscanf(q, "%x.%x", &op[0], &op[1]); break;
698*0928368fSKristof Beyls case 3: n = sscanf(q, "%x.%x.%x", &op[0], &op[1], &op[2]); break;
699*0928368fSKristof Beyls default: return -1;
700*0928368fSKristof Beyls }
701*0928368fSKristof Beyls }
702*0928368fSKristof Beyls if (verbose) {
703*0928368fSKristof Beyls printf("%s=",name);
704*0928368fSKristof Beyls for (i = 0; (i < n); ++i) printf("%x.", op[i]);
705*0928368fSKristof Beyls printf(" (n=%d)\n", n);
706*0928368fSKristof Beyls }
707*0928368fSKristof Beyls return n;
708*0928368fSKristof Beyls }
709*0928368fSKristof Beyls
parsetest(char * testbuf,testdetail oldtest)710*0928368fSKristof Beyls testdetail parsetest(char *testbuf, testdetail oldtest) {
711*0928368fSKristof Beyls char *p; /* Current part of line: Option name */
712*0928368fSKristof Beyls char *q; /* Current part of line: Option value */
713*0928368fSKristof Beyls testdetail ret; /* What we return */
714*0928368fSKristof Beyls int k; /* Function enum from k_* */
715*0928368fSKristof Beyls int n; /* Used as returns for scanfs */
716*0928368fSKristof Beyls int argtype=2, rettype=2; /* for do_op */
717*0928368fSKristof Beyls
718*0928368fSKristof Beyls /* clear ret */
719*0928368fSKristof Beyls memset(&ret, 0, sizeof(ret));
720*0928368fSKristof Beyls
721*0928368fSKristof Beyls if (verbose) printf("Parsing line: %s\n", testbuf);
722*0928368fSKristof Beyls while (*testbuf && isspace(*testbuf)) testbuf++;
723*0928368fSKristof Beyls if (testbuf[0] == ';' || testbuf[0] == '#' || testbuf[0] == '!' ||
724*0928368fSKristof Beyls testbuf[0] == '>' || testbuf[0] == '\0') {
725*0928368fSKristof Beyls ret.comment = 1;
726*0928368fSKristof Beyls if (verbose) printf("Line is a comment\n");
727*0928368fSKristof Beyls return ret;
728*0928368fSKristof Beyls }
729*0928368fSKristof Beyls ret.comment = 0;
730*0928368fSKristof Beyls
731*0928368fSKristof Beyls if (*testbuf == '+') {
732*0928368fSKristof Beyls if (oldtest.valid) {
733*0928368fSKristof Beyls ret = oldtest; /* structure copy */
734*0928368fSKristof Beyls } else {
735*0928368fSKristof Beyls fprintf(stderr, "copy from invalid: ignored\n");
736*0928368fSKristof Beyls }
737*0928368fSKristof Beyls testbuf++;
738*0928368fSKristof Beyls }
739*0928368fSKristof Beyls
740*0928368fSKristof Beyls ret.random = randomstate;
741*0928368fSKristof Beyls
742*0928368fSKristof Beyls ret.in_err = 0;
743*0928368fSKristof Beyls ret.in_err_limit = e_number_of_errnos;
744*0928368fSKristof Beyls
745*0928368fSKristof Beyls p = strtok(testbuf, " \t");
746*0928368fSKristof Beyls while (p != NULL) {
747*0928368fSKristof Beyls q = strchr(p, '=');
748*0928368fSKristof Beyls if (!q)
749*0928368fSKristof Beyls goto balderdash;
750*0928368fSKristof Beyls *q++ = '\0';
751*0928368fSKristof Beyls k = find(p, keywords, sizeof(keywords));
752*0928368fSKristof Beyls switch (k) {
753*0928368fSKristof Beyls case k_random:
754*0928368fSKristof Beyls randomstate = (!strcmp(q, "on"));
755*0928368fSKristof Beyls ret.comment = 1;
756*0928368fSKristof Beyls return ret; /* otherwise ignore this line */
757*0928368fSKristof Beyls case k_func:
758*0928368fSKristof Beyls if (verbose) printf("func=%s ", q);
759*0928368fSKristof Beyls //ret.func = find(q, funcs, sizeof(funcs));
760*0928368fSKristof Beyls ret.func = find_testfunc(q);
761*0928368fSKristof Beyls if (ret.func == NULL)
762*0928368fSKristof Beyls {
763*0928368fSKristof Beyls if (verbose) printf("(id=unknown)\n");
764*0928368fSKristof Beyls goto balderdash;
765*0928368fSKristof Beyls }
766*0928368fSKristof Beyls if(is_single_argtype(ret.func->argtype))
767*0928368fSKristof Beyls argtype = 0;
768*0928368fSKristof Beyls else if(is_double_argtype(ret.func->argtype))
769*0928368fSKristof Beyls argtype = 1;
770*0928368fSKristof Beyls if(is_single_rettype(ret.func->rettype))
771*0928368fSKristof Beyls rettype = 0;
772*0928368fSKristof Beyls else if(is_double_rettype(ret.func->rettype))
773*0928368fSKristof Beyls rettype = 1;
774*0928368fSKristof Beyls //ret.size = sizes[ret.func];
775*0928368fSKristof Beyls if (verbose) printf("(name=%s) (size=%d)\n", ret.func->name, ret.func->argtype);
776*0928368fSKristof Beyls break;
777*0928368fSKristof Beyls case k_op1:
778*0928368fSKristof Beyls case k_op1r:
779*0928368fSKristof Beyls n = do_op(q,ret.op1r,"op1r",2,argtype);
780*0928368fSKristof Beyls if (n < 1)
781*0928368fSKristof Beyls goto balderdash;
782*0928368fSKristof Beyls break;
783*0928368fSKristof Beyls case k_op1i:
784*0928368fSKristof Beyls n = do_op(q,ret.op1i,"op1i",2,argtype);
785*0928368fSKristof Beyls if (n < 1)
786*0928368fSKristof Beyls goto balderdash;
787*0928368fSKristof Beyls break;
788*0928368fSKristof Beyls case k_op2:
789*0928368fSKristof Beyls case k_op2r:
790*0928368fSKristof Beyls n = do_op(q,ret.op2r,"op2r",2,argtype);
791*0928368fSKristof Beyls if (n < 1)
792*0928368fSKristof Beyls goto balderdash;
793*0928368fSKristof Beyls break;
794*0928368fSKristof Beyls case k_op2i:
795*0928368fSKristof Beyls n = do_op(q,ret.op2i,"op2i",2,argtype);
796*0928368fSKristof Beyls if (n < 1)
797*0928368fSKristof Beyls goto balderdash;
798*0928368fSKristof Beyls break;
799*0928368fSKristof Beyls case k_resultc:
800*0928368fSKristof Beyls puts(q);
801*0928368fSKristof Beyls if(strncmp(q,"inf",3)==0) {
802*0928368fSKristof Beyls ret.resultc = rc_infinity;
803*0928368fSKristof Beyls } else if(strcmp(q,"zero")==0) {
804*0928368fSKristof Beyls ret.resultc = rc_zero;
805*0928368fSKristof Beyls } else if(strcmp(q,"nan")==0) {
806*0928368fSKristof Beyls ret.resultc = rc_nan;
807*0928368fSKristof Beyls } else if(strcmp(q,"finite")==0) {
808*0928368fSKristof Beyls ret.resultc = rc_finite;
809*0928368fSKristof Beyls } else {
810*0928368fSKristof Beyls goto balderdash;
811*0928368fSKristof Beyls }
812*0928368fSKristof Beyls break;
813*0928368fSKristof Beyls case k_result:
814*0928368fSKristof Beyls case k_resultr:
815*0928368fSKristof Beyls n = (do_op)(q,ret.resultr,"resultr",3,rettype);
816*0928368fSKristof Beyls if (n < 1)
817*0928368fSKristof Beyls goto balderdash;
818*0928368fSKristof Beyls ret.nresult = n; /* assume real and imaginary have same no. words */
819*0928368fSKristof Beyls break;
820*0928368fSKristof Beyls case k_resulti:
821*0928368fSKristof Beyls n = do_op(q,ret.resulti,"resulti",3,rettype);
822*0928368fSKristof Beyls if (n < 1)
823*0928368fSKristof Beyls goto balderdash;
824*0928368fSKristof Beyls break;
825*0928368fSKristof Beyls case k_res2:
826*0928368fSKristof Beyls n = do_op(q,ret.res2,"res2",2,rettype);
827*0928368fSKristof Beyls if (n < 1)
828*0928368fSKristof Beyls goto balderdash;
829*0928368fSKristof Beyls break;
830*0928368fSKristof Beyls case k_status:
831*0928368fSKristof Beyls while (*q) {
832*0928368fSKristof Beyls if (*q == 'i') ret.status |= FE_INVALID;
833*0928368fSKristof Beyls if (*q == 'z') ret.status |= FE_DIVBYZERO;
834*0928368fSKristof Beyls if (*q == 'o') ret.status |= FE_OVERFLOW;
835*0928368fSKristof Beyls if (*q == 'u') ret.status |= FE_UNDERFLOW;
836*0928368fSKristof Beyls q++;
837*0928368fSKristof Beyls }
838*0928368fSKristof Beyls break;
839*0928368fSKristof Beyls case k_maybeerror:
840*0928368fSKristof Beyls n = find(q, errors, sizeof(errors));
841*0928368fSKristof Beyls if (n < 0)
842*0928368fSKristof Beyls goto balderdash;
843*0928368fSKristof Beyls if(math_errhandling&MATH_ERREXCEPT) {
844*0928368fSKristof Beyls switch(n) {
845*0928368fSKristof Beyls case e_domain: ret.maybestatus |= FE_INVALID; break;
846*0928368fSKristof Beyls case e_divbyzero: ret.maybestatus |= FE_DIVBYZERO; break;
847*0928368fSKristof Beyls case e_overflow: ret.maybestatus |= FE_OVERFLOW; break;
848*0928368fSKristof Beyls case e_underflow: ret.maybestatus |= FE_UNDERFLOW; break;
849*0928368fSKristof Beyls }
850*0928368fSKristof Beyls }
851*0928368fSKristof Beyls {
852*0928368fSKristof Beyls switch(n) {
853*0928368fSKristof Beyls case e_domain:
854*0928368fSKristof Beyls ret.maybeerr = e_EDOM; break;
855*0928368fSKristof Beyls case e_divbyzero:
856*0928368fSKristof Beyls case e_overflow:
857*0928368fSKristof Beyls case e_underflow:
858*0928368fSKristof Beyls ret.maybeerr = e_ERANGE; break;
859*0928368fSKristof Beyls }
860*0928368fSKristof Beyls }
861*0928368fSKristof Beyls case k_maybestatus:
862*0928368fSKristof Beyls while (*q) {
863*0928368fSKristof Beyls if (*q == 'i') ret.maybestatus |= FE_INVALID;
864*0928368fSKristof Beyls if (*q == 'z') ret.maybestatus |= FE_DIVBYZERO;
865*0928368fSKristof Beyls if (*q == 'o') ret.maybestatus |= FE_OVERFLOW;
866*0928368fSKristof Beyls if (*q == 'u') ret.maybestatus |= FE_UNDERFLOW;
867*0928368fSKristof Beyls q++;
868*0928368fSKristof Beyls }
869*0928368fSKristof Beyls break;
870*0928368fSKristof Beyls case k_error:
871*0928368fSKristof Beyls n = find(q, errors, sizeof(errors));
872*0928368fSKristof Beyls if (n < 0)
873*0928368fSKristof Beyls goto balderdash;
874*0928368fSKristof Beyls if(math_errhandling&MATH_ERREXCEPT) {
875*0928368fSKristof Beyls switch(n) {
876*0928368fSKristof Beyls case e_domain: ret.status |= FE_INVALID; break;
877*0928368fSKristof Beyls case e_divbyzero: ret.status |= FE_DIVBYZERO; break;
878*0928368fSKristof Beyls case e_overflow: ret.status |= FE_OVERFLOW; break;
879*0928368fSKristof Beyls case e_underflow: ret.status |= FE_UNDERFLOW; break;
880*0928368fSKristof Beyls }
881*0928368fSKristof Beyls }
882*0928368fSKristof Beyls if(math_errhandling&MATH_ERRNO) {
883*0928368fSKristof Beyls switch(n) {
884*0928368fSKristof Beyls case e_domain:
885*0928368fSKristof Beyls ret.err = e_EDOM; break;
886*0928368fSKristof Beyls case e_divbyzero:
887*0928368fSKristof Beyls case e_overflow:
888*0928368fSKristof Beyls case e_underflow:
889*0928368fSKristof Beyls ret.err = e_ERANGE; break;
890*0928368fSKristof Beyls }
891*0928368fSKristof Beyls }
892*0928368fSKristof Beyls if(!(math_errhandling&MATH_ERRNO)) {
893*0928368fSKristof Beyls switch(n) {
894*0928368fSKristof Beyls case e_domain:
895*0928368fSKristof Beyls ret.maybeerr = e_EDOM; break;
896*0928368fSKristof Beyls case e_divbyzero:
897*0928368fSKristof Beyls case e_overflow:
898*0928368fSKristof Beyls case e_underflow:
899*0928368fSKristof Beyls ret.maybeerr = e_ERANGE; break;
900*0928368fSKristof Beyls }
901*0928368fSKristof Beyls }
902*0928368fSKristof Beyls break;
903*0928368fSKristof Beyls case k_errno:
904*0928368fSKristof Beyls ret.err = find(q, errnos, sizeof(errnos));
905*0928368fSKristof Beyls if (ret.err < 0)
906*0928368fSKristof Beyls goto balderdash;
907*0928368fSKristof Beyls break;
908*0928368fSKristof Beyls case k_errno_in:
909*0928368fSKristof Beyls ret.in_err = find(q, errnos, sizeof(errnos));
910*0928368fSKristof Beyls if (ret.err < 0)
911*0928368fSKristof Beyls goto balderdash;
912*0928368fSKristof Beyls ret.in_err_limit = ret.in_err + 1;
913*0928368fSKristof Beyls break;
914*0928368fSKristof Beyls case k_wrongresult:
915*0928368fSKristof Beyls case k_wrongstatus:
916*0928368fSKristof Beyls case k_wrongres2:
917*0928368fSKristof Beyls case k_wrongerrno:
918*0928368fSKristof Beyls /* quietly ignore these keys */
919*0928368fSKristof Beyls break;
920*0928368fSKristof Beyls default:
921*0928368fSKristof Beyls goto balderdash;
922*0928368fSKristof Beyls }
923*0928368fSKristof Beyls p = strtok(NULL, " \t");
924*0928368fSKristof Beyls }
925*0928368fSKristof Beyls ret.valid = 1;
926*0928368fSKristof Beyls return ret;
927*0928368fSKristof Beyls
928*0928368fSKristof Beyls /* come here from almost any error */
929*0928368fSKristof Beyls balderdash:
930*0928368fSKristof Beyls ret.valid = 0;
931*0928368fSKristof Beyls return ret;
932*0928368fSKristof Beyls }
933*0928368fSKristof Beyls
934*0928368fSKristof Beyls typedef enum {
935*0928368fSKristof Beyls test_comment, /* deliberately not a test */
936*0928368fSKristof Beyls test_invalid, /* accidentally not a test */
937*0928368fSKristof Beyls test_decline, /* was a test, and wasn't run */
938*0928368fSKristof Beyls test_fail, /* was a test, and failed */
939*0928368fSKristof Beyls test_pass /* was a test, and passed */
940*0928368fSKristof Beyls } testresult;
941*0928368fSKristof Beyls
942*0928368fSKristof Beyls char failtext[512];
943*0928368fSKristof Beyls
944*0928368fSKristof Beyls typedef union {
945*0928368fSKristof Beyls unsigned i[2];
946*0928368fSKristof Beyls double f;
947*0928368fSKristof Beyls double da[2];
948*0928368fSKristof Beyls } dbl;
949*0928368fSKristof Beyls
950*0928368fSKristof Beyls typedef union {
951*0928368fSKristof Beyls unsigned i;
952*0928368fSKristof Beyls float f;
953*0928368fSKristof Beyls float da[2];
954*0928368fSKristof Beyls } sgl;
955*0928368fSKristof Beyls
956*0928368fSKristof Beyls /* helper function for runtest */
print_error(int rettype,unsigned * result,char * text,char ** failp)957*0928368fSKristof Beyls void print_error(int rettype, unsigned *result, char* text, char** failp) {
958*0928368fSKristof Beyls special_op *sop;
959*0928368fSKristof Beyls char *str;
960*0928368fSKristof Beyls
961*0928368fSKristof Beyls if(result) {
962*0928368fSKristof Beyls *failp += sprintf(*failp," %s=",text);
963*0928368fSKristof Beyls sop = find_special_op_from_op(result[0],result[1],is_double_rettype(rettype));
964*0928368fSKristof Beyls if(sop) {
965*0928368fSKristof Beyls *failp += sprintf(*failp,"%s",sop->name);
966*0928368fSKristof Beyls } else {
967*0928368fSKristof Beyls if(is_double_rettype(rettype)) {
968*0928368fSKristof Beyls str="%08x.%08x";
969*0928368fSKristof Beyls } else {
970*0928368fSKristof Beyls str="%08x";
971*0928368fSKristof Beyls }
972*0928368fSKristof Beyls *failp += sprintf(*failp,str,result[0],result[1]);
973*0928368fSKristof Beyls }
974*0928368fSKristof Beyls }
975*0928368fSKristof Beyls }
976*0928368fSKristof Beyls
977*0928368fSKristof Beyls
print_ulps_helper(const char * name,long long ulps,char ** failp)978*0928368fSKristof Beyls void print_ulps_helper(const char *name, long long ulps, char** failp) {
979*0928368fSKristof Beyls if(ulps == LLONG_MAX) {
980*0928368fSKristof Beyls *failp += sprintf(*failp, " %s=HUGE", name);
981*0928368fSKristof Beyls } else {
982*0928368fSKristof Beyls *failp += sprintf(*failp, " %s=%.3f", name, (double)ulps / ULPUNIT);
983*0928368fSKristof Beyls }
984*0928368fSKristof Beyls }
985*0928368fSKristof Beyls
986*0928368fSKristof Beyls /* for complex args make ulpsr or ulpsri = 0 to not print */
print_ulps(int rettype,long long ulpsr,long long ulpsi,char ** failp)987*0928368fSKristof Beyls void print_ulps(int rettype, long long ulpsr, long long ulpsi, char** failp) {
988*0928368fSKristof Beyls if(is_complex_rettype(rettype)) {
989*0928368fSKristof Beyls if (ulpsr) print_ulps_helper("ulpsr",ulpsr,failp);
990*0928368fSKristof Beyls if (ulpsi) print_ulps_helper("ulpsi",ulpsi,failp);
991*0928368fSKristof Beyls } else {
992*0928368fSKristof Beyls if (ulpsr) print_ulps_helper("ulps",ulpsr,failp);
993*0928368fSKristof Beyls }
994*0928368fSKristof Beyls }
995*0928368fSKristof Beyls
runtest(testdetail t)996*0928368fSKristof Beyls int runtest(testdetail t) {
997*0928368fSKristof Beyls int err, status;
998*0928368fSKristof Beyls
999*0928368fSKristof Beyls dbl d_arg1, d_arg2, d_res, d_res2;
1000*0928368fSKristof Beyls sgl s_arg1, s_arg2, s_res, s_res2;
1001*0928368fSKristof Beyls
1002*0928368fSKristof Beyls int deferred_decline = FALSE;
1003*0928368fSKristof Beyls char *failp = failtext;
1004*0928368fSKristof Beyls
1005*0928368fSKristof Beyls unsigned int intres=0;
1006*0928368fSKristof Beyls
1007*0928368fSKristof Beyls int res2_adjust = 0;
1008*0928368fSKristof Beyls
1009*0928368fSKristof Beyls if (t.comment)
1010*0928368fSKristof Beyls return test_comment;
1011*0928368fSKristof Beyls if (!t.valid)
1012*0928368fSKristof Beyls return test_invalid;
1013*0928368fSKristof Beyls
1014*0928368fSKristof Beyls /* Set IEEE status to mathlib-normal */
1015*0928368fSKristof Beyls feclearexcept(FE_ALL_EXCEPT);
1016*0928368fSKristof Beyls
1017*0928368fSKristof Beyls /* Deal with operands */
1018*0928368fSKristof Beyls #define DO_DOP(arg,op) arg.i[dmsd] = t.op[0]; arg.i[dlsd] = t.op[1]
1019*0928368fSKristof Beyls DO_DOP(d_arg1,op1r);
1020*0928368fSKristof Beyls DO_DOP(d_arg2,op2r);
1021*0928368fSKristof Beyls s_arg1.i = t.op1r[0]; s_arg2.i = t.op2r[0];
1022*0928368fSKristof Beyls
1023*0928368fSKristof Beyls /*
1024*0928368fSKristof Beyls * Detect NaNs, infinities and denormals on input, and set a
1025*0928368fSKristof Beyls * deferred decline flag if we're in FO mode.
1026*0928368fSKristof Beyls *
1027*0928368fSKristof Beyls * (We defer the decline rather than doing it immediately
1028*0928368fSKristof Beyls * because even in FO mode the operation is not permitted to
1029*0928368fSKristof Beyls * crash or tight-loop; so we _run_ the test, and then ignore
1030*0928368fSKristof Beyls * all the results.)
1031*0928368fSKristof Beyls */
1032*0928368fSKristof Beyls if (fo) {
1033*0928368fSKristof Beyls if (is_double_argtype(t.func->argtype) && is_dhard(t.op1r))
1034*0928368fSKristof Beyls deferred_decline = TRUE;
1035*0928368fSKristof Beyls if (t.func->argtype==at_d2 && is_dhard(t.op2r))
1036*0928368fSKristof Beyls deferred_decline = TRUE;
1037*0928368fSKristof Beyls if (is_single_argtype(t.func->argtype) && is_shard(t.op1r))
1038*0928368fSKristof Beyls deferred_decline = TRUE;
1039*0928368fSKristof Beyls if (t.func->argtype==at_s2 && is_shard(t.op2r))
1040*0928368fSKristof Beyls deferred_decline = TRUE;
1041*0928368fSKristof Beyls if (is_double_rettype(t.func->rettype) && is_dhard(t.resultr))
1042*0928368fSKristof Beyls deferred_decline = TRUE;
1043*0928368fSKristof Beyls if (t.func->rettype==rt_d2 && is_dhard(t.res2))
1044*0928368fSKristof Beyls deferred_decline = TRUE;
1045*0928368fSKristof Beyls if (is_single_argtype(t.func->rettype) && is_shard(t.resultr))
1046*0928368fSKristof Beyls deferred_decline = TRUE;
1047*0928368fSKristof Beyls if (t.func->rettype==rt_s2 && is_shard(t.res2))
1048*0928368fSKristof Beyls deferred_decline = TRUE;
1049*0928368fSKristof Beyls if (t.err == e_ERANGE)
1050*0928368fSKristof Beyls deferred_decline = TRUE;
1051*0928368fSKristof Beyls }
1052*0928368fSKristof Beyls
1053*0928368fSKristof Beyls /*
1054*0928368fSKristof Beyls * Perform the operation
1055*0928368fSKristof Beyls */
1056*0928368fSKristof Beyls
1057*0928368fSKristof Beyls errno = t.in_err == e_EDOM ? EDOM : t.in_err == e_ERANGE ? ERANGE : 0;
1058*0928368fSKristof Beyls if (t.err == e_0)
1059*0928368fSKristof Beyls t.err = t.in_err;
1060*0928368fSKristof Beyls if (t.maybeerr == e_0)
1061*0928368fSKristof Beyls t.maybeerr = t.in_err;
1062*0928368fSKristof Beyls
1063*0928368fSKristof Beyls if(t.func->type == t_func) {
1064*0928368fSKristof Beyls switch(t.func->argtype) {
1065*0928368fSKristof Beyls case at_d: d_res.f = t.func->func.d_d_ptr(d_arg1.f); break;
1066*0928368fSKristof Beyls case at_s: s_res.f = t.func->func.s_s_ptr(s_arg1.f); break;
1067*0928368fSKristof Beyls case at_d2: d_res.f = t.func->func.d2_d_ptr(d_arg1.f, d_arg2.f); break;
1068*0928368fSKristof Beyls case at_s2: s_res.f = t.func->func.s2_s_ptr(s_arg1.f, s_arg2.f); break;
1069*0928368fSKristof Beyls case at_di: d_res.f = t.func->func.di_d_ptr(d_arg1.f, d_arg2.i[dmsd]); break;
1070*0928368fSKristof Beyls case at_si: s_res.f = t.func->func.si_s_ptr(s_arg1.f, s_arg2.i); break;
1071*0928368fSKristof Beyls case at_dip: d_res.f = t.func->func.dip_d_ptr(d_arg1.f, (int*)&intres); break;
1072*0928368fSKristof Beyls case at_sip: s_res.f = t.func->func.sip_s_ptr(s_arg1.f, (int*)&intres); break;
1073*0928368fSKristof Beyls case at_ddp: d_res.f = t.func->func.ddp_d_ptr(d_arg1.f, &d_res2.f); break;
1074*0928368fSKristof Beyls case at_ssp: s_res.f = t.func->func.ssp_s_ptr(s_arg1.f, &s_res2.f); break;
1075*0928368fSKristof Beyls default:
1076*0928368fSKristof Beyls printf("unhandled function: %s\n",t.func->name);
1077*0928368fSKristof Beyls return test_fail;
1078*0928368fSKristof Beyls }
1079*0928368fSKristof Beyls } else {
1080*0928368fSKristof Beyls /* printf("macro: name=%s, num=%i, s1.i=0x%08x s1.f=%f\n",t.func->name, t.func->macro_name, s_arg1.i, (double)s_arg1.f); */
1081*0928368fSKristof Beyls switch(t.func->macro_name) {
1082*0928368fSKristof Beyls case m_isfinite: intres = isfinite(d_arg1.f); break;
1083*0928368fSKristof Beyls case m_isinf: intres = isinf(d_arg1.f); break;
1084*0928368fSKristof Beyls case m_isnan: intres = isnan(d_arg1.f); break;
1085*0928368fSKristof Beyls case m_isnormal: intres = isnormal(d_arg1.f); break;
1086*0928368fSKristof Beyls case m_signbit: intres = signbit(d_arg1.f); break;
1087*0928368fSKristof Beyls case m_fpclassify: intres = fpclassify(d_arg1.f); break;
1088*0928368fSKristof Beyls case m_isgreater: intres = isgreater(d_arg1.f, d_arg2.f); break;
1089*0928368fSKristof Beyls case m_isgreaterequal: intres = isgreaterequal(d_arg1.f, d_arg2.f); break;
1090*0928368fSKristof Beyls case m_isless: intres = isless(d_arg1.f, d_arg2.f); break;
1091*0928368fSKristof Beyls case m_islessequal: intres = islessequal(d_arg1.f, d_arg2.f); break;
1092*0928368fSKristof Beyls case m_islessgreater: intres = islessgreater(d_arg1.f, d_arg2.f); break;
1093*0928368fSKristof Beyls case m_isunordered: intres = isunordered(d_arg1.f, d_arg2.f); break;
1094*0928368fSKristof Beyls
1095*0928368fSKristof Beyls case m_isfinitef: intres = isfinite(s_arg1.f); break;
1096*0928368fSKristof Beyls case m_isinff: intres = isinf(s_arg1.f); break;
1097*0928368fSKristof Beyls case m_isnanf: intres = isnan(s_arg1.f); break;
1098*0928368fSKristof Beyls case m_isnormalf: intres = isnormal(s_arg1.f); break;
1099*0928368fSKristof Beyls case m_signbitf: intres = signbit(s_arg1.f); break;
1100*0928368fSKristof Beyls case m_fpclassifyf: intres = fpclassify(s_arg1.f); break;
1101*0928368fSKristof Beyls case m_isgreaterf: intres = isgreater(s_arg1.f, s_arg2.f); break;
1102*0928368fSKristof Beyls case m_isgreaterequalf: intres = isgreaterequal(s_arg1.f, s_arg2.f); break;
1103*0928368fSKristof Beyls case m_islessf: intres = isless(s_arg1.f, s_arg2.f); break;
1104*0928368fSKristof Beyls case m_islessequalf: intres = islessequal(s_arg1.f, s_arg2.f); break;
1105*0928368fSKristof Beyls case m_islessgreaterf: intres = islessgreater(s_arg1.f, s_arg2.f); break;
1106*0928368fSKristof Beyls case m_isunorderedf: intres = isunordered(s_arg1.f, s_arg2.f); break;
1107*0928368fSKristof Beyls
1108*0928368fSKristof Beyls default:
1109*0928368fSKristof Beyls printf("unhandled macro: %s\n",t.func->name);
1110*0928368fSKristof Beyls return test_fail;
1111*0928368fSKristof Beyls }
1112*0928368fSKristof Beyls }
1113*0928368fSKristof Beyls
1114*0928368fSKristof Beyls /*
1115*0928368fSKristof Beyls * Decline the test if the deferred decline flag was set above.
1116*0928368fSKristof Beyls */
1117*0928368fSKristof Beyls if (deferred_decline)
1118*0928368fSKristof Beyls return test_decline;
1119*0928368fSKristof Beyls
1120*0928368fSKristof Beyls /* printf("intres=%i\n",intres); */
1121*0928368fSKristof Beyls
1122*0928368fSKristof Beyls /* Clear the fail text (indicating a pass unless we change it) */
1123*0928368fSKristof Beyls failp[0] = '\0';
1124*0928368fSKristof Beyls
1125*0928368fSKristof Beyls /* Check the IEEE status bits (except INX, which we disregard).
1126*0928368fSKristof Beyls * We don't bother with this for complex numbers, because the
1127*0928368fSKristof Beyls * complex functions are hard to get exactly right and we don't
1128*0928368fSKristof Beyls * have to anyway (C99 annex G is only informative). */
1129*0928368fSKristof Beyls if (!(is_complex_argtype(t.func->argtype) || is_complex_rettype(t.func->rettype))) {
1130*0928368fSKristof Beyls status = fetestexcept(FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW|FE_UNDERFLOW);
1131*0928368fSKristof Beyls if ((status|t.maybestatus|~statusmask) != (t.status|t.maybestatus|~statusmask)) {
1132*0928368fSKristof Beyls if (quiet) failtext[0]='x';
1133*0928368fSKristof Beyls else {
1134*0928368fSKristof Beyls failp += sprintf(failp,
1135*0928368fSKristof Beyls " wrongstatus=%s%s%s%s%s",
1136*0928368fSKristof Beyls (status & FE_INVALID ? "i" : ""),
1137*0928368fSKristof Beyls (status & FE_DIVBYZERO ? "z" : ""),
1138*0928368fSKristof Beyls (status & FE_OVERFLOW ? "o" : ""),
1139*0928368fSKristof Beyls (status & FE_UNDERFLOW ? "u" : ""),
1140*0928368fSKristof Beyls (status ? "" : "OK"));
1141*0928368fSKristof Beyls }
1142*0928368fSKristof Beyls }
1143*0928368fSKristof Beyls }
1144*0928368fSKristof Beyls
1145*0928368fSKristof Beyls /* Check the result */
1146*0928368fSKristof Beyls {
1147*0928368fSKristof Beyls unsigned resultr[2], resulti[2];
1148*0928368fSKristof Beyls unsigned tresultr[3], tresulti[3], wres;
1149*0928368fSKristof Beyls
1150*0928368fSKristof Beyls switch(t.func->rettype) {
1151*0928368fSKristof Beyls case rt_d:
1152*0928368fSKristof Beyls case rt_d2:
1153*0928368fSKristof Beyls tresultr[0] = t.resultr[0];
1154*0928368fSKristof Beyls tresultr[1] = t.resultr[1];
1155*0928368fSKristof Beyls resultr[0] = d_res.i[dmsd]; resultr[1] = d_res.i[dlsd];
1156*0928368fSKristof Beyls wres = 2;
1157*0928368fSKristof Beyls break;
1158*0928368fSKristof Beyls case rt_i:
1159*0928368fSKristof Beyls tresultr[0] = t.resultr[0];
1160*0928368fSKristof Beyls resultr[0] = intres;
1161*0928368fSKristof Beyls wres = 1;
1162*0928368fSKristof Beyls break;
1163*0928368fSKristof Beyls case rt_s:
1164*0928368fSKristof Beyls case rt_s2:
1165*0928368fSKristof Beyls tresultr[0] = t.resultr[0];
1166*0928368fSKristof Beyls resultr[0] = s_res.i;
1167*0928368fSKristof Beyls wres = 1;
1168*0928368fSKristof Beyls break;
1169*0928368fSKristof Beyls default:
1170*0928368fSKristof Beyls puts("unhandled rettype in runtest");
1171*0928368fSKristof Beyls wres = 0;
1172*0928368fSKristof Beyls }
1173*0928368fSKristof Beyls if(t.resultc != rc_none) {
1174*0928368fSKristof Beyls int err = 0;
1175*0928368fSKristof Beyls switch(t.resultc) {
1176*0928368fSKristof Beyls case rc_zero:
1177*0928368fSKristof Beyls if(resultr[0] != 0 || resulti[0] != 0 ||
1178*0928368fSKristof Beyls (wres==2 && (resultr[1] != 0 || resulti[1] != 0))) {
1179*0928368fSKristof Beyls err = 1;
1180*0928368fSKristof Beyls }
1181*0928368fSKristof Beyls break;
1182*0928368fSKristof Beyls case rc_infinity:
1183*0928368fSKristof Beyls if(wres==1) {
1184*0928368fSKristof Beyls if(!((resultr[0]&0x7fffffff)==0x7f800000 ||
1185*0928368fSKristof Beyls (resulti[0]&0x7fffffff)==0x7f800000)) {
1186*0928368fSKristof Beyls err = 1;
1187*0928368fSKristof Beyls }
1188*0928368fSKristof Beyls } else {
1189*0928368fSKristof Beyls if(!(((resultr[0]&0x7fffffff)==0x7ff00000 && resultr[1]==0) ||
1190*0928368fSKristof Beyls ((resulti[0]&0x7fffffff)==0x7ff00000 && resulti[1]==0))) {
1191*0928368fSKristof Beyls err = 1;
1192*0928368fSKristof Beyls }
1193*0928368fSKristof Beyls }
1194*0928368fSKristof Beyls break;
1195*0928368fSKristof Beyls case rc_nan:
1196*0928368fSKristof Beyls if(wres==1) {
1197*0928368fSKristof Beyls if(!((resultr[0]&0x7fffffff)>0x7f800000 ||
1198*0928368fSKristof Beyls (resulti[0]&0x7fffffff)>0x7f800000)) {
1199*0928368fSKristof Beyls err = 1;
1200*0928368fSKristof Beyls }
1201*0928368fSKristof Beyls } else {
1202*0928368fSKristof Beyls canon_dNaN(resultr);
1203*0928368fSKristof Beyls canon_dNaN(resulti);
1204*0928368fSKristof Beyls if(!(((resultr[0]&0x7fffffff)>0x7ff00000 && resultr[1]==1) ||
1205*0928368fSKristof Beyls ((resulti[0]&0x7fffffff)>0x7ff00000 && resulti[1]==1))) {
1206*0928368fSKristof Beyls err = 1;
1207*0928368fSKristof Beyls }
1208*0928368fSKristof Beyls }
1209*0928368fSKristof Beyls break;
1210*0928368fSKristof Beyls case rc_finite:
1211*0928368fSKristof Beyls if(wres==1) {
1212*0928368fSKristof Beyls if(!((resultr[0]&0x7fffffff)<0x7f800000 ||
1213*0928368fSKristof Beyls (resulti[0]&0x7fffffff)<0x7f800000)) {
1214*0928368fSKristof Beyls err = 1;
1215*0928368fSKristof Beyls }
1216*0928368fSKristof Beyls } else {
1217*0928368fSKristof Beyls if(!((resultr[0]&0x7fffffff)<0x7ff00000 ||
1218*0928368fSKristof Beyls (resulti[0]&0x7fffffff)<0x7ff00000)) {
1219*0928368fSKristof Beyls err = 1;
1220*0928368fSKristof Beyls }
1221*0928368fSKristof Beyls }
1222*0928368fSKristof Beyls break;
1223*0928368fSKristof Beyls default:
1224*0928368fSKristof Beyls break;
1225*0928368fSKristof Beyls }
1226*0928368fSKristof Beyls if(err) {
1227*0928368fSKristof Beyls print_error(t.func->rettype,resultr,"wrongresultr",&failp);
1228*0928368fSKristof Beyls print_error(t.func->rettype,resulti,"wrongresulti",&failp);
1229*0928368fSKristof Beyls }
1230*0928368fSKristof Beyls } else if (t.nresult > wres) {
1231*0928368fSKristof Beyls /*
1232*0928368fSKristof Beyls * The test case data has provided the result to more
1233*0928368fSKristof Beyls * than double precision. Instead of testing exact
1234*0928368fSKristof Beyls * equality, we test against our maximum error
1235*0928368fSKristof Beyls * tolerance.
1236*0928368fSKristof Beyls */
1237*0928368fSKristof Beyls int rshift, ishift;
1238*0928368fSKristof Beyls long long ulpsr, ulpsi, ulptolerance;
1239*0928368fSKristof Beyls
1240*0928368fSKristof Beyls tresultr[wres] = t.resultr[wres] << (32-EXTRABITS);
1241*0928368fSKristof Beyls tresulti[wres] = t.resulti[wres] << (32-EXTRABITS);
1242*0928368fSKristof Beyls if(strict) {
1243*0928368fSKristof Beyls ulptolerance = 4096; /* one ulp */
1244*0928368fSKristof Beyls } else {
1245*0928368fSKristof Beyls ulptolerance = t.func->tolerance;
1246*0928368fSKristof Beyls }
1247*0928368fSKristof Beyls rshift = ishift = 0;
1248*0928368fSKristof Beyls if (ulptolerance & ABSLOWERBOUND) {
1249*0928368fSKristof Beyls /*
1250*0928368fSKristof Beyls * Hack for the lgamma functions, which have an
1251*0928368fSKristof Beyls * error behaviour that can't conveniently be
1252*0928368fSKristof Beyls * characterised in pure ULPs. Really, we want to
1253*0928368fSKristof Beyls * say that the error in lgamma is "at most N ULPs,
1254*0928368fSKristof Beyls * or at most an absolute error of X, whichever is
1255*0928368fSKristof Beyls * larger", for appropriately chosen N,X. But since
1256*0928368fSKristof Beyls * these two functions are the only cases where it
1257*0928368fSKristof Beyls * arises, I haven't bothered to do it in a nice way
1258*0928368fSKristof Beyls * in the function table above.
1259*0928368fSKristof Beyls *
1260*0928368fSKristof Beyls * (The difficult cases arise with negative input
1261*0928368fSKristof Beyls * values such that |gamma(x)| is very near to 1; in
1262*0928368fSKristof Beyls * this situation implementations tend to separately
1263*0928368fSKristof Beyls * compute lgamma(|x|) and the log of the correction
1264*0928368fSKristof Beyls * term from the Euler reflection formula, and
1265*0928368fSKristof Beyls * subtract - which catastrophically loses
1266*0928368fSKristof Beyls * significance.)
1267*0928368fSKristof Beyls *
1268*0928368fSKristof Beyls * As far as I can tell, nobody cares about this:
1269*0928368fSKristof Beyls * GNU libm doesn't get those cases right either,
1270*0928368fSKristof Beyls * and OpenCL explicitly doesn't state a ULP error
1271*0928368fSKristof Beyls * limit for lgamma. So my guess is that this is
1272*0928368fSKristof Beyls * simply considered acceptable error behaviour for
1273*0928368fSKristof Beyls * this particular function, and hence I feel free
1274*0928368fSKristof Beyls * to allow for it here.
1275*0928368fSKristof Beyls */
1276*0928368fSKristof Beyls ulptolerance &= ~ABSLOWERBOUND;
1277*0928368fSKristof Beyls if (t.op1r[0] & 0x80000000) {
1278*0928368fSKristof Beyls if (t.func->rettype == rt_d)
1279*0928368fSKristof Beyls rshift = 0x400 - ((tresultr[0] >> 20) & 0x7ff);
1280*0928368fSKristof Beyls else if (t.func->rettype == rt_s)
1281*0928368fSKristof Beyls rshift = 0x80 - ((tresultr[0] >> 23) & 0xff);
1282*0928368fSKristof Beyls if (rshift < 0)
1283*0928368fSKristof Beyls rshift = 0;
1284*0928368fSKristof Beyls }
1285*0928368fSKristof Beyls }
1286*0928368fSKristof Beyls if (ulptolerance & PLUSMINUSPIO2) {
1287*0928368fSKristof Beyls ulptolerance &= ~PLUSMINUSPIO2;
1288*0928368fSKristof Beyls /*
1289*0928368fSKristof Beyls * Hack for range reduction, which can reduce
1290*0928368fSKristof Beyls * borderline cases in the wrong direction, i.e.
1291*0928368fSKristof Beyls * return a value just outside one end of the interval
1292*0928368fSKristof Beyls * [-pi/4,+pi/4] when it could have returned a value
1293*0928368fSKristof Beyls * just inside the other end by subtracting an
1294*0928368fSKristof Beyls * adjacent multiple of pi/2.
1295*0928368fSKristof Beyls *
1296*0928368fSKristof Beyls * We tolerate this, up to a point, because the
1297*0928368fSKristof Beyls * trigonometric functions making use of the output of
1298*0928368fSKristof Beyls * rred can cope and because making the range reducer
1299*0928368fSKristof Beyls * do the exactly right thing in every case would be
1300*0928368fSKristof Beyls * more expensive.
1301*0928368fSKristof Beyls */
1302*0928368fSKristof Beyls if (wres == 1) {
1303*0928368fSKristof Beyls /* Upper bound of overshoot derived in rredf.h */
1304*0928368fSKristof Beyls if ((resultr[0]&0x7FFFFFFF) <= 0x3f494b02 &&
1305*0928368fSKristof Beyls (resultr[0]&0x7FFFFFFF) > 0x3f490fda &&
1306*0928368fSKristof Beyls (resultr[0]&0x80000000) != (tresultr[0]&0x80000000)) {
1307*0928368fSKristof Beyls unsigned long long val;
1308*0928368fSKristof Beyls val = tresultr[0];
1309*0928368fSKristof Beyls val = (val << 32) | tresultr[1];
1310*0928368fSKristof Beyls /*
1311*0928368fSKristof Beyls * Compute the alternative permitted result by
1312*0928368fSKristof Beyls * subtracting from the sum of the extended
1313*0928368fSKristof Beyls * single-precision bit patterns of +pi/4 and
1314*0928368fSKristof Beyls * -pi/4. This is a horrible hack which only
1315*0928368fSKristof Beyls * works because we can be confident that
1316*0928368fSKristof Beyls * numbers in this range all have the same
1317*0928368fSKristof Beyls * exponent!
1318*0928368fSKristof Beyls */
1319*0928368fSKristof Beyls val = 0xfe921fb54442d184ULL - val;
1320*0928368fSKristof Beyls tresultr[0] = val >> 32;
1321*0928368fSKristof Beyls tresultr[1] = (val >> (32-EXTRABITS)) << (32-EXTRABITS);
1322*0928368fSKristof Beyls /*
1323*0928368fSKristof Beyls * Also, expect a correspondingly different
1324*0928368fSKristof Beyls * value of res2 as a result of this change.
1325*0928368fSKristof Beyls * The adjustment depends on whether we just
1326*0928368fSKristof Beyls * flipped the result from + to - or vice
1327*0928368fSKristof Beyls * versa.
1328*0928368fSKristof Beyls */
1329*0928368fSKristof Beyls if (resultr[0] & 0x80000000) {
1330*0928368fSKristof Beyls res2_adjust = +1;
1331*0928368fSKristof Beyls } else {
1332*0928368fSKristof Beyls res2_adjust = -1;
1333*0928368fSKristof Beyls }
1334*0928368fSKristof Beyls }
1335*0928368fSKristof Beyls }
1336*0928368fSKristof Beyls }
1337*0928368fSKristof Beyls ulpsr = calc_error(resultr, tresultr, rshift, t.func->rettype);
1338*0928368fSKristof Beyls if(is_complex_rettype(t.func->rettype)) {
1339*0928368fSKristof Beyls ulpsi = calc_error(resulti, tresulti, ishift, t.func->rettype);
1340*0928368fSKristof Beyls } else {
1341*0928368fSKristof Beyls ulpsi = 0;
1342*0928368fSKristof Beyls }
1343*0928368fSKristof Beyls unsigned *rr = (ulpsr > ulptolerance || ulpsr < -ulptolerance) ? resultr : NULL;
1344*0928368fSKristof Beyls unsigned *ri = (ulpsi > ulptolerance || ulpsi < -ulptolerance) ? resulti : NULL;
1345*0928368fSKristof Beyls /* printf("tolerance=%i, ulpsr=%i, ulpsi=%i, rr=%p, ri=%p\n",ulptolerance,ulpsr,ulpsi,rr,ri); */
1346*0928368fSKristof Beyls if (rr || ri) {
1347*0928368fSKristof Beyls if (quiet) failtext[0]='x';
1348*0928368fSKristof Beyls else {
1349*0928368fSKristof Beyls print_error(t.func->rettype,rr,"wrongresultr",&failp);
1350*0928368fSKristof Beyls print_error(t.func->rettype,ri,"wrongresulti",&failp);
1351*0928368fSKristof Beyls print_ulps(t.func->rettype,rr ? ulpsr : 0, ri ? ulpsi : 0,&failp);
1352*0928368fSKristof Beyls }
1353*0928368fSKristof Beyls }
1354*0928368fSKristof Beyls } else {
1355*0928368fSKristof Beyls if(is_complex_rettype(t.func->rettype))
1356*0928368fSKristof Beyls /*
1357*0928368fSKristof Beyls * Complex functions are not fully supported,
1358*0928368fSKristof Beyls * this is unreachable, but prevents warnings.
1359*0928368fSKristof Beyls */
1360*0928368fSKristof Beyls abort();
1361*0928368fSKristof Beyls /*
1362*0928368fSKristof Beyls * The test case data has provided the result in
1363*0928368fSKristof Beyls * exactly the output precision. Therefore we must
1364*0928368fSKristof Beyls * complain about _any_ violation.
1365*0928368fSKristof Beyls */
1366*0928368fSKristof Beyls switch(t.func->rettype) {
1367*0928368fSKristof Beyls case rt_dc:
1368*0928368fSKristof Beyls canon_dNaN(tresulti);
1369*0928368fSKristof Beyls canon_dNaN(resulti);
1370*0928368fSKristof Beyls if (fo) {
1371*0928368fSKristof Beyls dnormzero(tresulti);
1372*0928368fSKristof Beyls dnormzero(resulti);
1373*0928368fSKristof Beyls }
1374*0928368fSKristof Beyls /* deliberate fall-through */
1375*0928368fSKristof Beyls case rt_d:
1376*0928368fSKristof Beyls canon_dNaN(tresultr);
1377*0928368fSKristof Beyls canon_dNaN(resultr);
1378*0928368fSKristof Beyls if (fo) {
1379*0928368fSKristof Beyls dnormzero(tresultr);
1380*0928368fSKristof Beyls dnormzero(resultr);
1381*0928368fSKristof Beyls }
1382*0928368fSKristof Beyls break;
1383*0928368fSKristof Beyls case rt_sc:
1384*0928368fSKristof Beyls canon_sNaN(tresulti);
1385*0928368fSKristof Beyls canon_sNaN(resulti);
1386*0928368fSKristof Beyls if (fo) {
1387*0928368fSKristof Beyls snormzero(tresulti);
1388*0928368fSKristof Beyls snormzero(resulti);
1389*0928368fSKristof Beyls }
1390*0928368fSKristof Beyls /* deliberate fall-through */
1391*0928368fSKristof Beyls case rt_s:
1392*0928368fSKristof Beyls canon_sNaN(tresultr);
1393*0928368fSKristof Beyls canon_sNaN(resultr);
1394*0928368fSKristof Beyls if (fo) {
1395*0928368fSKristof Beyls snormzero(tresultr);
1396*0928368fSKristof Beyls snormzero(resultr);
1397*0928368fSKristof Beyls }
1398*0928368fSKristof Beyls break;
1399*0928368fSKristof Beyls default:
1400*0928368fSKristof Beyls break;
1401*0928368fSKristof Beyls }
1402*0928368fSKristof Beyls if(is_complex_rettype(t.func->rettype)) {
1403*0928368fSKristof Beyls unsigned *rr, *ri;
1404*0928368fSKristof Beyls if(resultr[0] != tresultr[0] ||
1405*0928368fSKristof Beyls (wres > 1 && resultr[1] != tresultr[1])) {
1406*0928368fSKristof Beyls rr = resultr;
1407*0928368fSKristof Beyls } else {
1408*0928368fSKristof Beyls rr = NULL;
1409*0928368fSKristof Beyls }
1410*0928368fSKristof Beyls if(resulti[0] != tresulti[0] ||
1411*0928368fSKristof Beyls (wres > 1 && resulti[1] != tresulti[1])) {
1412*0928368fSKristof Beyls ri = resulti;
1413*0928368fSKristof Beyls } else {
1414*0928368fSKristof Beyls ri = NULL;
1415*0928368fSKristof Beyls }
1416*0928368fSKristof Beyls if(rr || ri) {
1417*0928368fSKristof Beyls if (quiet) failtext[0]='x';
1418*0928368fSKristof Beyls print_error(t.func->rettype,rr,"wrongresultr",&failp);
1419*0928368fSKristof Beyls print_error(t.func->rettype,ri,"wrongresulti",&failp);
1420*0928368fSKristof Beyls }
1421*0928368fSKristof Beyls } else if (resultr[0] != tresultr[0] ||
1422*0928368fSKristof Beyls (wres > 1 && resultr[1] != tresultr[1])) {
1423*0928368fSKristof Beyls if (quiet) failtext[0]='x';
1424*0928368fSKristof Beyls print_error(t.func->rettype,resultr,"wrongresult",&failp);
1425*0928368fSKristof Beyls }
1426*0928368fSKristof Beyls }
1427*0928368fSKristof Beyls /*
1428*0928368fSKristof Beyls * Now test res2, for those functions (frexp, modf, rred)
1429*0928368fSKristof Beyls * which use it.
1430*0928368fSKristof Beyls */
1431*0928368fSKristof Beyls if (t.func->func.ptr == &frexp || t.func->func.ptr == &frexpf ||
1432*0928368fSKristof Beyls t.func->macro_name == m_rred || t.func->macro_name == m_rredf) {
1433*0928368fSKristof Beyls unsigned tres2 = t.res2[0];
1434*0928368fSKristof Beyls if (res2_adjust) {
1435*0928368fSKristof Beyls /* Fix for range reduction, propagated from further up */
1436*0928368fSKristof Beyls tres2 = (tres2 + res2_adjust) & 3;
1437*0928368fSKristof Beyls }
1438*0928368fSKristof Beyls if (tres2 != intres) {
1439*0928368fSKristof Beyls if (quiet) failtext[0]='x';
1440*0928368fSKristof Beyls else {
1441*0928368fSKristof Beyls failp += sprintf(failp,
1442*0928368fSKristof Beyls " wrongres2=%08x", intres);
1443*0928368fSKristof Beyls }
1444*0928368fSKristof Beyls }
1445*0928368fSKristof Beyls } else if (t.func->func.ptr == &modf || t.func->func.ptr == &modff) {
1446*0928368fSKristof Beyls tresultr[0] = t.res2[0];
1447*0928368fSKristof Beyls tresultr[1] = t.res2[1];
1448*0928368fSKristof Beyls if (is_double_rettype(t.func->rettype)) {
1449*0928368fSKristof Beyls canon_dNaN(tresultr);
1450*0928368fSKristof Beyls resultr[0] = d_res2.i[dmsd];
1451*0928368fSKristof Beyls resultr[1] = d_res2.i[dlsd];
1452*0928368fSKristof Beyls canon_dNaN(resultr);
1453*0928368fSKristof Beyls if (fo) {
1454*0928368fSKristof Beyls dnormzero(tresultr);
1455*0928368fSKristof Beyls dnormzero(resultr);
1456*0928368fSKristof Beyls }
1457*0928368fSKristof Beyls } else {
1458*0928368fSKristof Beyls canon_sNaN(tresultr);
1459*0928368fSKristof Beyls resultr[0] = s_res2.i;
1460*0928368fSKristof Beyls resultr[1] = s_res2.i;
1461*0928368fSKristof Beyls canon_sNaN(resultr);
1462*0928368fSKristof Beyls if (fo) {
1463*0928368fSKristof Beyls snormzero(tresultr);
1464*0928368fSKristof Beyls snormzero(resultr);
1465*0928368fSKristof Beyls }
1466*0928368fSKristof Beyls }
1467*0928368fSKristof Beyls if (resultr[0] != tresultr[0] ||
1468*0928368fSKristof Beyls (wres > 1 && resultr[1] != tresultr[1])) {
1469*0928368fSKristof Beyls if (quiet) failtext[0]='x';
1470*0928368fSKristof Beyls else {
1471*0928368fSKristof Beyls if (is_double_rettype(t.func->rettype))
1472*0928368fSKristof Beyls failp += sprintf(failp, " wrongres2=%08x.%08x",
1473*0928368fSKristof Beyls resultr[0], resultr[1]);
1474*0928368fSKristof Beyls else
1475*0928368fSKristof Beyls failp += sprintf(failp, " wrongres2=%08x",
1476*0928368fSKristof Beyls resultr[0]);
1477*0928368fSKristof Beyls }
1478*0928368fSKristof Beyls }
1479*0928368fSKristof Beyls }
1480*0928368fSKristof Beyls }
1481*0928368fSKristof Beyls
1482*0928368fSKristof Beyls /* Check errno */
1483*0928368fSKristof Beyls err = (errno == EDOM ? e_EDOM : errno == ERANGE ? e_ERANGE : e_0);
1484*0928368fSKristof Beyls if (err != t.err && err != t.maybeerr) {
1485*0928368fSKristof Beyls if (quiet) failtext[0]='x';
1486*0928368fSKristof Beyls else {
1487*0928368fSKristof Beyls failp += sprintf(failp, " wrongerrno=%s expecterrno=%s ", errnos[err], errnos[t.err]);
1488*0928368fSKristof Beyls }
1489*0928368fSKristof Beyls }
1490*0928368fSKristof Beyls
1491*0928368fSKristof Beyls return *failtext ? test_fail : test_pass;
1492*0928368fSKristof Beyls }
1493*0928368fSKristof Beyls
1494*0928368fSKristof Beyls int passed, failed, declined;
1495*0928368fSKristof Beyls
runtests(char * name,FILE * fp)1496*0928368fSKristof Beyls void runtests(char *name, FILE *fp) {
1497*0928368fSKristof Beyls char testbuf[512], linebuf[512];
1498*0928368fSKristof Beyls int lineno = 1;
1499*0928368fSKristof Beyls testdetail test;
1500*0928368fSKristof Beyls
1501*0928368fSKristof Beyls test.valid = 0;
1502*0928368fSKristof Beyls
1503*0928368fSKristof Beyls if (verbose) printf("runtests: %s\n", name);
1504*0928368fSKristof Beyls while (fgets(testbuf, sizeof(testbuf), fp)) {
1505*0928368fSKristof Beyls int res, print_errno;
1506*0928368fSKristof Beyls testbuf[strcspn(testbuf, "\r\n")] = '\0';
1507*0928368fSKristof Beyls strcpy(linebuf, testbuf);
1508*0928368fSKristof Beyls test = parsetest(testbuf, test);
1509*0928368fSKristof Beyls print_errno = 0;
1510*0928368fSKristof Beyls while (test.in_err < test.in_err_limit) {
1511*0928368fSKristof Beyls res = runtest(test);
1512*0928368fSKristof Beyls if (res == test_pass) {
1513*0928368fSKristof Beyls if (verbose)
1514*0928368fSKristof Beyls printf("%s:%d: pass\n", name, lineno);
1515*0928368fSKristof Beyls ++passed;
1516*0928368fSKristof Beyls } else if (res == test_decline) {
1517*0928368fSKristof Beyls if (verbose)
1518*0928368fSKristof Beyls printf("%s:%d: declined\n", name, lineno);
1519*0928368fSKristof Beyls ++declined;
1520*0928368fSKristof Beyls } else if (res == test_fail) {
1521*0928368fSKristof Beyls if (!quiet)
1522*0928368fSKristof Beyls printf("%s:%d: FAIL%s: %s%s%s%s\n", name, lineno,
1523*0928368fSKristof Beyls test.random ? " (random)" : "",
1524*0928368fSKristof Beyls linebuf,
1525*0928368fSKristof Beyls print_errno ? " errno_in=" : "",
1526*0928368fSKristof Beyls print_errno ? errnos[test.in_err] : "",
1527*0928368fSKristof Beyls failtext);
1528*0928368fSKristof Beyls ++failed;
1529*0928368fSKristof Beyls } else if (res == test_invalid) {
1530*0928368fSKristof Beyls printf("%s:%d: malformed: %s\n", name, lineno, linebuf);
1531*0928368fSKristof Beyls ++failed;
1532*0928368fSKristof Beyls }
1533*0928368fSKristof Beyls test.in_err++;
1534*0928368fSKristof Beyls print_errno = 1;
1535*0928368fSKristof Beyls }
1536*0928368fSKristof Beyls lineno++;
1537*0928368fSKristof Beyls }
1538*0928368fSKristof Beyls }
1539*0928368fSKristof Beyls
main(int ac,char ** av)1540*0928368fSKristof Beyls int main(int ac, char **av) {
1541*0928368fSKristof Beyls char **files;
1542*0928368fSKristof Beyls int i, nfiles = 0;
1543*0928368fSKristof Beyls dbl d;
1544*0928368fSKristof Beyls
1545*0928368fSKristof Beyls #ifdef MICROLIB
1546*0928368fSKristof Beyls /*
1547*0928368fSKristof Beyls * Invent argc and argv ourselves.
1548*0928368fSKristof Beyls */
1549*0928368fSKristof Beyls char *argv[256];
1550*0928368fSKristof Beyls char args[256];
1551*0928368fSKristof Beyls {
1552*0928368fSKristof Beyls int sargs[2];
1553*0928368fSKristof Beyls char *p;
1554*0928368fSKristof Beyls
1555*0928368fSKristof Beyls ac = 0;
1556*0928368fSKristof Beyls
1557*0928368fSKristof Beyls sargs[0]=(int)args;
1558*0928368fSKristof Beyls sargs[1]=(int)sizeof(args);
1559*0928368fSKristof Beyls if (!__semihost(0x15, sargs)) {
1560*0928368fSKristof Beyls args[sizeof(args)-1] = '\0'; /* just in case */
1561*0928368fSKristof Beyls p = args;
1562*0928368fSKristof Beyls while (1) {
1563*0928368fSKristof Beyls while (*p == ' ' || *p == '\t') p++;
1564*0928368fSKristof Beyls if (!*p) break;
1565*0928368fSKristof Beyls argv[ac++] = p;
1566*0928368fSKristof Beyls while (*p && *p != ' ' && *p != '\t') p++;
1567*0928368fSKristof Beyls if (*p) *p++ = '\0';
1568*0928368fSKristof Beyls }
1569*0928368fSKristof Beyls }
1570*0928368fSKristof Beyls
1571*0928368fSKristof Beyls av = argv;
1572*0928368fSKristof Beyls }
1573*0928368fSKristof Beyls #endif
1574*0928368fSKristof Beyls
1575*0928368fSKristof Beyls /* Sort tfuncs */
1576*0928368fSKristof Beyls qsort(tfuncs, sizeof(tfuncs)/sizeof(test_func), sizeof(test_func), &compare_tfuncs);
1577*0928368fSKristof Beyls
1578*0928368fSKristof Beyls /*
1579*0928368fSKristof Beyls * Autodetect the `double' endianness.
1580*0928368fSKristof Beyls */
1581*0928368fSKristof Beyls dmsd = 0;
1582*0928368fSKristof Beyls d.f = 1.0; /* 0x3ff00000 / 0x00000000 */
1583*0928368fSKristof Beyls if (d.i[dmsd] == 0) {
1584*0928368fSKristof Beyls dmsd = 1;
1585*0928368fSKristof Beyls }
1586*0928368fSKristof Beyls /*
1587*0928368fSKristof Beyls * Now dmsd denotes what the compiler thinks we're at. Let's
1588*0928368fSKristof Beyls * check that it agrees with what the runtime thinks.
1589*0928368fSKristof Beyls */
1590*0928368fSKristof Beyls d.i[0] = d.i[1] = 0x11111111;/* a random +ve number */
1591*0928368fSKristof Beyls d.f /= d.f; /* must now be one */
1592*0928368fSKristof Beyls if (d.i[dmsd] == 0) {
1593*0928368fSKristof Beyls fprintf(stderr, "YIKES! Compiler and runtime disagree on endianness"
1594*0928368fSKristof Beyls " of `double'. Bailing out\n");
1595*0928368fSKristof Beyls return 1;
1596*0928368fSKristof Beyls }
1597*0928368fSKristof Beyls dlsd = !dmsd;
1598*0928368fSKristof Beyls
1599*0928368fSKristof Beyls /* default is terse */
1600*0928368fSKristof Beyls verbose = 0;
1601*0928368fSKristof Beyls fo = 0;
1602*0928368fSKristof Beyls strict = 0;
1603*0928368fSKristof Beyls
1604*0928368fSKristof Beyls files = (char **)malloc((ac+1) * sizeof(char *));
1605*0928368fSKristof Beyls if (!files) {
1606*0928368fSKristof Beyls fprintf(stderr, "initial malloc failed!\n");
1607*0928368fSKristof Beyls return 1;
1608*0928368fSKristof Beyls }
1609*0928368fSKristof Beyls #ifdef NOCMDLINE
1610*0928368fSKristof Beyls files[nfiles++] = "testfile";
1611*0928368fSKristof Beyls #endif
1612*0928368fSKristof Beyls
1613*0928368fSKristof Beyls while (--ac) {
1614*0928368fSKristof Beyls char *p = *++av;
1615*0928368fSKristof Beyls if (*p == '-') {
1616*0928368fSKristof Beyls static char *options[] = {
1617*0928368fSKristof Beyls "-fo",
1618*0928368fSKristof Beyls #if 0
1619*0928368fSKristof Beyls "-noinexact",
1620*0928368fSKristof Beyls "-noround",
1621*0928368fSKristof Beyls #endif
1622*0928368fSKristof Beyls "-nostatus",
1623*0928368fSKristof Beyls "-quiet",
1624*0928368fSKristof Beyls "-strict",
1625*0928368fSKristof Beyls "-v",
1626*0928368fSKristof Beyls "-verbose",
1627*0928368fSKristof Beyls };
1628*0928368fSKristof Beyls enum {
1629*0928368fSKristof Beyls op_fo,
1630*0928368fSKristof Beyls #if 0
1631*0928368fSKristof Beyls op_noinexact,
1632*0928368fSKristof Beyls op_noround,
1633*0928368fSKristof Beyls #endif
1634*0928368fSKristof Beyls op_nostatus,
1635*0928368fSKristof Beyls op_quiet,
1636*0928368fSKristof Beyls op_strict,
1637*0928368fSKristof Beyls op_v,
1638*0928368fSKristof Beyls op_verbose,
1639*0928368fSKristof Beyls };
1640*0928368fSKristof Beyls switch (find(p, options, sizeof(options))) {
1641*0928368fSKristof Beyls case op_quiet:
1642*0928368fSKristof Beyls quiet = 1;
1643*0928368fSKristof Beyls break;
1644*0928368fSKristof Beyls #if 0
1645*0928368fSKristof Beyls case op_noinexact:
1646*0928368fSKristof Beyls statusmask &= 0x0F; /* remove bit 4 */
1647*0928368fSKristof Beyls break;
1648*0928368fSKristof Beyls case op_noround:
1649*0928368fSKristof Beyls doround = 0;
1650*0928368fSKristof Beyls break;
1651*0928368fSKristof Beyls #endif
1652*0928368fSKristof Beyls case op_nostatus: /* no status word => noinx,noround */
1653*0928368fSKristof Beyls statusmask = 0;
1654*0928368fSKristof Beyls doround = 0;
1655*0928368fSKristof Beyls break;
1656*0928368fSKristof Beyls case op_v:
1657*0928368fSKristof Beyls case op_verbose:
1658*0928368fSKristof Beyls verbose = 1;
1659*0928368fSKristof Beyls break;
1660*0928368fSKristof Beyls case op_fo:
1661*0928368fSKristof Beyls fo = 1;
1662*0928368fSKristof Beyls break;
1663*0928368fSKristof Beyls case op_strict: /* tolerance is 1 ulp */
1664*0928368fSKristof Beyls strict = 1;
1665*0928368fSKristof Beyls break;
1666*0928368fSKristof Beyls default:
1667*0928368fSKristof Beyls fprintf(stderr, "unrecognised option: %s\n", p);
1668*0928368fSKristof Beyls break;
1669*0928368fSKristof Beyls }
1670*0928368fSKristof Beyls } else {
1671*0928368fSKristof Beyls files[nfiles++] = p;
1672*0928368fSKristof Beyls }
1673*0928368fSKristof Beyls }
1674*0928368fSKristof Beyls
1675*0928368fSKristof Beyls passed = failed = declined = 0;
1676*0928368fSKristof Beyls
1677*0928368fSKristof Beyls if (nfiles) {
1678*0928368fSKristof Beyls for (i = 0; i < nfiles; i++) {
1679*0928368fSKristof Beyls FILE *fp = fopen(files[i], "r");
1680*0928368fSKristof Beyls if (!fp) {
1681*0928368fSKristof Beyls fprintf(stderr, "Couldn't open %s\n", files[i]);
1682*0928368fSKristof Beyls } else
1683*0928368fSKristof Beyls runtests(files[i], fp);
1684*0928368fSKristof Beyls }
1685*0928368fSKristof Beyls } else
1686*0928368fSKristof Beyls runtests("(stdin)", stdin);
1687*0928368fSKristof Beyls
1688*0928368fSKristof Beyls printf("Completed. Passed %d, failed %d (total %d",
1689*0928368fSKristof Beyls passed, failed, passed+failed);
1690*0928368fSKristof Beyls if (declined)
1691*0928368fSKristof Beyls printf(" plus %d declined", declined);
1692*0928368fSKristof Beyls printf(")\n");
1693*0928368fSKristof Beyls if (failed || passed == 0)
1694*0928368fSKristof Beyls return 1;
1695*0928368fSKristof Beyls printf("** TEST PASSED OK **\n");
1696*0928368fSKristof Beyls return 0;
1697*0928368fSKristof Beyls }
1698*0928368fSKristof Beyls
undef_func()1699*0928368fSKristof Beyls void undef_func() {
1700*0928368fSKristof Beyls failed++;
1701*0928368fSKristof Beyls puts("ERROR: undefined function called");
1702*0928368fSKristof Beyls }
1703