use super::lanes::{
from_i16x8, from_i32x4, from_i64x2, from_i8x16, from_u16x8, from_u32x4, from_u64x2, from_u8x16,
i16x8, i32x4, i8x16, u16x8, u32x4, u8x16,
};
use super::Execution;
use crate::module::op_simd::SimdOp;
use crate::Result;
impl Execution {
#[allow(clippy::too_many_lines, clippy::semicolon_if_nothing_returned)]
pub(super) fn exec_simd_iarith2(&mut self, s: &SimdOp) -> Result<()> {
use SimdOp as S;
match s {
S::I8x16AddSatS => self.v_binop(i8x16, from_i8x16, i8::saturating_add)?,
S::I8x16AddSatU => self.v_binop(u8x16, from_u8x16, u8::saturating_add)?,
S::I8x16SubSatS => self.v_binop(i8x16, from_i8x16, i8::saturating_sub)?,
S::I8x16SubSatU => self.v_binop(u8x16, from_u8x16, u8::saturating_sub)?,
S::I16x8AddSatS => self.v_binop(i16x8, from_i16x8, i16::saturating_add)?,
S::I16x8AddSatU => self.v_binop(u16x8, from_u16x8, u16::saturating_add)?,
S::I16x8SubSatS => self.v_binop(i16x8, from_i16x8, i16::saturating_sub)?,
S::I16x8SubSatU => self.v_binop(u16x8, from_u16x8, u16::saturating_sub)?,
S::I16x8Q15MulrSatS => self.v_binop(i16x8, from_i16x8, |a, b| {
(((i32::from(a) * i32::from(b)) + 0x4000) >> 15).clamp(-32768, 32767) as i16
})?,
S::I8x16NarrowI16x8S => {
self.v_narrow(i16x8, from_i8x16, |x| x.clamp(-128, 127) as i8)?
}
S::I8x16NarrowI16x8U => self.v_narrow(i16x8, from_u8x16, |x| x.clamp(0, 255) as u8)?,
S::I16x8NarrowI32x4S => {
self.v_narrow(i32x4, from_i16x8, |x| x.clamp(-32768, 32767) as i16)?;
}
S::I16x8NarrowI32x4U => {
self.v_narrow(i32x4, from_u16x8, |x| x.clamp(0, 65535) as u16)?;
}
S::I16x8ExtendLowI8x16S => self.v_extend(i8x16, from_i16x8, false, i16::from)?,
S::I16x8ExtendHighI8x16S => self.v_extend(i8x16, from_i16x8, true, i16::from)?,
S::I16x8ExtendLowI8x16U => self.v_extend(u8x16, from_u16x8, false, u16::from)?,
S::I16x8ExtendHighI8x16U => self.v_extend(u8x16, from_u16x8, true, u16::from)?,
S::I32x4ExtendLowI16x8S => self.v_extend(i16x8, from_i32x4, false, i32::from)?,
S::I32x4ExtendHighI16x8S => self.v_extend(i16x8, from_i32x4, true, i32::from)?,
S::I32x4ExtendLowI16x8U => self.v_extend(u16x8, from_u32x4, false, u32::from)?,
S::I32x4ExtendHighI16x8U => self.v_extend(u16x8, from_u32x4, true, u32::from)?,
S::I64x2ExtendLowI32x4S => self.v_extend(i32x4, from_i64x2, false, i64::from)?,
S::I64x2ExtendHighI32x4S => self.v_extend(i32x4, from_i64x2, true, i64::from)?,
S::I64x2ExtendLowI32x4U => self.v_extend(u32x4, from_u64x2, false, u64::from)?,
S::I64x2ExtendHighI32x4U => self.v_extend(u32x4, from_u64x2, true, u64::from)?,
S::I16x8ExtAddPairwiseI8x16S => {
self.v_extadd(i8x16, from_i16x8, |a, b| i16::from(a) + i16::from(b))?;
}
S::I16x8ExtAddPairwiseI8x16U => {
self.v_extadd(u8x16, from_u16x8, |a, b| u16::from(a) + u16::from(b))?;
}
S::I32x4ExtAddPairwiseI16x8S => {
self.v_extadd(i16x8, from_i32x4, |a, b| i32::from(a) + i32::from(b))?;
}
S::I32x4ExtAddPairwiseI16x8U => {
self.v_extadd(u16x8, from_u32x4, |a, b| u32::from(a) + u32::from(b))?;
}
S::I16x8ExtMulLowI8x16S => {
self.v_extmul(i8x16, from_i16x8, false, |a, b| i16::from(a) * i16::from(b))?
}
S::I16x8ExtMulHighI8x16S => {
self.v_extmul(i8x16, from_i16x8, true, |a, b| i16::from(a) * i16::from(b))?
}
S::I16x8ExtMulLowI8x16U => {
self.v_extmul(u8x16, from_u16x8, false, |a, b| u16::from(a) * u16::from(b))?
}
S::I16x8ExtMulHighI8x16U => {
self.v_extmul(u8x16, from_u16x8, true, |a, b| u16::from(a) * u16::from(b))?
}
S::I32x4ExtMulLowI16x8S => {
self.v_extmul(i16x8, from_i32x4, false, |a, b| i32::from(a) * i32::from(b))?
}
S::I32x4ExtMulHighI16x8S => {
self.v_extmul(i16x8, from_i32x4, true, |a, b| i32::from(a) * i32::from(b))?
}
S::I32x4ExtMulLowI16x8U => {
self.v_extmul(u16x8, from_u32x4, false, |a, b| u32::from(a) * u32::from(b))?
}
S::I32x4ExtMulHighI16x8U => {
self.v_extmul(u16x8, from_u32x4, true, |a, b| u32::from(a) * u32::from(b))?
}
S::I64x2ExtMulLowI32x4S => {
self.v_extmul(i32x4, from_i64x2, false, |a, b| i64::from(a) * i64::from(b))?
}
S::I64x2ExtMulHighI32x4S => {
self.v_extmul(i32x4, from_i64x2, true, |a, b| i64::from(a) * i64::from(b))?
}
S::I64x2ExtMulLowI32x4U => {
self.v_extmul(u32x4, from_u64x2, false, |a, b| u64::from(a) * u64::from(b))?
}
S::I64x2ExtMulHighI32x4U => {
self.v_extmul(u32x4, from_u64x2, true, |a, b| u64::from(a) * u64::from(b))?
}
S::I32x4DotI16x8S => {
let b = i16x8(self.pop_v128()?);
let a = i16x8(self.pop_v128()?);
self.push_v128(from_i32x4(core::array::from_fn(|i| {
(i32::from(a[2 * i]) * i32::from(b[2 * i]))
.wrapping_add(i32::from(a[2 * i + 1]) * i32::from(b[2 * i + 1]))
})));
}
_ => return self.exec_simd_farith(s),
}
Ok(())
}
fn v_extend<I: Copy, O, const NI: usize, const NO: usize>(
&mut self,
split: fn(u128) -> [I; NI],
join: fn([O; NO]) -> u128,
high: bool,
f: impl Fn(I) -> O,
) -> Result<()> {
let a = split(self.pop_v128()?);
let off = if high { NO } else { 0 };
self.push_v128(join(core::array::from_fn(|i| f(a[off + i]))));
Ok(())
}
fn v_extmul<I: Copy, O, const NI: usize, const NO: usize>(
&mut self,
split: fn(u128) -> [I; NI],
join: fn([O; NO]) -> u128,
high: bool,
f: impl Fn(I, I) -> O,
) -> Result<()> {
let b = split(self.pop_v128()?);
let a = split(self.pop_v128()?);
let off = if high { NO } else { 0 };
self.push_v128(join(core::array::from_fn(|i| f(a[off + i], b[off + i]))));
Ok(())
}
fn v_extadd<I: Copy, O, const NI: usize, const NO: usize>(
&mut self,
split: fn(u128) -> [I; NI],
join: fn([O; NO]) -> u128,
f: impl Fn(I, I) -> O,
) -> Result<()> {
let a = split(self.pop_v128()?);
self.push_v128(join(core::array::from_fn(|i| f(a[2 * i], a[2 * i + 1]))));
Ok(())
}
fn v_narrow<I: Copy, O, const NI: usize, const NO: usize>(
&mut self,
split: fn(u128) -> [I; NI],
join: fn([O; NO]) -> u128,
f: impl Fn(I) -> O,
) -> Result<()> {
let b = split(self.pop_v128()?);
let a = split(self.pop_v128()?);
self.push_v128(join(core::array::from_fn(|i| {
if i < NI {
f(a[i])
} else {
f(b[i - NI])
}
})));
Ok(())
}
}