use libm for float math in no_std

This commit is contained in:
Julius Rakow 2018-08-26 14:05:30 +02:00
parent 2a6103c29f
commit 0a0f8707c4
No known key found for this signature in database
GPG Key ID: 9AABD9B859435A93
3 changed files with 38 additions and 13 deletions

View File

@ -16,7 +16,7 @@ default = ["std"]
std = ["parity-wasm/std", "byteorder/std"] std = ["parity-wasm/std", "byteorder/std"]
# Enable for no_std support # Enable for no_std support
# hashmap_core only works on no_std # hashmap_core only works on no_std
core = ["hashmap_core"] core = ["hashmap_core", "libm"]
[dependencies] [dependencies]
parity-wasm = { version = "0.31", default-features = false } parity-wasm = { version = "0.31", default-features = false }
@ -24,6 +24,7 @@ byteorder = { version = "1.0", default-features = false }
hashmap_core = { version = "0.1.9", optional = true } hashmap_core = { version = "0.1.9", optional = true }
memory_units = "0.3.0" memory_units = "0.3.0"
nan-preserving-float = "0.1.0" nan-preserving-float = "0.1.0"
libm = { version = "0.1.2", optional = true }
[dev-dependencies] [dev-dependencies]
assert_matches = "1.1" assert_matches = "1.1"

View File

@ -131,6 +131,9 @@ use core::fmt;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::error; use std::error;
#[cfg(not(feature = "std"))]
extern crate libm;
/// Error type which can be thrown by wasm code or by host environment. /// Error type which can be thrown by wasm code or by host environment.
/// ///
/// Under some conditions, wasm execution may produce a `Trap`, which immediately aborts execution. /// Under some conditions, wasm execution may produce a `Trap`, which immediately aborts execution.

View File

@ -746,27 +746,48 @@ impl_integer!(u32);
impl_integer!(i64); impl_integer!(i64);
impl_integer!(u64); impl_integer!(u64);
// Use std float functions in std environment.
// And libm's implementation in no_std
#[cfg(feature = "std")]
macro_rules! call_math {
($op:ident, $e:expr, $fXX:ident, $FXXExt:ident) => {
$fXX::$op($e)
};
}
#[cfg(not(feature = "std"))]
macro_rules! call_math {
($op:ident, $e:expr, $fXX:ident, $FXXExt:ident) => {
::libm::$FXXExt::$op($e)
};
}
// We cannot call the math functions directly, because there are multiple available implementaitons in no_std.
// In std, there are only `Value::$op` and `std::$fXX:$op`.
// The `std` ones are preferred, because they are not from a trait.
// For `no_std`, the implementations are `Value::$op` and `libm::FXXExt::$op`,
// both of which are trait implementations and hence ambiguous.
// So we have to use a full path, which is what `call_math!` does.
macro_rules! impl_float { macro_rules! impl_float {
($type:ident, $fXX:ident, $iXX:ident) => { ($type:ident, $fXX:ident, $FXXExt:ident, $iXX:ident) => {
impl Float<$type> for $type { impl Float<$type> for $type {
fn abs(self) -> $type { fn abs(self) -> $type {
$fXX::abs(self.into()).into() call_math!(abs, $fXX::from(self), $fXX, $FXXExt).into()
} }
fn floor(self) -> $type { fn floor(self) -> $type {
$fXX::floor(self.into()).into() call_math!(floor, $fXX::from(self), $fXX, $FXXExt).into()
} }
fn ceil(self) -> $type { fn ceil(self) -> $type {
$fXX::ceil(self.into()).into() call_math!(ceil, $fXX::from(self), $fXX, $FXXExt).into()
} }
fn trunc(self) -> $type { fn trunc(self) -> $type {
$fXX::trunc(self.into()).into() call_math!(trunc, $fXX::from(self), $fXX, $FXXExt).into()
} }
fn round(self) -> $type { fn round(self) -> $type {
$fXX::round(self.into()).into() call_math!(round, $fXX::from(self), $fXX, $FXXExt).into()
} }
fn nearest(self) -> $type { fn nearest(self) -> $type {
let round = self.round(); let round = self.round();
if self.fract().abs() != 0.5 { if call_math!(fract, $fXX::from(self), $fXX, $FXXExt).abs() != 0.5 {
return round; return round;
} }
@ -780,7 +801,7 @@ macro_rules! impl_float {
} }
} }
fn sqrt(self) -> $type { fn sqrt(self) -> $type {
$fXX::sqrt(self.into()).into() call_math!(sqrt, $fXX::from(self), $fXX, $FXXExt).into()
} }
// This instruction corresponds to what is sometimes called "minNaN" in other languages. // This instruction corresponds to what is sometimes called "minNaN" in other languages.
fn min(self, other: $type) -> $type { fn min(self, other: $type) -> $type {
@ -828,7 +849,7 @@ macro_rules! impl_float {
}; };
} }
impl_float!(f32, f32, i32); impl_float!(f32, f32, F32Ext, i32);
impl_float!(f64, f64, i64); impl_float!(f64, f64, F64Ext, i64);
impl_float!(F32, f32, i32); impl_float!(F32, f32, F32Ext, i32);
impl_float!(F64, f64, i64); impl_float!(F64, f64, F64Ext, i64);