Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit 1815b8e

Browse files
authored
Merge pull request #163 from burrbull/m1elports
other functions from musl
2 parents d2d6158 + 1529836 commit 1815b8e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+4512
-110
lines changed

libm/build.rs

Lines changed: 147 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)