From a8f704129669d6a690452b13ccdb7c96e016fd39 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 31 Aug 2020 19:02:20 +0300 Subject: [PATCH] new implementations for nearest lib calls use approach with copysign for handling negative zero format refactor for better branch prediction move copysign back to internal branch format fix use abs instead branches better comments switch arms for better branch prediction --- crates/runtime/src/libcalls.rs | 49 +++++++++++----------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/crates/runtime/src/libcalls.rs b/crates/runtime/src/libcalls.rs index 4dcb0963de..a7dfe0a723 100644 --- a/crates/runtime/src/libcalls.rs +++ b/crates/runtime/src/libcalls.rs @@ -67,6 +67,9 @@ use wasmtime_environ::wasm::{ TableIndex, }; +const TOINT_32: f32 = 1.0 / f32::EPSILON; +const TOINT_64: f64 = 1.0 / f64::EPSILON; + /// Implementation of f32.ceil pub extern "C" fn wasmtime_f32_ceil(x: f32) -> f32 { x.ceil() @@ -86,25 +89,14 @@ pub extern "C" fn wasmtime_f32_trunc(x: f32) -> f32 { #[allow(clippy::float_arithmetic, clippy::float_cmp)] pub extern "C" fn wasmtime_f32_nearest(x: f32) -> f32 { // Rust doesn't have a nearest function, so do it manually. - if x == 0.0 { - // Preserve the sign of zero. + // Nearest is either ceil or floor depending on which is nearest or even. + // This approach exploited round half to even default mode. + let i = x.to_bits(); + let e = i >> 23 & 0xff; + if e >= 0x7f_u32 + 23 { x } else { - // Nearest is either ceil or floor depending on which is nearest or even. - let u = x.ceil(); - let d = x.floor(); - let um = (x - u).abs(); - let dm = (x - d).abs(); - if um < dm - || (um == dm && { - let h = u / 2.; - h.floor() == h - }) - { - u - } else { - d - } + (x.abs() + TOINT_32 - TOINT_32).copysign(x) } } @@ -162,25 +154,14 @@ pub extern "C" fn wasmtime_f64_trunc(x: f64) -> f64 { #[allow(clippy::float_arithmetic, clippy::float_cmp)] pub extern "C" fn wasmtime_f64_nearest(x: f64) -> f64 { // Rust doesn't have a nearest function, so do it manually. - if x == 0.0 { - // Preserve the sign of zero. + // Nearest is either ceil or floor depending on which is nearest or even. + // This approach exploited round half to even default mode. + let i = x.to_bits(); + let e = i >> 52 & 0x7ff; + if e >= 0x3ff_u64 + 52 { x } else { - // Nearest is either ceil or floor depending on which is nearest or even. - let u = x.ceil(); - let d = x.floor(); - let um = (x - u).abs(); - let dm = (x - d).abs(); - if um < dm - || (um == dm && { - let h = u / 2.; - h.floor() == h - }) - { - u - } else { - d - } + (x.abs() + TOINT_64 - TOINT_64).copysign(x) } }