forked from bytecodealliance/wasmtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Centralize handling of float operations
Add a new `wasmtime-math` crate which is tasked with providing the float math functions needed by Wasm with with, in theory, most optimal platform implementation available. prtest:full
- Loading branch information
1 parent
0b113f5
commit 2d11ac3
Showing
11 changed files
with
357 additions
and
513 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[package] | ||
name = "wasmtime-math" | ||
version.workspace = true | ||
authors.workspace = true | ||
description = "Low-level math routines used in Wasmtime" | ||
documentation = "https://docs.rs/wasmtime-math" | ||
license = "Apache-2.0 WITH LLVM-exception" | ||
repository = "https://github.com/bytecodealliance/wasmtime" | ||
readme = "README.md" | ||
edition.workspace = true | ||
rust-version.workspace = true | ||
|
||
[lints] | ||
workspace = true | ||
|
||
[package.metadata.docs.rs] | ||
all-features = true | ||
|
||
[features] | ||
std = [] | ||
|
||
[dependencies] | ||
libm = { workspace = true } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,279 @@ | ||
//! A minimal helper crate for implementing float-related operations for | ||
//! WebAssembly in terms of the native platform primitives. | ||
//! | ||
//! This crate is intended to assist with solving the portability issues such | ||
//! as: | ||
//! | ||
//! * Functions like `f32::trunc` are not available in `#![no_std]` targets. | ||
//! * The `f32::trunc` function is likely faster than the `libm` fallback. | ||
//! * Behavior of `f32::trunc` differs across platforms, for example it's | ||
//! different on Windows and glibc on Linux. | ||
//! * Some wasm functions are in the Rust standard library, but not stable yet. | ||
//! | ||
//! There are a few locations throughout the codebase that these functions are | ||
//! needed so they're implemented only in a single location here rather than | ||
//! multiple. | ||
#![no_std] | ||
|
||
#[cfg(feature = "std")] | ||
extern crate std; | ||
|
||
pub trait WasmFloat { | ||
fn wasm_trunc(self) -> Self; | ||
fn wasm_copysign(self, sign: Self) -> Self; | ||
fn wasm_floor(self) -> Self; | ||
fn wasm_ceil(self) -> Self; | ||
fn wasm_sqrt(self) -> Self; | ||
fn wasm_abs(self) -> Self; | ||
fn wasm_nearest(self) -> Self; | ||
fn wasm_minimum(self, other: Self) -> Self; | ||
fn wasm_maximum(self, other: Self) -> Self; | ||
fn mul_add(self, b: Self, c: Self) -> Self; | ||
} | ||
|
||
impl WasmFloat for f32 { | ||
#[inline] | ||
fn wasm_trunc(self) -> f32 { | ||
#[cfg(feature = "std")] | ||
if !cfg!(windows) { | ||
return self.trunc(); | ||
} | ||
if self.is_nan() { | ||
return f32::NAN; | ||
} | ||
libm::truncf(self) | ||
} | ||
#[inline] | ||
fn wasm_copysign(self, sign: f32) -> f32 { | ||
#[cfg(feature = "std")] | ||
if true { | ||
return self.copysign(sign); | ||
} | ||
libm::copysignf(self, sign) | ||
} | ||
#[inline] | ||
fn wasm_floor(self) -> f32 { | ||
#[cfg(feature = "std")] | ||
if true { | ||
return self.floor(); | ||
} | ||
if self.is_nan() { | ||
return f32::NAN; | ||
} | ||
libm::floorf(self) | ||
} | ||
#[inline] | ||
fn wasm_ceil(self) -> f32 { | ||
#[cfg(feature = "std")] | ||
if true { | ||
return self.ceil(); | ||
} | ||
if self.is_nan() { | ||
return f32::NAN; | ||
} | ||
libm::ceilf(self) | ||
} | ||
#[inline] | ||
fn wasm_sqrt(self) -> f32 { | ||
#[cfg(feature = "std")] | ||
if true { | ||
return self.sqrt(); | ||
} | ||
libm::sqrtf(self) | ||
} | ||
#[inline] | ||
fn wasm_abs(self) -> f32 { | ||
#[cfg(feature = "std")] | ||
if true { | ||
return self.abs(); | ||
} | ||
libm::fabsf(self) | ||
} | ||
#[inline] | ||
fn wasm_nearest(self) -> f32 { | ||
#[cfg(feature = "std")] | ||
if !cfg!(windows) { | ||
return self.round_ties_even(); | ||
} | ||
if self.is_nan() { | ||
return f32::NAN; | ||
} | ||
let round = self.round(); | ||
if (self - round).abs() != 0.5 { | ||
return round; | ||
} | ||
match round % 2.0 { | ||
1.0 => self.floor(), | ||
-1.0 => self.ceil(), | ||
_ => round, | ||
} | ||
} | ||
#[inline] | ||
fn wasm_maximum(self, other: f32) -> f32 { | ||
// FIXME: replace this with `a.maximum(b)` when rust-lang/rust#91079 is | ||
// stabilized | ||
if self > other { | ||
self | ||
} else if other > self { | ||
other | ||
} else if self == other { | ||
if self.is_sign_positive() && other.is_sign_negative() { | ||
self | ||
} else { | ||
other | ||
} | ||
} else { | ||
self + other | ||
} | ||
} | ||
#[inline] | ||
fn wasm_minimum(self, other: f32) -> f32 { | ||
// FIXME: replace this with `self.minimum(other)` when | ||
// rust-lang/rust#91079 is stabilized | ||
if self < other { | ||
self | ||
} else if other < self { | ||
other | ||
} else if self == other { | ||
if self.is_sign_negative() && other.is_sign_positive() { | ||
self | ||
} else { | ||
other | ||
} | ||
} else { | ||
self + other | ||
} | ||
} | ||
#[inline] | ||
fn mul_add(self, b: f32, c: f32) -> f32 { | ||
#[cfg(feature = "std")] | ||
if true { | ||
return self.mul_add(b, c); | ||
} | ||
libm::fmaf(self, b, c) | ||
} | ||
} | ||
|
||
impl WasmFloat for f64 { | ||
#[inline] | ||
fn wasm_trunc(self) -> f64 { | ||
#[cfg(feature = "std")] | ||
if !cfg!(windows) { | ||
return self.trunc(); | ||
} | ||
if self.is_nan() { | ||
return f64::NAN; | ||
} | ||
libm::trunc(self) | ||
} | ||
#[inline] | ||
fn wasm_copysign(self, sign: f64) -> f64 { | ||
#[cfg(feature = "std")] | ||
if true { | ||
return self.copysign(sign); | ||
} | ||
libm::copysign(self, sign) | ||
} | ||
#[inline] | ||
fn wasm_floor(self) -> f64 { | ||
#[cfg(feature = "std")] | ||
if true { | ||
return self.floor(); | ||
} | ||
if self.is_nan() { | ||
return f64::NAN; | ||
} | ||
libm::floor(self) | ||
} | ||
#[inline] | ||
fn wasm_ceil(self) -> f64 { | ||
#[cfg(feature = "std")] | ||
if true { | ||
return self.ceil(); | ||
} | ||
if self.is_nan() { | ||
return f64::NAN; | ||
} | ||
libm::ceil(self) | ||
} | ||
#[inline] | ||
fn wasm_sqrt(self) -> f64 { | ||
#[cfg(feature = "std")] | ||
if true { | ||
return self.sqrt(); | ||
} | ||
libm::sqrt(self) | ||
} | ||
#[inline] | ||
fn wasm_abs(self) -> f64 { | ||
#[cfg(feature = "std")] | ||
if true { | ||
return self.abs(); | ||
} | ||
libm::fabs(self) | ||
} | ||
#[inline] | ||
fn wasm_nearest(self) -> f64 { | ||
#[cfg(feature = "std")] | ||
if !cfg!(windows) { | ||
return self.round_ties_even(); | ||
} | ||
if self.is_nan() { | ||
return f64::NAN; | ||
} | ||
let round = self.round(); | ||
if (self - round).abs() != 0.5 { | ||
return round; | ||
} | ||
match round % 2.0 { | ||
1.0 => self.floor(), | ||
-1.0 => self.ceil(), | ||
_ => round, | ||
} | ||
} | ||
#[inline] | ||
fn wasm_maximum(self, other: f64) -> f64 { | ||
// FIXME: replace this with `a.maximum(b)` when rust-lang/rust#91079 is | ||
// stabilized | ||
if self > other { | ||
self | ||
} else if other > self { | ||
other | ||
} else if self == other { | ||
if self.is_sign_positive() && other.is_sign_negative() { | ||
self | ||
} else { | ||
other | ||
} | ||
} else { | ||
self + other | ||
} | ||
} | ||
#[inline] | ||
fn wasm_minimum(self, other: f64) -> f64 { | ||
// FIXME: replace this with `self.minimum(other)` when | ||
// rust-lang/rust#91079 is stabilized | ||
if self < other { | ||
self | ||
} else if other < self { | ||
other | ||
} else if self == other { | ||
if self.is_sign_negative() && other.is_sign_positive() { | ||
self | ||
} else { | ||
other | ||
} | ||
} else { | ||
self + other | ||
} | ||
} | ||
#[inline] | ||
fn mul_add(self, b: f64, c: f64) -> f64 { | ||
#[cfg(feature = "std")] | ||
if true { | ||
return self.mul_add(b, c); | ||
} | ||
libm::fma(self, b, c) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.