#![feature(i128_type)] use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").unwrap(); // Emscripten's runtime includes all the builtins if target.contains("emscripten") { return; } // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the // target triple. This is usually correct for our built-in targets but can break in presence of // custom targets, which can have arbitrary names. let llvm_target = target.split('-').collect::>(); // Build test files tests::generate(); // Build missing intrinsics from compiler-rt C source code #[cfg(feature = "c")] c::compile(&llvm_target); // To compile intrinsics.rs for thumb targets, where there is no libc if llvm_target[0].starts_with("thumb") { println!("cargo:rustc-cfg=thumb") } // compiler-rt `cfg`s away some intrinsics for thumbv6m because that target doesn't have full // THUMBv2 support. We have to cfg our code accordingly. if llvm_target[0] == "thumbv6m" { println!("cargo:rustc-cfg=thumbv6m") } } mod tests { extern crate rand; use std::collections::HashSet; use std::fmt::Write; use std::fs::File; use std::hash::Hash; use std::path::PathBuf; use std::{env, mem}; use self::rand::Rng; const NTESTS: usize = 10_000; macro_rules! test { ($($intrinsic:ident,)+) => { $( mk_file::<$intrinsic>(); )+ } } pub fn generate() { // TODO move to main test! { // float/add.rs Adddf3, Addsf3, // float/conv.rs // Fixdfdi, // Fixdfsi, // Fixsfdi, // Fixsfsi, // Fixunsdfdi, // Fixunsdfsi, // Fixunssfdi, // Fixunssfsi, // Floatdidf, // Floatsidf, // Floatsisf, // Floatundidf, // Floatunsidf, // Floatunsisf, // float/pow.rs Powidf2, Powisf2, // float/sub.rs Subdf3, Subsf3, // int/mul.rs Muldi3, Mulodi4, Mulosi4, Muloti4, Multi3, // int/sdiv.rs Divdi3, Divmoddi4, Divmodsi4, Divsi3, Divti3, Moddi3, Modsi3, Modti3, // int/shift.rs Ashldi3, Ashlti3, Ashrdi3, Ashrti3, Lshrdi3, Lshrti3, // int/udiv.rs Udivdi3, Udivmoddi4, Udivmodsi4, Udivmodti4, Udivsi3, Udivti3, Umoddi3, Umodsi3, Umodti3, } } #[derive(Eq, Hash, PartialEq)] pub struct Adddf3 { a: u64, b: u64, c: u64, } impl TestCase for Adddf3 { fn name() -> &'static str { "adddf3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_f64(rng); let b = gen_f64(rng); let c = a + b; // TODO accept NaNs. We don't do that right now because we can't check // for NaN-ness on the thumb targets (due to missing intrinsics) if a.is_nan() || b.is_nan() || c.is_nan() { return None; } Some( Adddf3 { a: to_u64(a), b: to_u64(b), c: to_u64(c), }, ) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { r#" #[cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test))] use core::mem; #[cfg(not(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test)))] use std::mem; use compiler_builtins::float::add::__adddf3; fn mk_f64(x: u64) -> f64 { unsafe { mem::transmute(x) } } fn to_u64(x: f64) -> u64 { unsafe { mem::transmute(x) } } static TEST_CASES: &[((u64, u64), u64)] = &[ "# } fn epilogue() -> &'static str { " ]; #[test] fn adddf3() { for &((a, b), c) in TEST_CASES { let c_ = __adddf3(mk_f64(a), mk_f64(b)); assert_eq!(((a, b), c), ((a, b), to_u64(c_))); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Addsf3 { a: u32, b: u32, c: u32, } impl TestCase for Addsf3 { fn name() -> &'static str { "addsf3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_f32(rng); let b = gen_f32(rng); let c = a + b; // TODO accept NaNs. We don't do that right now because we can't check // for NaN-ness on the thumb targets (due to missing intrinsics) if a.is_nan() || b.is_nan() || c.is_nan() { return None; } Some( Addsf3 { a: to_u32(a), b: to_u32(b), c: to_u32(c), }, ) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { r#" #[cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test))] use core::mem; #[cfg(not(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test)))] use std::mem; use compiler_builtins::float::add::__addsf3; fn mk_f32(x: u32) -> f32 { unsafe { mem::transmute(x) } } fn to_u32(x: f32) -> u32 { unsafe { mem::transmute(x) } } static TEST_CASES: &[((u32, u32), u32)] = &[ "# } fn epilogue() -> &'static str { " ]; #[test] fn addsf3() { for &((a, b), c) in TEST_CASES { let c_ = __addsf3(mk_f32(a), mk_f32(b)); assert_eq!(((a, b), c), ((a, b), to_u32(c_))); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Ashldi3 { a: u64, b: u32, c: u64, } impl TestCase for Ashldi3 { fn name() -> &'static str { "ashldi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u64(rng); let b = (rng.gen::() % 64) as u32; let c = a << b; Some(Ashldi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::shift::__ashldi3; static TEST_CASES: &[((u64, u32), u64)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn ashldi3() { for &((a, b), c) in TEST_CASES { let c_ = __ashldi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Ashlti3 { a: u128, b: u32, c: u128, } impl TestCase for Ashlti3 { fn name() -> &'static str { "ashlti3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u128(rng); let b = (rng.gen::() % 128) as u32; let c = a << b; Some(Ashlti3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::shift::__ashlti3; static TEST_CASES: &[((u128, u32), u128)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn ashlti3() { for &((a, b), c) in TEST_CASES { let c_ = __ashlti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Ashrdi3 { a: i64, b: u32, c: i64, } impl TestCase for Ashrdi3 { fn name() -> &'static str { "ashrdi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_i64(rng); let b = (rng.gen::() % 64) as u32; let c = a >> b; Some(Ashrdi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::shift::__ashrdi3; static TEST_CASES: &[((i64, u32), i64)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn ashrdi3() { for &((a, b), c) in TEST_CASES { let c_ = __ashrdi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Ashrti3 { a: i128, b: u32, c: i128, } impl TestCase for Ashrti3 { fn name() -> &'static str { "ashrti3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_i128(rng); let b = (rng.gen::() % 128) as u32; let c = a >> b; Some(Ashrti3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::shift::__ashrti3; static TEST_CASES: &[((i128, u32), i128)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn ashrti3() { for &((a, b), c) in TEST_CASES { let c_ = __ashrti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Divmoddi4 { a: i64, b: i64, c: i64, rem: i64, } impl TestCase for Divmoddi4 { fn name() -> &'static str { "divmoddi4" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_i64(rng); let b = gen_i64(rng); if b == 0 { return None; } let c = a / b; let rem = a % b; Some(Divmoddi4 { a, b, c, rem }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), ({c}, {rem})),", a = self.a, b = self.b, c = self.c, rem = self.rem ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::sdiv::__divmoddi4; static TEST_CASES: &[((i64, i64), (i64, i64))] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn divmoddi4() { for &((a, b), (c, rem)) in TEST_CASES { let mut rem_ = 0; let c_ = __divmoddi4(a, b, &mut rem_); assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Divdi3 { a: i64, b: i64, c: i64, } impl TestCase for Divdi3 { fn name() -> &'static str { "divdi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_i64(rng); let b = gen_i64(rng); if b == 0 { return None; } let c = a / b; Some(Divdi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::sdiv::__divdi3; static TEST_CASES: &[((i64, i64), i64)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn divdi3() { for &((a, b), c) in TEST_CASES { let c_ = __divdi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Divmodsi4 { a: i32, b: i32, c: i32, rem: i32, } impl TestCase for Divmodsi4 { fn name() -> &'static str { "divmodsi4" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_i32(rng); let b = gen_i32(rng); if b == 0 { return None; } let c = a / b; let rem = a % b; Some(Divmodsi4 { a, b, c, rem }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), ({c}, {rem})),", a = self.a, b = self.b, c = self.c, rem = self.rem ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::sdiv::__divmodsi4; static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn divmodsi4() { for &((a, b), (c, rem)) in TEST_CASES { let mut rem_ = 0; let c_ = __divmodsi4(a, b, &mut rem_); assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Divsi3 { a: i32, b: i32, c: i32, } impl TestCase for Divsi3 { fn name() -> &'static str { "divsi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_i32(rng); let b = gen_i32(rng); if b == 0 { return None; } let c = a / b; Some(Divsi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::sdiv::__divsi3; static TEST_CASES: &[((i32, i32), i32)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn divsi3() { for &((a, b), c) in TEST_CASES { let c_ = __divsi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Divti3 { a: i128, b: i128, c: i128, } impl TestCase for Divti3 { fn name() -> &'static str { "divti3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_i128(rng); let b = gen_i128(rng); if b == 0 { return None; } let c = a / b; Some(Divti3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::sdiv::__divti3; static TEST_CASES: &[((i128, i128), i128)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn divti3() { for &((a, b), c) in TEST_CASES { let c_ = __divti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Moddi3 { a: i64, b: i64, c: i64, } impl TestCase for Moddi3 { fn name() -> &'static str { "moddi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_i64(rng); let b = gen_i64(rng); if b == 0 { return None; } let c = a % b; Some(Moddi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::sdiv::__moddi3; static TEST_CASES: &[((i64, i64), i64)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn moddi3() { for &((a, b), c) in TEST_CASES { let c_ = __moddi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Modsi3 { a: i32, b: i32, c: i32, } impl TestCase for Modsi3 { fn name() -> &'static str { "modsi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_i32(rng); let b = gen_i32(rng); if b == 0 { return None; } let c = a % b; Some(Modsi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::sdiv::__modsi3; static TEST_CASES: &[((i32, i32), i32)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn modsi3() { for &((a, b), c) in TEST_CASES { let c_ = __modsi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Modti3 { a: i128, b: i128, c: i128, } impl TestCase for Modti3 { fn name() -> &'static str { "modti3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_i128(rng); let b = gen_i128(rng); if b == 0 { return None; } let c = a % b; Some(Modti3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::sdiv::__modti3; static TEST_CASES: &[((i128, i128), i128)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn modti3() { for &((a, b), c) in TEST_CASES { let c_ = __modti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] struct Muldi3 { a: u64, b: u64, c: u64, } impl TestCase for Muldi3 { fn name() -> &'static str { "muldi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u64(rng); let b = gen_u64(rng); let c = a.wrapping_mul(b); Some(Muldi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::mul::__muldi3; static TEST_CASES: &[((u64, u64), u64)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn muldi3() { for &((a, b), c) in TEST_CASES { let c_ = __muldi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Mulodi4 { a: i64, b: i64, c: i64, overflow: u32, } impl TestCase for Mulodi4 { fn name() -> &'static str { "mulodi4" } fn generate(rng: &mut R) -> Option where R: Rng, { let a = gen_i64(rng); let b = gen_i64(rng); let c = a.wrapping_mul(b); let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; Some(Mulodi4 { a, b, c, overflow }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), ({c}, {overflow})),", a = self.a, b = self.b, c = self.c, overflow = self.overflow ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::mul::__mulodi4; static TEST_CASES: &[((i64, i64), (i64, i32))] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn mulodi4() { let mut overflow_ = 2; for &((a, b), (c, overflow)) in TEST_CASES { let c_ = __mulodi4(a, b, &mut overflow_); assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Mulosi4 { a: i32, b: i32, c: i32, overflow: u32, } impl TestCase for Mulosi4 { fn name() -> &'static str { "mulosi4" } fn generate(rng: &mut R) -> Option where R: Rng, { let a = gen_i32(rng); let b = gen_i32(rng); let c = a.wrapping_mul(b); let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; Some(Mulosi4 { a, b, c, overflow }) } fn prologue() -> &'static str { " use compiler_builtins::int::mul::__mulosi4; static TEST_CASES: &[((i32, i32), (i32, i32))] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn mulosi4() { let mut overflow_ = 2; for &((a, b), (c, overflow)) in TEST_CASES { let c_ = __mulosi4(a, b, &mut overflow_); assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); } } " } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), ({c}, {overflow})),", a = self.a, b = self.b, c = self.c, overflow = self.overflow ) .unwrap(); } } #[derive(Eq, Hash, PartialEq)] pub struct Muloti4 { a: i128, b: i128, c: i128, overflow: u32, } impl TestCase for Muloti4 { fn name() -> &'static str { "muloti4" } fn generate(rng: &mut R) -> Option where R: Rng, { let a = gen_i128(rng); let b = gen_i128(rng); let c = a.wrapping_mul(b); let overflow = if a.checked_mul(b).is_some() { 0 } else { 1 }; Some(Muloti4 { a, b, c, overflow }) } fn prologue() -> &'static str { " use compiler_builtins::int::mul::__muloti4; static TEST_CASES: &[((i128, i128), (i128, i32))] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn muloti4() { let mut overflow_ = 2; for &((a, b), (c, overflow)) in TEST_CASES { let c_ = __muloti4(a, b, &mut overflow_); assert_eq!(((a, b), (c, overflow)), ((a, b), (c_, overflow_))); } } " } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), ({c}, {overflow})),", a = self.a, b = self.b, c = self.c, overflow = self.overflow ) .unwrap(); } } #[derive(Eq, Hash, PartialEq)] pub struct Multi3 { a: i128, b: i128, c: i128, } impl TestCase for Multi3 { fn name() -> &'static str { "multi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_i128(rng); let b = gen_i128(rng); let c = a.wrapping_mul(b); Some(Multi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::mul::__multi3; static TEST_CASES: &[((i128, i128), i128)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn multi3() { for &((a, b), c) in TEST_CASES { let c_ = __multi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Powidf2 { a: u64, b: i32, c: u64, } impl TestCase for Powidf2 { fn name() -> &'static str { "powidf2" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_f64(rng); let b = gen_i32(rng); let c = a.powi(b); // TODO accept NaNs. We don't do that right now because we can't check // for NaN-ness on the thumb targets if a.is_nan() || c.is_nan() { return None; } Some( Powidf2 { a: to_u64(a), b, c: to_u64(c), }, ) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { r#" #[cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test))] use core::mem; #[cfg(not(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test)))] use std::mem; use compiler_builtins::float::pow::__powidf2; fn mk_f64(x: u64) -> f64 { unsafe { mem::transmute(x) } } fn to_u64(x: f64) -> u64 { unsafe { mem::transmute(x) } } static TEST_CASES: &[((u64, i32), u64)] = &[ "# } fn epilogue() -> &'static str { " ]; #[test] fn powidf2() { for &((a, b), c) in TEST_CASES { let c_ = __powidf2(mk_f64(a), b); assert_eq!(((a, b), c), ((a, b), to_u64(c_))); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Powisf2 { a: u32, b: i32, c: u32, } impl TestCase for Powisf2 { fn name() -> &'static str { "powisf2" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_f32(rng); let b = gen_i32(rng); let c = a.powi(b); // TODO accept NaNs. We don't do that right now because we can't check // for NaN-ness on the thumb targets if a.is_nan() || c.is_nan() { return None; } Some( Powisf2 { a: to_u32(a), b, c: to_u32(c), }, ) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { r#" #[cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test))] use core::mem; #[cfg(not(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test)))] use std::mem; use compiler_builtins::float::pow::__powisf2; fn mk_f32(x: u32) -> f32 { unsafe { mem::transmute(x) } } fn to_u32(x: f32) -> u32 { unsafe { mem::transmute(x) } } static TEST_CASES: &[((u32, i32), u32)] = &[ "# } fn epilogue() -> &'static str { " ]; #[test] fn powisf2() { for &((a, b), c) in TEST_CASES { let c_ = __powisf2(mk_f32(a), b); assert_eq!(((a, b), c), ((a, b), to_u32(c_))); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Lshrdi3 { a: u64, b: u32, c: u64, } impl TestCase for Lshrdi3 { fn name() -> &'static str { "lshrdi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u64(rng); let b = (rng.gen::() % 64) as u32; let c = a >> b; Some(Lshrdi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::shift::__lshrdi3; static TEST_CASES: &[((u64, u32), u64)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn lshrdi3() { for &((a, b), c) in TEST_CASES { let c_ = __lshrdi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Lshrti3 { a: u128, b: u32, c: u128, } impl TestCase for Lshrti3 { fn name() -> &'static str { "lshrti3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u128(rng); let b = (rng.gen::() % 128) as u32; let c = a >> b; Some(Lshrti3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::shift::__lshrti3; static TEST_CASES: &[((u128, u32), u128)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn lshrti3() { for &((a, b), c) in TEST_CASES { let c_ = __lshrti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Subdf3 { a: u64, b: u64, c: u64, } impl TestCase for Subdf3 { fn name() -> &'static str { "subdf3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_f64(rng); let b = gen_f64(rng); let c = a - b; // TODO accept NaNs. We don't do that right now because we can't check // for NaN-ness on the thumb targets (due to missing intrinsics) if a.is_nan() || b.is_nan() || c.is_nan() { return None; } Some( Subdf3 { a: to_u64(a), b: to_u64(b), c: to_u64(c), }, ) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { r#" #[cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test))] use core::mem; #[cfg(not(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test)))] use std::mem; use compiler_builtins::float::sub::__subdf3; fn mk_f64(x: u64) -> f64 { unsafe { mem::transmute(x) } } fn to_u64(x: f64) -> u64 { unsafe { mem::transmute(x) } } static TEST_CASES: &[((u64, u64), u64)] = &[ "# } fn epilogue() -> &'static str { " ]; #[test] fn subdf3() { for &((a, b), c) in TEST_CASES { let c_ = __subdf3(mk_f64(a), mk_f64(b)); assert_eq!(((a, b), c), ((a, b), to_u64(c_))); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Subsf3 { a: u32, b: u32, c: u32, } impl TestCase for Subsf3 { fn name() -> &'static str { "subsf3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_f32(rng); let b = gen_f32(rng); let c = a - b; // TODO accept NaNs. We don't do that right now because we can't check // for NaN-ness on the thumb targets (due to missing intrinsics) if a.is_nan() || b.is_nan() || c.is_nan() { return None; } Some( Subsf3 { a: to_u32(a), b: to_u32(b), c: to_u32(c), }, ) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { r#" #[cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test))] use core::mem; #[cfg(not(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test)))] use std::mem; use compiler_builtins::float::sub::__subsf3; fn mk_f32(x: u32) -> f32 { unsafe { mem::transmute(x) } } fn to_u32(x: f32) -> u32 { unsafe { mem::transmute(x) } } static TEST_CASES: &[((u32, u32), u32)] = &[ "# } fn epilogue() -> &'static str { " ]; #[test] fn subsf3() { for &((a, b), c) in TEST_CASES { let c_ = __subsf3(mk_f32(a), mk_f32(b)); assert_eq!(((a, b), c), ((a, b), to_u32(c_))); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Udivdi3 { a: u64, b: u64, c: u64, } impl TestCase for Udivdi3 { fn name() -> &'static str { "udivdi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u64(rng); let b = gen_u64(rng); if b == 0 { return None; } let c = a / b; Some(Udivdi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::udiv::__udivdi3; static TEST_CASES: &[((u64, u64), u64)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn udivdi3() { for &((a, b), c) in TEST_CASES { let c_ = __udivdi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Udivmoddi4 { a: u64, b: u64, c: u64, rem: u64, } impl TestCase for Udivmoddi4 { fn name() -> &'static str { "udivmoddi4" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u64(rng); let b = gen_u64(rng); if b == 0 { return None; } let c = a / b; let rem = a % b; Some(Udivmoddi4 { a, b, c, rem }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), ({c}, {rem})),", a = self.a, b = self.b, c = self.c, rem = self.rem ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::udiv::__udivmoddi4; static TEST_CASES: &[((u64, u64), (u64, u64))] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn udivmoddi4() { for &((a, b), (c, rem)) in TEST_CASES { let mut rem_ = 0; let c_ = __udivmoddi4(a, b, Some(&mut rem_)); assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Udivmodsi4 { a: u32, b: u32, c: u32, rem: u32, } impl TestCase for Udivmodsi4 { fn name() -> &'static str { "udivmodsi4" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u32(rng); let b = gen_u32(rng); if b == 0 { return None; } let c = a / b; let rem = a % b; Some(Udivmodsi4 { a, b, c, rem }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), ({c}, {rem})),", a = self.a, b = self.b, c = self.c, rem = self.rem ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::udiv::__udivmodsi4; static TEST_CASES: &[((u32, u32), (u32, u32))] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn udivmodsi4() { for &((a, b), (c, rem)) in TEST_CASES { let mut rem_ = 0; let c_ = __udivmodsi4(a, b, Some(&mut rem_)); assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Udivmodti4 { a: u128, b: u128, c: u128, rem: u128, } impl TestCase for Udivmodti4 { fn name() -> &'static str { "udivmodti4" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u128(rng); let b = gen_u128(rng); if b == 0 { return None; } let c = a / b; let rem = a % b; Some(Udivmodti4 { a, b, c, rem }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), ({c}, {rem})),", a = self.a, b = self.b, c = self.c, rem = self.rem ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::udiv::__udivmodti4; static TEST_CASES: &[((u128, u128), (u128, u128))] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn udivmodti4() { for &((a, b), (c, rem)) in TEST_CASES { let mut rem_ = 0; let c_ = __udivmodti4(a, b, Some(&mut rem_)); assert_eq!(((a, b), (c, rem)), ((a, b), (c_, rem_))); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Udivsi3 { a: u32, b: u32, c: u32, } impl TestCase for Udivsi3 { fn name() -> &'static str { "udivsi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u32(rng); let b = gen_u32(rng); if b == 0 { return None; } let c = a / b; Some(Udivsi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::udiv::__udivsi3; static TEST_CASES: &[((u32, u32), u32)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn udivsi3() { for &((a, b), c) in TEST_CASES { let c_ = __udivsi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Udivti3 { a: u128, b: u128, c: u128, } impl TestCase for Udivti3 { fn name() -> &'static str { "udivti3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u128(rng); let b = gen_u128(rng); if b == 0 { return None; } let c = a / b; Some(Udivti3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::udiv::__udivti3; static TEST_CASES: &[((u128, u128), u128)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn udivti3() { for &((a, b), c) in TEST_CASES { let c_ = __udivti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Umoddi3 { a: u64, b: u64, c: u64, } impl TestCase for Umoddi3 { fn name() -> &'static str { "umoddi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u64(rng); let b = gen_u64(rng); if b == 0 { return None; } let c = a % b; Some(Umoddi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::udiv::__umoddi3; static TEST_CASES: &[((u64, u64), u64)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn umoddi3() { for &((a, b), c) in TEST_CASES { let c_ = __umoddi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Umodsi3 { a: u32, b: u32, c: u32, } impl TestCase for Umodsi3 { fn name() -> &'static str { "umodsi3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u32(rng); let b = gen_u32(rng); if b == 0 { return None; } let c = a % b; Some(Umodsi3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::udiv::__umodsi3; static TEST_CASES: &[((u32, u32), u32)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn umodsi3() { for &((a, b), c) in TEST_CASES { let c_ = __umodsi3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } #[derive(Eq, Hash, PartialEq)] pub struct Umodti3 { a: u128, b: u128, c: u128, } impl TestCase for Umodti3 { fn name() -> &'static str { "umodti3" } fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized, { let a = gen_u128(rng); let b = gen_u128(rng); if b == 0 { return None; } let c = a % b; Some(Umodti3 { a, b, c }) } fn to_string(&self, buffer: &mut String) { writeln!( buffer, "(({a}, {b}), {c}),", a = self.a, b = self.b, c = self.c ) .unwrap(); } fn prologue() -> &'static str { " use compiler_builtins::int::udiv::__umodti3; static TEST_CASES: &[((u128, u128), u128)] = &[ " } fn epilogue() -> &'static str { " ]; #[test] fn umodti3() { for &((a, b), c) in TEST_CASES { let c_ = __umodti3(a, b); assert_eq!(((a, b), c), ((a, b), c_)); } } " } } trait TestCase { /// Name of the intrinsic to test fn name() -> &'static str; /// Generates a valid test case fn generate(rng: &mut R) -> Option where R: Rng, Self: Sized; /// Stringifies a test case fn to_string(&self, buffer: &mut String); /// Prologue of the test file fn prologue() -> &'static str; /// Epilogue of the test file fn epilogue() -> &'static str; } const PROLOGUE: &'static str = r#" extern crate compiler_builtins; // test runner #[cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test))] extern crate utest_cortex_m_qemu; // overrides `panic!` #[cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test))] #[macro_use] extern crate utest_macros; #[cfg(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")), target_os = "linux", test))] macro_rules! panic { ($($tt:tt)*) => { upanic!($($tt)*); }; } "#; macro_rules! gen_int { ($name:ident, $ity:ident, $hty:ident) => { fn $name(rng: &mut R) -> $ity where R: Rng, { let mut mk = || if rng.gen_weighted_bool(10) { *rng.choose(&[::std::$hty::MAX, 0, ::std::$hty::MIN]).unwrap() } else { rng.gen::<$hty>() }; unsafe { mem::transmute([mk(), mk()]) } } } } gen_int!(gen_i32, i32, i16); gen_int!(gen_i64, i64, i32); gen_int!(gen_i128, i128, i64); macro_rules! gen_float { ($name:ident, $fty:ident, $uty:ident, $bits:expr, $significand_bits:expr) => { pub fn $name(rng: &mut R) -> $fty where R: Rng, { const BITS: u8 = $bits; const SIGNIFICAND_BITS: u8 = $significand_bits; const SIGNIFICAND_MASK: $uty = (1 << SIGNIFICAND_BITS) - 1; const SIGN_MASK: $uty = (1 << (BITS - 1)); const EXPONENT_MASK: $uty = !(SIGN_MASK | SIGNIFICAND_MASK); fn mk_f32(sign: bool, exponent: $uty, significand: $uty) -> $fty { unsafe { mem::transmute(((sign as $uty) << (BITS - 1)) | ((exponent & EXPONENT_MASK) << SIGNIFICAND_BITS) | (significand & SIGNIFICAND_MASK)) } } if rng.gen_weighted_bool(10) { // Special values *rng.choose(&[-0.0, 0.0, ::std::$fty::NAN, ::std::$fty::INFINITY, -::std::$fty::INFINITY]) .unwrap() } else if rng.gen_weighted_bool(10) { // NaN patterns mk_f32(rng.gen(), rng.gen(), 0) } else if rng.gen() { // Denormalized mk_f32(rng.gen(), 0, rng.gen()) } else { // Random anything mk_f32(rng.gen(), rng.gen(), rng.gen()) } } } } gen_float!(gen_f32, f32, u32, 32, 23); gen_float!(gen_f64, f64, u64, 64, 52); pub fn gen_u128(rng: &mut R) -> u128 where R: Rng, { gen_i128(rng) as u128 } pub fn gen_u32(rng: &mut R) -> u32 where R: Rng, { gen_i32(rng) as u32 } fn gen_u64(rng: &mut R) -> u64 where R: Rng, { gen_i64(rng) as u64 } pub fn to_u32(x: f32) -> u32 { unsafe { mem::transmute(x) } } pub fn to_u64(x: f64) -> u64 { unsafe { mem::transmute(x) } } fn mk_tests(mut n: usize, rng: &mut R) -> String where T: Eq + Hash + TestCase, R: Rng, { let mut buffer = PROLOGUE.to_owned(); buffer.push_str(T::prologue()); let mut cases = HashSet::new(); while n != 0 { if let Some(case) = T::generate(rng) { if cases.contains(&case) { continue; } case.to_string(&mut buffer); n -= 1; cases.insert(case); } } buffer.push_str(T::epilogue()); buffer } fn mk_file() where T: Eq + Hash + TestCase, { use std::io::Write; let rng = &mut rand::thread_rng(); let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let out_file = out_dir.join(format!("{}.rs", T::name())); let contents = mk_tests::(NTESTS, rng); File::create(out_file) .unwrap() .write_all(contents.as_bytes()) .unwrap(); } } #[cfg(feature = "c")] mod c { extern crate gcc; use std::collections::BTreeMap; use std::env; use std::path::Path; struct Sources { // SYMBOL -> PATH TO SOURCE map: BTreeMap<&'static str, &'static str>, } impl Sources { fn new() -> Sources { Sources { map: BTreeMap::new() } } fn extend(&mut self, sources: &[&'static str]) { // NOTE Some intrinsics have both a generic implementation (e.g. // `floatdidf.c`) and an arch optimized implementation // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized // implementation and discard the generic implementation. If we don't // and keep both implementations, the linker will yell at us about // duplicate symbols! for &src in sources { let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); if src.contains("/") { // Arch-optimized implementation (preferred) self.map.insert(symbol, src); } else { // Generic implementation if !self.map.contains_key(symbol) { self.map.insert(symbol, src); } } } } fn remove(&mut self, symbols: &[&str]) { for symbol in symbols { self.map.remove(*symbol).unwrap(); } } } /// Compile intrinsics from the compiler-rt C source code pub fn compile(llvm_target: &[&str]) { let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); let cfg = &mut gcc::Config::new(); if target_env == "msvc" { // Don't pull in extra libraries on MSVC cfg.flag("/Zl"); // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP cfg.define("__func__", Some("__FUNCTION__")); } else { // Turn off various features of gcc and such, mostly copying // compiler-rt's build system already cfg.flag("-fno-builtin"); cfg.flag("-fvisibility=hidden"); cfg.flag("-fomit-frame-pointer"); cfg.flag("-ffreestanding"); cfg.define("VISIBILITY_HIDDEN", None); } // NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going // to target to make sure that the assembly implementations really work for the target. If // the implementation is not valid for the arch, then gcc will error when compiling it. if llvm_target[0].starts_with("thumb") { cfg.flag("-mthumb"); if llvm_target.last() == Some(&"eabihf") { cfg.flag("-mfloat-abi=hard"); } } if llvm_target[0] == "thumbv6m" { cfg.flag("-march=armv6-m"); } if llvm_target[0] == "thumbv7m" { cfg.flag("-march=armv7-m"); } if llvm_target[0] == "thumbv7em" { cfg.flag("-march=armv7e-m"); } let mut sources = Sources::new(); sources.extend( &[ "absvdi2.c", "absvsi2.c", "addvdi3.c", "addvsi3.c", "apple_versioning.c", "clzdi2.c", "clzsi2.c", "cmpdi2.c", "comparedf2.c", "comparesf2.c", "ctzdi2.c", "ctzsi2.c", "divdc3.c", "divdf3.c", "divsc3.c", "divsf3.c", "divxc3.c", "extendsfdf2.c", "extendhfsf2.c", "ffsdi2.c", "fixdfdi.c", "fixdfsi.c", "fixsfdi.c", "fixsfsi.c", "fixunsdfdi.c", "fixunsdfsi.c", "fixunssfdi.c", "fixunssfsi.c", "fixunsxfdi.c", "fixunsxfsi.c", "fixxfdi.c", "floatdidf.c", "floatdisf.c", "floatdixf.c", "floatsidf.c", "floatsisf.c", "floatundidf.c", "floatundisf.c", "floatundixf.c", "floatunsidf.c", "floatunsisf.c", "int_util.c", "muldc3.c", "muldf3.c", "mulsc3.c", "mulsf3.c", "mulvdi3.c", "mulvsi3.c", "mulxc3.c", "negdf2.c", "negdi2.c", "negsf2.c", "negvdi2.c", "negvsi2.c", "paritydi2.c", "paritysi2.c", "popcountdi2.c", "popcountsi2.c", "powixf2.c", "subvdi3.c", "subvsi3.c", "truncdfhf2.c", "truncdfsf2.c", "truncsfhf2.c", "ucmpdi2.c", ], ); if target_os != "ios" { sources.extend( &[ "absvti2.c", "addvti3.c", "clzti2.c", "cmpti2.c", "ctzti2.c", "ffsti2.c", "fixdfti.c", "fixsfti.c", "fixunsdfti.c", "fixunssfti.c", "fixunsxfti.c", "fixxfti.c", "floattidf.c", "floattisf.c", "floattixf.c", "floatuntidf.c", "floatuntisf.c", "floatuntixf.c", "mulvti3.c", "negti2.c", "negvti2.c", "parityti2.c", "popcountti2.c", "subvti3.c", "ucmpti2.c", ], ); } if target_vendor == "apple" { sources.extend( &[ "atomic_flag_clear.c", "atomic_flag_clear_explicit.c", "atomic_flag_test_and_set.c", "atomic_flag_test_and_set_explicit.c", "atomic_signal_fence.c", "atomic_thread_fence.c", ], ); } if target_env == "msvc" { if target_arch == "x86_64" { sources.extend( &[ "x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c", ], ); } } else { if target_os != "freebsd" && target_os != "netbsd" { sources.extend(&["gcc_personality_v0.c"]); } if target_arch == "x86_64" { sources.extend( &[ "x86_64/chkstk.S", "x86_64/chkstk2.S", "x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c", "x86_64/floatundidf.S", "x86_64/floatundisf.S", "x86_64/floatundixf.S", ], ); } if target_arch == "x86" { sources.extend( &[ "i386/ashldi3.S", "i386/ashrdi3.S", "i386/chkstk.S", "i386/chkstk2.S", "i386/divdi3.S", "i386/floatdidf.S", "i386/floatdisf.S", "i386/floatdixf.S", "i386/floatundidf.S", "i386/floatundisf.S", "i386/floatundixf.S", "i386/lshrdi3.S", "i386/moddi3.S", "i386/muldi3.S", "i386/udivdi3.S", "i386/umoddi3.S", ], ); } } if target_arch == "arm" && target_os != "ios" { sources.extend( &[ "arm/aeabi_cdcmp.S", "arm/aeabi_cdcmpeq_check_nan.c", "arm/aeabi_cfcmp.S", "arm/aeabi_cfcmpeq_check_nan.c", "arm/aeabi_dcmp.S", "arm/aeabi_div0.c", "arm/aeabi_drsub.c", "arm/aeabi_fcmp.S", "arm/aeabi_frsub.c", "arm/bswapdi2.S", "arm/bswapsi2.S", "arm/clzdi2.S", "arm/clzsi2.S", "arm/comparesf2.S", "arm/divmodsi4.S", "arm/divsi3.S", "arm/modsi3.S", "arm/switch16.S", "arm/switch32.S", "arm/switch8.S", "arm/switchu8.S", "arm/sync_synchronize.S", "arm/udivmodsi4.S", "arm/udivsi3.S", "arm/umodsi3.S", ], ); } if llvm_target[0] == "armv7" { sources.extend( &[ "arm/sync_fetch_and_add_4.S", "arm/sync_fetch_and_add_8.S", "arm/sync_fetch_and_and_4.S", "arm/sync_fetch_and_and_8.S", "arm/sync_fetch_and_max_4.S", "arm/sync_fetch_and_max_8.S", "arm/sync_fetch_and_min_4.S", "arm/sync_fetch_and_min_8.S", "arm/sync_fetch_and_nand_4.S", "arm/sync_fetch_and_nand_8.S", "arm/sync_fetch_and_or_4.S", "arm/sync_fetch_and_or_8.S", "arm/sync_fetch_and_sub_4.S", "arm/sync_fetch_and_sub_8.S", "arm/sync_fetch_and_umax_4.S", "arm/sync_fetch_and_umax_8.S", "arm/sync_fetch_and_umin_4.S", "arm/sync_fetch_and_umin_8.S", "arm/sync_fetch_and_xor_4.S", "arm/sync_fetch_and_xor_8.S", ], ); } if llvm_target.last().unwrap().ends_with("eabihf") { if !llvm_target[0].starts_with("thumbv7em") { sources.extend( &[ "arm/adddf3vfp.S", "arm/addsf3vfp.S", "arm/divdf3vfp.S", "arm/divsf3vfp.S", "arm/eqdf2vfp.S", "arm/eqsf2vfp.S", "arm/extendsfdf2vfp.S", "arm/fixdfsivfp.S", "arm/fixsfsivfp.S", "arm/fixunsdfsivfp.S", "arm/fixunssfsivfp.S", "arm/floatsidfvfp.S", "arm/floatsisfvfp.S", "arm/floatunssidfvfp.S", "arm/floatunssisfvfp.S", "arm/gedf2vfp.S", "arm/gesf2vfp.S", "arm/gtdf2vfp.S", "arm/gtsf2vfp.S", "arm/ledf2vfp.S", "arm/lesf2vfp.S", "arm/ltdf2vfp.S", "arm/ltsf2vfp.S", "arm/muldf3vfp.S", "arm/mulsf3vfp.S", "arm/nedf2vfp.S", "arm/nesf2vfp.S", "arm/restore_vfp_d8_d15_regs.S", "arm/save_vfp_d8_d15_regs.S", "arm/subdf3vfp.S", "arm/subsf3vfp.S", ], ); } sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]); } if target_arch == "aarch64" { sources.extend( &[ "comparetf2.c", "extenddftf2.c", "extendsftf2.c", "fixtfdi.c", "fixtfsi.c", "fixtfti.c", "fixunstfdi.c", "fixunstfsi.c", "fixunstfti.c", "floatditf.c", "floatsitf.c", "floatunditf.c", "floatunsitf.c", "multc3.c", "trunctfdf2.c", "trunctfsf2.c", ], ); } // Remove the assembly implementations that won't compile for the target if llvm_target[0] == "thumbv6m" { sources.remove( &[ "aeabi_cdcmp", "aeabi_cfcmp", "aeabi_dcmp", "aeabi_fcmp", "clzdi2", "clzsi2", "comparesf2", "divmodsi4", "divsi3", "modsi3", "switch16", "switch32", "switch8", "switchu8", "udivmodsi4", "udivsi3", "umodsi3", ], ); // But use some generic implementations where possible sources.extend(&["clzdi2.c", "clzsi2.c"]) } if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" { sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]); } let root = if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() { Path::new("../../libcompiler_builtins") } else { Path::new(".") }; let src_dir = root.join("compiler-rt/lib/builtins"); for src in sources.map.values() { let src = src_dir.join(src); cfg.file(&src); println!("cargo:rerun-if-changed={}", src.display()); } cfg.compile("libcompiler-rt.a"); } }