Merge pull request #225 from paoloteti/armhf
Add support for mul[s/d]f3vfp and div[s/d]f3vfp
This commit is contained in:
commit
93977e65a0
|
@ -96,9 +96,9 @@ features = ["c"]
|
||||||
- [x] arm/aeabi_memset.S
|
- [x] arm/aeabi_memset.S
|
||||||
- [x] arm/aeabi_uidivmod.S
|
- [x] arm/aeabi_uidivmod.S
|
||||||
- [x] arm/aeabi_uldivmod.S
|
- [x] arm/aeabi_uldivmod.S
|
||||||
- [ ] arm/divdf3vfp.S
|
- [x] arm/divdf3vfp.S
|
||||||
- [ ] arm/divmodsi4.S (generic version is done)
|
- [ ] arm/divmodsi4.S (generic version is done)
|
||||||
- [ ] arm/divsf3vfp.S
|
- [x] arm/divsf3vfp.S
|
||||||
- [ ] arm/divsi3.S (generic version is done)
|
- [ ] arm/divsi3.S (generic version is done)
|
||||||
- [ ] arm/eqdf2vfp.S
|
- [ ] arm/eqdf2vfp.S
|
||||||
- [ ] arm/eqsf2vfp.S
|
- [ ] arm/eqsf2vfp.S
|
||||||
|
@ -120,8 +120,8 @@ features = ["c"]
|
||||||
- [ ] arm/ltdf2vfp.S
|
- [ ] arm/ltdf2vfp.S
|
||||||
- [ ] arm/ltsf2vfp.S
|
- [ ] arm/ltsf2vfp.S
|
||||||
- [ ] arm/modsi3.S (generic version is done)
|
- [ ] arm/modsi3.S (generic version is done)
|
||||||
- [ ] arm/muldf3vfp.S
|
- [x] arm/muldf3vfp.S
|
||||||
- [ ] arm/mulsf3vfp.S
|
- [x] arm/mulsf3vfp.S
|
||||||
- [ ] arm/nedf2vfp.S
|
- [ ] arm/nedf2vfp.S
|
||||||
- [ ] arm/negdf2vfp.S
|
- [ ] arm/negdf2vfp.S
|
||||||
- [ ] arm/negsf2vfp.S
|
- [ ] arm/negsf2vfp.S
|
||||||
|
|
363
build.rs
363
build.rs
|
@ -130,10 +130,14 @@ mod tests {
|
||||||
// float/mul.rs
|
// float/mul.rs
|
||||||
Mulsf3,
|
Mulsf3,
|
||||||
Muldf3,
|
Muldf3,
|
||||||
|
Mulsf3vfp,
|
||||||
|
Muldf3vfp,
|
||||||
|
|
||||||
// float/div.rs
|
// float/div.rs
|
||||||
Divsf3,
|
Divsf3,
|
||||||
Divdf3,
|
Divdf3,
|
||||||
|
Divsf3vfp,
|
||||||
|
Divdf3vfp,
|
||||||
|
|
||||||
// int/addsub.rs
|
// int/addsub.rs
|
||||||
AddU128,
|
AddU128,
|
||||||
|
@ -4203,6 +4207,181 @@ fn muldf3() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
pub struct Mulsf3vfp {
|
||||||
|
a: u32, // f32
|
||||||
|
b: u32, // f32
|
||||||
|
c: u32, // f32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCase for Mulsf3vfp {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"mulsf3vfp"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||||
|
where
|
||||||
|
R: Rng,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let a = gen_large_f32(rng);
|
||||||
|
let b = gen_large_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(
|
||||||
|
Mulsf3vfp {
|
||||||
|
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::mul::__mulsf3vfp;
|
||||||
|
|
||||||
|
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 mulsf3vfp() {
|
||||||
|
for &((a, b), c) in TEST_CASES {
|
||||||
|
let c_ = __mulsf3vfp(mk_f32(a), mk_f32(b));
|
||||||
|
assert_eq!(((a, b), c), ((a, b), to_u32(c_)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
pub struct Muldf3vfp {
|
||||||
|
a: u64, // f64
|
||||||
|
b: u64, // f64
|
||||||
|
c: u64, // f64
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCase for Muldf3vfp {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"muldf3vfp"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||||
|
where
|
||||||
|
R: Rng,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let a = gen_large_f64(rng);
|
||||||
|
let b = gen_large_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(
|
||||||
|
Muldf3vfp {
|
||||||
|
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::mul::__muldf3vfp;
|
||||||
|
|
||||||
|
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 muldf3vfp() {
|
||||||
|
for &((a, b), c) in TEST_CASES {
|
||||||
|
let c_ = __muldf3vfp(mk_f64(a), mk_f64(b));
|
||||||
|
assert_eq!(((a, b), c), ((a, b), to_u64(c_)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Eq, Hash, PartialEq)]
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
pub struct Divsf3 {
|
pub struct Divsf3 {
|
||||||
a: u32, // f32
|
a: u32, // f32
|
||||||
|
@ -4384,6 +4563,186 @@ fn divdf3() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
pub struct Divsf3vfp {
|
||||||
|
a: u32, // f32
|
||||||
|
b: u32, // f32
|
||||||
|
c: u32, // f32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCase for Divsf3vfp {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"divsf3vfp"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||||
|
where
|
||||||
|
R: Rng,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let a = gen_large_f32(rng);
|
||||||
|
let b = gen_large_f32(rng);
|
||||||
|
if b == 0.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
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()|| c.abs() <= unsafe { mem::transmute(16777215u32) } {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(
|
||||||
|
Divsf3vfp {
|
||||||
|
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::div::__divsf3vfp;
|
||||||
|
|
||||||
|
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 divsf3vfp() {
|
||||||
|
for &((a, b), c) in TEST_CASES {
|
||||||
|
let c_ = __divsf3vfp(mk_f32(a), mk_f32(b));
|
||||||
|
assert_eq!(((a, b), c), ((a, b), to_u32(c_)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
pub struct Divdf3vfp {
|
||||||
|
a: u64, // f64
|
||||||
|
b: u64, // f64
|
||||||
|
c: u64, // f64
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCase for Divdf3vfp {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"divdf3vfp"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||||
|
where
|
||||||
|
R: Rng,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let a = gen_large_f64(rng);
|
||||||
|
let b = gen_large_f64(rng);
|
||||||
|
if b == 0.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
|| c.abs() <= unsafe { mem::transmute(4503599627370495u64) } {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(
|
||||||
|
Divdf3vfp {
|
||||||
|
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::div::__divdf3vfp;
|
||||||
|
|
||||||
|
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 divdf3vfp() {
|
||||||
|
for &((a, b), c) in TEST_CASES {
|
||||||
|
let c_ = __divdf3vfp(mk_f64(a), mk_f64(b));
|
||||||
|
assert_eq!(((a, b), c), ((a, b), to_u64(c_)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Eq, Hash, PartialEq)]
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
pub struct Udivdi3 {
|
pub struct Udivdi3 {
|
||||||
|
@ -5511,8 +5870,6 @@ mod c {
|
||||||
&[
|
&[
|
||||||
"arm/adddf3vfp.S",
|
"arm/adddf3vfp.S",
|
||||||
"arm/addsf3vfp.S",
|
"arm/addsf3vfp.S",
|
||||||
"arm/divdf3vfp.S",
|
|
||||||
"arm/divsf3vfp.S",
|
|
||||||
"arm/eqdf2vfp.S",
|
"arm/eqdf2vfp.S",
|
||||||
"arm/eqsf2vfp.S",
|
"arm/eqsf2vfp.S",
|
||||||
"arm/extendsfdf2vfp.S",
|
"arm/extendsfdf2vfp.S",
|
||||||
|
@ -5532,8 +5889,6 @@ mod c {
|
||||||
"arm/lesf2vfp.S",
|
"arm/lesf2vfp.S",
|
||||||
"arm/ltdf2vfp.S",
|
"arm/ltdf2vfp.S",
|
||||||
"arm/ltsf2vfp.S",
|
"arm/ltsf2vfp.S",
|
||||||
"arm/muldf3vfp.S",
|
|
||||||
"arm/mulsf3vfp.S",
|
|
||||||
"arm/nedf2vfp.S",
|
"arm/nedf2vfp.S",
|
||||||
"arm/nesf2vfp.S",
|
"arm/nesf2vfp.S",
|
||||||
"arm/restore_vfp_d8_d15_regs.S",
|
"arm/restore_vfp_d8_d15_regs.S",
|
||||||
|
|
|
@ -454,4 +454,13 @@ intrinsics! {
|
||||||
div64(a, b)
|
div64(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
pub extern "C" fn __divsf3vfp(a: f32, b: f32) -> f32 {
|
||||||
|
a / b
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
pub extern "C" fn __divdf3vfp(a: f64, b: f64) -> f64 {
|
||||||
|
a / b
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,4 +188,14 @@ intrinsics! {
|
||||||
pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 {
|
pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 {
|
||||||
mul(a, b)
|
mul(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
pub extern "C" fn __mulsf3vfp(a: f32, b: f32) -> f32 {
|
||||||
|
a * b
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
pub extern "C" fn __muldf3vfp(a: f64, b: f64) -> f64 {
|
||||||
|
a * b
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#![feature(compiler_builtins_lib)]
|
||||||
|
#![feature(i128_type)]
|
||||||
|
#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
|
||||||
|
target_os = "linux", test),
|
||||||
|
no_std)]
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/divdf3vfp.rs"));
|
|
@ -0,0 +1,8 @@
|
||||||
|
#![feature(compiler_builtins_lib)]
|
||||||
|
#![feature(i128_type)]
|
||||||
|
#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
|
||||||
|
target_os = "linux", test),
|
||||||
|
no_std)]
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/divsf3vfp.rs"));
|
|
@ -0,0 +1,8 @@
|
||||||
|
#![feature(compiler_builtins_lib)]
|
||||||
|
#![feature(i128_type)]
|
||||||
|
#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
|
||||||
|
target_os = "linux", test),
|
||||||
|
no_std)]
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/muldf3vfp.rs"));
|
|
@ -0,0 +1,8 @@
|
||||||
|
#![feature(compiler_builtins_lib)]
|
||||||
|
#![feature(i128_type)]
|
||||||
|
#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
|
||||||
|
target_os = "linux", test),
|
||||||
|
no_std)]
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/mulsf3vfp.rs"));
|
Loading…
Reference in New Issue