use super::{stack::ValueStack, Provider, TypedProvider, TypedVal};
use crate::{
engine::bytecode::{BoundedRegSpan, Const16, Reg, RegSpan, Sign},
Error,
};
pub trait WasmInteger:
Copy + Eq + From<TypedVal> + Into<TypedVal> + TryInto<Const16<Self>>
{
fn eq_zero(self) -> bool;
}
impl WasmInteger for i32 {
fn eq_zero(self) -> bool {
self == 0
}
}
impl WasmInteger for u32 {
fn eq_zero(self) -> bool {
self == 0
}
}
impl WasmInteger for i64 {
fn eq_zero(self) -> bool {
self == 0
}
}
impl WasmInteger for u64 {
fn eq_zero(self) -> bool {
self == 0
}
}
pub trait WasmFloat: Copy + Into<TypedVal> + From<TypedVal> {
fn is_nan(self) -> bool;
fn sign(self) -> Sign<Self>;
}
impl WasmFloat for f32 {
fn is_nan(self) -> bool {
self.is_nan()
}
fn sign(self) -> Sign<Self> {
Sign::from(self)
}
}
impl WasmFloat for f64 {
fn is_nan(self) -> bool {
self.is_nan()
}
fn sign(self) -> Sign<Self> {
Sign::from(self)
}
}
impl Provider<Const16<u32>> {
pub fn new(provider: TypedProvider, stack: &mut ValueStack) -> Result<Self, Error> {
match provider {
TypedProvider::Const(value) => match Const16::try_from(u32::from(value)).ok() {
Some(value) => Ok(Self::Const(value)),
None => {
let register = stack.alloc_const(value)?;
Ok(Self::Register(register))
}
},
TypedProvider::Register(index) => Ok(Self::Register(index)),
}
}
}
impl TypedProvider {
fn register_index(&self) -> Option<i16> {
match self {
TypedProvider::Register(index) => Some(i16::from(*index)),
TypedProvider::Const(_) => None,
}
}
}
pub trait FromProviders: Sized {
fn from_providers(providers: &[TypedProvider]) -> Option<Self>;
}
impl FromProviders for BoundedRegSpan {
fn from_providers(providers: &[TypedProvider]) -> Option<Self> {
let (first, rest) = providers.split_first()?;
let first_index = first.register_index()?;
let mut prev_index = first_index;
for next in rest {
let next_index = next.register_index()?;
if next_index.checked_sub(prev_index)? != 1 {
return None;
}
prev_index = next_index;
}
let end_index = prev_index.checked_add(1)?;
let len = (end_index - first_index) as u16;
Some(Self::new(RegSpan::new(Reg::from(first_index)), len))
}
}
pub trait Wrap<T> {
fn wrap(self) -> T;
}
impl<T> Wrap<T> for T {
#[inline]
fn wrap(self) -> T {
self
}
}
macro_rules! impl_wrap_for {
( $($from_ty:ty => $to_ty:ty),* $(,)? ) => {
$(
impl Wrap<$to_ty> for $from_ty {
#[inline]
fn wrap(self) -> $to_ty { self as _ }
}
)*
};
}
impl_wrap_for! {
i16 => i8,
i32 => i8,
i32 => i16,
i64 => i8,
i64 => i16,
i64 => i32,
u16 => u8,
u32 => u8,
u32 => u16,
u64 => u8,
u64 => u16,
u64 => u32,
}