brintos

brintos / llvm-project-archived public Read only

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