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