4 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 * See https://llvm.org/LICENSE.txt for license information.
6 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
18 void gencases(Testable
*fn
, int number
);
19 void docase(Testable
*fn
, uint32
*args
);
20 void vet_for_decline(Testable
*fn
, uint32
*args
, uint32
*result
, int got_errno_in
);
21 void seed_random(uint32 seed
);
23 int check_declines
= 0;
28 int nargs_(Testable
* f
) {
51 static int isdouble(Testable
*f
)
83 assert(0 && "Bad function type");
87 Testable
*find_function(const char *func
)
90 for (i
= 0; i
< nfunctions
; i
++) {
91 if (func
&& !strcmp(func
, functions
[i
].name
)) {
98 void get_operand(const char *str
, Testable
*f
, uint32
*word0
, uint32
*word1
)
101 unsigned dblword0
, dblword1
, sglword
;
104 {0x00000000,0x00000000,0x00000000,"0"},
105 {0x3FF00000,0x00000000,0x3f800000,"1"},
106 {0x7FF00000,0x00000000,0x7f800000,"inf"},
107 {0x7FF80000,0x00000001,0x7fc00000,"qnan"},
108 {0x7FF00000,0x00000001,0x7f800001,"snan"},
109 {0x3ff921fb,0x54442d18,0x3fc90fdb,"pi2"},
110 {0x400921fb,0x54442d18,0x40490fdb,"pi"},
111 {0x3fe921fb,0x54442d18,0x3f490fdb,"pi4"},
112 {0x4002d97c,0x7f3321d2,0x4016cbe4,"3pi4"},
116 for (i
= 0; i
< (int)(sizeof(specials
)/sizeof(*specials
)); i
++) {
117 if (!strcmp(str
, specials
[i
].name
) ||
118 ((str
[0] == '-' || str
[0] == '+') &&
119 !strcmp(str
+1, specials
[i
].name
))) {
122 *word0
= specials
[i
].dblword0
;
123 *word1
= specials
[i
].dblword1
;
125 *word0
= specials
[i
].sglword
;
129 *word0
|= 0x80000000U
;
134 sscanf(str
, "%"I32
"x.%"I32
"x", word0
, word1
);
137 void dofile(FILE *fp
, int translating
) {
138 char buf
[1024], sparebuf
[1024], *p
;
143 * - "seed <integer>" sets a random seed
145 * - "test <function> <ntests>" generates random test lines
147 * - "<function> op1=foo [op2=bar]" generates a specific test
148 * - "func=<function> op1=foo [op2=bar]" does the same
149 * - "func=<function> op1=foo result=bar" will just output the line as-is
151 * - a semicolon or a blank line is ignored
153 while (fgets(buf
, sizeof(buf
), fp
)) {
154 buf
[strcspn(buf
, "\r\n")] = '\0';
155 strcpy(sparebuf
, buf
);
157 while (*p
&& isspace(*p
)) p
++;
158 if (!*p
|| *p
== ';') {
159 /* Comment or blank line. Only print if `translating' is set. */
164 if (!strncmp(buf
, "seed ", 5)) {
165 seed_random(atoi(buf
+5));
166 } else if (!strncmp(buf
, "random=", 7)) {
168 * Copy 'random=on' / 'random=off' lines unconditionally
169 * to the output, so that random test failures can be
170 * accumulated into a recent-failures-list file and
171 * still identified as random-in-origin when re-run the
175 } else if (!strncmp(buf
, "test ", 5)) {
180 while (*p
&& !isspace(*p
)) p
++;
182 while (*p
&& isspace(*p
)) p
++;
186 ntests
= 100; /* *shrug* */
187 for (i
= 0; i
< nfunctions
; i
++) {
188 if (!strcmp(q
, functions
[i
].name
)) {
189 gencases(&functions
[i
], ntests
);
193 if (i
== nfunctions
) {
194 fprintf(stderr
, "unknown test `%s'\n", q
);
198 * Parse a specific test line.
200 uint32 ops
[8], result
[8];
201 int got_op
= 0; /* &1 for got_op1, &4 for got_op3 etc. */
204 int got_result
= 0, got_errno_in
= 0;
206 for (q
= strtok(p
, " \t"); q
; q
= strtok(NULL
, " \t")) {
209 f
= find_function(q
);
213 if (!strcmp(q
, "func"))
214 f
= find_function(r
);
215 else if (!strcmp(q
, "op1") || !strcmp(q
, "op1r")) {
216 get_operand(r
, f
, &ops
[0], &ops
[1]);
218 } else if (!strcmp(q
, "op2") || !strcmp(q
, "op1i")) {
219 get_operand(r
, f
, &ops
[2], &ops
[3]);
221 } else if (!strcmp(q
, "op2r")) {
222 get_operand(r
, f
, &ops
[4], &ops
[5]);
224 } else if (!strcmp(q
, "op2i")) {
225 get_operand(r
, f
, &ops
[6], &ops
[7]);
227 } else if (!strcmp(q
, "result") || !strcmp(q
, "resultr")) {
228 get_operand(r
, f
, &result
[0], &result
[1]);
230 } else if (!strcmp(q
, "resulti")) {
231 get_operand(r
, f
, &result
[4], &result
[5]);
233 } else if (!strcmp(q
, "res2")) {
234 get_operand(r
, f
, &result
[2], &result
[3]);
236 } else if (!strcmp(q
, "errno_in")) {
243 * Test cases already set up by the input are not
244 * reprocessed by default, unlike the fplib tests. (This
245 * is mostly for historical reasons, because we used to
246 * use a very slow and incomplete internal reference
247 * implementation; now our ref impl is MPFR/MPC it
248 * probably wouldn't be such a bad idea, though we'd still
249 * have to make sure all the special cases came out
250 * right.) If translating==2 (corresponding to the -T
251 * command-line option) then we regenerate everything
254 if (got_result
&& translating
< 2) {
256 vet_for_decline(f
, ops
, result
, got_errno_in
);
261 if (f
&& got_op
==(1<<nargs_(f
))-1) {
271 int main(int argc
, char **argv
) {
272 int errs
= 0, opts
= 1, files
= 0, translating
= 0;
273 unsigned int seed
= 1; /* in case no explicit seed provided */
277 setvbuf(stdout
, NULL
, _IOLBF
, BUFSIZ
); /* stops incomplete lines being printed when out of time */
283 if (opts
&& *p
== '-') {
284 if(*(p
+1) == 0) { /* single -, read from stdin */
286 } else if (!strcmp(p
, "-t")) {
288 } else if (!strcmp(p
, "-T")) {
290 } else if (!strcmp(p
, "-c")) {
292 } else if (!strcmp(p
, "--")) {
294 } else if (!strcmp(p
,"--seed") && argc
> 1 && 1==sscanf(*(argv
+1),"%u",&seed
)) {
296 argv
++; /* next in argv is seed value, so skip */
298 } else if (!strcmp(p
, "-fo")) {
300 } else if (!strcmp(p
, "-noarith")) {
304 "rtest: ignoring unrecognised option '%s'\n", p
);
312 dofile(fp
, translating
);
323 * If no filename arguments, use stdin.
325 if (!files
&& !errs
) {
326 dofile(stdin
, translating
);
329 if (check_declines
) {
330 fprintf(stderr
, "Tests expected to run: %d\n", ntests
);