Skip to content

Commit 5935a0c

Browse files
authored
Fix libm based f{32,64}.{floor,ceil,trunc} corner cases (#1860)
* update libm * use libm::roundeven in f{32,64}_nearest impl * make it possible to test libm implementation This adds the libm crate feature to the following crates: - wasmi_core - wasmi - wasmi_wast * opt into_quiet_nan by using unlikely in branch * fix libm based ceil, floor and trunc impls
1 parent a8f6d80 commit 5935a0c

4 files changed

Lines changed: 21 additions & 18 deletions

File tree

crates/core/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ categories.workspace = true
1414
exclude.workspace = true
1515

1616
[dependencies]
17-
libm = { version = "0.2.11", default-features = false }
17+
libm = { version = "0.2.16", default-features = false }
1818

1919
[features]
2020
default = ["std"]
@@ -25,6 +25,7 @@ std = []
2525
# This also changes the size of `RawVal` from 64-bit to 128-bit
2626
# which may have significant impact on performance and memory usage.
2727
simd = []
28+
libm = []
2829

2930
[package.metadata.cargo-udeps.ignore]
3031
# cargo-udeps cannot detect that libm is used for no_std targets only.

crates/core/src/value.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ trait WasmFloatExt {
444444
fn mul_add(self, a: Self, b: Self) -> Self;
445445
}
446446

447-
#[cfg(not(feature = "std"))]
447+
#[cfg(any(not(feature = "std"), feature = "libm"))]
448448
macro_rules! impl_wasm_float {
449449
($ty:ty) => {
450450
impl WasmFloatExt for $ty {
@@ -455,33 +455,34 @@ macro_rules! impl_wasm_float {
455455

456456
#[inline]
457457
fn ceil(self) -> Self {
458+
if let Some(qnan) = self.into_quiet_nan() {
459+
return qnan;
460+
}
458461
<libm::Libm<Self>>::ceil(self)
459462
}
460463

461464
#[inline]
462465
fn floor(self) -> Self {
466+
if let Some(qnan) = self.into_quiet_nan() {
467+
return qnan;
468+
}
463469
<libm::Libm<Self>>::floor(self)
464470
}
465471

466472
#[inline]
467473
fn trunc(self) -> Self {
474+
if let Some(qnan) = self.into_quiet_nan() {
475+
return qnan;
476+
}
468477
<libm::Libm<Self>>::trunc(self)
469478
}
470479

471480
#[inline]
472481
fn nearest(self) -> Self {
473-
let round = <libm::Libm<Self>>::round(self);
474-
if <Self as WasmFloatExt>::abs(self - <Self as WasmFloatExt>::trunc(self)) != 0.5 {
475-
return round;
476-
}
477-
let rem = round % 2.0;
478-
if rem == 1.0 {
479-
<Self as WasmFloatExt>::floor(self)
480-
} else if rem == -1.0 {
481-
<Self as WasmFloatExt>::ceil(self)
482-
} else {
483-
round
482+
if let Some(qnan) = self.into_quiet_nan() {
483+
return qnan;
484484
}
485+
<libm::Libm<Self>>::roundeven(self)
485486
}
486487

487488
#[inline]
@@ -522,21 +523,19 @@ impl V128 {
522523
}
523524

524525
/// Extension trait for `f32` and `f64` to turn a NaN value into a quiet-NaN value.
525-
#[cfg(feature = "std")]
526526
trait IntoQuietNan: Sized {
527527
/// Converts `self` into a quiet-NaN if `self` is a NaN, otherwise returns `None`.
528528
fn into_quiet_nan(self) -> Option<Self>;
529529
}
530530

531-
#[cfg(feature = "std")]
532531
macro_rules! impl_into_quiet_nan {
533532
( $( ($float:ty, $bits:ty, $mask:literal) );* $(;)? ) => {
534533
$(
535534
impl IntoQuietNan for $float {
536535
#[inline]
537536
fn into_quiet_nan(self) -> Option<Self> {
538537
const QUIET_BIT: $bits = $mask;
539-
if !self.is_nan() {
538+
if unlikely(!self.is_nan()) {
540539
return None;
541540
}
542541
Some(Self::from_bits(self.to_bits() | QUIET_BIT))
@@ -545,13 +544,12 @@ macro_rules! impl_into_quiet_nan {
545544
)*
546545
};
547546
}
548-
#[cfg(feature = "std")]
549547
impl_into_quiet_nan! {
550548
(f32, u32, 0x0040_0000);
551549
(f64, u64, 0x0008_0000_0000_0000);
552550
}
553551

554-
#[cfg(feature = "std")]
552+
#[cfg(not(any(not(feature = "std"), feature = "libm")))]
555553
macro_rules! impl_wasm_float {
556554
($ty:ty) => {
557555
impl WasmFloatExt for $ty {

crates/wasmi/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ indirect-dispatch = []
7373
# - Enable if your focus is on safety.
7474
# - Disable if your focus is on execution speed.
7575
extra-checks = []
76+
# Forces usage of `libm` for implementations of certain Wasm operators.
77+
# This mostly is used for testing the `libm` based Wasmi implementation.
78+
libm = ["wasmi_core/libm"]
7679

7780
[[bench]]
7881
name = "benches"

crates/wast/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ indirect-dispatch = ["wasmi/indirect-dispatch"]
2525
extra-checks = ["wasmi/extra-checks"]
2626
stable = []
2727
unstable = ["wasmi/unstable"]
28+
libm = ["wasmi/libm"]

0 commit comments

Comments
 (0)