1
2 /*
3 ===============================================================================
4
5 This C source file is part of TestFloat, Release 2a, a package of programs
6 for testing the correctness of floating-point arithmetic complying to the
7 IEC/IEEE Standard for Floating-Point.
8
9 Written by John R. Hauser. More information is available through the Web
10 page `http://HTTP.CS.Berkeley.EDU/~jhauser/arithmetic/TestFloat.html'.
11
12 THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
13 has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
14 TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
15 PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
16 AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
17
18 Derivative works are acceptable, even for commercial purposes, so long as
19 (1) they include prominent notice that the work is derivative, and (2) they
20 include prominent notice akin to these four paragraphs for those parts of
21 this code that are retained.
22
23 ===============================================================================
24 */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
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
catchSIGINT(int signalCode)40 static void catchSIGINT( int signalCode )
41 {
42
43 if ( stop ) exit( EXIT_FAILURE );
44 stop = TRUE;
45
46 }
47
48 int
main(int argc,char ** argv)49 main( 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