xref: /freebsd/contrib/arm-optimized-routines/math/test/rtest/main.c (revision 31914882fca502069810b9e9ddea4bcd8136a4f4)
1*31914882SAlex Richardson /*
2*31914882SAlex Richardson  * main.c
3*31914882SAlex Richardson  *
4*31914882SAlex Richardson  * Copyright (c) 1999-2019, Arm Limited.
5*31914882SAlex Richardson  * SPDX-License-Identifier: MIT
6*31914882SAlex Richardson  */
7*31914882SAlex Richardson 
8*31914882SAlex Richardson #include <assert.h>
9*31914882SAlex Richardson #include <stdio.h>
10*31914882SAlex Richardson #include <string.h>
11*31914882SAlex Richardson #include <ctype.h>
12*31914882SAlex Richardson #include <stdlib.h>
13*31914882SAlex Richardson #include <time.h>
14*31914882SAlex Richardson 
15*31914882SAlex Richardson #include "intern.h"
16*31914882SAlex Richardson 
17*31914882SAlex Richardson void gencases(Testable *fn, int number);
18*31914882SAlex Richardson void docase(Testable *fn, uint32 *args);
19*31914882SAlex Richardson void vet_for_decline(Testable *fn, uint32 *args, uint32 *result, int got_errno_in);
20*31914882SAlex Richardson void seed_random(uint32 seed);
21*31914882SAlex Richardson 
22*31914882SAlex Richardson int check_declines = 0;
23*31914882SAlex Richardson int lib_fo = 0;
24*31914882SAlex Richardson int lib_no_arith = 0;
25*31914882SAlex Richardson int ntests = 0;
26*31914882SAlex Richardson 
27*31914882SAlex Richardson int nargs_(Testable* f) {
28*31914882SAlex Richardson     switch((f)->type) {
29*31914882SAlex Richardson     case args2:
30*31914882SAlex Richardson     case args2f:
31*31914882SAlex Richardson     case semi2:
32*31914882SAlex Richardson     case semi2f:
33*31914882SAlex Richardson     case t_ldexp:
34*31914882SAlex Richardson     case t_ldexpf:
35*31914882SAlex Richardson     case args1c:
36*31914882SAlex Richardson     case args1fc:
37*31914882SAlex Richardson     case args1cr:
38*31914882SAlex Richardson     case args1fcr:
39*31914882SAlex Richardson     case compare:
40*31914882SAlex Richardson     case comparef:
41*31914882SAlex Richardson         return 2;
42*31914882SAlex Richardson     case args2c:
43*31914882SAlex Richardson     case args2fc:
44*31914882SAlex Richardson         return 4;
45*31914882SAlex Richardson     default:
46*31914882SAlex Richardson         return 1;
47*31914882SAlex Richardson     }
48*31914882SAlex Richardson }
49*31914882SAlex Richardson 
50*31914882SAlex Richardson static int isdouble(Testable *f)
51*31914882SAlex Richardson {
52*31914882SAlex Richardson     switch (f->type) {
53*31914882SAlex Richardson       case args1:
54*31914882SAlex Richardson       case rred:
55*31914882SAlex Richardson       case semi1:
56*31914882SAlex Richardson       case t_frexp:
57*31914882SAlex Richardson       case t_modf:
58*31914882SAlex Richardson       case classify:
59*31914882SAlex Richardson       case t_ldexp:
60*31914882SAlex Richardson       case args2:
61*31914882SAlex Richardson       case semi2:
62*31914882SAlex Richardson       case args1c:
63*31914882SAlex Richardson       case args1cr:
64*31914882SAlex Richardson       case compare:
65*31914882SAlex Richardson       case args2c:
66*31914882SAlex Richardson         return 1;
67*31914882SAlex Richardson       case args1f:
68*31914882SAlex Richardson       case rredf:
69*31914882SAlex Richardson       case semi1f:
70*31914882SAlex Richardson       case t_frexpf:
71*31914882SAlex Richardson       case t_modff:
72*31914882SAlex Richardson       case classifyf:
73*31914882SAlex Richardson       case args2f:
74*31914882SAlex Richardson       case semi2f:
75*31914882SAlex Richardson       case t_ldexpf:
76*31914882SAlex Richardson       case comparef:
77*31914882SAlex Richardson       case args1fc:
78*31914882SAlex Richardson       case args1fcr:
79*31914882SAlex Richardson       case args2fc:
80*31914882SAlex Richardson         return 0;
81*31914882SAlex Richardson       default:
82*31914882SAlex Richardson         assert(0 && "Bad function type");
83*31914882SAlex Richardson     }
84*31914882SAlex Richardson }
85*31914882SAlex Richardson 
86*31914882SAlex Richardson Testable *find_function(const char *func)
87*31914882SAlex Richardson {
88*31914882SAlex Richardson     int i;
89*31914882SAlex Richardson     for (i = 0; i < nfunctions; i++) {
90*31914882SAlex Richardson         if (func && !strcmp(func, functions[i].name)) {
91*31914882SAlex Richardson             return &functions[i];
92*31914882SAlex Richardson         }
93*31914882SAlex Richardson     }
94*31914882SAlex Richardson     return NULL;
95*31914882SAlex Richardson }
96*31914882SAlex Richardson 
97*31914882SAlex Richardson void get_operand(const char *str, Testable *f, uint32 *word0, uint32 *word1)
98*31914882SAlex Richardson {
99*31914882SAlex Richardson     struct special {
100*31914882SAlex Richardson         unsigned dblword0, dblword1, sglword;
101*31914882SAlex Richardson         const char *name;
102*31914882SAlex Richardson     } specials[] = {
103*31914882SAlex Richardson         {0x00000000,0x00000000,0x00000000,"0"},
104*31914882SAlex Richardson         {0x3FF00000,0x00000000,0x3f800000,"1"},
105*31914882SAlex Richardson         {0x7FF00000,0x00000000,0x7f800000,"inf"},
106*31914882SAlex Richardson         {0x7FF80000,0x00000001,0x7fc00000,"qnan"},
107*31914882SAlex Richardson         {0x7FF00000,0x00000001,0x7f800001,"snan"},
108*31914882SAlex Richardson         {0x3ff921fb,0x54442d18,0x3fc90fdb,"pi2"},
109*31914882SAlex Richardson         {0x400921fb,0x54442d18,0x40490fdb,"pi"},
110*31914882SAlex Richardson         {0x3fe921fb,0x54442d18,0x3f490fdb,"pi4"},
111*31914882SAlex Richardson         {0x4002d97c,0x7f3321d2,0x4016cbe4,"3pi4"},
112*31914882SAlex Richardson     };
113*31914882SAlex Richardson     int i;
114*31914882SAlex Richardson 
115*31914882SAlex Richardson     for (i = 0; i < (int)(sizeof(specials)/sizeof(*specials)); i++) {
116*31914882SAlex Richardson         if (!strcmp(str, specials[i].name) ||
117*31914882SAlex Richardson             ((str[0] == '-' || str[0] == '+') &&
118*31914882SAlex Richardson              !strcmp(str+1, specials[i].name))) {
119*31914882SAlex Richardson             assert(f);
120*31914882SAlex Richardson             if (isdouble(f)) {
121*31914882SAlex Richardson                 *word0 = specials[i].dblword0;
122*31914882SAlex Richardson                 *word1 = specials[i].dblword1;
123*31914882SAlex Richardson             } else {
124*31914882SAlex Richardson                 *word0 = specials[i].sglword;
125*31914882SAlex Richardson                 *word1 = 0;
126*31914882SAlex Richardson             }
127*31914882SAlex Richardson             if (str[0] == '-')
128*31914882SAlex Richardson                 *word0 |= 0x80000000U;
129*31914882SAlex Richardson             return;
130*31914882SAlex Richardson         }
131*31914882SAlex Richardson     }
132*31914882SAlex Richardson 
133*31914882SAlex Richardson     sscanf(str, "%"I32"x.%"I32"x", word0, word1);
134*31914882SAlex Richardson }
135*31914882SAlex Richardson 
136*31914882SAlex Richardson void dofile(FILE *fp, int translating) {
137*31914882SAlex Richardson     char buf[1024], sparebuf[1024], *p;
138*31914882SAlex Richardson 
139*31914882SAlex Richardson     /*
140*31914882SAlex Richardson      * Command syntax is:
141*31914882SAlex Richardson      *
142*31914882SAlex Richardson      *  - "seed <integer>" sets a random seed
143*31914882SAlex Richardson      *
144*31914882SAlex Richardson      *  - "test <function> <ntests>" generates random test lines
145*31914882SAlex Richardson      *
146*31914882SAlex Richardson      *  - "<function> op1=foo [op2=bar]" generates a specific test
147*31914882SAlex Richardson      *  - "func=<function> op1=foo [op2=bar]" does the same
148*31914882SAlex Richardson      *  - "func=<function> op1=foo result=bar" will just output the line as-is
149*31914882SAlex Richardson      *
150*31914882SAlex Richardson      *  - a semicolon or a blank line is ignored
151*31914882SAlex Richardson      */
152*31914882SAlex Richardson     while (fgets(buf, sizeof(buf), fp)) {
153*31914882SAlex Richardson         buf[strcspn(buf, "\r\n")] = '\0';
154*31914882SAlex Richardson         strcpy(sparebuf, buf);
155*31914882SAlex Richardson         p = buf;
156*31914882SAlex Richardson         while (*p && isspace(*p)) p++;
157*31914882SAlex Richardson         if (!*p || *p == ';') {
158*31914882SAlex Richardson             /* Comment or blank line. Only print if `translating' is set. */
159*31914882SAlex Richardson             if (translating)
160*31914882SAlex Richardson                 printf("%s\n", buf);
161*31914882SAlex Richardson             continue;
162*31914882SAlex Richardson         }
163*31914882SAlex Richardson         if (!strncmp(buf, "seed ", 5)) {
164*31914882SAlex Richardson             seed_random(atoi(buf+5));
165*31914882SAlex Richardson         } else if (!strncmp(buf, "random=", 7)) {
166*31914882SAlex Richardson             /*
167*31914882SAlex Richardson              * Copy 'random=on' / 'random=off' lines unconditionally
168*31914882SAlex Richardson              * to the output, so that random test failures can be
169*31914882SAlex Richardson              * accumulated into a recent-failures-list file and
170*31914882SAlex Richardson              * still identified as random-in-origin when re-run the
171*31914882SAlex Richardson              * next day.
172*31914882SAlex Richardson              */
173*31914882SAlex Richardson             printf("%s\n", buf);
174*31914882SAlex Richardson         } else if (!strncmp(buf, "test ", 5)) {
175*31914882SAlex Richardson             char *p = buf+5;
176*31914882SAlex Richardson             char *q;
177*31914882SAlex Richardson             int ntests, i;
178*31914882SAlex Richardson             q = p;
179*31914882SAlex Richardson             while (*p && !isspace(*p)) p++;
180*31914882SAlex Richardson             if (*p) *p++ = '\0';
181*31914882SAlex Richardson             while (*p && isspace(*p)) p++;
182*31914882SAlex Richardson             if (*p)
183*31914882SAlex Richardson                 ntests = atoi(p);
184*31914882SAlex Richardson             else
185*31914882SAlex Richardson                 ntests = 100;          /* *shrug* */
186*31914882SAlex Richardson             for (i = 0; i < nfunctions; i++) {
187*31914882SAlex Richardson                 if (!strcmp(q, functions[i].name)) {
188*31914882SAlex Richardson                     gencases(&functions[i], ntests);
189*31914882SAlex Richardson                     break;
190*31914882SAlex Richardson                 }
191*31914882SAlex Richardson             }
192*31914882SAlex Richardson             if (i == nfunctions) {
193*31914882SAlex Richardson                 fprintf(stderr, "unknown test `%s'\n", q);
194*31914882SAlex Richardson             }
195*31914882SAlex Richardson         } else {
196*31914882SAlex Richardson             /*
197*31914882SAlex Richardson              * Parse a specific test line.
198*31914882SAlex Richardson              */
199*31914882SAlex Richardson             uint32 ops[8], result[8];
200*31914882SAlex Richardson             int got_op = 0; /* &1 for got_op1, &4 for got_op3 etc. */
201*31914882SAlex Richardson             Testable *f = 0;
202*31914882SAlex Richardson             char *q, *r;
203*31914882SAlex Richardson             int got_result = 0, got_errno_in = 0;
204*31914882SAlex Richardson 
205*31914882SAlex Richardson             for (q = strtok(p, " \t"); q; q = strtok(NULL, " \t")) {
206*31914882SAlex Richardson                 r = strchr(q, '=');
207*31914882SAlex Richardson                 if (!r) {
208*31914882SAlex Richardson                     f = find_function(q);
209*31914882SAlex Richardson                 } else {
210*31914882SAlex Richardson                     *r++ = '\0';
211*31914882SAlex Richardson 
212*31914882SAlex Richardson                     if (!strcmp(q, "func"))
213*31914882SAlex Richardson                         f = find_function(r);
214*31914882SAlex Richardson                     else if (!strcmp(q, "op1") || !strcmp(q, "op1r")) {
215*31914882SAlex Richardson                         get_operand(r, f, &ops[0], &ops[1]);
216*31914882SAlex Richardson                         got_op |= 1;
217*31914882SAlex Richardson                     } else if (!strcmp(q, "op2") || !strcmp(q, "op1i")) {
218*31914882SAlex Richardson                         get_operand(r, f, &ops[2], &ops[3]);
219*31914882SAlex Richardson                         got_op |= 2;
220*31914882SAlex Richardson                     } else if (!strcmp(q, "op2r")) {
221*31914882SAlex Richardson                         get_operand(r, f, &ops[4], &ops[5]);
222*31914882SAlex Richardson                         got_op |= 4;
223*31914882SAlex Richardson                     } else if (!strcmp(q, "op2i")) {
224*31914882SAlex Richardson                         get_operand(r, f, &ops[6], &ops[7]);
225*31914882SAlex Richardson                         got_op |= 8;
226*31914882SAlex Richardson                     } else if (!strcmp(q, "result") || !strcmp(q, "resultr")) {
227*31914882SAlex Richardson                         get_operand(r, f, &result[0], &result[1]);
228*31914882SAlex Richardson                         got_result |= 1;
229*31914882SAlex Richardson                     } else if (!strcmp(q, "resulti")) {
230*31914882SAlex Richardson                         get_operand(r, f, &result[4], &result[5]);
231*31914882SAlex Richardson                         got_result |= 2;
232*31914882SAlex Richardson                     } else if (!strcmp(q, "res2")) {
233*31914882SAlex Richardson                         get_operand(r, f, &result[2], &result[3]);
234*31914882SAlex Richardson                         got_result |= 4;
235*31914882SAlex Richardson                     } else if (!strcmp(q, "errno_in")) {
236*31914882SAlex Richardson                         got_errno_in = 1;
237*31914882SAlex Richardson                     }
238*31914882SAlex Richardson                 }
239*31914882SAlex Richardson             }
240*31914882SAlex Richardson 
241*31914882SAlex Richardson             /*
242*31914882SAlex Richardson              * Test cases already set up by the input are not
243*31914882SAlex Richardson              * reprocessed by default, unlike the fplib tests. (This
244*31914882SAlex Richardson              * is mostly for historical reasons, because we used to
245*31914882SAlex Richardson              * use a very slow and incomplete internal reference
246*31914882SAlex Richardson              * implementation; now our ref impl is MPFR/MPC it
247*31914882SAlex Richardson              * probably wouldn't be such a bad idea, though we'd still
248*31914882SAlex Richardson              * have to make sure all the special cases came out
249*31914882SAlex Richardson              * right.) If translating==2 (corresponding to the -T
250*31914882SAlex Richardson              * command-line option) then we regenerate everything
251*31914882SAlex Richardson              * regardless.
252*31914882SAlex Richardson              */
253*31914882SAlex Richardson             if (got_result && translating < 2) {
254*31914882SAlex Richardson                 if (f)
255*31914882SAlex Richardson                     vet_for_decline(f, ops, result, got_errno_in);
256*31914882SAlex Richardson                 puts(sparebuf);
257*31914882SAlex Richardson                 continue;
258*31914882SAlex Richardson             }
259*31914882SAlex Richardson 
260*31914882SAlex Richardson             if (f && got_op==(1<<nargs_(f))-1) {
261*31914882SAlex Richardson                 /*
262*31914882SAlex Richardson                  * And do it!
263*31914882SAlex Richardson                  */
264*31914882SAlex Richardson                 docase(f, ops);
265*31914882SAlex Richardson             }
266*31914882SAlex Richardson         }
267*31914882SAlex Richardson     }
268*31914882SAlex Richardson }
269*31914882SAlex Richardson 
270*31914882SAlex Richardson int main(int argc, char **argv) {
271*31914882SAlex Richardson     int errs = 0, opts = 1, files = 0, translating = 0;
272*31914882SAlex Richardson     unsigned int seed = 1; /* in case no explicit seed provided */
273*31914882SAlex Richardson 
274*31914882SAlex Richardson     seed_random(seed);
275*31914882SAlex Richardson 
276*31914882SAlex Richardson     setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* stops incomplete lines being printed when out of time */
277*31914882SAlex Richardson 
278*31914882SAlex Richardson     while (--argc) {
279*31914882SAlex Richardson         FILE *fp;
280*31914882SAlex Richardson         char *p = *++argv;
281*31914882SAlex Richardson 
282*31914882SAlex Richardson         if (opts && *p == '-') {
283*31914882SAlex Richardson             if(*(p+1) == 0) { /* single -, read from stdin */
284*31914882SAlex Richardson                 break;
285*31914882SAlex Richardson             } else if (!strcmp(p, "-t")) {
286*31914882SAlex Richardson                 translating = 1;
287*31914882SAlex Richardson             } else if (!strcmp(p, "-T")) {
288*31914882SAlex Richardson                 translating = 2;
289*31914882SAlex Richardson             } else if (!strcmp(p, "-c")) {
290*31914882SAlex Richardson                 check_declines = 1;
291*31914882SAlex Richardson             } else if (!strcmp(p, "--")) {
292*31914882SAlex Richardson                 opts = 0;
293*31914882SAlex Richardson             } else if (!strcmp(p,"--seed") && argc > 1 && 1==sscanf(*(argv+1),"%u",&seed)) {
294*31914882SAlex Richardson                 seed_random(seed);
295*31914882SAlex Richardson                 argv++; /* next in argv is seed value, so skip */
296*31914882SAlex Richardson                 --argc;
297*31914882SAlex Richardson             } else if (!strcmp(p, "-fo")) {
298*31914882SAlex Richardson                 lib_fo = 1;
299*31914882SAlex Richardson             } else if (!strcmp(p, "-noarith")) {
300*31914882SAlex Richardson                 lib_no_arith = 1;
301*31914882SAlex Richardson             } else {
302*31914882SAlex Richardson                 fprintf(stderr,
303*31914882SAlex Richardson                         "rtest: ignoring unrecognised option '%s'\n", p);
304*31914882SAlex Richardson                 errs = 1;
305*31914882SAlex Richardson             }
306*31914882SAlex Richardson         } else {
307*31914882SAlex Richardson             files = 1;
308*31914882SAlex Richardson             if (!errs) {
309*31914882SAlex Richardson                 fp = fopen(p, "r");
310*31914882SAlex Richardson                 if (fp) {
311*31914882SAlex Richardson                     dofile(fp, translating);
312*31914882SAlex Richardson                     fclose(fp);
313*31914882SAlex Richardson                 } else {
314*31914882SAlex Richardson                     perror(p);
315*31914882SAlex Richardson                     errs = 1;
316*31914882SAlex Richardson                 }
317*31914882SAlex Richardson             }
318*31914882SAlex Richardson         }
319*31914882SAlex Richardson     }
320*31914882SAlex Richardson 
321*31914882SAlex Richardson     /*
322*31914882SAlex Richardson      * If no filename arguments, use stdin.
323*31914882SAlex Richardson      */
324*31914882SAlex Richardson     if (!files && !errs) {
325*31914882SAlex Richardson         dofile(stdin, translating);
326*31914882SAlex Richardson     }
327*31914882SAlex Richardson 
328*31914882SAlex Richardson     if (check_declines) {
329*31914882SAlex Richardson         fprintf(stderr, "Tests expected to run: %d\n", ntests);
330*31914882SAlex Richardson         fflush(stderr);
331*31914882SAlex Richardson     }
332*31914882SAlex Richardson 
333*31914882SAlex Richardson     return errs;
334*31914882SAlex Richardson }
335