@@ -26,27 +26,12 @@ mod musl_reference_tests {
2626
2727 // These files are all internal functions or otherwise miscellaneous, not
2828 // 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" ] ;
4530
4631 struct Function {
4732 name : String ,
4833 args : Vec < Ty > ,
49- ret : Ty ,
34+ ret : Vec < Ty > ,
5035 tests : Vec < Test > ,
5136 }
5237
@@ -59,7 +44,7 @@ mod musl_reference_tests {
5944
6045 struct Test {
6146 inputs : Vec < i64 > ,
62- output : i64 ,
47+ outputs : Vec < i64 > ,
6348 }
6449
6550 pub fn generate ( ) {
@@ -78,12 +63,9 @@ mod musl_reference_tests {
7863
7964 let contents = fs:: read_to_string ( file) . unwrap ( ) ;
8065 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) ) ;
8468 }
85-
86- math. push ( parse ( function_to_test) ) ;
8769 }
8870
8971 // Generate a bunch of random inputs for each function. This will
@@ -94,7 +76,7 @@ mod musl_reference_tests {
9476 // After we have all our inputs, use the x86_64-unknown-linux-musl
9577 // target to generate the expected output.
9678 generate_test_outputs ( & mut math) ;
97-
79+ //panic!("Boo");
9880 // ... and now that we have both inputs and expected outputs, do a bunch
9981 // of codegen to create the unit tests which we'll actually execute.
10082 generate_unit_tests ( & math) ;
@@ -116,7 +98,7 @@ mod musl_reference_tests {
11698 . collect :: < Vec < _ > > ( ) ;
11799 let tail = & s[ end + 1 ..] ;
118100 let tail = eat ( tail, " -> " ) ;
119- let ret = parse_ty ( tail. trim ( ) . split ( ' ' ) . next ( ) . unwrap ( ) ) ;
101+ let ret = parse_retty ( tail. replace ( "{" , "" ) . trim ( ) ) ;
120102
121103 return Function {
122104 name : name. to_string ( ) ,
@@ -135,6 +117,16 @@ mod musl_reference_tests {
135117 }
136118 }
137119
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+
138130 fn eat < ' a > ( s : & ' a str , prefix : & str ) -> & ' a str {
139131 if s. starts_with ( prefix) {
140132 & s[ prefix. len ( ) ..]
@@ -147,22 +139,59 @@ mod musl_reference_tests {
147139 fn generate_random_tests < R : Rng > ( functions : & mut [ Function ] , rng : & mut R ) {
148140 for function in functions {
149141 for _ in 0 ..NTESTS {
150- function. tests . push ( generate_test ( & function. args , rng) ) ;
142+ function. tests . push ( generate_test ( function, rng) ) ;
151143 }
152144 }
153145
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+ }
158166 }
159167 }
160168
161169 impl Ty {
162170 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+ }
166195 Ty :: I32 => {
167196 if r. gen_range ( 0 , 10 ) < 1 {
168197 let i = * [ i32:: max_value ( ) , 0 , i32:: min_value ( ) ] . choose ( r) . unwrap ( ) ;
@@ -172,7 +201,7 @@ mod musl_reference_tests {
172201 }
173202 }
174203 Ty :: Bool => r. gen :: < bool > ( ) as i64 ,
175- }
204+ } ;
176205 }
177206
178207 fn libc_ty ( & self ) -> & ' static str {
@@ -183,6 +212,33 @@ mod musl_reference_tests {
183212 Ty :: Bool => "i32" ,
184213 }
185214 }
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+ }
186242 }
187243
188244 fn generate_test_outputs ( functions : & mut [ Function ] ) {
@@ -200,11 +256,22 @@ mod musl_reference_tests {
200256 src. push_str ( "extern { fn " ) ;
201257 src. push_str ( & function. name ) ;
202258 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+ } ;
203264 for ( i, arg) in function. args . iter ( ) . enumerate ( ) {
204265 src. push_str ( & format ! ( "arg{}: {}," , i, arg. libc_ty( ) ) ) ;
205266 }
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+ }
208275 src. push_str ( "; }" ) ;
209276
210277 src. push_str ( & format ! ( "static TESTS: &[[i64; {}]]" , function. args. len( ) ) ) ;
@@ -220,6 +287,9 @@ mod musl_reference_tests {
220287 src. push_str ( "];" ) ;
221288
222289 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+ }
223293 src. push_str ( "let output = " ) ;
224294 src. push_str ( & function. name ) ;
225295 src. push_str ( "(" ) ;
@@ -232,17 +302,22 @@ mod musl_reference_tests {
232302 } ) ;
233303 src. push_str ( "," ) ;
234304 }
305+ for ( i, _) in retptr. iter ( ) . enumerate ( ) {
306+ src. push_str ( & format ! ( "&mut argret{}," , i) ) ;
307+ }
235308 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+ }
245313
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+ }
246321 src. push_str ( "}" ) ;
247322
248323 src. push_str ( "}" ) ;
@@ -279,8 +354,10 @@ mod musl_reference_tests {
279354 i64:: from_le_bytes ( exact)
280355 } ) ;
281356
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+ }
284361 }
285362 assert ! ( results. next( ) . is_none( ) ) ;
286363 }
@@ -297,8 +374,9 @@ mod musl_reference_tests {
297374 src. push_str ( & function. name ) ;
298375 src. push_str ( "_matches_musl() {" ) ;
299376 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( ) ,
302380 ) ) ;
303381 src. push_str ( " = &[" ) ;
304382 for test in function. tests . iter ( ) {
@@ -308,7 +386,12 @@ mod musl_reference_tests {
308386 src. push_str ( "," ) ;
309387 }
310388 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 ( "]," ) ;
312395 src. push_str ( ")," ) ;
313396 }
314397 src. push_str ( "];" ) ;
@@ -327,12 +410,20 @@ mod musl_reference_tests {
327410 src. push_str ( "," ) ;
328411 }
329412 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+ }
336427
337428 src. push_str (
338429 r#"
0 commit comments