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