Implement fma/fabs/fneg/fcopysign on the interpreter (#4367)

* cranelift: Implement `fma` on interpreter

* cranelift: Implement `fabs` on interpreter

* cranelift: Fix `fneg` implementation on interpreter

`fneg` was implemented as `0 - x` which is not correct according to the
standard since that operation makes no guarantees on what the output
is when the input is `NaN`. However for `fneg` the output for `NaN`
inputs is fully defined.

* cranelift: Implement `fcopysign` on interpreter
This commit is contained in:
Afonso Bordado
2022-07-05 17:03:04 +01:00
committed by GitHub
parent 5542c4ef26
commit 2003ae99a0
7 changed files with 511 additions and 10 deletions

View File

@@ -12,6 +12,7 @@ use core::str::FromStr;
use core::{i32, u32};
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
use std::ops::Neg;
/// Convert a type into a vector of bytes; all implementors in this file must use little-endian
/// orderings of bytes to match WebAssembly's little-endianness.
@@ -761,18 +762,39 @@ impl Ieee32 {
/// Check if the value is a NaN.
pub fn is_nan(&self) -> bool {
f32::from_bits(self.0).is_nan()
self.as_f32().is_nan()
}
/// Converts Self to a rust f32
pub fn as_f32(self) -> f32 {
f32::from_bits(self.0)
}
/// Fused multiply-add. Computes (self * a) + b with only one rounding error, yielding a
/// more accurate result than an unfused multiply-add.
pub fn mul_add(&self, a: Self, b: Self) -> Self {
Self::with_float(self.as_f32().mul_add(a.as_f32(), b.as_f32()))
}
/// Returns the square root of self.
pub fn sqrt(self) -> Self {
Self::with_float(f32::from_bits(self.0).sqrt())
Self::with_float(self.as_f32().sqrt())
}
/// Computes the absolute value of self.
pub fn abs(self) -> Self {
Self::with_float(self.as_f32().abs())
}
/// Returns a number composed of the magnitude of self and the sign of sign.
pub fn copysign(self, sign: Self) -> Self {
Self::with_float(self.as_f32().copysign(sign.as_f32()))
}
}
impl PartialOrd for Ieee32 {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
f32::from_bits(self.0).partial_cmp(&f32::from_bits(other.0))
self.as_f32().partial_cmp(&other.as_f32())
}
}
@@ -806,6 +828,14 @@ impl IntoBytes for Ieee32 {
}
}
impl Neg for Ieee32 {
type Output = Ieee32;
fn neg(self) -> Self::Output {
Self::with_float(self.as_f32().neg())
}
}
impl Ieee64 {
/// Create a new `Ieee64` containing the bits of `x`.
pub fn with_bits(x: u64) -> Self {
@@ -851,18 +881,39 @@ impl Ieee64 {
/// Check if the value is a NaN. For [Ieee64], this means checking that the 11 exponent bits are
/// all set.
pub fn is_nan(&self) -> bool {
f64::from_bits(self.0).is_nan()
self.as_f64().is_nan()
}
/// Converts Self to a rust f64
pub fn as_f64(self) -> f64 {
f64::from_bits(self.0)
}
/// Fused multiply-add. Computes (self * a) + b with only one rounding error, yielding a
/// more accurate result than an unfused multiply-add.
pub fn mul_add(&self, a: Self, b: Self) -> Self {
Self::with_float(self.as_f64().mul_add(a.as_f64(), b.as_f64()))
}
/// Returns the square root of self.
pub fn sqrt(self) -> Self {
Self::with_float(f64::from_bits(self.0).sqrt())
Self::with_float(self.as_f64().sqrt())
}
/// Computes the absolute value of self.
pub fn abs(self) -> Self {
Self::with_float(self.as_f64().abs())
}
/// Returns a number composed of the magnitude of self and the sign of sign.
pub fn copysign(self, sign: Self) -> Self {
Self::with_float(self.as_f64().copysign(sign.as_f64()))
}
}
impl PartialOrd for Ieee64 {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
f64::from_bits(self.0).partial_cmp(&f64::from_bits(other.0))
self.as_f64().partial_cmp(&other.as_f64())
}
}
@@ -902,6 +953,14 @@ impl IntoBytes for Ieee64 {
}
}
impl Neg for Ieee64 {
type Output = Ieee64;
fn neg(self) -> Self::Output {
Self::with_float(self.as_f64().neg())
}
}
#[cfg(test)]
mod tests {
use super::*;