@@ -26,27 +26,12 @@ mod musl_reference_tests {
26
26
27
27
// These files are all internal functions or otherwise miscellaneous, not
28
28
// defining a function we want to test.
29
- const IGNORED_FILES : & [ & str ] = & [
30
- "expo2.rs" ,
31
- "fenv.rs" ,
32
- "k_cos.rs" ,
33
- "k_cosf.rs" ,
34
- "k_expo2.rs" ,
35
- "k_expo2f.rs" ,
36
- "k_sin.rs" ,
37
- "k_sinf.rs" ,
38
- "k_tan.rs" ,
39
- "k_tanf.rs" ,
40
- "mod.rs" ,
41
- "rem_pio2.rs" ,
42
- "rem_pio2_large.rs" ,
43
- "rem_pio2f.rs" ,
44
- ] ;
29
+ const IGNORED_FILES : & [ & str ] = & [ "fenv.rs" ] ;
45
30
46
31
struct Function {
47
32
name : String ,
48
33
args : Vec < Ty > ,
49
- ret : Ty ,
34
+ ret : Vec < Ty > ,
50
35
tests : Vec < Test > ,
51
36
}
52
37
@@ -59,7 +44,7 @@ mod musl_reference_tests {
59
44
60
45
struct Test {
61
46
inputs : Vec < i64 > ,
62
- output : i64 ,
47
+ outputs : Vec < i64 > ,
63
48
}
64
49
65
50
pub fn generate ( ) {
@@ -78,12 +63,9 @@ mod musl_reference_tests {
78
63
79
64
let contents = fs:: read_to_string ( file) . unwrap ( ) ;
80
65
let mut functions = contents. lines ( ) . filter ( |f| f. starts_with ( "pub fn" ) ) ;
81
- let function_to_test = functions. next ( ) . unwrap ( ) ;
82
- if functions. next ( ) . is_some ( ) {
83
- panic ! ( "more than one function in" ) ;
66
+ while let Some ( function_to_test) = functions. next ( ) {
67
+ math. push ( parse ( function_to_test) ) ;
84
68
}
85
-
86
- math. push ( parse ( function_to_test) ) ;
87
69
}
88
70
89
71
// Generate a bunch of random inputs for each function. This will
@@ -94,7 +76,7 @@ mod musl_reference_tests {
94
76
// After we have all our inputs, use the x86_64-unknown-linux-musl
95
77
// target to generate the expected output.
96
78
generate_test_outputs ( & mut math) ;
97
-
79
+ //panic!("Boo");
98
80
// ... and now that we have both inputs and expected outputs, do a bunch
99
81
// of codegen to create the unit tests which we'll actually execute.
100
82
generate_unit_tests ( & math) ;
@@ -116,7 +98,7 @@ mod musl_reference_tests {
116
98
. collect :: < Vec < _ > > ( ) ;
117
99
let tail = & s[ end + 1 ..] ;
118
100
let tail = eat ( tail, " -> " ) ;
119
- let ret = parse_ty ( tail. trim ( ) . split ( ' ' ) . next ( ) . unwrap ( ) ) ;
101
+ let ret = parse_retty ( tail. replace ( "{" , "" ) . trim ( ) ) ;
120
102
121
103
return Function {
122
104
name : name. to_string ( ) ,
@@ -135,6 +117,16 @@ mod musl_reference_tests {
135
117
}
136
118
}
137
119
120
+ fn parse_retty ( s : & str ) -> Vec < Ty > {
121
+ match s {
122
+ "(f32, f32)" => vec ! [ Ty :: F32 , Ty :: F32 ] ,
123
+ "(f32, i32)" => vec ! [ Ty :: F32 , Ty :: I32 ] ,
124
+ "(f64, f64)" => vec ! [ Ty :: F64 , Ty :: F64 ] ,
125
+ "(f64, i32)" => vec ! [ Ty :: F64 , Ty :: I32 ] ,
126
+ other => vec ! [ parse_ty( other) ] ,
127
+ }
128
+ }
129
+
138
130
fn eat < ' a > ( s : & ' a str , prefix : & str ) -> & ' a str {
139
131
if s. starts_with ( prefix) {
140
132
& s[ prefix. len ( ) ..]
@@ -147,22 +139,59 @@ mod musl_reference_tests {
147
139
fn generate_random_tests < R : Rng > ( functions : & mut [ Function ] , rng : & mut R ) {
148
140
for function in functions {
149
141
for _ in 0 ..NTESTS {
150
- function. tests . push ( generate_test ( & function. args , rng) ) ;
142
+ function. tests . push ( generate_test ( function, rng) ) ;
151
143
}
152
144
}
153
145
154
- fn generate_test < R : Rng > ( args : & [ Ty ] , rng : & mut R ) -> Test {
155
- let inputs = args. iter ( ) . map ( |ty| ty. gen_i64 ( rng) ) . collect ( ) ;
156
- // zero output for now since we'll generate it later
157
- Test { inputs, output : 0 }
146
+ fn generate_test < R : Rng > ( function : & Function , rng : & mut R ) -> Test {
147
+ let mut inputs = function
148
+ . args
149
+ . iter ( )
150
+ . map ( |ty| ty. gen_i64 ( rng) )
151
+ . collect :: < Vec < _ > > ( ) ;
152
+
153
+ // First argument to this function appears to be a number of
154
+ // iterations, so passing in massive random numbers causes it to
155
+ // take forever to execute, so make sure we're not running random
156
+ // math code until the heat death of the universe.
157
+ if function. name == "jn" || function. name == "jnf" {
158
+ inputs[ 0 ] &= 0xffff ;
159
+ }
160
+
161
+ Test {
162
+ inputs,
163
+ // zero output for now since we'll generate it later
164
+ outputs : vec ! [ ] ,
165
+ }
158
166
}
159
167
}
160
168
161
169
impl Ty {
162
170
fn gen_i64 < R : Rng > ( & self , r : & mut R ) -> i64 {
163
- match self {
164
- Ty :: F32 => r. gen :: < f32 > ( ) . to_bits ( ) . into ( ) ,
165
- Ty :: F64 => r. gen :: < f64 > ( ) . to_bits ( ) as i64 ,
171
+ use std:: f32;
172
+ use std:: f64;
173
+
174
+ return match self {
175
+ Ty :: F32 => {
176
+ if r. gen_range ( 0 , 20 ) < 1 {
177
+ let i = * [ f32:: NAN , f32:: INFINITY , f32:: NEG_INFINITY ]
178
+ . choose ( r)
179
+ . unwrap ( ) ;
180
+ i. to_bits ( ) . into ( )
181
+ } else {
182
+ r. gen :: < f32 > ( ) . to_bits ( ) . into ( )
183
+ }
184
+ }
185
+ Ty :: F64 => {
186
+ if r. gen_range ( 0 , 20 ) < 1 {
187
+ let i = * [ f64:: NAN , f64:: INFINITY , f64:: NEG_INFINITY ]
188
+ . choose ( r)
189
+ . unwrap ( ) ;
190
+ i. to_bits ( ) as i64
191
+ } else {
192
+ r. gen :: < f64 > ( ) . to_bits ( ) as i64
193
+ }
194
+ }
166
195
Ty :: I32 => {
167
196
if r. gen_range ( 0 , 10 ) < 1 {
168
197
let i = * [ i32:: max_value ( ) , 0 , i32:: min_value ( ) ] . choose ( r) . unwrap ( ) ;
@@ -172,7 +201,7 @@ mod musl_reference_tests {
172
201
}
173
202
}
174
203
Ty :: Bool => r. gen :: < bool > ( ) as i64 ,
175
- }
204
+ } ;
176
205
}
177
206
178
207
fn libc_ty ( & self ) -> & ' static str {
@@ -183,6 +212,33 @@ mod musl_reference_tests {
183
212
Ty :: Bool => "i32" ,
184
213
}
185
214
}
215
+
216
+ fn libc_pty ( & self ) -> & ' static str {
217
+ match self {
218
+ Ty :: F32 => "*mut f32" ,
219
+ Ty :: F64 => "*mut f64" ,
220
+ Ty :: I32 => "*mut i32" ,
221
+ Ty :: Bool => "*mut i32" ,
222
+ }
223
+ }
224
+
225
+ fn default ( & self ) -> & ' static str {
226
+ match self {
227
+ Ty :: F32 => "0_f32" ,
228
+ Ty :: F64 => "0_f64" ,
229
+ Ty :: I32 => "0_i32" ,
230
+ Ty :: Bool => "false" ,
231
+ }
232
+ }
233
+
234
+ fn to_i64 ( & self ) -> & ' static str {
235
+ match self {
236
+ Ty :: F32 => ".to_bits() as i64" ,
237
+ Ty :: F64 => ".to_bits() as i64" ,
238
+ Ty :: I32 => " as i64" ,
239
+ Ty :: Bool => " as i64" ,
240
+ }
241
+ }
186
242
}
187
243
188
244
fn generate_test_outputs ( functions : & mut [ Function ] ) {
@@ -200,11 +256,22 @@ mod musl_reference_tests {
200
256
src. push_str ( "extern { fn " ) ;
201
257
src. push_str ( & function. name ) ;
202
258
src. push_str ( "(" ) ;
259
+
260
+ let ( ret, retptr) = match function. name . as_str ( ) {
261
+ "sincos" | "sincosf" => ( None , & function. ret [ ..] ) ,
262
+ _ => ( Some ( & function. ret [ 0 ] ) , & function. ret [ 1 ..] ) ,
263
+ } ;
203
264
for ( i, arg) in function. args . iter ( ) . enumerate ( ) {
204
265
src. push_str ( & format ! ( "arg{}: {}," , i, arg. libc_ty( ) ) ) ;
205
266
}
206
- src. push_str ( ") -> " ) ;
207
- src. push_str ( function. ret . libc_ty ( ) ) ;
267
+ for ( i, ret) in retptr. iter ( ) . enumerate ( ) {
268
+ src. push_str ( & format ! ( "argret{}: {}," , i, ret. libc_pty( ) ) ) ;
269
+ }
270
+ src. push_str ( ")" ) ;
271
+ if let Some ( ty) = ret {
272
+ src. push_str ( " -> " ) ;
273
+ src. push_str ( ty. libc_ty ( ) ) ;
274
+ }
208
275
src. push_str ( "; }" ) ;
209
276
210
277
src. push_str ( & format ! ( "static TESTS: &[[i64; {}]]" , function. args. len( ) ) ) ;
@@ -220,6 +287,9 @@ mod musl_reference_tests {
220
287
src. push_str ( "];" ) ;
221
288
222
289
src. push_str ( "for test in TESTS {" ) ;
290
+ for ( i, arg) in retptr. iter ( ) . enumerate ( ) {
291
+ src. push_str ( & format ! ( "let mut argret{} = {};" , i, arg. default ( ) ) ) ;
292
+ }
223
293
src. push_str ( "let output = " ) ;
224
294
src. push_str ( & function. name ) ;
225
295
src. push_str ( "(" ) ;
@@ -232,17 +302,22 @@ mod musl_reference_tests {
232
302
} ) ;
233
303
src. push_str ( "," ) ;
234
304
}
305
+ for ( i, _) in retptr. iter ( ) . enumerate ( ) {
306
+ src. push_str ( & format ! ( "&mut argret{}," , i) ) ;
307
+ }
235
308
src. push_str ( ");" ) ;
236
- src. push_str ( "let output = " ) ;
237
- src. push_str ( match function. ret {
238
- Ty :: F32 => "output.to_bits() as i64" ,
239
- Ty :: F64 => "output.to_bits() as i64" ,
240
- Ty :: I32 => "output as i64" ,
241
- Ty :: Bool => "output as i64" ,
242
- } ) ;
243
- src. push_str ( ";" ) ;
244
- src. push_str ( "result.extend_from_slice(&output.to_le_bytes());" ) ;
309
+ if let Some ( ty) = & ret {
310
+ src. push_str ( & format ! ( "let output = output{};" , ty. to_i64( ) ) ) ;
311
+ src. push_str ( "result.extend_from_slice(&output.to_le_bytes());" ) ;
312
+ }
245
313
314
+ for ( i, ret) in retptr. iter ( ) . enumerate ( ) {
315
+ src. push_str ( & format ! (
316
+ "result.extend_from_slice(&(argret{}{}).to_le_bytes());" ,
317
+ i,
318
+ ret. to_i64( ) ,
319
+ ) ) ;
320
+ }
246
321
src. push_str ( "}" ) ;
247
322
248
323
src. push_str ( "}" ) ;
@@ -279,8 +354,10 @@ mod musl_reference_tests {
279
354
i64:: from_le_bytes ( exact)
280
355
} ) ;
281
356
282
- for test in functions. iter_mut ( ) . flat_map ( |f| f. tests . iter_mut ( ) ) {
283
- test. output = results. next ( ) . unwrap ( ) ;
357
+ for f in functions. iter_mut ( ) {
358
+ for test in f. tests . iter_mut ( ) {
359
+ test. outputs = ( 0 ..f. ret . len ( ) ) . map ( |_| results. next ( ) . unwrap ( ) ) . collect ( ) ;
360
+ }
284
361
}
285
362
assert ! ( results. next( ) . is_none( ) ) ;
286
363
}
@@ -297,8 +374,9 @@ mod musl_reference_tests {
297
374
src. push_str ( & function. name ) ;
298
375
src. push_str ( "_matches_musl() {" ) ;
299
376
src. push_str ( & format ! (
300
- "static TESTS: &[([i64; {}], i64)]" ,
301
- function. args. len( )
377
+ "static TESTS: &[([i64; {}], [i64; {}])]" ,
378
+ function. args. len( ) ,
379
+ function. ret. len( ) ,
302
380
) ) ;
303
381
src. push_str ( " = &[" ) ;
304
382
for test in function. tests . iter ( ) {
@@ -308,7 +386,12 @@ mod musl_reference_tests {
308
386
src. push_str ( "," ) ;
309
387
}
310
388
src. push_str ( "]," ) ;
311
- src. push_str ( & test. output . to_string ( ) ) ;
389
+ src. push_str ( "[" ) ;
390
+ for val in test. outputs . iter ( ) {
391
+ src. push_str ( & val. to_string ( ) ) ;
392
+ src. push_str ( "," ) ;
393
+ }
394
+ src. push_str ( "]," ) ;
312
395
src. push_str ( ")," ) ;
313
396
}
314
397
src. push_str ( "];" ) ;
@@ -327,12 +410,20 @@ mod musl_reference_tests {
327
410
src. push_str ( "," ) ;
328
411
}
329
412
src. push_str ( ");" ) ;
330
- src. push_str ( match function. ret {
331
- Ty :: F32 => "if _eqf(output, f32::from_bits(*expected as u32)).is_ok() { continue }" ,
332
- Ty :: F64 => "if _eq(output, f64::from_bits(*expected as u64)).is_ok() { continue }" ,
333
- Ty :: I32 => "if output as i64 == expected { continue }" ,
334
- Ty :: Bool => unreachable ! ( ) ,
335
- } ) ;
413
+
414
+ for ( i, ret) in function. ret . iter ( ) . enumerate ( ) {
415
+ let get = if function. ret . len ( ) == 1 {
416
+ String :: new ( )
417
+ } else {
418
+ format ! ( ".{}" , i)
419
+ } ;
420
+ src. push_str ( & ( match ret {
421
+ Ty :: F32 => format ! ( "if _eqf(output{}, f32::from_bits(expected[{}] as u32)).is_ok() {{ continue }}" , get, i) ,
422
+ Ty :: F64 => format ! ( "if _eq(output{}, f64::from_bits(expected[{}] as u64)).is_ok() {{ continue }}" , get, i) ,
423
+ Ty :: I32 => format ! ( "if output{} as i64 == expected[{}] {{ continue }}" , get, i) ,
424
+ Ty :: Bool => unreachable ! ( ) ,
425
+ } ) ) ;
426
+ }
336
427
337
428
src. push_str (
338
429
r#"
0 commit comments