pub(crate) trait TinywasmIntExt: Sized {
fn checked_wrapping_rem(self, rhs: Self) -> Result<Self, Trap>;
fn wasm_checked_div(self, rhs: Self) -> Result<Self, Trap>;
}
#[rustfmt::skip]
macro_rules! float_min_max {
(f32, i32) => {(i32::MIN as f32 - (1 << 8) as f32, i32::MAX as f32 + 1.0)}; (f64, i32) => {(i32::MIN as f64 - 1.0, i32::MAX as f64 + 1.0)};
(f32, u32) => {(-1.0_f32, u32::MAX as f32 + 1.0)};
(f64, u32) => {(-1.0_f64, u32::MAX as f64 + 1.0)};
(f32, i64) => {(i64::MIN as f32 - (1i64 << 40) as f32, i64::MAX as f32 + 1.0)}; (f64, i64) => {(i64::MIN as f64 - (1i64 << 11) as f64, i64::MAX as f64 + 1.0)}; (f32, u64) => {(-1.0_f32, u64::MAX as f32 + 1.0)};
(f64, u64) => {(-1.0_f64, u64::MAX as f64 + 1.0)};
($from:ty, $to:ty) => {compile_error!("invalid float conversion")};
}
macro_rules! checked_conv_float {
($from:tt, $to:tt, $self:expr) => {
checked_conv_float!($from, $to, $to, $self)
};
($from:tt, $intermediate:tt, $to:tt, $self:expr) => {{
let v = <$from>::stack_pop(&mut $self.store.value_stack);
let (min, max) = float_min_max!($from, $intermediate);
if unlikely(v.is_nan()) {
return Err(crate::Trap::InvalidConversionToInt);
}
if unlikely(v <= min || v >= max) {
return Err(crate::Trap::IntegerOverflow);
}
$self.store.value_stack.push::<$to>((v as $intermediate as $to).into())?;
}};
}
pub(crate) use checked_conv_float;
pub(crate) use float_min_max;
pub(super) fn trap_0() -> Trap {
crate::Trap::DivisionByZero
}
pub(crate) trait TinywasmFloatExt {
fn tw_minimum(self, other: Self) -> Self;
fn tw_maximum(self, other: Self) -> Self;
fn tw_nearest(self) -> Self;
}
use crate::{Result, Trap};
#[cfg(not(feature = "std"))]
use super::no_std_floats::NoStdFloatExt;
macro_rules! impl_wasm_float_ops {
($($t:ty)*) => ($(
impl TinywasmFloatExt for $t {
#[inline]
fn tw_nearest(self) -> Self {
match self {
#[cfg(not(feature = "canonicalize-nans"))]
x if x.is_nan() => x, #[cfg(feature = "canonicalize-nans")]
x if x.is_nan() => Self::NAN, x if x.is_infinite() || x == 0.0 => x, x if (0.0..=0.5).contains(&x) => 0.0,
x if (-0.5..0.0).contains(&x) => -0.0,
x => {
let rounded = x.round();
let diff = (x - rounded).abs();
if diff != 0.5 || rounded % 2.0 == 0.0 {
return rounded
}
rounded - x.signum() }
}
}
#[inline]
fn tw_minimum(self, other: Self) -> Self {
match self.partial_cmp(&other) {
Some(core::cmp::Ordering::Less) => self,
Some(core::cmp::Ordering::Greater) => other,
Some(core::cmp::Ordering::Equal) => if self.is_sign_negative() && other.is_sign_positive() { self } else { other },
#[cfg(not(feature = "canonicalize-nans"))]
None => self + other, #[cfg(feature = "canonicalize-nans")]
None => Self::NAN, }
}
#[inline]
fn tw_maximum(self, other: Self) -> Self {
match self.partial_cmp(&other) {
Some(core::cmp::Ordering::Greater) => self,
Some(core::cmp::Ordering::Less) => other,
Some(core::cmp::Ordering::Equal) => if self.is_sign_negative() && other.is_sign_positive() { other } else { self },
#[cfg(not(feature = "canonicalize-nans"))]
None => self + other, #[cfg(feature = "canonicalize-nans")]
None => Self::NAN, }
}
}
)*)
}
impl_wasm_float_ops! { f32 f64 }
pub(crate) trait WasmIntOps {
fn wasm_shl(self, rhs: Self) -> Self;
fn wasm_shr(self, rhs: Self) -> Self;
fn wasm_rotl(self, rhs: Self) -> Self;
fn wasm_rotr(self, rhs: Self) -> Self;
}
macro_rules! impl_wrapping_self_sh {
($($t:ty)*) => ($(
impl WasmIntOps for $t {
#[inline]
fn wasm_shl(self, rhs: Self) -> Self {
self.wrapping_shl(rhs as u32)
}
#[inline]
fn wasm_shr(self, rhs: Self) -> Self {
self.wrapping_shr(rhs as u32)
}
#[inline]
fn wasm_rotl(self, rhs: Self) -> Self {
self.rotate_left(rhs as u32)
}
#[inline]
fn wasm_rotr(self, rhs: Self) -> Self {
self.rotate_right(rhs as u32)
}
}
)*)
}
impl_wrapping_self_sh! { i32 i64 u32 u64 }
macro_rules! impl_checked_wrapping_rem {
($($t:ty)*) => ($(
impl TinywasmIntExt for $t {
fn checked_wrapping_rem(self, rhs: Self) -> Result<Self, crate::Trap> {
if rhs == 0 {
Err(crate::Trap::DivisionByZero)
} else {
Ok(self.wrapping_rem(rhs))
}
}
fn wasm_checked_div(self, rhs: Self) -> Result<Self, crate::Trap> {
if rhs == 0 {
Err(crate::Trap::DivisionByZero)
} else {
self.checked_div(rhs).ok_or_else(|| crate::Trap::IntegerOverflow)
}
}
}
)*)
}
impl_checked_wrapping_rem! { i32 i64 u32 u64 }