1206917Smarius
2206917Smarius/*
3206917Smarius===============================================================================
4206917Smarius
5206917SmariusThis C source file is part of TestFloat, Release 2a, a package of programs
6206917Smariusfor testing the correctness of floating-point arithmetic complying to the
7206917SmariusIEC/IEEE Standard for Floating-Point.
8206917Smarius
9206917SmariusWritten by John R. Hauser.  More information is available through the Web
10206917Smariuspage `http://HTTP.CS.Berkeley.EDU/~jhauser/arithmetic/TestFloat.html'.
11206917Smarius
12206917SmariusTHIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
13206917Smariushas been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
14206917SmariusTIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
15206917SmariusPERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
16206917SmariusAND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
17206917Smarius
18206917SmariusDerivative works are acceptable, even for commercial purposes, so long as
19206917Smarius(1) they include prominent notice that the work is derivative, and (2) they
20206917Smariusinclude prominent notice akin to these four paragraphs for those parts of
21206917Smariusthis code that are retained.
22206917Smarius
23206917Smarius===============================================================================
24206917Smarius*/
25206917Smarius
26207151Smarius#include <sys/cdefs.h>
27207151Smarius__FBSDID("$FreeBSD: releng/11.0/tools/test/testfloat/testfloat.c 207151 2010-04-24 12:11:41Z marius $");
28207151Smarius
29206917Smarius#include <stdlib.h>
30206917Smarius#include <signal.h>
31206917Smarius#include <string.h>
32206917Smarius#include "milieu.h"
33206917Smarius#include "fail.h"
34206917Smarius#include "softfloat.h"
35206917Smarius#include "testCases.h"
36206917Smarius#include "testLoops.h"
37206917Smarius#include "systflags.h"
38206917Smarius#include "testFunction.h"
39206917Smarius
40206917Smariusstatic void catchSIGINT( int signalCode )
41206917Smarius{
42206917Smarius
43206917Smarius    if ( stop ) exit( EXIT_FAILURE );
44206917Smarius    stop = TRUE;
45206917Smarius
46206917Smarius}
47206917Smarius
48207151Smariusint
49206917Smariusmain( int argc, char **argv )
50206917Smarius{
51206917Smarius    char *argPtr;
52206917Smarius    flag functionArgument;
53206917Smarius    uint8 functionCode;
54206917Smarius    int8 operands, roundingPrecision, roundingMode;
55206917Smarius
56206917Smarius    fail_programName = "testfloat";
57206917Smarius    if ( argc <= 1 ) goto writeHelpMessage;
58206917Smarius    testCases_setLevel( 1 );
59206917Smarius    trueName = "soft";
60206917Smarius    testName = "syst";
61206917Smarius    errorStop = FALSE;
62206917Smarius    forever = FALSE;
63206917Smarius    maxErrorCount = 20;
64206917Smarius    trueFlagsPtr = &float_exception_flags;
65206917Smarius    testFlagsFunctionPtr = syst_float_flags_clear;
66206917Smarius    tininessModeName = 0;
67206917Smarius    functionArgument = FALSE;
68206917Smarius    functionCode = 0;
69206917Smarius    operands = 0;
70206917Smarius    roundingPrecision = 0;
71206917Smarius    roundingMode = 0;
72206917Smarius    --argc;
73206917Smarius    ++argv;
74206917Smarius    while ( argc && ( argPtr = argv[ 0 ] ) ) {
75206917Smarius        if ( argPtr[ 0 ] == '-' ) ++argPtr;
76206917Smarius        if ( strcmp( argPtr, "help" ) == 0 ) {
77206917Smarius writeHelpMessage:
78206917Smarius            fputs(
79206917Smarius"testfloat [<option>...] <function>\n"
80206917Smarius"  <option>:  (* is default)\n"
81206917Smarius"    -help            --Write this message and exit.\n"
82206917Smarius"    -list            --List all testable functions and exit.\n"
83206917Smarius"    -level <num>     --Testing level <num> (1 or 2).\n"
84206917Smarius" *  -level 1\n"
85206917Smarius"    -errors <num>    --Stop each function test after <num> errors.\n"
86206917Smarius" *  -errors 20\n"
87206917Smarius"    -errorstop       --Exit after first function with any error.\n"
88206917Smarius"    -forever         --Test one function repeatedly (implies `-level 2').\n"
89206917Smarius"    -checkNaNs       --Check for bitwise correctness of NaN results.\n"
90206917Smarius#ifdef FLOATX80
91206917Smarius"    -precision32     --Only test rounding precision equivalent to float32.\n"
92206917Smarius"    -precision64     --Only test rounding precision equivalent to float64.\n"
93206917Smarius"    -precision80     --Only test maximum rounding precision.\n"
94206917Smarius#endif
95206917Smarius"    -nearesteven     --Only test rounding to nearest/even.\n"
96206917Smarius"    -tozero          --Only test rounding to zero.\n"
97206917Smarius"    -down            --Only test rounding down.\n"
98206917Smarius"    -up              --Only test rounding up.\n"
99206917Smarius"    -tininessbefore  --Underflow tininess detected before rounding.\n"
100206917Smarius"    -tininessafter   --Underflow tininess detected after rounding.\n"
101206917Smarius"  <function>:\n"
102206917Smarius"    int32_to_<float>                 <float>_add   <float>_eq\n"
103206917Smarius"    <float>_to_int32                 <float>_sub   <float>_le\n"
104206917Smarius"    <float>_to_int32_round_to_zero   <float>_mul   <float>_lt\n"
105206917Smarius#ifdef BITS64
106206917Smarius"    int64_to_<float>                 <float>_div   <float>_eq_signaling\n"
107206917Smarius"    <float>_to_int64                 <float>_rem   <float>_le_quiet\n"
108206917Smarius"    <float>_to_int64_round_to_zero                 <float>_lt_quiet\n"
109206917Smarius"    <float>_to_<float>\n"
110206917Smarius"    <float>_round_to_int\n"
111206917Smarius"    <float>_sqrt\n"
112206917Smarius#else
113206917Smarius"    <float>_to_<float>               <float>_div   <float>_eq_signaling\n"
114206917Smarius"    <float>_round_to_int             <float>_rem   <float>_le_quiet\n"
115206917Smarius"    <float>_sqrt                                   <float>_lt_quiet\n"
116206917Smarius#endif
117206917Smarius"    -all1            --All 1-operand functions.\n"
118206917Smarius"    -all2            --All 2-operand functions.\n"
119206917Smarius"    -all             --All functions.\n"
120206917Smarius"  <float>:\n"
121206917Smarius"    float32          --Single precision.\n"
122206917Smarius"    float64          --Double precision.\n"
123206917Smarius#ifdef FLOATX80
124206917Smarius"    floatx80         --Extended double precision.\n"
125206917Smarius#endif
126206917Smarius#ifdef FLOAT128
127206917Smarius"    float128         --Quadruple precision.\n"
128206917Smarius#endif
129206917Smarius                ,
130206917Smarius                stdout
131206917Smarius            );
132206917Smarius            return EXIT_SUCCESS;
133206917Smarius        }
134206917Smarius        else if ( strcmp( argPtr, "list" ) == 0 ) {
135206917Smarius            for ( functionCode = 1;
136206917Smarius                  functionCode < NUM_FUNCTIONS;
137206917Smarius                  ++functionCode
138206917Smarius                ) {
139206917Smarius                if ( functionExists[ functionCode ] ) {
140206917Smarius                    puts( functions[ functionCode ].name );
141206917Smarius                }
142206917Smarius            }
143206917Smarius            return EXIT_SUCCESS;
144206917Smarius        }
145206917Smarius        else if ( strcmp( argPtr, "level" ) == 0 ) {
146206917Smarius            if ( argc < 2 ) goto optionError;
147206917Smarius            testCases_setLevel( atoi( argv[ 1 ] ) );
148206917Smarius            --argc;
149206917Smarius            ++argv;
150206917Smarius        }
151206917Smarius        else if ( strcmp( argPtr, "level1" ) == 0 ) {
152206917Smarius            testCases_setLevel( 1 );
153206917Smarius        }
154206917Smarius        else if ( strcmp( argPtr, "level2" ) == 0 ) {
155206917Smarius            testCases_setLevel( 2 );
156206917Smarius        }
157206917Smarius        else if ( strcmp( argPtr, "errors" ) == 0 ) {
158206917Smarius            if ( argc < 2 ) {
159206917Smarius     optionError:
160206917Smarius                fail( "`%s' option requires numeric argument", argv[ 0 ] );
161206917Smarius            }
162206917Smarius            maxErrorCount = atoi( argv[ 1 ] );
163206917Smarius            --argc;
164206917Smarius            ++argv;
165206917Smarius        }
166206917Smarius        else if ( strcmp( argPtr, "errorstop" ) == 0 ) {
167206917Smarius            errorStop = TRUE;
168206917Smarius        }
169206917Smarius        else if ( strcmp( argPtr, "forever" ) == 0 ) {
170206917Smarius            testCases_setLevel( 2 );
171206917Smarius            forever = TRUE;
172206917Smarius        }
173206917Smarius        else if (    ( strcmp( argPtr, "checkNaNs" ) == 0 )
174206917Smarius                  || ( strcmp( argPtr, "checknans" ) == 0 ) ) {
175206917Smarius            checkNaNs = TRUE;
176206917Smarius        }
177206917Smarius#ifdef FLOATX80
178206917Smarius        else if ( strcmp( argPtr, "precision32" ) == 0 ) {
179206917Smarius            roundingPrecision = 32;
180206917Smarius        }
181206917Smarius        else if ( strcmp( argPtr, "precision64" ) == 0 ) {
182206917Smarius            roundingPrecision = 64;
183206917Smarius        }
184206917Smarius        else if ( strcmp( argPtr, "precision80" ) == 0 ) {
185206917Smarius            roundingPrecision = 80;
186206917Smarius        }
187206917Smarius#endif
188206917Smarius        else if (    ( strcmp( argPtr, "nearesteven" ) == 0 )
189206917Smarius                  || ( strcmp( argPtr, "nearest_even" ) == 0 ) ) {
190206917Smarius            roundingMode = ROUND_NEAREST_EVEN;
191206917Smarius        }
192206917Smarius        else if (    ( strcmp( argPtr, "tozero" ) == 0 )
193206917Smarius                  || ( strcmp( argPtr, "to_zero" ) == 0 ) ) {
194206917Smarius            roundingMode = ROUND_TO_ZERO;
195206917Smarius        }
196206917Smarius        else if ( strcmp( argPtr, "down" ) == 0 ) {
197206917Smarius            roundingMode = ROUND_DOWN;
198206917Smarius        }
199206917Smarius        else if ( strcmp( argPtr, "up" ) == 0 ) {
200206917Smarius            roundingMode = ROUND_UP;
201206917Smarius        }
202206917Smarius        else if ( strcmp( argPtr, "tininessbefore" ) == 0 ) {
203206917Smarius            float_detect_tininess = float_tininess_before_rounding;
204206917Smarius        }
205206917Smarius        else if ( strcmp( argPtr, "tininessafter" ) == 0 ) {
206206917Smarius            float_detect_tininess = float_tininess_after_rounding;
207206917Smarius        }
208206917Smarius        else if ( strcmp( argPtr, "all1" ) == 0 ) {
209206917Smarius            functionArgument = TRUE;
210206917Smarius            functionCode = 0;
211206917Smarius            operands = 1;
212206917Smarius        }
213206917Smarius        else if ( strcmp( argPtr, "all2" ) == 0 ) {
214206917Smarius            functionArgument = TRUE;
215206917Smarius            functionCode = 0;
216206917Smarius            operands = 2;
217206917Smarius        }
218206917Smarius        else if ( strcmp( argPtr, "all" ) == 0 ) {
219206917Smarius            functionArgument = TRUE;
220206917Smarius            functionCode = 0;
221206917Smarius            operands = 0;
222206917Smarius        }
223206917Smarius        else {
224206917Smarius            for ( functionCode = 1;
225206917Smarius                  functionCode < NUM_FUNCTIONS;
226206917Smarius                  ++functionCode
227206917Smarius                ) {
228206917Smarius                if ( strcmp( argPtr, functions[ functionCode ].name ) == 0 ) {
229206917Smarius                    break;
230206917Smarius                }
231206917Smarius            }
232206917Smarius            if ( functionCode == NUM_FUNCTIONS ) {
233206917Smarius                fail( "Invalid option or function `%s'", argv[ 0 ] );
234206917Smarius            }
235206917Smarius            if ( ! functionExists[ functionCode ] ) {
236206917Smarius                fail(
237206917Smarius                    "Function `%s' is not supported or cannot be tested",
238206917Smarius                    argPtr
239206917Smarius                );
240206917Smarius            }
241206917Smarius            functionArgument = TRUE;
242206917Smarius        }
243206917Smarius        --argc;
244206917Smarius        ++argv;
245206917Smarius    }
246206917Smarius    if ( ! functionArgument ) fail( "Function argument required" );
247206917Smarius    (void) signal( SIGINT, catchSIGINT );
248206917Smarius    (void) signal( SIGTERM, catchSIGINT );
249206917Smarius    if ( functionCode ) {
250206917Smarius        if ( forever ) {
251206917Smarius            if ( ! roundingPrecision ) roundingPrecision = 80;
252206917Smarius            if ( ! roundingMode ) roundingMode = ROUND_NEAREST_EVEN;
253206917Smarius        }
254206917Smarius        testFunction( functionCode, roundingPrecision, roundingMode );
255206917Smarius    }
256206917Smarius    else {
257206917Smarius        if ( forever ) {
258206917Smarius            fail( "Can only test one function with `-forever' option" );
259206917Smarius        }
260206917Smarius        if ( operands == 1 ) {
261206917Smarius            for ( functionCode = 1;
262206917Smarius                  functionCode < NUM_FUNCTIONS;
263206917Smarius                  ++functionCode
264206917Smarius                ) {
265206917Smarius                if (    functionExists[ functionCode ]
266206917Smarius                     && ( functions[ functionCode ].numInputs == 1 ) ) {
267206917Smarius                    testFunction(
268206917Smarius                        functionCode, roundingPrecision, roundingMode );
269206917Smarius                }
270206917Smarius            }
271206917Smarius        }
272206917Smarius        else if ( operands == 2 ) {
273206917Smarius            for ( functionCode = 1;
274206917Smarius                  functionCode < NUM_FUNCTIONS;
275206917Smarius                  ++functionCode
276206917Smarius                ) {
277206917Smarius                if (    functionExists[ functionCode ]
278206917Smarius                     && ( functions[ functionCode ].numInputs == 2 ) ) {
279206917Smarius                    testFunction(
280206917Smarius                        functionCode, roundingPrecision, roundingMode );
281206917Smarius                }
282206917Smarius            }
283206917Smarius        }
284206917Smarius        else {
285206917Smarius            for ( functionCode = 1;
286206917Smarius                  functionCode < NUM_FUNCTIONS;
287206917Smarius                  ++functionCode
288206917Smarius                ) {
289206917Smarius                if ( functionExists[ functionCode ] ) {
290206917Smarius                    testFunction(
291206917Smarius                        functionCode, roundingPrecision, roundingMode );
292206917Smarius                }
293206917Smarius            }
294206917Smarius        }
295206917Smarius    }
296206917Smarius    exitWithStatus();
297206917Smarius
298206917Smarius}
299206917Smarius
300