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