diff --git a/cranelift/codegen/src/ir/immediates.rs b/cranelift/codegen/src/ir/immediates.rs index d48747cc27..6355cbff9c 100644 --- a/cranelift/codegen/src/ir/immediates.rs +++ b/cranelift/codegen/src/ir/immediates.rs @@ -8,11 +8,11 @@ use alloc::vec::Vec; use core::cmp::Ordering; use core::convert::TryFrom; use core::fmt::{self, Display, Formatter}; +use core::ops::{Add, Div, Mul, Neg, Sub}; 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. @@ -877,6 +877,38 @@ impl Neg for Ieee32 { } } +impl Add for Ieee32 { + type Output = Ieee32; + + fn add(self, rhs: Self) -> Self::Output { + Self::with_float(self.as_f32() + rhs.as_f32()) + } +} + +impl Sub for Ieee32 { + type Output = Ieee32; + + fn sub(self, rhs: Self) -> Self::Output { + Self::with_float(self.as_f32() - rhs.as_f32()) + } +} + +impl Mul for Ieee32 { + type Output = Ieee32; + + fn mul(self, rhs: Self) -> Self::Output { + Self::with_float(self.as_f32() * rhs.as_f32()) + } +} + +impl Div for Ieee32 { + type Output = Ieee32; + + fn div(self, rhs: Self) -> Self::Output { + Self::with_float(self.as_f32() / rhs.as_f32()) + } +} + impl Ieee64 { /// Create a new `Ieee64` containing the bits of `x`. pub fn with_bits(x: u64) -> Self { @@ -1043,6 +1075,38 @@ impl Neg for Ieee64 { } } +impl Add for Ieee64 { + type Output = Ieee64; + + fn add(self, rhs: Self) -> Self::Output { + Self::with_float(self.as_f64() + rhs.as_f64()) + } +} + +impl Sub for Ieee64 { + type Output = Ieee64; + + fn sub(self, rhs: Self) -> Self::Output { + Self::with_float(self.as_f64() - rhs.as_f64()) + } +} + +impl Mul for Ieee64 { + type Output = Ieee64; + + fn mul(self, rhs: Self) -> Self::Output { + Self::with_float(self.as_f64() * rhs.as_f64()) + } +} + +impl Div for Ieee64 { + type Output = Ieee64; + + fn div(self, rhs: Self) -> Self::Output { + Self::with_float(self.as_f64() / rhs.as_f64()) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/cranelift/filetests/filetests/runtests/fadd.clif b/cranelift/filetests/filetests/runtests/fadd.clif new file mode 100644 index 0000000000..6448615ae6 --- /dev/null +++ b/cranelift/filetests/filetests/runtests/fadd.clif @@ -0,0 +1,132 @@ +test interpret +test run +target x86_64 +target aarch64 +target s390x + +function %fadd_f32(f32, f32) -> f32 { +block0(v0: f32, v1: f32): + v2 = fadd v0, v1 + return v2 +} +; run: %fadd_f32(0x0.5, 0x1.0) == 0x1.5 +; run: %fadd_f32(0x1.5, 0x2.9) == 0x1.fp1 +; run: %fadd_f32(0x1.1p10, 0x1.400000p1) == 0x1.10ap10 +; run: %fadd_f32(0x1.4cccccp0, 0x1.800000p0) == 0x1.666666p1 +; run: %fadd_f32(0x1.b33334p0, 0x1.99999ap-2) == 0x1.0ccccep1 +; run: %fadd_f32(0x1.333334p-1, 0x1.666666p1) == 0x1.b33334p1 +; run: %fadd_f32(-0x0.5, -0x1.0) == -0x1.5p0 +; run: %fadd_f32(-0x1.5, -0x2.9) == -0x1.fp1 +; run: %fadd_f32(-0x1.1p10, -0x1.333334p-1) == -0x1.102666p10 +; run: %fadd_f32(-0x1.99999ap-2, -0x1.4cccccp0) == -0x1.b33332p0 +; run: %fadd_f32(-0x1.800000p0, -0x1.b33334p0) == -0x1.99999ap1 +; run: %fadd_f32(-0x1.400000p1, -0x1.666666p1) == -0x1.533334p2 +; run: %fadd_f32(0x0.5, -0x1.0) == -0x1.6p-1 +; run: %fadd_f32(0x1.b33334p0, -0x1.b33334p0) == 0x0.0 + +; Specials +; run: %fadd_f32(0x0.0, -0x0.0) == 0x0.0 +; run: %fadd_f32(-0x0.0, 0x0.0) == 0x0.0 +; run: %fadd_f32(-0x0.0, +Inf) == +Inf +; run: %fadd_f32(0x0.0, -Inf) == -Inf + +; F32 Epsilon / Max / Min Positive +; run: %fadd_f32(0x1.000000p-23, 0x1.fffffep127) == 0x1.fffffep127 +; run: %fadd_f32(0x1.000000p-23, 0x1.000000p-126) == 0x1.000000p-23 +; run: %fadd_f32(0x1.fffffep127, 0x1.fffffep127) == +Inf +; run: %fadd_f32(0x1.000000p-126, 0x1.fffffep127) == 0x1.fffffep127 +; run: %fadd_f32(0x1.000000p-126, 0x1.000000p-126) == 0x1.000000p-125 + +; F32 Subnormals +; run: %fadd_f32(0x0.800000p-126, -0x0.800002p-126) == -0x0.000002p-126 +; run: %fadd_f32(0x0.800000p-126, 0x1.0) == 0x1.0 +; run: %fadd_f32(-0x0.800002p-126, 0x1.0) == 0x1.0 + +; F32 NaN's +; For NaN's this operation is specified as producing a value that is a NaN +function %fadd_is_nan_f32(f32, f32) -> i32 { +block0(v0: f32, v1: f32): + v2 = fadd v0, v1 + v3 = fcmp ne v2, v2 + v4 = bint.i32 v3 + return v4 +} +; run: %fadd_is_nan_f32(+Inf, -Inf) == 1 +; run: %fadd_is_nan_f32(-Inf, +Inf) == 1 +; run: %fadd_is_nan_f32(0x0.0, +NaN) == 1 +; run: %fadd_is_nan_f32(0x0.0, -NaN) == 1 +; run: %fadd_is_nan_f32(0x0.0, +NaN:0x0) == 1 +; run: %fadd_is_nan_f32(0x0.0, +NaN:0x1) == 1 +; run: %fadd_is_nan_f32(0x0.0, +NaN:0x300001) == 1 +; run: %fadd_is_nan_f32(0x0.0, -NaN:0x0) == 1 +; run: %fadd_is_nan_f32(0x0.0, -NaN:0x1) == 1 +; run: %fadd_is_nan_f32(0x0.0, -NaN:0x300001) == 1 +; run: %fadd_is_nan_f32(0x0.0, +sNaN:0x1) == 1 +; run: %fadd_is_nan_f32(0x0.0, -sNaN:0x1) == 1 +; run: %fadd_is_nan_f32(0x0.0, +sNaN:0x200001) == 1 +; run: %fadd_is_nan_f32(0x0.0, -sNaN:0x200001) == 1 + + + +function %fadd_f64(f64, f64) -> f64 { +block0(v0: f64, v1: f64): + v2 = fadd v0, v1 + return v2 +} +; run: %fadd_f64(0x0.5, 0x1.0) == 0x1.5 +; run: %fadd_f64(0x1.5, 0x2.9) == 0x1.fp1 +; run: %fadd_f64(0x1.1p10, 0x1.4p1) == 0x1.10ap10 +; run: %fadd_f64(0x1.4cccccccccccdp0, 0x1.8p0) == 0x1.6666666666666p1 +; run: %fadd_f64(0x1.b333333333333p0, 0x1.999999999999ap-2) == 0x1.0cccccccccccdp1 +; run: %fadd_f64(0x1.3333333333333p-1, 0x1.6666666666666p1) == 0x1.b333333333333p1 +; run: %fadd_f64(-0x0.5, -0x1.0) == -0x1.5p0 +; run: %fadd_f64(-0x1.5, -0x2.9) == -0x1.fp1 +; run: %fadd_f64(-0x1.1p10, -0x1.3333333333333p-1) == -0x1.1026666666666p10 +; run: %fadd_f64(-0x1.999999999999ap-2, -0x1.4cccccccccccdp0) == -0x1.b333333333334p0 +; run: %fadd_f64(-0x1.8p0, -0x1.b333333333333p0) == -0x1.999999999999ap1 +; run: %fadd_f64(-0x1.4p1, -0x1.6666666666666p1) == -0x1.5333333333333p2 +; run: %fadd_f64(0x0.5, -0x1.0) == -0x1.6p-1 +; run: %fadd_f64(0x1.b333333333333p0, -0x1.b333333333333p0) == 0x0.0 + +; Specials +; run: %fadd_f64(0x0.0, -0x0.0) == 0x0.0 +; run: %fadd_f64(-0x0.0, 0x0.0) == 0x0.0 +; run: %fadd_f64(-0x0.0, +Inf) == +Inf +; run: %fadd_f64(0x0.0, -Inf) == -Inf + +; F64 Epsilon / Max / Min Positive +; run: %fadd_f64(0x1.0p-52, 0x1.fffffffffffffp1023) == 0x1.fffffffffffffp1023 +; run: %fadd_f64(0x1.0p-52, 0x1.0p-1022) == 0x1.0p-52 +; run: %fadd_f64(0x1.fffffffffffffp1023, 0x1.fffffffffffffp1023) == +Inf +; run: %fadd_f64(0x1.0p-1022, 0x1.fffffffffffffp1023) == 0x1.fffffffffffffp1023 +; run: %fadd_f64(0x1.0p-1022, 0x1.0p-1022) == 0x1.0p-1021 + +; F64 Subnormals +; run: %fadd_f64(0x0.8p-1022, -0x0.8p-1022) == 0x0.0 +; run: %fadd_f64(0x0.8p-1022, 0x1.0) == 0x1.0 +; run: %fadd_f64(-0x0.8p-1022, 0x1.0) == 0x1.0 + + +; F64 NaN's +; For NaN's this operation is specified as producing a value that is a NaN +function %fadd_is_nan_f64(f64, f64) -> i32 { +block0(v0: f64, v1: f64): + v2 = fadd v0, v1 + v3 = fcmp ne v2, v2 + v4 = bint.i32 v3 + return v4 +} +; run: %fadd_is_nan_f64(+Inf, -Inf) == 1 +; run: %fadd_is_nan_f64(-Inf, +Inf) == 1 +; run: %fadd_is_nan_f64(0x0.0, +NaN) == 1 +; run: %fadd_is_nan_f64(0x0.0, -NaN) == 1 +; run: %fadd_is_nan_f64(0x0.0, +NaN:0x0) == 1 +; run: %fadd_is_nan_f64(0x0.0, +NaN:0x1) == 1 +; run: %fadd_is_nan_f64(0x0.0, +NaN:0x4000000000001) == 1 +; run: %fadd_is_nan_f64(0x0.0, -NaN:0x0) == 1 +; run: %fadd_is_nan_f64(0x0.0, -NaN:0x1) == 1 +; run: %fadd_is_nan_f64(0x0.0, -NaN:0x4000000000001) == 1 +; run: %fadd_is_nan_f64(0x0.0, +sNaN:0x1) == 1 +; run: %fadd_is_nan_f64(0x0.0, -sNaN:0x1) == 1 +; run: %fadd_is_nan_f64(0x0.0, +sNaN:0x4000000000001) == 1 +; run: %fadd_is_nan_f64(0x0.0, -sNaN:0x4000000000001) == 1 diff --git a/cranelift/filetests/filetests/runtests/fdiv.clif b/cranelift/filetests/filetests/runtests/fdiv.clif new file mode 100644 index 0000000000..681f9b4bdb --- /dev/null +++ b/cranelift/filetests/filetests/runtests/fdiv.clif @@ -0,0 +1,170 @@ +test interpret +test run +target x86_64 +target aarch64 +target s390x + +function %fdiv_f32(f32, f32) -> f32 { +block0(v0: f32, v1: f32): + v2 = fdiv v0, v1 + return v2 +} +; run: %fdiv_f32(0x0.5, 0x1.0) == 0x1.4p-2 +; run: %fdiv_f32(0x1.5, 0x2.9) == 0x1.063e70p-1 +; run: %fdiv_f32(0x1.1p10, 0x1.4p1) == 0x1.b33334p8 +; run: %fdiv_f32(0x1.4cccccp0, 0x1.8p0) == 0x1.bbbbbap-1 +; run: %fdiv_f32(0x1.b33334p0, 0x1.99999ap-2) == 0x1.1p2 +; run: %fdiv_f32(0x1.333334p-1, 0x1.666666p1) == 0x1.b6db70p-3 +; run: %fdiv_f32(-0x0.5, -0x1.0) == 0x1.4p-2 +; run: %fdiv_f32(-0x1.5, -0x2.9) == 0x1.063e70p-1 +; run: %fdiv_f32(-0x1.1p10, -0x1.333334p-1) == 0x1.c55554p10 +; run: %fdiv_f32(-0x1.99999ap-2, -0x1.4cccccp0) == 0x1.3b13b2p-2 +; run: %fdiv_f32(-0x1.8p0, -0x1.b33334p0) == 0x1.c3c3c2p-1 +; run: %fdiv_f32(-0x1.4p1, -0x1.666666p1) == 0x1.c92492p-1 +; run: %fdiv_f32(0x0.5, -0x1.0) == -0x1.4p-2 +; run: %fdiv_f32(0x1.b33334p0, -0x1.b33334p0) == -0x1.0p0 +; run: %fdiv_f32(0x0.5, 0x0.0) == +Inf +; run: %fdiv_f32(0x1.5, -0x0.0) == -Inf +; run: %fdiv_f32(0x1.1p10, 0x0.0) == +Inf +; run: %fdiv_f32(0x1.4cccccp0, -0x0.0) == -Inf +; run: %fdiv_f32(-0x0.5, 0x0.0) == -Inf +; run: %fdiv_f32(-0x1.5, -0x0.0) == +Inf +; run: %fdiv_f32(-0x1.1p10, 0x0.0) == -Inf +; run: %fdiv_f32(-0x1.4cccccp0, -0x0.0) == +Inf + +; F32 Epsilon / Max / Min Positive +; run: %fdiv_f32(0x1.0p-23, 0x1.fffffep127) == 0x0.0 +; run: %fdiv_f32(0x1.0p-23, 0x1.0p-126) == 0x1.0p103 +; run: %fdiv_f32(0x1.fffffep127, 0x1.fffffep127) == 0x1.0 +; run: %fdiv_f32(0x1.0p-126, 0x1.fffffep127) == 0x0.0 +; run: %fdiv_f32(0x1.0p-126, 0x1.0p-126) == 0x1.0 + +; Specials +; run: %fdiv_f32(0x0.0, -Inf) == -0x0.0 +; run: %fdiv_f32(0x0.0, -0x1.0) == -0x0.0 +; run: %fdiv_f32(0x0.0, +Inf) == 0x0.0 +; run: %fdiv_f32(0x0.0, 0x1.0) == 0x0.0 +; run: %fdiv_f32(-0x0.0, -Inf) == 0x0.0 +; run: %fdiv_f32(-0x0.0, -0x1.0) == 0x0.0 +; run: %fdiv_f32(-0x0.0, +Inf) == -0x0.0 +; run: %fdiv_f32(-0x0.0, 0x1.0) == -0x0.0 +; run: %fdiv_f32(Inf, -0x1.0) == -Inf +; run: %fdiv_f32(Inf, 0x1.0) == +Inf +; run: %fdiv_f32(-Inf, -0x1.0) == +Inf + +; F32 Subnormals +; run: %fdiv_f32(0x0.8p-126, -0x0.800002p-126) == -0x1.fffff8p-1 +; run: %fdiv_f32(0x0.8p-126, 0x1.0) == 0x0.8p-126 +; run: %fdiv_f32(-0x0.800002p-126, 0x1.0) == -0x0.800002p-126 + +; F32 NaN's +; For NaN's this operation is specified as producing a value that is a NaN +function %fdiv_is_nan_f32(f32, f32) -> i32 { +block0(v0: f32, v1: f32): + v2 = fdiv v0, v1 + v3 = fcmp ne v2, v2 + v4 = bint.i32 v3 + return v4 +} +; run: %fdiv_is_nan_f32(0x0.0, -0x0.0) == 1 +; run: %fdiv_is_nan_f32(-0x0.0, 0x0.0) == 1 +; run: %fdiv_is_nan_f32(+Inf, +Inf) == 1 +; run: %fdiv_is_nan_f32(-Inf, -Inf) == 1 +; run: %fdiv_is_nan_f32(+Inf, -Inf) == 1 +; run: %fdiv_is_nan_f32(-Inf, +Inf) == 1 +; run: %fdiv_is_nan_f32(0x0.0, +NaN) == 1 +; run: %fdiv_is_nan_f32(-NaN, 0x0.0) == 1 +; run: %fdiv_is_nan_f32(0x0.0, +NaN:0x0) == 1 +; run: %fdiv_is_nan_f32(+NaN:0x1, 0x0.0) == 1 +; run: %fdiv_is_nan_f32(0x0.0, +NaN:0x300001) == 1 +; run: %fdiv_is_nan_f32(-NaN:0x0, 0x0.0) == 1 +; run: %fdiv_is_nan_f32(0x0.0, -NaN:0x1) == 1 +; run: %fdiv_is_nan_f32(-NaN:0x300001, 0x0.0) == 1 +; run: %fdiv_is_nan_f32(0x0.0, +sNaN:0x1) == 1 +; run: %fdiv_is_nan_f32(-sNaN:0x1, 0x0.0) == 1 +; run: %fdiv_is_nan_f32(0x0.0, +sNaN:0x200001) == 1 +; run: %fdiv_is_nan_f32(-sNaN:0x200001, 0x0.0) == 1 + + + +function %fdiv_f64(f64, f64) -> f64 { +block0(v0: f64, v1: f64): + v2 = fdiv v0, v1 + return v2 +} +; run: %fdiv_f64(0x0.5, 0x1.0) == 0x1.4p-2 +; run: %fdiv_f64(0x1.5, 0x2.9) == 0x1.063e7063e7064p-1 +; run: %fdiv_f64(0x1.1p10, 0x1.4p1) == 0x1.b333333333333p8 +; run: %fdiv_f64(0x1.4cccccccccccdp0, 0x1.8p0) == 0x1.bbbbbbbbbbbbcp-1 +; run: %fdiv_f64(0x1.b333333333333p0, 0x1.999999999999ap-2) == 0x1.1p2 +; run: %fdiv_f64(0x1.3333333333333p-1, 0x1.6666666666666p1) == 0x1.b6db6db6db6dcp-3 +; run: %fdiv_f64(-0x0.5, -0x1.0) == 0x1.4p-2 +; run: %fdiv_f64(-0x1.5, -0x2.9) == 0x1.063e7063e7064p-1 +; run: %fdiv_f64(-0x1.1p10, -0x1.3333333333333p-1) == 0x1.c555555555556p10 +; run: %fdiv_f64(-0x1.999999999999ap-2, -0x1.4cccccccccccdp0) == 0x1.3b13b13b13b14p-2 +; run: %fdiv_f64(-0x1.8p0, -0x1.b333333333333p0) == 0x1.c3c3c3c3c3c3cp-1 +; run: %fdiv_f64(-0x1.4p1, -0x1.6666666666666p1) == 0x1.c924924924925p-1 +; run: %fdiv_f64(0x0.5, -0x1.0) == -0x1.4p-2 +; run: %fdiv_f64(0x1.b333333333333p0, -0x1.b333333333333p0) == -0x1.0 +; run: %fdiv_f64(0x0.5, 0x0.0) == +Inf +; run: %fdiv_f64(0x1.5, -0x0.0) == -Inf +; run: %fdiv_f64(0x1.1p10, 0x0.0) == +Inf +; run: %fdiv_f64(0x1.4cccccccccccdp0, -0x0.0) == -Inf +; run: %fdiv_f64(-0x0.5, 0x0.0) == -Inf +; run: %fdiv_f64(-0x1.5, -0x0.0) == +Inf +; run: %fdiv_f64(-0x1.1p10, 0x0.0) == -Inf +; run: %fdiv_f64(-0x1.4cccccccccccdp0, -0x0.0) == +Inf + +; Specials +; run: %fdiv_f64(0x0.0, -Inf) == -0x0.0 +; run: %fdiv_f64(0x0.0, -0x1.0) == -0x0.0 +; run: %fdiv_f64(0x0.0, +Inf) == 0x0.0 +; run: %fdiv_f64(0x0.0, 0x1.0) == 0x0.0 +; run: %fdiv_f64(-0x0.0, -Inf) == 0x0.0 +; run: %fdiv_f64(-0x0.0, -0x1.0) == 0x0.0 +; run: %fdiv_f64(-0x0.0, +Inf) == -0x0.0 +; run: %fdiv_f64(-0x0.0, 0x1.0) == -0x0.0 +; run: %fdiv_f64(Inf, -0x1.0) == -Inf +; run: %fdiv_f64(Inf, 0x1.0) == +Inf +; run: %fdiv_f64(-Inf, -0x1.0) == +Inf + +; F64 Epsilon / Max / Min Positive +; run: %fdiv_f64(0x1.0p-52, 0x1.fffffffffffffp1023) == 0x0.0 +; run: %fdiv_f64(0x1.0p-52, 0x1.0p-1022) == 0x1.0p970 +; run: %fdiv_f64(0x1.fffffffffffffp1023, 0x1.fffffffffffffp1023) == 0x1.0 +; run: %fdiv_f64(0x1.0p-1022, 0x1.fffffffffffffp1023) == 0x0.0 +; run: %fdiv_f64(0x1.0p-1022, 0x1.0p-1022) == 0x1.0 + +; F64 Subnormals +; run: %fdiv_f64(0x0.8p-1022, -0x0.8p-1022) == -0x1.0 +; run: %fdiv_f64(0x0.8p-1022, 0x1.0) == 0x0.8p-1022 +; run: %fdiv_f64(-0x0.8p-1022, 0x1.0) == -0x0.8p-1022 + + +; F64 NaN's +; For NaN's this operation is specified as producing a value that is a NaN +function %fdiv_is_nan_f64(f64, f64) -> i32 { +block0(v0: f64, v1: f64): + v2 = fdiv v0, v1 + v3 = fcmp ne v2, v2 + v4 = bint.i32 v3 + return v4 +} +; run: %fdiv_is_nan_f64(0x0.0, -0x0.0) == 1 +; run: %fdiv_is_nan_f64(-0x0.0, 0x0.0) == 1 +; run: %fdiv_is_nan_f64(+Inf, +Inf) == 1 +; run: %fdiv_is_nan_f64(-Inf, -Inf) == 1 +; run: %fdiv_is_nan_f64(+Inf, -Inf) == 1 +; run: %fdiv_is_nan_f64(-Inf, +Inf) == 1 +; run: %fdiv_is_nan_f64(0x0.0, +NaN) == 1 +; run: %fdiv_is_nan_f64(-NaN, 0x0.0) == 1 +; run: %fdiv_is_nan_f64(0x0.0, +NaN:0x0) == 1 +; run: %fdiv_is_nan_f64(+NaN:0x1, 0x0.0) == 1 +; run: %fdiv_is_nan_f64(0x0.0, +NaN:0x4000000000001) == 1 +; run: %fdiv_is_nan_f64(-NaN:0x0, 0x0.0) == 1 +; run: %fdiv_is_nan_f64(0x0.0, -NaN:0x1) == 1 +; run: %fdiv_is_nan_f64(-NaN:0x4000000000001, 0x0.0) == 1 +; run: %fdiv_is_nan_f64(0x0.0, +sNaN:0x1) == 1 +; run: %fdiv_is_nan_f64(-sNaN:0x1, 0x0.0) == 1 +; run: %fdiv_is_nan_f64(0x0.0, +sNaN:0x4000000000001) == 1 +; run: %fdiv_is_nan_f64(-sNaN:0x4000000000001, 0x0.0) == 1 diff --git a/cranelift/filetests/filetests/runtests/fmul.clif b/cranelift/filetests/filetests/runtests/fmul.clif new file mode 100644 index 0000000000..d477032010 --- /dev/null +++ b/cranelift/filetests/filetests/runtests/fmul.clif @@ -0,0 +1,132 @@ +test interpret +test run +target x86_64 +target aarch64 +target s390x + +function %fmul_f32(f32, f32) -> f32 { +block0(v0: f32, v1: f32): + v2 = fmul v0, v1 + return v2 +} +; run: %fmul_f32(0x0.5, 0x1.0) == 0x1.4p-2 +; run: %fmul_f32(0x1.5, 0x2.9) == 0x1.ae8p1 +; run: %fmul_f32(0x1.1p10, 0x1.4p1) == 0x1.54p11 +; run: %fmul_f32(0x1.4cccccp0, 0x1.8p0) == 0x1.f33332p0 +; run: %fmul_f32(0x1.b33334p0, 0x1.99999ap-2) == 0x1.5c28f6p-1 +; run: %fmul_f32(0x1.333334p-1, 0x1.666666p1) == 0x1.ae147cp0 +; run: %fmul_f32(-0x0.5, -0x1.0) == 0x1.4p-2 +; run: %fmul_f32(-0x1.5, -0x2.9) == 0x1.ae8p1 +; run: %fmul_f32(-0x1.1p10, -0x1.333334p-1) == 0x1.466668p9 +; run: %fmul_f32(-0x1.99999ap-2, -0x1.4cccccp0) == 0x1.0a3d70p-1 +; run: %fmul_f32(-0x1.8p0, -0x1.b33334p0) == 0x1.466668p1 +; run: %fmul_f32(-0x1.4p1, -0x1.666666p1) == 0x1.c00000p2 +; run: %fmul_f32(0x0.5, -0x1.0) == -0x1.4p-2 +; run: %fmul_f32(0x1.b33334p0, -0x1.b33334p0) == -0x1.71eb86p1 + +; Specials +; run: %fmul_f32(0x0.0, -0x0.0) == -0x0.0 +; run: %fmul_f32(-0x0.0, 0x0.0) == -0x0.0 +; run: %fmul_f32(+Inf, -Inf) == -Inf +; run: %fmul_f32(-Inf, +Inf) == -Inf + +; F32 Epsilon / Max / Min Positive +; run: %fmul_f32(0x1.0p-23, 0x1.fffffep127) == 0x1.fffffep104 +; run: %fmul_f32(0x1.0p-23, 0x1.0p-126) == 0x0.000002p-126 +; run: %fmul_f32(0x1.fffffep127, 0x1.fffffep127) == +Inf +; run: %fmul_f32(0x1.0p-126, 0x1.fffffep127) == 0x1.fffffep1 +; run: %fmul_f32(0x1.0p-126, 0x1.0p-126) == 0x0.0 + +; F32 Subnormals +; run: %fmul_f32(0x0.8p-126, -0x0.800002p-126) == -0x0.0 +; run: %fmul_f32(0x0.8p-126, 0x1.0) == 0x0.8p-126 +; run: %fmul_f32(-0x0.800002p-126, 0x1.0) == -0x0.800002p-126 + +; F32 NaN's +; For NaN's this operation is specified as producing a value that is a NaN +function %fmul_is_nan_f32(f32, f32) -> i32 { +block0(v0: f32, v1: f32): + v2 = fmul v0, v1 + v3 = fcmp ne v2, v2 + v4 = bint.i32 v3 + return v4 +} +; run: %fmul_is_nan_f32(-0x0.0, +Inf) == 1 +; run: %fmul_is_nan_f32(0x0.0, -Inf) == 1 +; run: %fmul_is_nan_f32(0x0.0, +NaN) == 1 +; run: %fmul_is_nan_f32(0x0.0, -NaN) == 1 +; run: %fmul_is_nan_f32(0x0.0, +NaN:0x0) == 1 +; run: %fmul_is_nan_f32(0x0.0, +NaN:0x1) == 1 +; run: %fmul_is_nan_f32(0x0.0, +NaN:0x300001) == 1 +; run: %fmul_is_nan_f32(0x0.0, -NaN:0x0) == 1 +; run: %fmul_is_nan_f32(0x0.0, -NaN:0x1) == 1 +; run: %fmul_is_nan_f32(0x0.0, -NaN:0x300001) == 1 +; run: %fmul_is_nan_f32(0x0.0, +sNaN:0x1) == 1 +; run: %fmul_is_nan_f32(0x0.0, -sNaN:0x1) == 1 +; run: %fmul_is_nan_f32(0x0.0, +sNaN:0x200001) == 1 +; run: %fmul_is_nan_f32(0x0.0, -sNaN:0x200001) == 1 + + + +function %fmul_f64(f64, f64) -> f64 { +block0(v0: f64, v1: f64): + v2 = fmul v0, v1 + return v2 +} +; run: %fmul_f64(0x0.5, 0x1.0) == 0x1.4p-2 +; run: %fmul_f64(0x1.5, 0x2.9) == 0x1.ae8p1 +; run: %fmul_f64(0x1.1p10, 0x1.4p1) == 0x1.54p11 +; run: %fmul_f64(0x1.4cccccccccccdp0, 0x1.8p0) == 0x1.f333333333334p0 +; run: %fmul_f64(0x1.b333333333333p0, 0x1.999999999999ap-2) == 0x1.5c28f5c28f5c3p-1 +; run: %fmul_f64(0x1.3333333333333p-1, 0x1.6666666666666p1) == 0x1.ae147ae147ae1p0 +; run: %fmul_f64(-0x0.5, -0x1.0) == 0x1.4p-2 +; run: %fmul_f64(-0x1.5, -0x2.9) == 0x1.ae8p1 +; run: %fmul_f64(-0x1.1p10, -0x1.3333333333333p-1) == 0x1.4666666666666p9 +; run: %fmul_f64(-0x1.999999999999ap-2, -0x1.4cccccccccccdp0) == 0x1.0a3d70a3d70a4p-1 +; run: %fmul_f64(-0x1.8p0, -0x1.b333333333333p0) == 0x1.4666666666666p1 +; run: %fmul_f64(-0x1.4p1, -0x1.6666666666666p1) == 0x1.cp2 +; run: %fmul_f64(0x0.5, -0x1.0) == -0x1.4p-2 +; run: %fmul_f64(0x1.b333333333333p0, -0x1.b333333333333p0) == -0x1.71eb851eb851ep1 + +; Specials +; run: %fmul_f64(0x0.0, -0x0.0) == -0x0.0 +; run: %fmul_f64(-0x0.0, 0x0.0) == -0x0.0 +; run: %fmul_f64(+Inf, -Inf) == -Inf +; run: %fmul_f64(-Inf, +Inf) == -Inf + +; F64 Epsilon / Max / Min Positive +; run: %fmul_f64(0x1.0p-52, 0x1.fffffffffffffp1023) == 0x1.fffffffffffffp971 +; run: %fmul_f64(0x1.0p-52, 0x1.0p-1022) == 0x0.0000000000001p-1022 +; run: %fmul_f64(0x1.fffffffffffffp1023, 0x1.fffffffffffffp1023) == +Inf +; run: %fmul_f64(0x1.0p-1022, 0x1.fffffffffffffp1023) == 0x1.fffffffffffffp1 +; run: %fmul_f64(0x1.0p-1022, 0x1.0p-1022) == 0x0.0 + +; F64 Subnormals +; run: %fmul_f64(0x0.8p-1022, -0x0.8p-1022) == -0x0.0 +; run: %fmul_f64(0x0.8p-1022, 0x1.0) == 0x0.8p-1022 +; run: %fmul_f64(-0x0.8p-1022, 0x1.0) == -0x0.8p-1022 + + +; F64 NaN's +; For NaN's this operation is specified as producing a value that is a NaN +function %fmul_is_nan_f64(f64, f64) -> i32 { +block0(v0: f64, v1: f64): + v2 = fmul v0, v1 + v3 = fcmp ne v2, v2 + v4 = bint.i32 v3 + return v4 +} +; run: %fmul_is_nan_f64(-0x0.0, +Inf) == 1 +; run: %fmul_is_nan_f64(0x0.0, -Inf) == 1 +; run: %fmul_is_nan_f64(0x0.0, +NaN) == 1 +; run: %fmul_is_nan_f64(0x0.0, -NaN) == 1 +; run: %fmul_is_nan_f64(0x0.0, +NaN:0x0) == 1 +; run: %fmul_is_nan_f64(0x0.0, +NaN:0x1) == 1 +; run: %fmul_is_nan_f64(0x0.0, +NaN:0x4000000000001) == 1 +; run: %fmul_is_nan_f64(0x0.0, -NaN:0x0) == 1 +; run: %fmul_is_nan_f64(0x0.0, -NaN:0x1) == 1 +; run: %fmul_is_nan_f64(0x0.0, -NaN:0x4000000000001) == 1 +; run: %fmul_is_nan_f64(0x0.0, +sNaN:0x1) == 1 +; run: %fmul_is_nan_f64(0x0.0, -sNaN:0x1) == 1 +; run: %fmul_is_nan_f64(0x0.0, +sNaN:0x4000000000001) == 1 +; run: %fmul_is_nan_f64(0x0.0, -sNaN:0x4000000000001) == 1 diff --git a/cranelift/filetests/filetests/runtests/fsub.clif b/cranelift/filetests/filetests/runtests/fsub.clif new file mode 100644 index 0000000000..8976af7a85 --- /dev/null +++ b/cranelift/filetests/filetests/runtests/fsub.clif @@ -0,0 +1,132 @@ +test interpret +test run +target x86_64 +target aarch64 +target s390x + +function %fsub_f32(f32, f32) -> f32 { +block0(v0: f32, v1: f32): + v2 = fsub v0, v1 + return v2 +} +; run: %fsub_f32(0x0.5, 0x1.0) == -0x1.6p-1 +; run: %fsub_f32(0x1.5, 0x2.9) == -0x1.4p0 +; run: %fsub_f32(0x1.1p10, 0x1.4p1) == 0x1.0f6p10 +; run: %fsub_f32(0x1.4cccccp0, 0x1.8p0) == -0x1.9999a0p-3 +; run: %fsub_f32(0x1.b33334p0, 0x1.99999ap-2) == 0x1.4ccccep0 +; run: %fsub_f32(0x1.333334p-1, 0x1.666666p1) == -0x1.199998p1 +; run: %fsub_f32(-0x0.5, -0x1.0) == 0x1.6p-1 +; run: %fsub_f32(-0x1.5, -0x2.9) == 0x1.4p0 +; run: %fsub_f32(-0x1.1p10, -0x1.333334p-1) == -0x1.0fd99ap10 +; run: %fsub_f32(-0x1.99999ap-2, -0x1.4cccccp0) == 0x1.ccccccp-1 +; run: %fsub_f32(-0x1.8p0, -0x1.b33334p0) == 0x1.9999a0p-3 +; run: %fsub_f32(-0x1.4p1, -0x1.666666p1) == 0x1.333330p-2 +; run: %fsub_f32(0x0.5, -0x1.0) == 0x1.5p0 +; run: %fsub_f32(0x1.b33334p0, -0x1.b33334p0) == 0x1.b33334p1 + +; Specials +; run: %fsub_f32(0x0.0, -0x0.0) == 0x0.0 +; run: %fsub_f32(-0x0.0, 0x0.0) == -0x0.0 +; run: %fsub_f32(-0x0.0, +Inf) == -Inf +; run: %fsub_f32(0x0.0, -Inf) == +Inf +; run: %fsub_f32(+Inf, -Inf) == +Inf +; run: %fsub_f32(-Inf, +Inf) == -Inf + +; F32 Epsilon / Max / Min Positive +; run: %fsub_f32(0x1.0p-23, 0x1.fffffep127) == -0x1.fffffep127 +; run: %fsub_f32(0x1.0p-23, 0x1.0p-126) == 0x1.0p-23 +; run: %fsub_f32(0x1.fffffep127, 0x1.fffffep127) == 0x0.0 +; run: %fsub_f32(0x1.0p-126, 0x1.fffffep127) == -0x1.fffffep127 +; run: %fsub_f32(0x1.0p-126, 0x1.0p-126) == 0x0.0 + +; F32 Subnormals +; run: %fsub_f32(0x0.8p-126, -0x0.800002p-126) == 0x1.000002p-126 +; run: %fsub_f32(0x0.8p-126, 0x1.0) == -0x1.0 +; run: %fsub_f32(-0x0.800002p-126, 0x1.0) == -0x1.0 + +; F32 NaN's +; For NaN's this operation is specified as producing a value that is a NaN +function %fsub_is_nan_f32(f32, f32) -> i32 { +block0(v0: f32, v1: f32): + v2 = fsub v0, v1 + v3 = fcmp ne v2, v2 + v4 = bint.i32 v3 + return v4 +} +; run: %fsub_is_nan_f32(0x0.0, +NaN) == 1 +; run: %fsub_is_nan_f32(0x0.0, -NaN) == 1 +; run: %fsub_is_nan_f32(0x0.0, +NaN:0x0) == 1 +; run: %fsub_is_nan_f32(0x0.0, +NaN:0x1) == 1 +; run: %fsub_is_nan_f32(0x0.0, +NaN:0x300001) == 1 +; run: %fsub_is_nan_f32(0x0.0, -NaN:0x0) == 1 +; run: %fsub_is_nan_f32(0x0.0, -NaN:0x1) == 1 +; run: %fsub_is_nan_f32(0x0.0, -NaN:0x300001) == 1 +; run: %fsub_is_nan_f32(0x0.0, +sNaN:0x1) == 1 +; run: %fsub_is_nan_f32(0x0.0, -sNaN:0x1) == 1 +; run: %fsub_is_nan_f32(0x0.0, +sNaN:0x200001) == 1 +; run: %fsub_is_nan_f32(0x0.0, -sNaN:0x200001) == 1 + + + +function %fsub_f64(f64, f64) -> f64 { +block0(v0: f64, v1: f64): + v2 = fsub v0, v1 + return v2 +} +; run: %fsub_f64(0x0.5, 0x1.0) == -0x1.6p-1 +; run: %fsub_f64(0x1.5, 0x2.9) == -0x1.4 +; run: %fsub_f64(0x1.1p10, 0x1.4p1) == 0x1.0f6p10 +; run: %fsub_f64(0x1.4cccccccccccdp0, 0x1.8p0) == -0x1.9999999999998p-3 +; run: %fsub_f64(0x1.b333333333333p0, 0x1.999999999999ap-2) == 0x1.4ccccccccccccp0 +; run: %fsub_f64(0x1.3333333333333p-1, 0x1.6666666666666p1) == -0x1.1999999999999p1 +; run: %fsub_f64(-0x0.5, -0x1.0) == 0x1.6p-1 +; run: %fsub_f64(-0x1.5, -0x2.9) == 0x1.4 +; run: %fsub_f64(-0x1.1p10, -0x1.3333333333333p-1) == -0x1.0fd999999999ap10 +; run: %fsub_f64(-0x1.999999999999ap-2, -0x1.4cccccccccccdp0) == 0x1.ccccccccccccdp-1 +; run: %fsub_f64(-0x1.8p0, -0x1.b333333333333p0) == 0x1.9999999999998p-3 +; run: %fsub_f64(-0x1.4p1, -0x1.6666666666666p1) == 0x1.3333333333330p-2 +; run: %fsub_f64(0x0.5, -0x1.0) == 0x1.5 +; run: %fsub_f64(0x1.b333333333333p0, -0x1.b333333333333p0) == 0x1.b333333333333p1 + +; Specials +; run: %fsub_f64(0x0.0, -0x0.0) == 0x0.0 +; run: %fsub_f64(-0x0.0, 0x0.0) == -0x0.0 +; run: %fsub_f64(-0x0.0, +Inf) == -Inf +; run: %fsub_f64(0x0.0, -Inf) == +Inf +; run: %fsub_f64(+Inf, -Inf) == +Inf +; run: %fsub_f64(-Inf, +Inf) == -Inf + +; F64 Epsilon / Max / Min Positive +; run: %fsub_f64(0x1.0p-52, 0x1.fffffffffffffp1023) == -0x1.fffffffffffffp1023 +; run: %fsub_f64(0x1.0p-52, 0x1.0p-1022) == 0x1.0p-52 +; run: %fsub_f64(0x1.fffffffffffffp1023, 0x1.fffffffffffffp1023) == 0x0.0 +; run: %fsub_f64(0x1.0p-1022, 0x1.fffffffffffffp1023) == -0x1.fffffffffffffp1023 +; run: %fsub_f64(0x1.0p-1022, 0x1.0p-1022) == 0x0.0 + +; F64 Subnormals +; run: %fsub_f64(0x0.8p-1022, -0x0.8p-1022) == 0x1.0000000000000p-1022 +; run: %fsub_f64(0x0.8p-1022, 0x1.0) == -0x1.0 +; run: %fsub_f64(-0x0.8p-1022, 0x1.0) == -0x1.0 + + +; F64 NaN's +; For NaN's this operation is specified as producing a value that is a NaN +function %fsub_is_nan_f64(f64, f64) -> i32 { +block0(v0: f64, v1: f64): + v2 = fsub v0, v1 + v3 = fcmp ne v2, v2 + v4 = bint.i32 v3 + return v4 +} +; run: %fsub_is_nan_f64(0x0.0, +NaN) == 1 +; run: %fsub_is_nan_f64(0x0.0, -NaN) == 1 +; run: %fsub_is_nan_f64(0x0.0, +NaN:0x0) == 1 +; run: %fsub_is_nan_f64(0x0.0, +NaN:0x1) == 1 +; run: %fsub_is_nan_f64(0x0.0, +NaN:0x4000000000001) == 1 +; run: %fsub_is_nan_f64(0x0.0, -NaN:0x0) == 1 +; run: %fsub_is_nan_f64(0x0.0, -NaN:0x1) == 1 +; run: %fsub_is_nan_f64(0x0.0, -NaN:0x4000000000001) == 1 +; run: %fsub_is_nan_f64(0x0.0, +sNaN:0x1) == 1 +; run: %fsub_is_nan_f64(0x0.0, -sNaN:0x1) == 1 +; run: %fsub_is_nan_f64(0x0.0, +sNaN:0x4000000000001) == 1 +; run: %fsub_is_nan_f64(0x0.0, -sNaN:0x4000000000001) == 1 diff --git a/cranelift/interpreter/src/value.rs b/cranelift/interpreter/src/value.rs index c3a5ac91bb..e90da9e223 100644 --- a/cranelift/interpreter/src/value.rs +++ b/cranelift/interpreter/src/value.rs @@ -18,6 +18,7 @@ pub trait Value: Clone + From { fn into_int(self) -> ValueResult; fn float(n: u64, ty: Type) -> ValueResult; fn into_float(self) -> ValueResult; + fn is_float(&self) -> bool; fn is_nan(&self) -> ValueResult; fn bool(b: bool, ty: Type) -> ValueResult; fn into_bool(self) -> ValueResult; @@ -250,6 +251,13 @@ impl Value for DataValue { unimplemented!() } + fn is_float(&self) -> bool { + match self { + DataValue::F32(_) | DataValue::F64(_) => true, + _ => false, + } + } + fn is_nan(&self) -> ValueResult { match self { DataValue::F32(f) => Ok(f.is_nan()), @@ -457,19 +465,34 @@ impl Value for DataValue { } fn add(self, other: Self) -> ValueResult { - // TODO: floats must handle NaNs, +/-0 - binary_match!(wrapping_add(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]) + if self.is_float() { + binary_match!(+(self, other); [F32, F64]) + } else { + binary_match!(wrapping_add(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]) + } } fn sub(self, other: Self) -> ValueResult { - binary_match!(wrapping_sub(&self, &other); [I8, I16, I32, I64, I128]) // TODO: floats must handle NaNs, +/-0 + if self.is_float() { + binary_match!(-(self, other); [F32, F64]) + } else { + binary_match!(wrapping_sub(&self, &other); [I8, I16, I32, I64, I128]) + } } fn mul(self, other: Self) -> ValueResult { - binary_match!(wrapping_mul(&self, &other); [I8, I16, I32, I64, I128]) + if self.is_float() { + binary_match!(*(self, other); [F32, F64]) + } else { + binary_match!(wrapping_mul(&self, &other); [I8, I16, I32, I64, I128]) + } } fn div(self, other: Self) -> ValueResult { + if self.is_float() { + return binary_match!(/(self, other); [F32, F64]); + } + let denominator = other.clone().into_int()?; // Check if we are dividing INT_MIN / -1. This causes an integer overflow trap.