diff --git a/cranelift/codegen/src/ir/immediates.rs b/cranelift/codegen/src/ir/immediates.rs index 27108de5f7..d48747cc27 100644 --- a/cranelift/codegen/src/ir/immediates.rs +++ b/cranelift/codegen/src/ir/immediates.rs @@ -816,9 +816,20 @@ impl Ieee32 { Self::with_float(self.as_f32().trunc()) } - /// Returns the nearest integer to `self`. Round half-way cases away from `0.0`. - pub fn nearest(self) -> Self { - Self::with_float(self.as_f32().round()) + /// Returns the nearest integer to `self`. Rounds half-way cases to the number + /// with an even least significant digit. + pub fn round_ties_even(self) -> Self { + // TODO: Replace with the native implementation once + // https://github.com/rust-lang/rust/issues/96710 is stabilized + let toint_32: f32 = 1.0 / f32::EPSILON; + + let f = self.as_f32(); + let e = self.0 >> 23 & 0xff; + if e >= 0x7f_u32 + 23 { + self + } else { + Self::with_float((f.abs() + toint_32 - toint_32).copysign(f)) + } } } @@ -965,9 +976,20 @@ impl Ieee64 { Self::with_float(self.as_f64().trunc()) } - /// Returns the nearest integer to `self`. Round half-way cases away from `0.0`. - pub fn nearest(self) -> Self { - Self::with_float(self.as_f64().round()) + /// Returns the nearest integer to `self`. Rounds half-way cases to the number + /// with an even least significant digit. + pub fn round_ties_even(self) -> Self { + // TODO: Replace with the native implementation once + // https://github.com/rust-lang/rust/issues/96710 is stabilized + let toint_64: f64 = 1.0 / f64::EPSILON; + + let f = self.as_f64(); + let e = self.0 >> 52 & 0x7ff_u64; + if e >= 0x3ff_u64 + 52 { + self + } else { + Self::with_float((f.abs() + toint_64 - toint_64).copysign(f)) + } } } diff --git a/cranelift/filetests/filetests/runtests/ceil.clif b/cranelift/filetests/filetests/runtests/ceil.clif index e7367550c1..8031c76d57 100644 --- a/cranelift/filetests/filetests/runtests/ceil.clif +++ b/cranelift/filetests/filetests/runtests/ceil.clif @@ -14,6 +14,13 @@ block0(v0: f32): ; run: %ceil_f32(0x1.5) == 0x1.0p1 ; run: %ceil_f32(0x2.9) == 0x1.8p1 ; run: %ceil_f32(0x1.1p10) == 0x1.1p10 +; run: %ceil_f32(0x1.400000p1) == 0x1.8p1 +; run: %ceil_f32(0x1.4cccccp0) == 0x1.0p1 +; run: %ceil_f32(0x1.800000p0) == 0x1.0p1 +; run: %ceil_f32(0x1.b33334p0) == 0x1.0p1 +; run: %ceil_f32(0x1.99999ap-2) == 0x1.0 +; run: %ceil_f32(0x1.333334p-1) == 0x1.0 +; run: %ceil_f32(0x1.666666p1) == 0x1.8p1 ; Negatives ; run: %ceil_f32(-0x0.5) == -0x0.0 @@ -21,6 +28,13 @@ block0(v0: f32): ; run: %ceil_f32(-0x1.5) == -0x1.0 ; run: %ceil_f32(-0x2.9) == -0x1.0p1 ; run: %ceil_f32(-0x1.1p10) == -0x1.1p10 +; run: %ceil_f32(-0x1.333334p-1) == -0x0.0 +; run: %ceil_f32(-0x1.99999ap-2) == -0x0.0 +; run: %ceil_f32(-0x1.4cccccp0) == -0x1.0 +; run: %ceil_f32(-0x1.800000p0) == -0x1.0 +; run: %ceil_f32(-0x1.b33334p0) == -0x1.0 +; run: %ceil_f32(-0x1.400000p1) == -0x1.0p1 +; run: %ceil_f32(-0x1.666666p1) == -0x1.0p1 ; Specials ; run: %ceil_f32(0x0.0) == 0x0.0 @@ -71,6 +85,13 @@ block0(v0: f64): ; run: %ceil_f64(0x1.5) == 0x1.0p1 ; run: %ceil_f64(0x2.9) == 0x1.8p1 ; run: %ceil_f64(0x1.1p10) == 0x1.1p10 +; run: %ceil_f64(0x1.4000000000000p1) == 0x1.8p1 +; run: %ceil_f64(0x1.4cccccccccccdp0) == 0x1.0p1 +; run: %ceil_f64(0x1.8000000000000p0) == 0x1.0p1 +; run: %ceil_f64(0x1.b333333333333p0) == 0x1.0p1 +; run: %ceil_f64(0x1.999999999999ap-2) == 0x1.0 +; run: %ceil_f64(0x1.3333333333333p-1) == 0x1.0 +; run: %ceil_f64(0x1.6666666666666p1) == 0x1.8p1 ; Negatives ; run: %ceil_f64(-0x0.5) == -0x0.0 @@ -78,6 +99,13 @@ block0(v0: f64): ; run: %ceil_f64(-0x1.5) == -0x1.0 ; run: %ceil_f64(-0x2.9) == -0x1.0p1 ; run: %ceil_f64(-0x1.1p10) == -0x1.1p10 +; run: %ceil_f64(-0x1.3333333333333p-1) == -0x0.0 +; run: %ceil_f64(-0x1.999999999999ap-2) == -0x0.0 +; run: %ceil_f64(-0x1.4cccccccccccdp0) == -0x1.0 +; run: %ceil_f64(-0x1.8000000000000p0) == -0x1.0 +; run: %ceil_f64(-0x1.b333333333333p0) == -0x1.0 +; run: %ceil_f64(-0x1.4000000000000p1) == -0x1.0p1 +; run: %ceil_f64(-0x1.6666666666666p1) == -0x1.0p1 ; Specials ; run: %ceil_f64(0x0.0) == 0x0.0 diff --git a/cranelift/filetests/filetests/runtests/floor.clif b/cranelift/filetests/filetests/runtests/floor.clif index 6df5568834..5a15c8be8c 100644 --- a/cranelift/filetests/filetests/runtests/floor.clif +++ b/cranelift/filetests/filetests/runtests/floor.clif @@ -14,6 +14,13 @@ block0(v0: f32): ; run: %floor_f32(0x1.5) == 0x1.0 ; run: %floor_f32(0x2.9) == 0x1.0p1 ; run: %floor_f32(0x1.1p10) == 0x1.1p10 +; run: %floor_f32(0x1.400000p1) == 0x1.0p1 +; run: %floor_f32(0x1.4cccccp0) == 0x1.0 +; run: %floor_f32(0x1.800000p0) == 0x1.0 +; run: %floor_f32(0x1.b33334p0) == 0x1.0 +; run: %floor_f32(0x1.99999ap-2) == 0x0.0 +; run: %floor_f32(0x1.333334p-1) == 0x0.0 +; run: %floor_f32(0x1.666666p1) == 0x1.0p1 ; Negatives ; run: %floor_f32(-0x0.5) == -0x1.0 @@ -21,6 +28,13 @@ block0(v0: f32): ; run: %floor_f32(-0x1.5) == -0x1.0p1 ; run: %floor_f32(-0x2.9) == -0x1.8p1 ; run: %floor_f32(-0x1.1p10) == -0x1.1p10 +; run: %floor_f32(-0x1.333334p-1) == -0x1.0 +; run: %floor_f32(-0x1.99999ap-2) == -0x1.0 +; run: %floor_f32(-0x1.4cccccp0) == -0x1.0p1 +; run: %floor_f32(-0x1.800000p0) == -0x1.0p1 +; run: %floor_f32(-0x1.b33334p0) == -0x1.0p1 +; run: %floor_f32(-0x1.400000p1) == -0x1.8p1 +; run: %floor_f32(-0x1.666666p1) == -0x1.8p1 ; Specials ; run: %floor_f32(0x0.0) == 0x0.0 @@ -71,6 +85,13 @@ block0(v0: f64): ; run: %floor_f64(0x1.5) == 0x1.0 ; run: %floor_f64(0x2.9) == 0x1.0p1 ; run: %floor_f64(0x1.1p10) == 0x1.1p10 +; run: %floor_f64(0x1.4000000000000p1) == 0x1.0p1 +; run: %floor_f64(0x1.4cccccccccccdp0) == 0x1.0 +; run: %floor_f64(0x1.8000000000000p0) == 0x1.0 +; run: %floor_f64(0x1.b333333333333p0) == 0x1.0 +; run: %floor_f64(0x1.999999999999ap-2) == 0x0.0 +; run: %floor_f64(0x1.3333333333333p-1) == 0x0.0 +; run: %floor_f64(0x1.6666666666666p1) == 0x1.0p1 ; Negatives ; run: %floor_f64(-0x0.5) == -0x1.0 @@ -78,6 +99,13 @@ block0(v0: f64): ; run: %floor_f64(-0x1.5) == -0x1.0p1 ; run: %floor_f64(-0x2.9) == -0x1.8p1 ; run: %floor_f64(-0x1.1p10) == -0x1.1p10 +; run: %floor_f64(-0x1.3333333333333p-1) == -0x1.0 +; run: %floor_f64(-0x1.999999999999ap-2) == -0x1.0 +; run: %floor_f64(-0x1.4cccccccccccdp0) == -0x1.0p1 +; run: %floor_f64(-0x1.8000000000000p0) == -0x1.0p1 +; run: %floor_f64(-0x1.b333333333333p0) == -0x1.0p1 +; run: %floor_f64(-0x1.4000000000000p1) == -0x1.8p1 +; run: %floor_f64(-0x1.6666666666666p1) == -0x1.8p1 ; Specials ; run: %floor_f64(0x0.0) == 0x0.0 diff --git a/cranelift/filetests/filetests/runtests/nearest.clif b/cranelift/filetests/filetests/runtests/nearest.clif index 1268d75e72..dd265a18e2 100644 --- a/cranelift/filetests/filetests/runtests/nearest.clif +++ b/cranelift/filetests/filetests/runtests/nearest.clif @@ -14,6 +14,13 @@ block0(v0: f32): ; run: %nearest_f32(0x1.5) == 0x1.0 ; run: %nearest_f32(0x2.9) == 0x1.8p1 ; run: %nearest_f32(0x1.1p10) == 0x1.1p10 +; run: %nearest_f32(0x1.400000p1) == 0x1.0p1 +; run: %nearest_f32(0x1.4cccccp0) == 0x1.0 +; run: %nearest_f32(0x1.800000p0) == 0x1.0p1 +; run: %nearest_f32(0x1.b33334p0) == 0x1.0p1 +; run: %nearest_f32(0x1.99999ap-2) == 0x0.0 +; run: %nearest_f32(0x1.333334p-1) == 0x1.0 +; run: %nearest_f32(0x1.666666p1) == 0x1.8p1 ; Negatives ; run: %nearest_f32(-0x0.5) == -0x0.0 @@ -21,6 +28,13 @@ block0(v0: f32): ; run: %nearest_f32(-0x1.5) == -0x1.0 ; run: %nearest_f32(-0x2.9) == -0x1.8p1 ; run: %nearest_f32(-0x1.1p10) == -0x1.1p10 +; run: %nearest_f32(-0x1.333334p-1) == -0x1.0 +; run: %nearest_f32(-0x1.99999ap-2) == -0x0.0 +; run: %nearest_f32(-0x1.4cccccp0) == -0x1.0 +; run: %nearest_f32(-0x1.800000p0) == -0x1.0p1 +; run: %nearest_f32(-0x1.b33334p0) == -0x1.0p1 +; run: %nearest_f32(-0x1.400000p1) == -0x1.0p1 +; run: %nearest_f32(-0x1.666666p1) == -0x1.8p1 ; Specials ; run: %nearest_f32(0x0.0) == 0x0.0 @@ -71,6 +85,13 @@ block0(v0: f64): ; run: %nearest_f64(0x1.5) == 0x1.0 ; run: %nearest_f64(0x2.9) == 0x1.8p1 ; run: %nearest_f64(0x1.1p10) == 0x1.1p10 +; run: %nearest_f64(0x1.4000000000000p1) == 0x1.0p1 +; run: %nearest_f64(0x1.4cccccccccccdp0) == 0x1.0 +; run: %nearest_f64(0x1.8000000000000p0) == 0x1.0p1 +; run: %nearest_f64(0x1.b333333333333p0) == 0x1.0p1 +; run: %nearest_f64(0x1.999999999999ap-2) == 0x0.0 +; run: %nearest_f64(0x1.3333333333333p-1) == 0x1.0 +; run: %nearest_f64(0x1.6666666666666p1) == 0x1.8p1 ; Negatives ; run: %nearest_f64(-0x0.5) == -0x0.0 @@ -78,6 +99,13 @@ block0(v0: f64): ; run: %nearest_f64(-0x1.5) == -0x1.0 ; run: %nearest_f64(-0x2.9) == -0x1.8p1 ; run: %nearest_f64(-0x1.1p10) == -0x1.1p10 +; run: %nearest_f64(-0x1.3333333333333p-1) == -0x1.0 +; run: %nearest_f64(-0x1.999999999999ap-2) == -0x0.0 +; run: %nearest_f64(-0x1.4cccccccccccdp0) == -0x1.0 +; run: %nearest_f64(-0x1.8000000000000p0) == -0x1.0p1 +; run: %nearest_f64(-0x1.b333333333333p0) == -0x1.0p1 +; run: %nearest_f64(-0x1.4000000000000p1) == -0x1.0p1 +; run: %nearest_f64(-0x1.6666666666666p1) == -0x1.8p1 ; Specials ; run: %nearest_f64(0x0.0) == 0x0.0 diff --git a/cranelift/filetests/filetests/runtests/trunc.clif b/cranelift/filetests/filetests/runtests/trunc.clif index a05ade2ec5..99410b6043 100644 --- a/cranelift/filetests/filetests/runtests/trunc.clif +++ b/cranelift/filetests/filetests/runtests/trunc.clif @@ -14,6 +14,13 @@ block0(v0: f32): ; run: %trunc_f32(0x1.5) == 0x1.0 ; run: %trunc_f32(0x2.9) == 0x1.0p1 ; run: %trunc_f32(0x1.1p10) == 0x1.1p10 +; run: %trunc_f32(0x1.400000p1) == 0x1.0p1 +; run: %trunc_f32(0x1.4cccccp0) == 0x1.0 +; run: %trunc_f32(0x1.800000p0) == 0x1.0 +; run: %trunc_f32(0x1.b33334p0) == 0x1.0 +; run: %trunc_f32(0x1.99999ap-2) == 0x0.0 +; run: %trunc_f32(0x1.333334p-1) == 0x0.0 +; run: %trunc_f32(0x1.666666p1) == 0x1.0p1 ; Negatives ; run: %trunc_f32(-0x0.5) == -0x0.0 @@ -21,6 +28,13 @@ block0(v0: f32): ; run: %trunc_f32(-0x1.5) == -0x1.0 ; run: %trunc_f32(-0x2.9) == -0x1.0p1 ; run: %trunc_f32(-0x1.1p10) == -0x1.1p10 +; run: %trunc_f32(-0x1.333334p-1) == -0x0.0 +; run: %trunc_f32(-0x1.99999ap-2) == -0x0.0 +; run: %trunc_f32(-0x1.4cccccp0) == -0x1.0 +; run: %trunc_f32(-0x1.800000p0) == -0x1.0 +; run: %trunc_f32(-0x1.b33334p0) == -0x1.0 +; run: %trunc_f32(-0x1.400000p1) == -0x1.0p1 +; run: %trunc_f32(-0x1.666666p1) == -0x1.0p1 ; Specials ; run: %trunc_f32(0x0.0) == 0x0.0 @@ -71,6 +85,13 @@ block0(v0: f64): ; run: %trunc_f64(0x1.5) == 0x1.0 ; run: %trunc_f64(0x2.9) == 0x1.0p1 ; run: %trunc_f64(0x1.1p10) == 0x1.1p10 +; run: %trunc_f64(0x1.4000000000000p1) == 0x1.0p1 +; run: %trunc_f64(0x1.4cccccccccccdp0) == 0x1.0 +; run: %trunc_f64(0x1.8000000000000p0) == 0x1.0 +; run: %trunc_f64(0x1.b333333333333p0) == 0x1.0 +; run: %trunc_f64(0x1.999999999999ap-2) == 0x0.0 +; run: %trunc_f64(0x1.3333333333333p-1) == 0x0.0 +; run: %trunc_f64(0x1.6666666666666p1) == 0x1.0p1 ; Negatives ; run: %trunc_f64(-0x0.5) == -0x0.0 @@ -78,6 +99,13 @@ block0(v0: f64): ; run: %trunc_f64(-0x1.5) == -0x1.0 ; run: %trunc_f64(-0x2.9) == -0x1.0p1 ; run: %trunc_f64(-0x1.1p10) == -0x1.1p10 +; run: %trunc_f64(-0x1.3333333333333p-1) == -0x0.0 +; run: %trunc_f64(-0x1.999999999999ap-2) == -0x0.0 +; run: %trunc_f64(-0x1.4cccccccccccdp0) == -0x1.0 +; run: %trunc_f64(-0x1.8000000000000p0) == -0x1.0 +; run: %trunc_f64(-0x1.b333333333333p0) == -0x1.0 +; run: %trunc_f64(-0x1.4000000000000p1) == -0x1.0p1 +; run: %trunc_f64(-0x1.6666666666666p1) == -0x1.0p1 ; Specials ; run: %trunc_f64(0x0.0) == 0x0.0 diff --git a/cranelift/interpreter/src/value.rs b/cranelift/interpreter/src/value.rs index 1a5db35395..c3a5ac91bb 100644 --- a/cranelift/interpreter/src/value.rs +++ b/cranelift/interpreter/src/value.rs @@ -534,7 +534,7 @@ impl Value for DataValue { } fn nearest(self) -> ValueResult { - unary_match!(nearest(&self); [F32, F64]) + unary_match!(round_ties_even(&self); [F32, F64]) } fn add_sat(self, other: Self) -> ValueResult {