1
2/*
3===============================================================================
4
5This C source file is part of TestFloat, Release 2a, a package of programs
6for testing the correctness of floating-point arithmetic complying to the
7IEC/IEEE Standard for Floating-Point.
8
9Written by John R. Hauser.  More information is available through the Web
10page `http://HTTP.CS.Berkeley.EDU/~jhauser/arithmetic/TestFloat.html'.
11
12THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
13has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
14TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
15PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
16AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
17
18Derivative works are acceptable, even for commercial purposes, so long as
19(1) they include prominent notice that the work is derivative, and (2) they
20include prominent notice akin to these four paragraphs for those parts of
21this code that are retained.
22
23===============================================================================
24*/
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: releng/11.0/tools/test/testfloat/testfloat.c 207151 2010-04-24 12:11:41Z marius $");
28
29#include <stdlib.h>
30#include <signal.h>
31#include <string.h>
32#include "milieu.h"
33#include "fail.h"
34#include "softfloat.h"
35#include "testCases.h"
36#include "testLoops.h"
37#include "systflags.h"
38#include "testFunction.h"
39
40static void catchSIGINT( int signalCode )
41{
42
43    if ( stop ) exit( EXIT_FAILURE );
44    stop = TRUE;
45
46}
47
48int
49main( int argc, char **argv )
50{
51    char *argPtr;
52    flag functionArgument;
53    uint8 functionCode;
54    int8 operands, roundingPrecision, roundingMode;
55
56    fail_programName = "testfloat";
57    if ( argc <= 1 ) goto writeHelpMessage;
58    testCases_setLevel( 1 );
59    trueName = "soft";
60    testName = "syst";
61    errorStop = FALSE;
62    forever = FALSE;
63    maxErrorCount = 20;
64    trueFlagsPtr = &float_exception_flags;
65    testFlagsFunctionPtr = syst_float_flags_clear;
66    tininessModeName = 0;
67    functionArgument = FALSE;
68    functionCode = 0;
69    operands = 0;
70    roundingPrecision = 0;
71    roundingMode = 0;
72    --argc;
73    ++argv;
74    while ( argc && ( argPtr = argv[ 0 ] ) ) {
75        if ( argPtr[ 0 ] == '-' ) ++argPtr;
76        if ( strcmp( argPtr, "help" ) == 0 ) {
77 writeHelpMessage:
78            fputs(
79"testfloat [<option>...] <function>\n"
80"  <option>:  (* is default)\n"
81"    -help            --Write this message and exit.\n"
82"    -list            --List all testable functions and exit.\n"
83"    -level <num>     --Testing level <num> (1 or 2).\n"
84" *  -level 1\n"
85"    -errors <num>    --Stop each function test after <num> errors.\n"
86" *  -errors 20\n"
87"    -errorstop       --Exit after first function with any error.\n"
88"    -forever         --Test one function repeatedly (implies `-level 2').\n"
89"    -checkNaNs       --Check for bitwise correctness of NaN results.\n"
90#ifdef FLOATX80
91"    -precision32     --Only test rounding precision equivalent to float32.\n"
92"    -precision64     --Only test rounding precision equivalent to float64.\n"
93"    -precision80     --Only test maximum rounding precision.\n"
94#endif
95"    -nearesteven     --Only test rounding to nearest/even.\n"
96"    -tozero          --Only test rounding to zero.\n"
97"    -down            --Only test rounding down.\n"
98"    -up              --Only test rounding up.\n"
99"    -tininessbefore  --Underflow tininess detected before rounding.\n"
100"    -tininessafter   --Underflow tininess detected after rounding.\n"
101"  <function>:\n"
102"    int32_to_<float>                 <float>_add   <float>_eq\n"
103"    <float>_to_int32                 <float>_sub   <float>_le\n"
104"    <float>_to_int32_round_to_zero   <float>_mul   <float>_lt\n"
105#ifdef BITS64
106"    int64_to_<float>                 <float>_div   <float>_eq_signaling\n"
107"    <float>_to_int64                 <float>_rem   <float>_le_quiet\n"
108"    <float>_to_int64_round_to_zero                 <float>_lt_quiet\n"
109"    <float>_to_<float>\n"
110"    <float>_round_to_int\n"
111"    <float>_sqrt\n"
112#else
113"    <float>_to_<float>               <float>_div   <float>_eq_signaling\n"
114"    <float>_round_to_int             <float>_rem   <float>_le_quiet\n"
115"    <float>_sqrt                                   <float>_lt_quiet\n"
116#endif
117"    -all1            --All 1-operand functions.\n"
118"    -all2            --All 2-operand functions.\n"
119"    -all             --All functions.\n"
120"  <float>:\n"
121"    float32          --Single precision.\n"
122"    float64          --Double precision.\n"
123#ifdef FLOATX80
124"    floatx80         --Extended double precision.\n"
125#endif
126#ifdef FLOAT128
127"    float128         --Quadruple precision.\n"
128#endif
129                ,
130                stdout
131            );
132            return EXIT_SUCCESS;
133        }
134        else if ( strcmp( argPtr, "list" ) == 0 ) {
135            for ( functionCode = 1;
136                  functionCode < NUM_FUNCTIONS;
137                  ++functionCode
138                ) {
139                if ( functionExists[ functionCode ] ) {
140                    puts( functions[ functionCode ].name );
141                }
142            }
143            return EXIT_SUCCESS;
144        }
145        else if ( strcmp( argPtr, "level" ) == 0 ) {
146            if ( argc < 2 ) goto optionError;
147            testCases_setLevel( atoi( argv[ 1 ] ) );
148            --argc;
149            ++argv;
150        }
151        else if ( strcmp( argPtr, "level1" ) == 0 ) {
152            testCases_setLevel( 1 );
153        }
154        else if ( strcmp( argPtr, "level2" ) == 0 ) {
155            testCases_setLevel( 2 );
156        }
157        else if ( strcmp( argPtr, "errors" ) == 0 ) {
158            if ( argc < 2 ) {
159     optionError:
160                fail( "`%s' option requires numeric argument", argv[ 0 ] );
161            }
162            maxErrorCount = atoi( argv[ 1 ] );
163            --argc;
164            ++argv;
165        }
166        else if ( strcmp( argPtr, "errorstop" ) == 0 ) {
167            errorStop = TRUE;
168        }
169        else if ( strcmp( argPtr, "forever" ) == 0 ) {
170            testCases_setLevel( 2 );
171            forever = TRUE;
172        }
173        else if (    ( strcmp( argPtr, "checkNaNs" ) == 0 )
174                  || ( strcmp( argPtr, "checknans" ) == 0 ) ) {
175            checkNaNs = TRUE;
176        }
177#ifdef FLOATX80
178        else if ( strcmp( argPtr, "precision32" ) == 0 ) {
179            roundingPrecision = 32;
180        }
181        else if ( strcmp( argPtr, "precision64" ) == 0 ) {
182            roundingPrecision = 64;
183        }
184        else if ( strcmp( argPtr, "precision80" ) == 0 ) {
185            roundingPrecision = 80;
186        }
187#endif
188        else if (    ( strcmp( argPtr, "nearesteven" ) == 0 )
189                  || ( strcmp( argPtr, "nearest_even" ) == 0 ) ) {
190            roundingMode = ROUND_NEAREST_EVEN;
191        }
192        else if (    ( strcmp( argPtr, "tozero" ) == 0 )
193                  || ( strcmp( argPtr, "to_zero" ) == 0 ) ) {
194            roundingMode = ROUND_TO_ZERO;
195        }
196        else if ( strcmp( argPtr, "down" ) == 0 ) {
197            roundingMode = ROUND_DOWN;
198        }
199        else if ( strcmp( argPtr, "up" ) == 0 ) {
200            roundingMode = ROUND_UP;
201        }
202        else if ( strcmp( argPtr, "tininessbefore" ) == 0 ) {
203            float_detect_tininess = float_tininess_before_rounding;
204        }
205        else if ( strcmp( argPtr, "tininessafter" ) == 0 ) {
206            float_detect_tininess = float_tininess_after_rounding;
207        }
208        else if ( strcmp( argPtr, "all1" ) == 0 ) {
209            functionArgument = TRUE;
210            functionCode = 0;
211            operands = 1;
212        }
213        else if ( strcmp( argPtr, "all2" ) == 0 ) {
214            functionArgument = TRUE;
215            functionCode = 0;
216            operands = 2;
217        }
218        else if ( strcmp( argPtr, "all" ) == 0 ) {
219            functionArgument = TRUE;
220            functionCode = 0;
221            operands = 0;
222        }
223        else {
224            for ( functionCode = 1;
225                  functionCode < NUM_FUNCTIONS;
226                  ++functionCode
227                ) {
228                if ( strcmp( argPtr, functions[ functionCode ].name ) == 0 ) {
229                    break;
230                }
231            }
232            if ( functionCode == NUM_FUNCTIONS ) {
233                fail( "Invalid option or function `%s'", argv[ 0 ] );
234            }
235            if ( ! functionExists[ functionCode ] ) {
236                fail(
237                    "Function `%s' is not supported or cannot be tested",
238                    argPtr
239                );
240            }
241            functionArgument = TRUE;
242        }
243        --argc;
244        ++argv;
245    }
246    if ( ! functionArgument ) fail( "Function argument required" );
247    (void) signal( SIGINT, catchSIGINT );
248    (void) signal( SIGTERM, catchSIGINT );
249    if ( functionCode ) {
250        if ( forever ) {
251            if ( ! roundingPrecision ) roundingPrecision = 80;
252            if ( ! roundingMode ) roundingMode = ROUND_NEAREST_EVEN;
253        }
254        testFunction( functionCode, roundingPrecision, roundingMode );
255    }
256    else {
257        if ( forever ) {
258            fail( "Can only test one function with `-forever' option" );
259        }
260        if ( operands == 1 ) {
261            for ( functionCode = 1;
262                  functionCode < NUM_FUNCTIONS;
263                  ++functionCode
264                ) {
265                if (    functionExists[ functionCode ]
266                     && ( functions[ functionCode ].numInputs == 1 ) ) {
267                    testFunction(
268                        functionCode, roundingPrecision, roundingMode );
269                }
270            }
271        }
272        else if ( operands == 2 ) {
273            for ( functionCode = 1;
274                  functionCode < NUM_FUNCTIONS;
275                  ++functionCode
276                ) {
277                if (    functionExists[ functionCode ]
278                     && ( functions[ functionCode ].numInputs == 2 ) ) {
279                    testFunction(
280                        functionCode, roundingPrecision, roundingMode );
281                }
282            }
283        }
284        else {
285            for ( functionCode = 1;
286                  functionCode < NUM_FUNCTIONS;
287                  ++functionCode
288                ) {
289                if ( functionExists[ functionCode ] ) {
290                    testFunction(
291                        functionCode, roundingPrecision, roundingMode );
292                }
293            }
294        }
295    }
296    exitWithStatus();
297
298}
299
300