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