summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/tinywasm/src/error.rs1
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs162
-rw-r--r--crates/tinywasm/src/interpreter/num_helpers.rs2
-rw-r--r--crates/tinywasm/src/interpreter/stack/call_stack.rs1
-rw-r--r--crates/tinywasm/src/interpreter/stack/value_stack.rs58
-rw-r--r--crates/tinywasm/src/interpreter/value128.rs2773
-rw-r--r--crates/tinywasm/src/interpreter/values.rs24
-rw-r--r--crates/tinywasm/src/store/memory.rs6
-rw-r--r--crates/tinywasm/tests/host_func_signature_check.rs103
-rw-r--r--examples/funcref_callbacks.rs71
10 files changed, 748 insertions, 2453 deletions
diff --git a/crates/tinywasm/src/error.rs b/crates/tinywasm/src/error.rs
index 106f9d1..24912e3 100644
--- a/crates/tinywasm/src/error.rs
+++ b/crates/tinywasm/src/error.rs
@@ -268,6 +268,7 @@ pub(crate) trait Controlify<T> {
}
impl<T> Controlify<T> for Result<T, Error> {
+ #[inline(always)]
fn to_cf(self) -> ControlFlow<Option<Error>, T> {
match self {
Ok(value) => ControlFlow::Continue(value),
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index 91234cc..3457120 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -14,7 +14,6 @@ use super::values::*;
use crate::instance::ModuleInstanceInner;
use crate::interpreter::Value128;
use crate::*;
-
pub(crate) struct Executor<'store> {
cf: CallFrame,
func: Rc<WasmFunction>,
@@ -45,37 +44,24 @@ impl<'store> Executor<'store> {
use tinywasm_types::Instruction::*;
macro_rules! stack_op {
- (simd_unary $method:ident) => {
- self.store.stack.values.unary_same::<Value128>(|v| Ok(v.$method())).to_cf()?
- };
- (simd_binary $method:ident) => {
- self.store.stack.values.binary_same::<Value128>(|a, b| Ok(a.$method(b))).to_cf()?
- };
- (unary $ty:ty, |$v:ident| $expr:expr) => {
- self.store.stack.values.unary_same::<$ty>(|$v| Ok($expr)).to_cf()?
- };
- (binary $ty:ty, |$a:ident, $b:ident| $expr:expr) => {
- self.store.stack.values.binary_same::<$ty>(|$a, $b| Ok($expr)).to_cf()?
- };
- (binary_try $ty:ty, |$a:ident, $b:ident| $expr:expr) => {
- self.store.stack.values.binary_same::<$ty>(|$a, $b| $expr).to_cf()?
- };
- (unary $from:ty => $to:ty, |$v:ident| $expr:expr) => {
- self.store.stack.values.unary::<$from, $to>(|$v| Ok($expr)).to_cf()?
- };
- (binary $from:ty => $to:ty, |$a:ident, $b:ident| $expr:expr) => {
- self.store.stack.values.binary::<$from, $to>(|$a, $b| Ok($expr)).to_cf()?
- };
- (binary $a:ty, $b:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {
- self.store.stack.values.binary_diff::<$a, $b, $b>(|$lhs, $rhs| Ok($expr)).to_cf()?
- };
- (binary $a:ty, $b:ty => $res:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {
- self.store.stack.values.binary_diff::<$a, $b, $res>(|$lhs, $rhs| Ok($expr)).to_cf()?
- };
+ (simd_unary $method:ident) => { stack_op!(unary Value128, |v| v.$method()) };
+ (simd_binary $method:ident) => { stack_op!(binary Value128, |a, b| a.$method(b)) };
+ (unary $ty:ty, |$v:ident| $expr:expr) => { self.store.stack.values.unary::<$ty>(|$v| Ok($expr)).to_cf()? };
+ (binary $ty:ty, |$a:ident, $b:ident| $expr:expr) => { self.store.stack.values.binary::<$ty>(|$a, $b| Ok($expr)).to_cf()? };
+ (binary try $ty:ty, |$a:ident, $b:ident| $expr:expr) => { self.store.stack.values.binary::<$ty>(|$a, $b| $expr).to_cf()? };
+ (unary $from:ty => $to:ty, |$v:ident| $expr:expr) => { self.store.stack.values.unary_into::<$from, $to>(|$v| Ok($expr)).to_cf()? };
+ (binary $from:ty => $to:ty, |$a:ident, $b:ident| $expr:expr) => { self.store.stack.values.binary_into::<$from, $to>(|$a, $b| Ok($expr)).to_cf()? };
+ (binary $a:ty, $b:ty, |$lhs:ident, $rhs:ident| $expr:expr) => { stack_op!(binary $a, $b => $b, |$lhs, $rhs| $expr) };
+ (binary $a:ty, $b:ty => $res:ty, |$lhs:ident, $rhs:ident| $expr:expr) => { self.store.stack.values.binary_mixed::<$a, $b, $res>(|$lhs, $rhs| Ok($expr)).to_cf()? };
+ (ternary $ty:ty, |$a:ident, $b:ident, $c:ident| $expr:expr) => { self.store.stack.values.ternary::<$ty>(|$a, $b, $c| Ok($expr)).to_cf()? };
(local_set_pop $ty:ty, $local_index:expr) => {{
let val = self.store.stack.values.pop::<$ty>();
self.store.stack.values.local_set(&self.cf, *$local_index, val);
}};
+ (local_tee $ty:ty, $local_index:expr) => {{
+ let val = self.store.stack.values.peek::<$ty>();
+ self.store.stack.values.local_set(&self.cf, *$local_index, val);
+ }};
}
let next = match self.func.instructions.0.get(self.cf.instr_ptr as usize) {
@@ -89,7 +75,7 @@ impl<'store> Executor<'store> {
#[rustfmt::skip]
match next {
- Nop | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 | BranchTableTarget {..} => {}
+ Nop | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {}
Unreachable => return ControlFlow::Break(Some(Trap::Unreachable.into())),
Drop32 => self.store.stack.values.drop::<Value32>(),
Drop64 => self.store.stack.values.drop::<Value64>(),
@@ -106,20 +92,8 @@ impl<'store> Executor<'store> {
ReturnCall(v) => return self.exec_call_direct::<true>(*v),
ReturnCallSelf => return self.exec_call_self::<true>(),
ReturnCallIndirect(ty, table) => return self.exec_call_indirect::<true>(*ty, *table),
- Jump(ip) => {
- self.cf.instr_ptr = *ip;
- return ControlFlow::Continue(());
- }
- JumpIfZero(ip) => {
- let cond = self.store.stack.values.pop::<i32>();
-
- if cond == 0 {
- self.cf.instr_ptr = *ip;
- } else {
- self.cf.incr_instr_ptr();
- }
- return ControlFlow::Continue(());
- }
+ Jump(ip) => return self.exec_jump(*ip),
+ JumpIfZero(ip) => if self.exec_jump_if_zero(*ip) { return ControlFlow::Continue(()); },
DropKeepSmall { base32, keep32, base64, keep64, base128, keep128, base_ref, keep_ref } => {
let b32 = self.cf.stack_base().s32 + *base32 as u32;
let k32 = *keep32 as usize;
@@ -154,21 +128,8 @@ impl<'store> Executor<'store> {
let k = *keep as usize;
self.store.stack.values.stack_ref.truncate_keep(b as usize, k);
}
- BranchTable(default_ip, len) => {
- let idx = self.store.stack.values.pop::<i32>();
- let start = self.cf.instr_ptr + 1;
-
- let target_ip = if idx >= 0 && (idx as u32) < *len {
- match self.func.instructions.0.get((start + idx as u32) as usize) {
- Some(Instruction::BranchTableTarget(ip)) => *ip,
- _ => *default_ip,
- }
- } else {
- *default_ip
- };
- self.cf.instr_ptr = target_ip;
- return ControlFlow::Continue(());
- }
+ BranchTable(default_ip, len) => return self.exec_branch_table(*default_ip, *len),
+ BranchTableTarget {..} => {},
Return => return self.exec_return(),
LocalGet32(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::<Value32>(&self.cf, *local_index)).to_cf()?,
LocalGet64(local_index) => self.store.stack.values.push(self.store.stack.values.local_get::<Value64>(&self.cf, *local_index)).to_cf()?,
@@ -214,14 +175,13 @@ impl<'store> Executor<'store> {
}
I64XorRotlConst(c) => stack_op!(binary i64, |lhs, rhs| (lhs ^ rhs).rotate_left(*c as u32)),
I64XorRotlConstTee(c, local_index) => {
- self.store.stack.values.binary_same::<i64>(|lhs, rhs| Ok((lhs ^ rhs).rotate_left(*c as u32))).to_cf()?;
- let val = self.store.stack.values.peek::<i64>();
- self.store.stack.values.local_set(&self.cf, *local_index, val);
+ stack_op!(binary i64, |lhs, rhs| (lhs ^ rhs).rotate_left(*c as u32));
+ stack_op!(local_tee i64, local_index);
}
- LocalTee32(local_index) => self.store.stack.values.local_set(&self.cf, *local_index, self.store.stack.values.peek::<Value32>()),
- LocalTee64(local_index) => self.store.stack.values.local_set(&self.cf, *local_index, self.store.stack.values.peek::<Value64>()),
- LocalTee128(local_index) => self.store.stack.values.local_set(&self.cf, *local_index, self.store.stack.values.peek::<Value128>()),
- LocalTeeRef(local_index) => self.store.stack.values.local_set(&self.cf, *local_index, self.store.stack.values.peek::<ValueRef>()),
+ LocalTee32(local_index) => stack_op!(local_tee Value32, local_index),
+ LocalTee64(local_index) => stack_op!(local_tee Value64, local_index),
+ LocalTee128(local_index) => stack_op!(local_tee Value128, local_index),
+ LocalTeeRef(local_index) => stack_op!(local_tee ValueRef, local_index),
GlobalGet(global_index) => self.exec_global_get(*global_index).to_cf()?,
GlobalSet32(global_index) => self.exec_global_set::<Value32>(*global_index),
GlobalSet64(global_index) => self.exec_global_set::<Value64>(*global_index),
@@ -279,14 +239,14 @@ impl<'store> Executor<'store> {
I64Mul => stack_op!(binary i64, |a, b| a.wrapping_mul(b)),
F32Mul => stack_op!(binary f32, |a, b| a * b),
F64Mul => stack_op!(binary f64, |a, b| a * b),
- I32DivS => stack_op!(binary_try i32, |a, b| a.wasm_checked_div(b)),
- I64DivS => stack_op!(binary_try i64, |a, b| a.wasm_checked_div(b)),
- I32DivU => stack_op!(binary_try u32, |a, b| a.checked_div(b).ok_or_else(trap_0)),
- I64DivU => stack_op!(binary_try u64, |a, b| a.checked_div(b).ok_or_else(trap_0)),
- I32RemS => stack_op!(binary_try i32, |a, b| a.checked_wrapping_rem(b)),
- I64RemS => stack_op!(binary_try i64, |a, b| a.checked_wrapping_rem(b)),
- I32RemU => stack_op!(binary_try u32, |a, b| a.checked_wrapping_rem(b)),
- I64RemU => stack_op!(binary_try u64, |a, b| a.checked_wrapping_rem(b)),
+ I32DivS => stack_op!(binary try i32, |a, b| a.wasm_checked_div(b)),
+ I64DivS => stack_op!(binary try i64, |a, b| a.wasm_checked_div(b)),
+ I32DivU => stack_op!(binary try u32, |a, b| a.checked_div(b).ok_or_else(trap_0)),
+ I64DivU => stack_op!(binary try u64, |a, b| a.checked_div(b).ok_or_else(trap_0)),
+ I32RemS => stack_op!(binary try i32, |a, b| a.checked_wrapping_rem(b)),
+ I64RemS => stack_op!(binary try i64, |a, b| a.checked_wrapping_rem(b)),
+ I32RemU => stack_op!(binary try u32, |a, b| a.checked_wrapping_rem(b)),
+ I64RemU => stack_op!(binary try u64, |a, b| a.checked_wrapping_rem(b)),
I32And => stack_op!(binary i32, |a, b| a & b),
I64And => stack_op!(binary i64, |a, b| a & b),
I32Or => stack_op!(binary i32, |a, b| a | b),
@@ -424,7 +384,7 @@ impl<'store> Executor<'store> {
V128AndNot => stack_op!(binary Value128, |a, b| a.v128_andnot(b)),
V128Or => stack_op!(binary Value128, |a, b| a.v128_or(b)),
V128Xor => stack_op!(binary Value128, |a, b| a.v128_xor(b)),
- V128Bitselect => self.store.stack.values.ternary_same::<Value128>(|v1, v2, c| Ok(Value128::v128_bitselect(v1, v2, c))).to_cf()?,
+ V128Bitselect => stack_op!(ternary Value128, |v1, v2, c| Value128::v128_bitselect(v1, v2, c)),
V128AnyTrue => stack_op!(unary Value128 => i32, |v| v.v128_any_true() as i32),
I8x16Swizzle => stack_op!(binary Value128, |a, s| a.i8x16_swizzle(s)),
V128Load(arg) => self.exec_mem_load::<Value128, 16, _>(arg.mem_addr(), arg.offset(), |v| v)?,
@@ -661,6 +621,39 @@ impl<'store> Executor<'store> {
ControlFlow::Continue(())
}
+ #[inline(always)]
+ fn exec_jump(&mut self, ip: u32) -> ControlFlow<Option<Error>> {
+ self.cf.instr_ptr = ip;
+ ControlFlow::Continue(())
+ }
+
+ #[inline(always)]
+ fn exec_jump_if_zero(&mut self, ip: u32) -> bool {
+ if self.store.stack.values.pop::<i32>() == 0 {
+ self.cf.instr_ptr = ip;
+ return true;
+ }
+ false
+ }
+
+ #[inline(always)]
+ fn exec_branch_table(&mut self, default_ip: u32, len: u32) -> ControlFlow<Option<Error>> {
+ let idx = self.store.stack.values.pop::<i32>();
+ let start = self.cf.instr_ptr + 1;
+
+ let target_ip = if idx >= 0 && (idx as u32) < len {
+ match self.func.instructions.0.get((start + idx as u32) as usize) {
+ Some(Instruction::BranchTableTarget(ip)) => *ip,
+ _ => default_ip,
+ }
+ } else {
+ default_ip
+ };
+
+ self.cf.instr_ptr = target_ip;
+ ControlFlow::Continue(())
+ }
+
fn exec_call<const IS_RETURN_CALL: bool>(
&mut self,
wasm_func: Rc<WasmFunction>,
@@ -943,6 +936,7 @@ impl<'store> Executor<'store> {
ControlFlow::Continue(())
}
+ #[inline(always)]
fn exec_mem_load<LOAD: MemValue<LOAD_SIZE>, const LOAD_SIZE: usize, TARGET: InternalValue>(
&mut self,
mem_addr: tinywasm_types::MemAddr,
@@ -951,18 +945,28 @@ impl<'store> Executor<'store> {
) -> ControlFlow<Option<Error>> {
let mem = self.store.state.get_mem(self.module.resolve_mem_addr(mem_addr));
- let addr = match mem.is_64bit() {
- true => self.store.stack.values.pop::<i64>() as u64,
- false => u64::from(self.store.stack.values.pop::<i32>() as u32),
+ let base: u64 = if mem.is_64bit() {
+ self.store.stack.values.pop::<i64>() as u64
+ } else {
+ self.store.stack.values.pop::<i32>() as u32 as u64
+ };
+
+ let Some(addr) = base.checked_add(offset) else {
+ return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds {
+ offset: base as usize,
+ len: LOAD_SIZE,
+ max: 0,
+ })));
};
- let Some(Ok(addr)) = offset.checked_add(addr).map(|a| a.try_into()) else {
+ let Ok(addr) = usize::try_from(addr) else {
return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds {
- offset: addr as usize,
+ offset: base as usize,
len: LOAD_SIZE,
max: 0,
})));
};
+
let val = mem.load_as::<LOAD_SIZE, LOAD>(addr).to_cf()?;
self.store.stack.values.push(cast(val)).to_cf()?;
ControlFlow::Continue(())
diff --git a/crates/tinywasm/src/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs
index f800575..cf13260 100644
--- a/crates/tinywasm/src/interpreter/num_helpers.rs
+++ b/crates/tinywasm/src/interpreter/num_helpers.rs
@@ -35,7 +35,7 @@ macro_rules! checked_conv_float {
.store
.stack
.values
- .unary::<$from, $to>(|v| {
+ .unary_into::<$from, $to>(|v| {
let (min, max) = float_min_max!($from, $intermediate);
if unlikely(v.is_nan()) {
return Err(Error::Trap(crate::Trap::InvalidConversionToInt));
diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs
index 1b8117c..133f910 100644
--- a/crates/tinywasm/src/interpreter/stack/call_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs
@@ -69,6 +69,7 @@ impl CallFrame {
}
}
+ #[inline(always)]
pub(crate) fn incr_instr_ptr(&mut self) {
self.instr_ptr += 1;
}
diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs
index 81a5c5d..7fa0502 100644
--- a/crates/tinywasm/src/interpreter/stack/value_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs
@@ -172,7 +172,7 @@ impl ValueStack {
T::stack_pop(self);
}
- #[inline]
+ #[inline(always)]
pub(crate) fn select<T: InternalValue>(&mut self) -> Result<()> {
let cond: i32 = self.pop();
let val2: T = self.pop();
@@ -192,51 +192,51 @@ impl ValueStack {
self.stack_ref.select_many(counts.cref as usize, condition);
}
- #[inline]
- pub(crate) fn binary_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T) -> Result<T>) -> Result<()> {
- T::stack_calculate(self, func)
- }
-
- #[inline]
- pub(crate) fn ternary_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T, T) -> Result<T>) -> Result<()> {
- T::stack_calculate3(self, func)
+ #[inline(always)]
+ pub(crate) fn unary<T: InternalValue>(&mut self, func: impl FnOnce(T) -> Result<T>) -> Result<()> {
+ T::stack_apply1(self, func)
}
- #[inline]
- pub(crate) fn binary<T: InternalValue, U: InternalValue>(
+ #[inline(always)]
+ pub(crate) fn unary_into<IN: InternalValue, OUT: InternalValue>(
&mut self,
- func: impl FnOnce(T, T) -> Result<U>,
+ func: impl FnOnce(IN) -> Result<OUT>,
) -> Result<()> {
- let v2 = T::stack_pop(self);
- let v1 = T::stack_pop(self);
- U::stack_push(self, func(v1, v2)?)?;
+ let v = IN::stack_pop(self);
+ OUT::stack_push(self, func(v)?)?;
Ok(())
}
- #[inline]
- pub(crate) fn binary_diff<A: InternalValue, B: InternalValue, RES: InternalValue>(
+ #[inline(always)]
+ pub(crate) fn binary<T: InternalValue>(&mut self, func: impl FnOnce(T, T) -> Result<T>) -> Result<()> {
+ T::stack_apply2(self, func)
+ }
+
+ #[inline(always)]
+ pub(crate) fn binary_into<IN: InternalValue, OUT: InternalValue>(
&mut self,
- func: impl FnOnce(A, B) -> Result<RES>,
+ func: impl FnOnce(IN, IN) -> Result<OUT>,
) -> Result<()> {
- let v2 = B::stack_pop(self);
- let v1 = A::stack_pop(self);
- RES::stack_push(self, func(v1, v2)?)?;
+ let rhs = IN::stack_pop(self);
+ let lhs = IN::stack_pop(self);
+ OUT::stack_push(self, func(lhs, rhs)?)?;
Ok(())
}
- #[inline]
- pub(crate) fn unary<T: InternalValue, U: InternalValue>(
+ #[inline(always)]
+ pub(crate) fn binary_mixed<A: InternalValue, B: InternalValue, OUT: InternalValue>(
&mut self,
- func: impl FnOnce(T) -> Result<U>,
+ func: impl FnOnce(A, B) -> Result<OUT>,
) -> Result<()> {
- let v1 = T::stack_pop(self);
- U::stack_push(self, func(v1)?)?;
+ let rhs = B::stack_pop(self);
+ let lhs = A::stack_pop(self);
+ OUT::stack_push(self, func(lhs, rhs)?)?;
Ok(())
}
- #[inline]
- pub(crate) fn unary_same<T: InternalValue>(&mut self, func: impl Fn(T) -> Result<T>) -> Result<()> {
- T::replace_top(self, func)
+ #[inline(always)]
+ pub(crate) fn ternary<T: InternalValue>(&mut self, func: impl FnOnce(T, T, T) -> Result<T>) -> Result<()> {
+ T::stack_apply3(self, func)
}
pub(crate) fn pop_types<'a>(
diff --git a/crates/tinywasm/src/interpreter/value128.rs b/crates/tinywasm/src/interpreter/value128.rs
index bb2c686..7de4dca 100644
--- a/crates/tinywasm/src/interpreter/value128.rs
+++ b/crates/tinywasm/src/interpreter/value128.rs
@@ -8,8 +8,281 @@ use core::arch::wasm32 as wasm;
use core::arch::wasm64 as wasm;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
+/// A 128-bit SIMD value
pub struct Value128(i128);
+impl From<Value128> for i128 {
+ fn from(val: Value128) -> Self {
+ val.0
+ }
+}
+
+impl From<i128> for Value128 {
+ fn from(value: i128) -> Self {
+ Self(value)
+ }
+}
+
+macro_rules! simd_wrapping_binop {
+ ($name:ident, $doc:literal, $wasm_op:ident, $lane_ty:ty, $lane_count:expr, $as_lanes:ident, $from_lanes:ident, $op:ident) => {
+ #[doc(alias = $doc)]
+ pub fn $name(self, rhs: Self) -> Self {
+ #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
+ return Self::from_wasm_v128(wasm::$wasm_op(self.to_wasm_v128(), rhs.to_wasm_v128()));
+
+ let a = self.$as_lanes();
+ let b = rhs.$as_lanes();
+ Self::$from_lanes(core::array::from_fn(|i| a[i].$op(b[i])))
+ }
+ };
+}
+
+macro_rules! simd_sat_binop {
+ ($name:ident, $doc:literal, $wasm_op:ident, $lane_ty:ty, $lane_count:expr, $as_lanes:ident, $from_lanes:ident, $op:ident) => {
+ #[doc(alias = $doc)]
+ pub fn $name(self, rhs: Self) -> Self {
+ #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
+ return Self::from_wasm_v128(wasm::$wasm_op(self.to_wasm_v128(), rhs.to_wasm_v128()));
+
+ let a = self.$as_lanes();
+ let b = rhs.$as_lanes();
+ Self::$from_lanes(core::array::from_fn(|i| a[i].$op(b[i])))
+ }
+ };
+}
+
+macro_rules! simd_all_true {
+ ($name:ident, $doc:literal, $as_lanes:ident, $count:expr) => {
+ #[doc(alias = $doc)]
+ pub const fn $name(self) -> bool {
+ let lanes = self.$as_lanes();
+ let mut i = 0;
+ while i < $count {
+ if lanes[i] == 0 {
+ return false;
+ }
+ i += 1;
+ }
+ true
+ }
+ };
+}
+
+macro_rules! simd_bitmask {
+ ($name:ident, $doc:literal, $as_lanes:ident, $count:expr) => {
+ #[doc(alias = $doc)]
+ pub const fn $name(self) -> u32 {
+ let lanes = self.$as_lanes();
+ let mut mask = 0u32;
+ let mut i = 0;
+ while i < $count {
+ mask |= ((lanes[i] < 0) as u32) << i;
+ i += 1;
+ }
+ mask
+ }
+ };
+}
+
+macro_rules! simd_shift_left {
+ ($name:ident, $doc:literal, $lane_ty:ty, $count:expr, $as_lanes:ident, $from_lanes:ident, $mask:expr) => {
+ #[doc(alias = $doc)]
+ pub const fn $name(self, shift: u32) -> Self {
+ let lanes = self.$as_lanes();
+ let s = shift & $mask;
+ let mut out = [0 as $lane_ty; $count];
+ let mut i = 0;
+ while i < $count {
+ out[i] = lanes[i].wrapping_shl(s);
+ i += 1;
+ }
+ Self::$from_lanes(out)
+ }
+ };
+}
+
+macro_rules! simd_shift_right {
+ ($name:ident, $doc:literal, $lane_ty:ty, $count:expr, $as_lanes:ident, $from_lanes:ident, $mask:expr) => {
+ #[doc(alias = $doc)]
+ pub const fn $name(self, shift: u32) -> Self {
+ let lanes = self.$as_lanes();
+ let s = shift & $mask;
+ let mut out = [0 as $lane_ty; $count];
+ let mut i = 0;
+ while i < $count {
+ out[i] = lanes[i] >> s;
+ i += 1;
+ }
+ Self::$from_lanes(out)
+ }
+ };
+}
+
+macro_rules! simd_avgr_u {
+ ($name:ident, $doc:literal, $wasm_op:ident, $lane_ty:ty, $wide_ty:ty, $count:expr, $as_lanes:ident, $from_lanes:ident) => {
+ #[doc(alias = $doc)]
+ pub fn $name(self, rhs: Self) -> Self {
+ #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
+ return Self::from_wasm_v128(wasm::$wasm_op(self.to_wasm_v128(), rhs.to_wasm_v128()));
+
+ let a = self.$as_lanes();
+ let b = rhs.$as_lanes();
+ Self::$from_lanes(core::array::from_fn(|i| ((a[i] as $wide_ty + b[i] as $wide_ty + 1) >> 1) as $lane_ty))
+ }
+ };
+}
+
+macro_rules! simd_extend_cast {
+ ($name:ident, $doc:literal, $src_as:ident, $dst_from:ident, $dst_ty:ty, $dst_count:expr, $offset:expr) => {
+ #[doc(alias = $doc)]
+ pub const fn $name(self) -> Self {
+ let lanes = self.$src_as();
+ let mut out = [0 as $dst_ty; $dst_count];
+ let mut i = 0;
+ while i < $dst_count {
+ out[i] = lanes[i + $offset] as $dst_ty;
+ i += 1;
+ }
+ Self::$dst_from(out)
+ }
+ };
+}
+
+macro_rules! simd_extmul_signed {
+ ($name:ident, $doc:literal, $src_as:ident, $dst_from:ident, $dst_ty:ty, $dst_count:expr, $offset:expr) => {
+ #[doc(alias = $doc)]
+ pub const fn $name(self, rhs: Self) -> Self {
+ let a = self.$src_as();
+ let b = rhs.$src_as();
+ let mut out = [0 as $dst_ty; $dst_count];
+ let mut i = 0;
+ while i < $dst_count {
+ out[i] = (a[i + $offset] as $dst_ty).wrapping_mul(b[i + $offset] as $dst_ty);
+ i += 1;
+ }
+ Self::$dst_from(out)
+ }
+ };
+}
+
+macro_rules! simd_extmul_unsigned {
+ ($name:ident, $doc:literal, $src_as:ident, $dst_from:ident, $dst_ty:ty, $dst_count:expr, $offset:expr) => {
+ #[doc(alias = $doc)]
+ pub const fn $name(self, rhs: Self) -> Self {
+ let a = self.$src_as();
+ let b = rhs.$src_as();
+ let mut out = [0 as $dst_ty; $dst_count];
+ let mut i = 0;
+ while i < $dst_count {
+ out[i] = (a[i + $offset] as $dst_ty) * (b[i + $offset] as $dst_ty);
+ i += 1;
+ }
+ Self::$dst_from(out)
+ }
+ };
+}
+
+macro_rules! simd_cmp_mask {
+ ($name:ident, $doc:literal, $wasm_op:ident, $out_ty:ty, $count:expr, $as_lanes:ident, $from_lanes:ident, $cmp:tt) => {
+ #[doc(alias = $doc)]
+ pub fn $name(self, rhs: Self) -> Self {
+ #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
+ return Self::from_wasm_v128(wasm::$wasm_op(self.to_wasm_v128(), rhs.to_wasm_v128()));
+
+ let a = self.$as_lanes();
+ let b = rhs.$as_lanes();
+ Self::$from_lanes(core::array::from_fn(|i| if a[i] $cmp b[i] { -1 } else { 0 }))
+ }
+ };
+}
+
+macro_rules! simd_cmp_mask_const {
+ ($name:ident, $doc:literal, $out_ty:ty, $count:expr, $as_lanes:ident, $from_lanes:ident, $cmp:tt) => {
+ #[doc(alias = $doc)]
+ pub const fn $name(self, rhs: Self) -> Self {
+ let a = self.$as_lanes();
+ let b = rhs.$as_lanes();
+ let mut out = [0 as $out_ty; $count];
+ let mut i = 0;
+ while i < $count {
+ out[i] = if a[i] $cmp b[i] { -1 } else { 0 };
+ i += 1;
+ }
+ Self::$from_lanes(out)
+ }
+ };
+}
+
+macro_rules! simd_cmp_delegate {
+ ($name:ident, $doc:literal, $delegate:ident) => {
+ #[doc(alias = $doc)]
+ pub fn $name(self, rhs: Self) -> Self {
+ rhs.$delegate(self)
+ }
+ };
+}
+
+macro_rules! simd_abs_const {
+ ($name:ident, $doc:literal, $lane_ty:ty, $count:expr, $as_lanes:ident, $from_lanes:ident) => {
+ #[doc(alias = $doc)]
+ pub const fn $name(self) -> Self {
+ let a = self.$as_lanes();
+ let mut out = [0 as $lane_ty; $count];
+ let mut i = 0;
+ while i < $count {
+ out[i] = a[i].wrapping_abs();
+ i += 1;
+ }
+ Self::$from_lanes(out)
+ }
+ };
+}
+
+macro_rules! simd_neg {
+ ($name:ident, $doc:literal, $wasm_op:ident, $lane_ty:ty, $count:expr, $as_lanes:ident, $from_lanes:ident) => {
+ #[doc(alias = $doc)]
+ pub fn $name(self) -> Self {
+ #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
+ return Self::from_wasm_v128(wasm::$wasm_op(self.to_wasm_v128()));
+
+ let a = self.$as_lanes();
+ Self::$from_lanes(core::array::from_fn(|i| a[i].wrapping_neg()))
+ }
+ };
+}
+
+macro_rules! simd_minmax {
+ ($name:ident, $doc:literal, $wasm_op:ident, $lane_ty:ty, $count:expr, $as_lanes:ident, $from_lanes:ident, $cmp:tt) => {
+ #[doc(alias = $doc)]
+ pub fn $name(self, rhs: Self) -> Self {
+ #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
+ return Self::from_wasm_v128(wasm::$wasm_op(self.to_wasm_v128(), rhs.to_wasm_v128()));
+
+ let a = self.$as_lanes();
+ let b = rhs.$as_lanes();
+ Self::$from_lanes(core::array::from_fn(|i| if a[i] $cmp b[i] { a[i] } else { b[i] }))
+ }
+ };
+}
+
+macro_rules! simd_float_unary {
+ ($name:ident, $doc:literal, $map:ident, $op:expr) => {
+ #[doc(alias = $doc)]
+ pub fn $name(self) -> Self {
+ self.$map($op)
+ }
+ };
+}
+
+macro_rules! simd_float_binary {
+ ($name:ident, $doc:literal, $zip:ident, $op:expr) => {
+ #[doc(alias = $doc)]
+ pub fn $name(self, rhs: Self) -> Self {
+ self.$zip(rhs, $op)
+ }
+ };
+}
+
#[cfg_attr(any(target_arch = "wasm32", target_arch = "wasm64"), allow(unreachable_code))]
impl Value128 {
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
@@ -24,24 +297,8 @@ impl Value128 {
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
#[inline(always)]
fn from_wasm_v128(value: wasm::v128) -> Self {
- Self::from_le_bytes([
- wasm::u8x16_extract_lane::<0>(value),
- wasm::u8x16_extract_lane::<1>(value),
- wasm::u8x16_extract_lane::<2>(value),
- wasm::u8x16_extract_lane::<3>(value),
- wasm::u8x16_extract_lane::<4>(value),
- wasm::u8x16_extract_lane::<5>(value),
- wasm::u8x16_extract_lane::<6>(value),
- wasm::u8x16_extract_lane::<7>(value),
- wasm::u8x16_extract_lane::<8>(value),
- wasm::u8x16_extract_lane::<9>(value),
- wasm::u8x16_extract_lane::<10>(value),
- wasm::u8x16_extract_lane::<11>(value),
- wasm::u8x16_extract_lane::<12>(value),
- wasm::u8x16_extract_lane::<13>(value),
- wasm::u8x16_extract_lane::<14>(value),
- wasm::u8x16_extract_lane::<15>(value),
- ])
+ #[rustfmt::skip]
+ Self::from_le_bytes([ wasm::u8x16_extract_lane::<0>(value), wasm::u8x16_extract_lane::<1>(value), wasm::u8x16_extract_lane::<2>(value), wasm::u8x16_extract_lane::<3>(value), wasm::u8x16_extract_lane::<4>(value), wasm::u8x16_extract_lane::<5>(value), wasm::u8x16_extract_lane::<6>(value), wasm::u8x16_extract_lane::<7>(value), wasm::u8x16_extract_lane::<8>(value), wasm::u8x16_extract_lane::<9>(value), wasm::u8x16_extract_lane::<10>(value), wasm::u8x16_extract_lane::<11>(value), wasm::u8x16_extract_lane::<12>(value), wasm::u8x16_extract_lane::<13>(value), wasm::u8x16_extract_lane::<14>(value), wasm::u8x16_extract_lane::<15>(value)])
}
#[inline]
@@ -54,163 +311,163 @@ impl Value128 {
self.0.to_le_bytes()
}
- #[rustfmt::skip]
#[inline]
- pub const fn as_i8x16(self) -> [i8; 16] {
+ #[rustfmt::skip]
+ const fn as_i8x16(self) -> [i8; 16] {
let b = self.to_le_bytes();
[b[0] as i8, b[1] as i8, b[2] as i8, b[3] as i8, b[4] as i8, b[5] as i8, b[6] as i8, b[7] as i8, b[8] as i8, b[9] as i8, b[10] as i8, b[11] as i8, b[12] as i8, b[13] as i8, b[14] as i8, b[15] as i8]
}
- #[rustfmt::skip]
#[inline]
- pub const fn as_u8x16(self) -> [u8; 16] {
+ #[rustfmt::skip]
+ const fn as_u8x16(self) -> [u8; 16] {
self.to_le_bytes()
}
- #[rustfmt::skip]
#[inline]
- pub const fn from_i8x16(x: [i8; 16]) -> Self {
+ #[rustfmt::skip]
+ const fn from_i8x16(x: [i8; 16]) -> Self {
Self::from_le_bytes([x[0] as u8, x[1] as u8, x[2] as u8, x[3] as u8, x[4] as u8, x[5] as u8, x[6] as u8, x[7] as u8, x[8] as u8, x[9] as u8, x[10] as u8, x[11] as u8, x[12] as u8, x[13] as u8, x[14] as u8, x[15] as u8])
}
- #[rustfmt::skip]
#[inline]
- pub const fn from_u8x16(x: [u8; 16]) -> Self {
+ #[rustfmt::skip]
+ const fn from_u8x16(x: [u8; 16]) -> Self {
Self::from_le_bytes(x)
}
- #[rustfmt::skip]
#[inline]
- pub const fn as_i16x8(self) -> [i16; 8] {
+ #[rustfmt::skip]
+ const fn as_i16x8(self) -> [i16; 8] {
let b = self.to_le_bytes();
[i16::from_le_bytes([b[0], b[1]]), i16::from_le_bytes([b[2], b[3]]), i16::from_le_bytes([b[4], b[5]]), i16::from_le_bytes([b[6], b[7]]), i16::from_le_bytes([b[8], b[9]]), i16::from_le_bytes([b[10], b[11]]), i16::from_le_bytes([b[12], b[13]]), i16::from_le_bytes([b[14], b[15]])]
}
- #[rustfmt::skip]
#[inline]
- pub const fn as_u16x8(self) -> [u16; 8] {
+ #[rustfmt::skip]
+ const fn as_u16x8(self) -> [u16; 8] {
let b = self.to_le_bytes();
[u16::from_le_bytes([b[0], b[1]]), u16::from_le_bytes([b[2], b[3]]), u16::from_le_bytes([b[4], b[5]]), u16::from_le_bytes([b[6], b[7]]), u16::from_le_bytes([b[8], b[9]]), u16::from_le_bytes([b[10], b[11]]), u16::from_le_bytes([b[12], b[13]]), u16::from_le_bytes([b[14], b[15]])]
}
- #[rustfmt::skip]
#[inline]
- pub const fn from_i16x8(x: [i16; 8]) -> Self {
+ #[rustfmt::skip]
+ const fn from_i16x8(x: [i16; 8]) -> Self {
Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[4].to_le_bytes()[0], x[4].to_le_bytes()[1], x[5].to_le_bytes()[0], x[5].to_le_bytes()[1], x[6].to_le_bytes()[0], x[6].to_le_bytes()[1], x[7].to_le_bytes()[0], x[7].to_le_bytes()[1]])
}
- #[rustfmt::skip]
#[inline]
- pub const fn from_u16x8(x: [u16; 8]) -> Self {
+ #[rustfmt::skip]
+ const fn from_u16x8(x: [u16; 8]) -> Self {
Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[4].to_le_bytes()[0], x[4].to_le_bytes()[1], x[5].to_le_bytes()[0], x[5].to_le_bytes()[1], x[6].to_le_bytes()[0], x[6].to_le_bytes()[1], x[7].to_le_bytes()[0], x[7].to_le_bytes()[1]])
}
- #[rustfmt::skip]
#[inline]
- pub const fn as_i32x4(self) -> [i32; 4] {
+ #[rustfmt::skip]
+ const fn as_i32x4(self) -> [i32; 4] {
let b = self.to_le_bytes();
[i32::from_le_bytes([b[0], b[1], b[2], b[3]]), i32::from_le_bytes([b[4], b[5], b[6], b[7]]), i32::from_le_bytes([b[8], b[9], b[10], b[11]]), i32::from_le_bytes([b[12], b[13], b[14], b[15]])]
}
- #[rustfmt::skip]
#[inline]
- pub const fn as_u32x4(self) -> [u32; 4] {
+ #[rustfmt::skip]
+ const fn as_u32x4(self) -> [u32; 4] {
let b = self.to_le_bytes();
[u32::from_le_bytes([b[0], b[1], b[2], b[3]]), u32::from_le_bytes([b[4], b[5], b[6], b[7]]), u32::from_le_bytes([b[8], b[9], b[10], b[11]]), u32::from_le_bytes([b[12], b[13], b[14], b[15]])]
}
- #[rustfmt::skip]
#[inline]
- pub const fn as_f32x4(self) -> [f32; 4] {
+ #[rustfmt::skip]
+ const fn as_f32x4(self) -> [f32; 4] {
let b = self.to_le_bytes();
[f32::from_bits(u32::from_le_bytes([b[0], b[1], b[2], b[3]])), f32::from_bits(u32::from_le_bytes([b[4], b[5], b[6], b[7]])), f32::from_bits(u32::from_le_bytes([b[8], b[9], b[10], b[11]])), f32::from_bits(u32::from_le_bytes([b[12], b[13], b[14], b[15]]))]
}
- #[rustfmt::skip]
#[inline]
+ #[rustfmt::skip]
pub const fn from_i32x4(x: [i32; 4]) -> Self {
Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[2].to_le_bytes()[2], x[2].to_le_bytes()[3], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[3].to_le_bytes()[2], x[3].to_le_bytes()[3]])
}
- #[rustfmt::skip]
#[inline]
- pub const fn from_u32x4(x: [u32; 4]) -> Self {
+ #[rustfmt::skip]
+ const fn from_u32x4(x: [u32; 4]) -> Self {
Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[2].to_le_bytes()[2], x[2].to_le_bytes()[3], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[3].to_le_bytes()[2], x[3].to_le_bytes()[3]])
}
- #[rustfmt::skip]
#[inline]
- pub const fn from_f32x4(x: [f32; 4]) -> Self {
+ #[rustfmt::skip]
+ const fn from_f32x4(x: [f32; 4]) -> Self {
Self::from_le_bytes([x[0].to_bits().to_le_bytes()[0], x[0].to_bits().to_le_bytes()[1], x[0].to_bits().to_le_bytes()[2], x[0].to_bits().to_le_bytes()[3], x[1].to_bits().to_le_bytes()[0], x[1].to_bits().to_le_bytes()[1], x[1].to_bits().to_le_bytes()[2], x[1].to_bits().to_le_bytes()[3], x[2].to_bits().to_le_bytes()[0], x[2].to_bits().to_le_bytes()[1], x[2].to_bits().to_le_bytes()[2], x[2].to_bits().to_le_bytes()[3], x[3].to_bits().to_le_bytes()[0], x[3].to_bits().to_le_bytes()[1], x[3].to_bits().to_le_bytes()[2], x[3].to_bits().to_le_bytes()[3]])
}
- #[rustfmt::skip]
#[inline]
- pub const fn as_i64x2(self) -> [i64; 2] {
+ #[rustfmt::skip]
+ const fn as_i64x2(self) -> [i64; 2] {
let b = self.to_le_bytes();
[i64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]), i64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]])]
}
- #[rustfmt::skip]
#[inline]
- pub const fn as_u64x2(self) -> [u64; 2] {
+ #[rustfmt::skip]
+ const fn as_u64x2(self) -> [u64; 2] {
let b = self.to_le_bytes();
[u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]), u64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]])]
}
- #[rustfmt::skip]
#[inline]
- pub const fn as_f64x2(self) -> [f64; 2] {
+ #[rustfmt::skip]
+ const fn as_f64x2(self) -> [f64; 2] {
let b = self.to_le_bytes();
[f64::from_bits(u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])), f64::from_bits(u64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]]))]
}
- #[rustfmt::skip]
#[inline]
+ #[rustfmt::skip]
pub const fn from_i64x2(x: [i64; 2]) -> Self {
Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[0].to_le_bytes()[4], x[0].to_le_bytes()[5], x[0].to_le_bytes()[6], x[0].to_le_bytes()[7], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[1].to_le_bytes()[4], x[1].to_le_bytes()[5], x[1].to_le_bytes()[6], x[1].to_le_bytes()[7]])
}
- #[rustfmt::skip]
#[inline]
- pub const fn from_u64x2(x: [u64; 2]) -> Self {
+ #[rustfmt::skip]
+ const fn from_u64x2(x: [u64; 2]) -> Self {
Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[0].to_le_bytes()[4], x[0].to_le_bytes()[5], x[0].to_le_bytes()[6], x[0].to_le_bytes()[7], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[1].to_le_bytes()[4], x[1].to_le_bytes()[5], x[1].to_le_bytes()[6], x[1].to_le_bytes()[7]])
}
- #[rustfmt::skip]
#[inline]
- pub const fn from_f64x2(x: [f64; 2]) -> Self {
+ #[rustfmt::skip]
+ const fn from_f64x2(x: [f64; 2]) -> Self {
Self::from_le_bytes([x[0].to_bits().to_le_bytes()[0], x[0].to_bits().to_le_bytes()[1], x[0].to_bits().to_le_bytes()[2], x[0].to_bits().to_le_bytes()[3], x[0].to_bits().to_le_bytes()[4], x[0].to_bits().to_le_bytes()[5], x[0].to_bits().to_le_bytes()[6], x[0].to_bits().to_le_bytes()[7], x[1].to_bits().to_le_bytes()[0], x[1].to_bits().to_le_bytes()[1], x[1].to_bits().to_le_bytes()[2], x[1].to_bits().to_le_bytes()[3], x[1].to_bits().to_le_bytes()[4], x[1].to_bits().to_le_bytes()[5], x[1].to_bits().to_le_bytes()[6], x[1].to_bits().to_le_bytes()[7]])
}
#[inline]
fn map_f32x4(self, mut op: impl FnMut(f32) -> f32) -> Self {
let lanes = self.as_f32x4();
- Self::from_f32x4([op(lanes[0]), op(lanes[1]), op(lanes[2]), op(lanes[3])])
+ Self::from_f32x4(core::array::from_fn(|i| op(lanes[i])))
}
#[inline]
fn zip_f32x4(self, rhs: Self, mut op: impl FnMut(f32, f32) -> f32) -> Self {
let a = self.as_f32x4();
let b = rhs.as_f32x4();
- Self::from_f32x4([op(a[0], b[0]), op(a[1], b[1]), op(a[2], b[2]), op(a[3], b[3])])
+ Self::from_f32x4(core::array::from_fn(|i| op(a[i], b[i])))
}
#[inline]
fn map_f64x2(self, mut op: impl FnMut(f64) -> f64) -> Self {
let lanes = self.as_f64x2();
- Self::from_f64x2([op(lanes[0]), op(lanes[1])])
+ Self::from_f64x2(core::array::from_fn(|i| op(lanes[i])))
}
#[inline]
fn zip_f64x2(self, rhs: Self, mut op: impl FnMut(f64, f64) -> f64) -> Self {
let a = self.as_f64x2();
let b = rhs.as_f64x2();
- Self::from_f64x2([op(a[0], b[0]), op(a[1], b[1])])
+ Self::from_f64x2(core::array::from_fn(|i| op(a[i], b[i])))
}
#[inline]
- pub const fn reduce_or(self) -> u8 {
+ const fn reduce_or(self) -> u8 {
let mut result = 0u8;
let bytes = self.to_le_bytes();
let mut i = 0;
@@ -224,70 +481,52 @@ impl Value128 {
#[doc(alias = "v128.any_true")]
pub fn v128_any_true(self) -> bool {
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return wasm::v128_any_true(self.to_wasm_v128());
- }
+ return wasm::v128_any_true(self.to_wasm_v128());
self.reduce_or() != 0
}
#[doc(alias = "v128.not")]
pub fn v128_not(self) -> Self {
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::v128_not(self.to_wasm_v128()));
- }
+ return Self::from_wasm_v128(wasm::v128_not(self.to_wasm_v128()));
Self(!self.0)
}
#[doc(alias = "v128.and")]
pub fn v128_and(self, rhs: Self) -> Self {
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::v128_and(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
+ return Self::from_wasm_v128(wasm::v128_and(self.to_wasm_v128(), rhs.to_wasm_v128()));
Self(self.0 & rhs.0)
}
#[doc(alias = "v128.andnot")]
pub fn v128_andnot(self, rhs: Self) -> Self {
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::v128_andnot(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
+ return Self::from_wasm_v128(wasm::v128_andnot(self.to_wasm_v128(), rhs.to_wasm_v128()));
Self(self.0 & !rhs.0)
}
#[doc(alias = "v128.or")]
pub fn v128_or(self, rhs: Self) -> Self {
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::v128_or(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
+ return Self::from_wasm_v128(wasm::v128_or(self.to_wasm_v128(), rhs.to_wasm_v128()));
Self(self.0 | rhs.0)
}
#[doc(alias = "v128.xor")]
pub fn v128_xor(self, rhs: Self) -> Self {
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::v128_xor(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
+ return Self::from_wasm_v128(wasm::v128_xor(self.to_wasm_v128(), rhs.to_wasm_v128()));
Self(self.0 ^ rhs.0)
}
#[doc(alias = "v128.bitselect")]
pub fn v128_bitselect(v1: Self, v2: Self, c: Self) -> Self {
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::v128_bitselect(v1.to_wasm_v128(), v2.to_wasm_v128(), c.to_wasm_v128()));
- }
+ return Self::from_wasm_v128(wasm::v128_bitselect(v1.to_wasm_v128(), v2.to_wasm_v128(), c.to_wasm_v128()));
Self((v1.0 & c.0) | (v2.0 & !c.0))
}
- pub fn swizzle(self, s: Self) -> Self {
- self.i8x16_swizzle(s)
- }
-
#[doc(alias = "v128.load8x8_s")]
pub const fn v128_load8x8_s(src: [u8; 8]) -> Self {
Self::from_i16x8([
@@ -355,9 +594,7 @@ impl Value128 {
#[doc(alias = "i8x16.swizzle")]
pub fn i8x16_swizzle(self, s: Self) -> Self {
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i8x16_swizzle(self.to_wasm_v128(), s.to_wasm_v128()));
- }
+ return Self::from_wasm_v128(wasm::i8x16_swizzle(self.to_wasm_v128(), s.to_wasm_v128()));
let a_bytes = self.to_le_bytes();
let s_bytes = s.to_le_bytes();
let mut result_bytes = [0u8; 16];
@@ -382,92 +619,6 @@ impl Value128 {
Self::from_le_bytes(result_bytes)
}
- pub const fn extend_8_i8(src: i8) -> Self {
- let mut result_bytes = [0u8; 16];
- let mut i = 0;
- while i < 8 {
- result_bytes[i * 2] = src as u8;
- result_bytes[i * 2 + 1] = if src < 0 { 0xFF } else { 0x00 };
- i += 1;
- }
- Self::from_le_bytes(result_bytes)
- }
-
- pub const fn extend_8_u8(src: u8) -> Self {
- let mut result_bytes = [0u8; 16];
- let mut i = 0;
- while i < 8 {
- result_bytes[i * 2] = src;
- result_bytes[i * 2 + 1] = 0x00;
- i += 1;
- }
- Self::from_le_bytes(result_bytes)
- }
-
- pub const fn extend_4_i16(src: i16) -> Self {
- let mut result_bytes = [0u8; 16];
- let mut i = 0;
- while i < 4 {
- let bytes = src.to_le_bytes();
- result_bytes[i * 4] = bytes[0];
- result_bytes[i * 4 + 1] = bytes[1];
- result_bytes[i * 4 + 2] = if src < 0 { 0xFF } else { 0x00 };
- result_bytes[i * 4 + 3] = if src < 0 { 0xFF } else { 0x00 };
- i += 1;
- }
- Self::from_le_bytes(result_bytes)
- }
-
- pub const fn extend_4_u16(src: u16) -> Self {
- let mut result_bytes = [0u8; 16];
- let mut i = 0;
- while i < 4 {
- let bytes = src.to_le_bytes();
- result_bytes[i * 4] = bytes[0];
- result_bytes[i * 4 + 1] = bytes[1];
- result_bytes[i * 4 + 2] = 0x00;
- result_bytes[i * 4 + 3] = 0x00;
- i += 1;
- }
- Self::from_le_bytes(result_bytes)
- }
-
- pub const fn extend_2_i32(src: i32) -> Self {
- let mut result_bytes = [0u8; 16];
- let mut i = 0;
- while i < 2 {
- let bytes = src.to_le_bytes();
- result_bytes[i * 8] = bytes[0];
- result_bytes[i * 8 + 1] = bytes[1];
- result_bytes[i * 8 + 2] = bytes[2];
- result_bytes[i * 8 + 3] = bytes[3];
- result_bytes[i * 8 + 4] = if src < 0 { 0xFF } else { 0x00 };
- result_bytes[i * 8 + 5] = if src < 0 { 0xFF } else { 0x00 };
- result_bytes[i * 8 + 6] = if src < 0 { 0xFF } else { 0x00 };
- result_bytes[i * 8 + 7] = if src < 0 { 0xFF } else { 0x00 };
- i += 1;
- }
- Self::from_le_bytes(result_bytes)
- }
-
- pub const fn extend_2_u32(src: u32) -> Self {
- let mut result_bytes = [0u8; 16];
- let mut i = 0;
- while i < 2 {
- let bytes = src.to_le_bytes();
- result_bytes[i * 8] = bytes[0];
- result_bytes[i * 8 + 1] = bytes[1];
- result_bytes[i * 8 + 2] = bytes[2];
- result_bytes[i * 8 + 3] = bytes[3];
- result_bytes[i * 8 + 4] = 0x00;
- result_bytes[i * 8 + 5] = 0x00;
- result_bytes[i * 8 + 6] = 0x00;
- result_bytes[i * 8 + 7] = 0x00;
- i += 1;
- }
- Self::from_le_bytes(result_bytes)
- }
-
pub const fn splat_i8(src: i8) -> Self {
let mut result_bytes = [0u8; 16];
let byte = src as u8;
@@ -509,105 +660,15 @@ impl Value128 {
self.replace_lane_bytes::<8>(lane, value.to_bits().to_le_bytes(), 2)
}
- #[doc(alias = "i8x16.all_true")]
- pub const fn i8x16_all_true(self) -> bool {
- let lanes = self.as_i8x16();
- let mut i = 0;
- while i < 16 {
- if lanes[i] == 0 {
- return false;
- }
- i += 1;
- }
- true
- }
-
- #[doc(alias = "i16x8.all_true")]
- pub const fn i16x8_all_true(self) -> bool {
- let lanes = self.as_i16x8();
- let mut i = 0;
- while i < 8 {
- if lanes[i] == 0 {
- return false;
- }
- i += 1;
- }
- true
- }
+ simd_all_true!(i8x16_all_true, "i8x16.all_true", as_i8x16, 16);
+ simd_all_true!(i16x8_all_true, "i16x8.all_true", as_i16x8, 8);
+ simd_all_true!(i32x4_all_true, "i32x4.all_true", as_i32x4, 4);
+ simd_all_true!(i64x2_all_true, "i64x2.all_true", as_i64x2, 2);
- #[doc(alias = "i32x4.all_true")]
- pub const fn i32x4_all_true(self) -> bool {
- let lanes = self.as_i32x4();
- let mut i = 0;
- while i < 4 {
- if lanes[i] == 0 {
- return false;
- }
- i += 1;
- }
- true
- }
-
- #[doc(alias = "i64x2.all_true")]
- pub const fn i64x2_all_true(self) -> bool {
- let lanes = self.as_i64x2();
- let mut i = 0;
- while i < 2 {
- if lanes[i] == 0 {
- return false;
- }
- i += 1;
- }
- true
- }
-
- #[doc(alias = "i8x16.bitmask")]
- pub const fn i8x16_bitmask(self) -> u32 {
- let lanes = self.as_i8x16();
- let mut mask = 0u32;
- let mut i = 0;
- while i < 16 {
- mask |= ((lanes[i] < 0) as u32) << i;
- i += 1;
- }
- mask
- }
-
- #[doc(alias = "i16x8.bitmask")]
- pub const fn i16x8_bitmask(self) -> u32 {
- let lanes = self.as_i16x8();
- let mut mask = 0u32;
- let mut i = 0;
- while i < 8 {
- mask |= ((lanes[i] < 0) as u32) << i;
- i += 1;
- }
- mask
- }
-
- #[doc(alias = "i32x4.bitmask")]
- pub const fn i32x4_bitmask(self) -> u32 {
- let lanes = self.as_i32x4();
- let mut mask = 0u32;
- let mut i = 0;
- while i < 4 {
- mask |= ((lanes[i] < 0) as u32) << i;
- i += 1;
- }
- mask
- }
-
- #[doc(alias = "i64x2.bitmask")]
- pub const fn i64x2_bitmask(self) -> u32 {
- let lanes = self.as_i64x2();
- let mut mask = 0u32;
- let mut i = 0;
- while i < 2 {
- mask |= ((lanes[i] < 0) as u32) << i;
- i += 1;
- }
- mask
- }
+ simd_bitmask!(i8x16_bitmask, "i8x16.bitmask", as_i8x16, 16);
+ simd_bitmask!(i16x8_bitmask, "i16x8.bitmask", as_i16x8, 8);
+ simd_bitmask!(i32x4_bitmask, "i32x4.bitmask", as_i32x4, 4);
+ simd_bitmask!(i64x2_bitmask, "i64x2.bitmask", as_i64x2, 2);
#[doc(alias = "i8x16.popcnt")]
pub const fn i8x16_popcnt(self) -> Self {
@@ -621,518 +682,44 @@ impl Value128 {
Self::from_u8x16(out)
}
- #[doc(alias = "i8x16.shl")]
- pub const fn i8x16_shl(self, shift: u32) -> Self {
- let lanes = self.as_i8x16();
- let s = shift & 7;
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = lanes[i].wrapping_shl(s);
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.shl")]
- pub const fn i16x8_shl(self, shift: u32) -> Self {
- let lanes = self.as_i16x8();
- let s = shift & 15;
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = lanes[i].wrapping_shl(s);
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.shl")]
- pub const fn i32x4_shl(self, shift: u32) -> Self {
- let lanes = self.as_i32x4();
- let s = shift & 31;
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = lanes[i].wrapping_shl(s);
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i64x2.shl")]
- pub const fn i64x2_shl(self, shift: u32) -> Self {
- let lanes = self.as_i64x2();
- let s = shift & 63;
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = lanes[i].wrapping_shl(s);
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "i8x16.shr_s")]
- pub const fn i8x16_shr_s(self, shift: u32) -> Self {
- let lanes = self.as_i8x16();
- let s = shift & 7;
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = lanes[i] >> s;
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.shr_s")]
- pub const fn i16x8_shr_s(self, shift: u32) -> Self {
- let lanes = self.as_i16x8();
- let s = shift & 15;
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = lanes[i] >> s;
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.shr_s")]
- pub const fn i32x4_shr_s(self, shift: u32) -> Self {
- let lanes = self.as_i32x4();
- let s = shift & 31;
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = lanes[i] >> s;
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i64x2.shr_s")]
- pub const fn i64x2_shr_s(self, shift: u32) -> Self {
- let lanes = self.as_i64x2();
- let s = shift & 63;
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = lanes[i] >> s;
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "i8x16.shr_u")]
- pub const fn i8x16_shr_u(self, shift: u32) -> Self {
- let lanes = self.as_u8x16();
- let s = shift & 7;
- let mut out = [0u8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = lanes[i] >> s;
- i += 1;
- }
- Self::from_u8x16(out)
- }
-
- #[doc(alias = "i16x8.shr_u")]
- pub const fn i16x8_shr_u(self, shift: u32) -> Self {
- let lanes = self.as_u16x8();
- let s = shift & 15;
- let mut out = [0u16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = lanes[i] >> s;
- i += 1;
- }
- Self::from_u16x8(out)
- }
-
- #[doc(alias = "i32x4.shr_u")]
- pub const fn i32x4_shr_u(self, shift: u32) -> Self {
- let lanes = self.as_u32x4();
- let s = shift & 31;
- let mut out = [0u32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = lanes[i] >> s;
- i += 1;
- }
- Self::from_u32x4(out)
- }
-
- #[doc(alias = "i64x2.shr_u")]
- pub const fn i64x2_shr_u(self, shift: u32) -> Self {
- let lanes = self.as_u64x2();
- let s = shift & 63;
- let mut out = [0u64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = lanes[i] >> s;
- i += 1;
- }
- Self::from_u64x2(out)
- }
-
- #[doc(alias = "i8x16.add")]
- pub fn i8x16_add(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i8x16_add(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i8x16();
- let b = rhs.as_i8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = a[i].wrapping_add(b[i]);
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.add")]
- pub fn i16x8_add(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i16x8_add(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = a[i].wrapping_add(b[i]);
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.add")]
- pub fn i32x4_add(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i32x4_add(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i32x4();
- let b = rhs.as_i32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = a[i].wrapping_add(b[i]);
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i64x2.add")]
- pub fn i64x2_add(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i64x2_add(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i64x2();
- let b = rhs.as_i64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = a[i].wrapping_add(b[i]);
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "i8x16.sub")]
- pub fn i8x16_sub(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i8x16_sub(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i8x16();
- let b = rhs.as_i8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = a[i].wrapping_sub(b[i]);
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.sub")]
- pub fn i16x8_sub(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i16x8_sub(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = a[i].wrapping_sub(b[i]);
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.sub")]
- pub fn i32x4_sub(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i32x4_sub(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i32x4();
- let b = rhs.as_i32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = a[i].wrapping_sub(b[i]);
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i64x2.sub")]
- pub fn i64x2_sub(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i64x2_sub(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i64x2();
- let b = rhs.as_i64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = a[i].wrapping_sub(b[i]);
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "i16x8.mul")]
- pub fn i16x8_mul(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i16x8_mul(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = a[i].wrapping_mul(b[i]);
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.mul")]
- pub fn i32x4_mul(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i32x4_mul(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i32x4();
- let b = rhs.as_i32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = a[i].wrapping_mul(b[i]);
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i64x2.mul")]
- pub fn i64x2_mul(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i64x2_mul(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i64x2();
- let b = rhs.as_i64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = a[i].wrapping_mul(b[i]);
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "i8x16.add_sat_s")]
- pub fn i8x16_add_sat_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i8x16_add_sat(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i8x16();
- let b = rhs.as_i8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = a[i].saturating_add(b[i]);
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.add_sat_s")]
- pub fn i16x8_add_sat_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i16x8_add_sat(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = a[i].saturating_add(b[i]);
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i8x16.add_sat_u")]
- pub fn i8x16_add_sat_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u8x16_add_sat(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u8x16();
- let b = rhs.as_u8x16();
- let mut out = [0u8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = a[i].saturating_add(b[i]);
- i += 1;
- }
- Self::from_u8x16(out)
- }
-
- #[doc(alias = "i16x8.add_sat_u")]
- pub fn i16x8_add_sat_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u16x8_add_sat(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u16x8();
- let b = rhs.as_u16x8();
- let mut out = [0u16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = a[i].saturating_add(b[i]);
- i += 1;
- }
- Self::from_u16x8(out)
- }
-
- #[doc(alias = "i8x16.sub_sat_s")]
- pub fn i8x16_sub_sat_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i8x16_sub_sat(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i8x16();
- let b = rhs.as_i8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = a[i].saturating_sub(b[i]);
- i += 1;
- }
- Self::from_i8x16(out)
- }
+ simd_shift_left!(i8x16_shl, "i8x16.shl", i8, 16, as_i8x16, from_i8x16, 7);
+ simd_shift_left!(i16x8_shl, "i16x8.shl", i16, 8, as_i16x8, from_i16x8, 15);
+ simd_shift_left!(i32x4_shl, "i32x4.shl", i32, 4, as_i32x4, from_i32x4, 31);
+ simd_shift_left!(i64x2_shl, "i64x2.shl", i64, 2, as_i64x2, from_i64x2, 63);
- #[doc(alias = "i16x8.sub_sat_s")]
- pub fn i16x8_sub_sat_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i16x8_sub_sat(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = a[i].saturating_sub(b[i]);
- i += 1;
- }
- Self::from_i16x8(out)
- }
+ simd_shift_right!(i8x16_shr_s, "i8x16.shr_s", i8, 16, as_i8x16, from_i8x16, 7);
+ simd_shift_right!(i16x8_shr_s, "i16x8.shr_s", i16, 8, as_i16x8, from_i16x8, 15);
+ simd_shift_right!(i32x4_shr_s, "i32x4.shr_s", i32, 4, as_i32x4, from_i32x4, 31);
+ simd_shift_right!(i64x2_shr_s, "i64x2.shr_s", i64, 2, as_i64x2, from_i64x2, 63);
- #[doc(alias = "i8x16.sub_sat_u")]
- pub fn i8x16_sub_sat_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u8x16_sub_sat(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u8x16();
- let b = rhs.as_u8x16();
- let mut out = [0u8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = a[i].saturating_sub(b[i]);
- i += 1;
- }
- Self::from_u8x16(out)
- }
+ simd_shift_right!(i8x16_shr_u, "i8x16.shr_u", u8, 16, as_u8x16, from_u8x16, 7);
+ simd_shift_right!(i16x8_shr_u, "i16x8.shr_u", u16, 8, as_u16x8, from_u16x8, 15);
+ simd_shift_right!(i32x4_shr_u, "i32x4.shr_u", u32, 4, as_u32x4, from_u32x4, 31);
+ simd_shift_right!(i64x2_shr_u, "i64x2.shr_u", u64, 2, as_u64x2, from_u64x2, 63);
- #[doc(alias = "i16x8.sub_sat_u")]
- pub fn i16x8_sub_sat_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u16x8_sub_sat(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u16x8();
- let b = rhs.as_u16x8();
- let mut out = [0u16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = a[i].saturating_sub(b[i]);
- i += 1;
- }
- Self::from_u16x8(out)
- }
+ simd_wrapping_binop!(i8x16_add, "i8x16.add", i8x16_add, i8, 16, as_i8x16, from_i8x16, wrapping_add);
+ simd_wrapping_binop!(i16x8_add, "i16x8.add", i16x8_add, i16, 8, as_i16x8, from_i16x8, wrapping_add);
+ simd_wrapping_binop!(i32x4_add, "i32x4.add", i32x4_add, i32, 4, as_i32x4, from_i32x4, wrapping_add);
+ simd_wrapping_binop!(i64x2_add, "i64x2.add", i64x2_add, i64, 2, as_i64x2, from_i64x2, wrapping_add);
+ simd_wrapping_binop!(i8x16_sub, "i8x16.sub", i8x16_sub, i8, 16, as_i8x16, from_i8x16, wrapping_sub);
+ simd_wrapping_binop!(i16x8_sub, "i16x8.sub", i16x8_sub, i16, 8, as_i16x8, from_i16x8, wrapping_sub);
+ simd_wrapping_binop!(i32x4_sub, "i32x4.sub", i32x4_sub, i32, 4, as_i32x4, from_i32x4, wrapping_sub);
+ simd_wrapping_binop!(i64x2_sub, "i64x2.sub", i64x2_sub, i64, 2, as_i64x2, from_i64x2, wrapping_sub);
+ simd_wrapping_binop!(i16x8_mul, "i16x8.mul", i16x8_mul, i16, 8, as_i16x8, from_i16x8, wrapping_mul);
+ simd_wrapping_binop!(i32x4_mul, "i32x4.mul", i32x4_mul, i32, 4, as_i32x4, from_i32x4, wrapping_mul);
+ simd_wrapping_binop!(i64x2_mul, "i64x2.mul", i64x2_mul, i64, 2, as_i64x2, from_i64x2, wrapping_mul);
- #[doc(alias = "i8x16.avgr_u")]
- pub fn i8x16_avgr_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u8x16_avgr(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u8x16();
- let b = rhs.as_u8x16();
- let mut out = [0u8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = ((a[i] as u16 + b[i] as u16 + 1) >> 1) as u8;
- i += 1;
- }
- Self::from_u8x16(out)
- }
+ simd_sat_binop!(i8x16_add_sat_s, "i8x16.add_sat_s", i8x16_add_sat, i8, 16, as_i8x16, from_i8x16, saturating_add);
+ simd_sat_binop!(i16x8_add_sat_s, "i16x8.add_sat_s", i16x8_add_sat, i16, 8, as_i16x8, from_i16x8, saturating_add);
+ simd_sat_binop!(i8x16_add_sat_u, "i8x16.add_sat_u", u8x16_add_sat, u8, 16, as_u8x16, from_u8x16, saturating_add);
+ simd_sat_binop!(i16x8_add_sat_u, "i16x8.add_sat_u", u16x8_add_sat, u16, 8, as_u16x8, from_u16x8, saturating_add);
+ simd_sat_binop!(i8x16_sub_sat_s, "i8x16.sub_sat_s", i8x16_sub_sat, i8, 16, as_i8x16, from_i8x16, saturating_sub);
+ simd_sat_binop!(i16x8_sub_sat_s, "i16x8.sub_sat_s", i16x8_sub_sat, i16, 8, as_i16x8, from_i16x8, saturating_sub);
+ simd_sat_binop!(i8x16_sub_sat_u, "i8x16.sub_sat_u", u8x16_sub_sat, u8, 16, as_u8x16, from_u8x16, saturating_sub);
+ simd_sat_binop!(i16x8_sub_sat_u, "i16x8.sub_sat_u", u16x8_sub_sat, u16, 8, as_u16x8, from_u16x8, saturating_sub);
- #[doc(alias = "i16x8.avgr_u")]
- pub fn i16x8_avgr_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u16x8_avgr(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u16x8();
- let b = rhs.as_u16x8();
- let mut out = [0u16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = ((a[i] as u32 + b[i] as u32 + 1) >> 1) as u16;
- i += 1;
- }
- Self::from_u16x8(out)
- }
+ simd_avgr_u!(i8x16_avgr_u, "i8x16.avgr_u", u8x16_avgr, u8, u16, 16, as_u8x16, from_u8x16);
+ simd_avgr_u!(i16x8_avgr_u, "i16x8.avgr_u", u16x8_avgr, u16, u32, 8, as_u16x8, from_u16x8);
#[doc(alias = "i8x16.narrow_i16x8_s")]
pub const fn i8x16_narrow_i16x8_s(a: Self, b: Self) -> Self {
@@ -1242,269 +829,31 @@ impl Value128 {
Self::from_u32x4(out)
}
- #[doc(alias = "i16x8.extend_low_i8x16_s")]
- pub const fn i16x8_extend_low_i8x16_s(self) -> Self {
- let lanes = self.as_i8x16();
- Self::from_i16x8([
- lanes[0] as i16,
- lanes[1] as i16,
- lanes[2] as i16,
- lanes[3] as i16,
- lanes[4] as i16,
- lanes[5] as i16,
- lanes[6] as i16,
- lanes[7] as i16,
- ])
- }
-
- #[doc(alias = "i16x8.extend_low_i8x16_u")]
- pub const fn i16x8_extend_low_i8x16_u(self) -> Self {
- let lanes = self.as_u8x16();
- Self::from_u16x8([
- lanes[0] as u16,
- lanes[1] as u16,
- lanes[2] as u16,
- lanes[3] as u16,
- lanes[4] as u16,
- lanes[5] as u16,
- lanes[6] as u16,
- lanes[7] as u16,
- ])
- }
-
- #[doc(alias = "i16x8.extend_high_i8x16_s")]
- pub const fn i16x8_extend_high_i8x16_s(self) -> Self {
- let lanes = self.as_i8x16();
- Self::from_i16x8([
- lanes[8] as i16,
- lanes[9] as i16,
- lanes[10] as i16,
- lanes[11] as i16,
- lanes[12] as i16,
- lanes[13] as i16,
- lanes[14] as i16,
- lanes[15] as i16,
- ])
- }
-
- #[doc(alias = "i16x8.extend_high_i8x16_u")]
- pub const fn i16x8_extend_high_i8x16_u(self) -> Self {
- let lanes = self.as_u8x16();
- Self::from_u16x8([
- lanes[8] as u16,
- lanes[9] as u16,
- lanes[10] as u16,
- lanes[11] as u16,
- lanes[12] as u16,
- lanes[13] as u16,
- lanes[14] as u16,
- lanes[15] as u16,
- ])
- }
-
- #[doc(alias = "i32x4.extend_low_i16x8_s")]
- pub const fn i32x4_extend_low_i16x8_s(self) -> Self {
- let lanes = self.as_i16x8();
- Self::from_i32x4([lanes[0] as i32, lanes[1] as i32, lanes[2] as i32, lanes[3] as i32])
- }
-
- #[doc(alias = "i32x4.extend_low_i16x8_u")]
- pub const fn i32x4_extend_low_i16x8_u(self) -> Self {
- let lanes = self.as_u16x8();
- Self::from_u32x4([lanes[0] as u32, lanes[1] as u32, lanes[2] as u32, lanes[3] as u32])
- }
-
- #[doc(alias = "i32x4.extend_high_i16x8_s")]
- pub const fn i32x4_extend_high_i16x8_s(self) -> Self {
- let lanes = self.as_i16x8();
- Self::from_i32x4([lanes[4] as i32, lanes[5] as i32, lanes[6] as i32, lanes[7] as i32])
- }
-
- #[doc(alias = "i32x4.extend_high_i16x8_u")]
- pub const fn i32x4_extend_high_i16x8_u(self) -> Self {
- let lanes = self.as_u16x8();
- Self::from_u32x4([lanes[4] as u32, lanes[5] as u32, lanes[6] as u32, lanes[7] as u32])
- }
-
- #[doc(alias = "i64x2.extend_low_i32x4_s")]
- pub const fn i64x2_extend_low_i32x4_s(self) -> Self {
- let lanes = self.as_i32x4();
- Self::from_i64x2([lanes[0] as i64, lanes[1] as i64])
- }
-
- #[doc(alias = "i64x2.extend_low_i32x4_u")]
- pub const fn i64x2_extend_low_i32x4_u(self) -> Self {
- let lanes = self.as_u32x4();
- Self::from_u64x2([lanes[0] as u64, lanes[1] as u64])
- }
-
- #[doc(alias = "i64x2.extend_high_i32x4_s")]
- pub const fn i64x2_extend_high_i32x4_s(self) -> Self {
- let lanes = self.as_i32x4();
- Self::from_i64x2([lanes[2] as i64, lanes[3] as i64])
- }
-
- #[doc(alias = "i64x2.extend_high_i32x4_u")]
- pub const fn i64x2_extend_high_i32x4_u(self) -> Self {
- let lanes = self.as_u32x4();
- Self::from_u64x2([lanes[2] as u64, lanes[3] as u64])
- }
-
- #[doc(alias = "i16x8.extmul_low_i8x16_s")]
- pub const fn i16x8_extmul_low_i8x16_s(self, rhs: Self) -> Self {
- let a = self.as_i8x16();
- let b = rhs.as_i8x16();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = (a[i] as i16).wrapping_mul(b[i] as i16);
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i16x8.extmul_low_i8x16_u")]
- pub const fn i16x8_extmul_low_i8x16_u(self, rhs: Self) -> Self {
- let a = self.as_u8x16();
- let b = rhs.as_u8x16();
- let mut out = [0u16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = (a[i] as u16) * (b[i] as u16);
- i += 1;
- }
- Self::from_u16x8(out)
- }
-
- #[doc(alias = "i16x8.extmul_high_i8x16_s")]
- pub const fn i16x8_extmul_high_i8x16_s(self, rhs: Self) -> Self {
- let a = self.as_i8x16();
- let b = rhs.as_i8x16();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = (a[i + 8] as i16).wrapping_mul(b[i + 8] as i16);
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i16x8.extmul_high_i8x16_u")]
- pub const fn i16x8_extmul_high_i8x16_u(self, rhs: Self) -> Self {
- let a = self.as_u8x16();
- let b = rhs.as_u8x16();
- let mut out = [0u16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = (a[i + 8] as u16) * (b[i + 8] as u16);
- i += 1;
- }
- Self::from_u16x8(out)
- }
-
- #[doc(alias = "i32x4.extmul_low_i16x8_s")]
- pub const fn i32x4_extmul_low_i16x8_s(self, rhs: Self) -> Self {
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = (a[i] as i32).wrapping_mul(b[i] as i32);
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i32x4.extmul_low_i16x8_u")]
- pub const fn i32x4_extmul_low_i16x8_u(self, rhs: Self) -> Self {
- let a = self.as_u16x8();
- let b = rhs.as_u16x8();
- let mut out = [0u32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = (a[i] as u32) * (b[i] as u32);
- i += 1;
- }
- Self::from_u32x4(out)
- }
-
- #[doc(alias = "i32x4.extmul_high_i16x8_s")]
- pub const fn i32x4_extmul_high_i16x8_s(self, rhs: Self) -> Self {
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = (a[i + 4] as i32).wrapping_mul(b[i + 4] as i32);
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i32x4.extmul_high_i16x8_u")]
- pub const fn i32x4_extmul_high_i16x8_u(self, rhs: Self) -> Self {
- let a = self.as_u16x8();
- let b = rhs.as_u16x8();
- let mut out = [0u32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = (a[i + 4] as u32) * (b[i + 4] as u32);
- i += 1;
- }
- Self::from_u32x4(out)
- }
-
- #[doc(alias = "i64x2.extmul_low_i32x4_s")]
- pub const fn i64x2_extmul_low_i32x4_s(self, rhs: Self) -> Self {
- let a = self.as_i32x4();
- let b = rhs.as_i32x4();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = (a[i] as i64).wrapping_mul(b[i] as i64);
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "i64x2.extmul_low_i32x4_u")]
- pub const fn i64x2_extmul_low_i32x4_u(self, rhs: Self) -> Self {
- let a = self.as_u32x4();
- let b = rhs.as_u32x4();
- let mut out = [0u64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = (a[i] as u64) * (b[i] as u64);
- i += 1;
- }
- Self::from_u64x2(out)
- }
-
- #[doc(alias = "i64x2.extmul_high_i32x4_s")]
- pub const fn i64x2_extmul_high_i32x4_s(self, rhs: Self) -> Self {
- let a = self.as_i32x4();
- let b = rhs.as_i32x4();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = (a[i + 2] as i64).wrapping_mul(b[i + 2] as i64);
- i += 1;
- }
- Self::from_i64x2(out)
- }
+ simd_extend_cast!(i16x8_extend_low_i8x16_s, "i16x8.extend_low_i8x16_s", as_i8x16, from_i16x8, i16, 8, 0);
+ simd_extend_cast!(i16x8_extend_low_i8x16_u, "i16x8.extend_low_i8x16_u", as_u8x16, from_u16x8, u16, 8, 0);
+ simd_extend_cast!(i16x8_extend_high_i8x16_s, "i16x8.extend_high_i8x16_s", as_i8x16, from_i16x8, i16, 8, 8);
+ simd_extend_cast!(i16x8_extend_high_i8x16_u, "i16x8.extend_high_i8x16_u", as_u8x16, from_u16x8, u16, 8, 8);
+ simd_extend_cast!(i32x4_extend_low_i16x8_s, "i32x4.extend_low_i16x8_s", as_i16x8, from_i32x4, i32, 4, 0);
+ simd_extend_cast!(i32x4_extend_low_i16x8_u, "i32x4.extend_low_i16x8_u", as_u16x8, from_u32x4, u32, 4, 0);
+ simd_extend_cast!(i32x4_extend_high_i16x8_s, "i32x4.extend_high_i16x8_s", as_i16x8, from_i32x4, i32, 4, 4);
+ simd_extend_cast!(i32x4_extend_high_i16x8_u, "i32x4.extend_high_i16x8_u", as_u16x8, from_u32x4, u32, 4, 4);
+ simd_extend_cast!(i64x2_extend_low_i32x4_s, "i64x2.extend_low_i32x4_s", as_i32x4, from_i64x2, i64, 2, 0);
+ simd_extend_cast!(i64x2_extend_low_i32x4_u, "i64x2.extend_low_i32x4_u", as_u32x4, from_u64x2, u64, 2, 0);
+ simd_extend_cast!(i64x2_extend_high_i32x4_s, "i64x2.extend_high_i32x4_s", as_i32x4, from_i64x2, i64, 2, 2);
+ simd_extend_cast!(i64x2_extend_high_i32x4_u, "i64x2.extend_high_i32x4_u", as_u32x4, from_u64x2, u64, 2, 2);
- #[doc(alias = "i64x2.extmul_high_i32x4_u")]
- pub const fn i64x2_extmul_high_i32x4_u(self, rhs: Self) -> Self {
- let a = self.as_u32x4();
- let b = rhs.as_u32x4();
- let mut out = [0u64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = (a[i + 2] as u64) * (b[i + 2] as u64);
- i += 1;
- }
- Self::from_u64x2(out)
- }
+ simd_extmul_signed!(i16x8_extmul_low_i8x16_s, "i16x8.extmul_low_i8x16_s", as_i8x16, from_i16x8, i16, 8, 0);
+ simd_extmul_unsigned!(i16x8_extmul_low_i8x16_u, "i16x8.extmul_low_i8x16_u", as_u8x16, from_u16x8, u16, 8, 0);
+ simd_extmul_signed!(i16x8_extmul_high_i8x16_s, "i16x8.extmul_high_i8x16_s", as_i8x16, from_i16x8, i16, 8, 8);
+ simd_extmul_unsigned!(i16x8_extmul_high_i8x16_u, "i16x8.extmul_high_i8x16_u", as_u8x16, from_u16x8, u16, 8, 8);
+ simd_extmul_signed!(i32x4_extmul_low_i16x8_s, "i32x4.extmul_low_i16x8_s", as_i16x8, from_i32x4, i32, 4, 0);
+ simd_extmul_unsigned!(i32x4_extmul_low_i16x8_u, "i32x4.extmul_low_i16x8_u", as_u16x8, from_u32x4, u32, 4, 0);
+ simd_extmul_signed!(i32x4_extmul_high_i16x8_s, "i32x4.extmul_high_i16x8_s", as_i16x8, from_i32x4, i32, 4, 4);
+ simd_extmul_unsigned!(i32x4_extmul_high_i16x8_u, "i32x4.extmul_high_i16x8_u", as_u16x8, from_u32x4, u32, 4, 4);
+ simd_extmul_signed!(i64x2_extmul_low_i32x4_s, "i64x2.extmul_low_i32x4_s", as_i32x4, from_i64x2, i64, 2, 0);
+ simd_extmul_unsigned!(i64x2_extmul_low_i32x4_u, "i64x2.extmul_low_i32x4_u", as_u32x4, from_u64x2, u64, 2, 0);
+ simd_extmul_signed!(i64x2_extmul_high_i32x4_s, "i64x2.extmul_high_i32x4_s", as_i32x4, from_i64x2, i64, 2, 2);
+ simd_extmul_unsigned!(i64x2_extmul_high_i32x4_u, "i64x2.extmul_high_i32x4_u", as_u32x4, from_u64x2, u64, 2, 2);
#[doc(alias = "i16x8.q15mulr_sat_s")]
pub const fn i16x8_q15mulr_sat_s(self, rhs: Self) -> Self {
@@ -1538,843 +887,74 @@ impl Value128 {
])
}
- #[doc(alias = "i8x16.eq")]
- pub fn i8x16_eq(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i8x16_eq(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i8x16();
- let b = rhs.as_i8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = if a[i] == b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.eq")]
- pub fn i16x8_eq(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i16x8_eq(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = if a[i] == b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.eq")]
- pub fn i32x4_eq(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i32x4_eq(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i32x4();
- let b = rhs.as_i32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] == b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i64x2.eq")]
- pub fn i64x2_eq(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i64x2_eq(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i64x2();
- let b = rhs.as_i64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = if a[i] == b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "i8x16.ne")]
- pub fn i8x16_ne(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i8x16_ne(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i8x16();
- let b = rhs.as_i8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = if a[i] != b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.ne")]
- pub fn i16x8_ne(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i16x8_ne(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = if a[i] != b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.ne")]
- pub fn i32x4_ne(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i32x4_ne(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i32x4();
- let b = rhs.as_i32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] != b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i64x2.ne")]
- pub fn i64x2_ne(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i64x2_ne(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i64x2();
- let b = rhs.as_i64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = if a[i] != b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "i8x16.lt_s")]
- pub fn i8x16_lt_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i8x16_lt(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i8x16();
- let b = rhs.as_i8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = if a[i] < b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.lt_s")]
- pub fn i16x8_lt_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i16x8_lt(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = if a[i] < b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.lt_s")]
- pub fn i32x4_lt_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i32x4_lt(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i32x4();
- let b = rhs.as_i32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] < b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i64x2.lt_s")]
- pub fn i64x2_lt_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i64x2_lt(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i64x2();
- let b = rhs.as_i64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = if a[i] < b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "i8x16.lt_u")]
- pub fn i8x16_lt_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u8x16_lt(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u8x16();
- let b = rhs.as_u8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = if a[i] < b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.lt_u")]
- pub fn i16x8_lt_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u16x8_lt(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u16x8();
- let b = rhs.as_u16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = if a[i] < b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.lt_u")]
- pub fn i32x4_lt_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u32x4_lt(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u32x4();
- let b = rhs.as_u32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] < b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i8x16.gt_s")]
- pub fn i8x16_gt_s(self, rhs: Self) -> Self {
- rhs.i8x16_lt_s(self)
- }
-
- #[doc(alias = "i16x8.gt_s")]
- pub fn i16x8_gt_s(self, rhs: Self) -> Self {
- rhs.i16x8_lt_s(self)
- }
-
- #[doc(alias = "i32x4.gt_s")]
- pub fn i32x4_gt_s(self, rhs: Self) -> Self {
- rhs.i32x4_lt_s(self)
- }
-
- #[doc(alias = "i64x2.gt_s")]
- pub fn i64x2_gt_s(self, rhs: Self) -> Self {
- rhs.i64x2_lt_s(self)
- }
-
- #[doc(alias = "i8x16.gt_u")]
- pub fn i8x16_gt_u(self, rhs: Self) -> Self {
- rhs.i8x16_lt_u(self)
- }
-
- #[doc(alias = "i16x8.gt_u")]
- pub fn i16x8_gt_u(self, rhs: Self) -> Self {
- rhs.i16x8_lt_u(self)
- }
-
- #[doc(alias = "i32x4.gt_u")]
- pub fn i32x4_gt_u(self, rhs: Self) -> Self {
- rhs.i32x4_lt_u(self)
- }
-
- #[doc(alias = "i8x16.le_s")]
- pub fn i8x16_le_s(self, rhs: Self) -> Self {
- rhs.i8x16_ge_s(self)
- }
-
- #[doc(alias = "i16x8.le_s")]
- pub fn i16x8_le_s(self, rhs: Self) -> Self {
- rhs.i16x8_ge_s(self)
- }
-
- #[doc(alias = "i32x4.le_s")]
- pub fn i32x4_le_s(self, rhs: Self) -> Self {
- rhs.i32x4_ge_s(self)
- }
-
- #[doc(alias = "i64x2.le_s")]
- pub fn i64x2_le_s(self, rhs: Self) -> Self {
- rhs.i64x2_ge_s(self)
- }
-
- #[doc(alias = "i8x16.le_u")]
- pub fn i8x16_le_u(self, rhs: Self) -> Self {
- rhs.i8x16_ge_u(self)
- }
-
- #[doc(alias = "i16x8.le_u")]
- pub fn i16x8_le_u(self, rhs: Self) -> Self {
- rhs.i16x8_ge_u(self)
- }
-
- #[doc(alias = "i32x4.le_u")]
- pub fn i32x4_le_u(self, rhs: Self) -> Self {
- rhs.i32x4_ge_u(self)
- }
-
- #[doc(alias = "i8x16.ge_s")]
- pub fn i8x16_ge_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i8x16_ge(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i8x16();
- let b = rhs.as_i8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = if a[i] >= b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.ge_s")]
- pub fn i16x8_ge_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i16x8_ge(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = if a[i] >= b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.ge_s")]
- pub fn i32x4_ge_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i32x4_ge(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i32x4();
- let b = rhs.as_i32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] >= b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i64x2.ge_s")]
- pub fn i64x2_ge_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i64x2_ge(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i64x2();
- let b = rhs.as_i64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = if a[i] >= b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "i8x16.ge_u")]
- pub fn i8x16_ge_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u8x16_ge(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u8x16();
- let b = rhs.as_u8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = if a[i] >= b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.ge_u")]
- pub fn i16x8_ge_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u16x8_ge(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u16x8();
- let b = rhs.as_u16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = if a[i] >= b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.ge_u")]
- pub fn i32x4_ge_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u32x4_ge(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u32x4();
- let b = rhs.as_u32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] >= b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i8x16.abs")]
- pub const fn i8x16_abs(self) -> Self {
- let a = self.as_i8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = a[i].wrapping_abs();
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.abs")]
- pub const fn i16x8_abs(self) -> Self {
- let a = self.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = a[i].wrapping_abs();
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.abs")]
- pub const fn i32x4_abs(self) -> Self {
- let a = self.as_i32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = a[i].wrapping_abs();
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i64x2.abs")]
- pub const fn i64x2_abs(self) -> Self {
- let a = self.as_i64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = a[i].wrapping_abs();
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "i8x16.neg")]
- pub fn i8x16_neg(self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i8x16_neg(self.to_wasm_v128()));
- }
- let a = self.as_i8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = a[i].wrapping_neg();
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.neg")]
- pub fn i16x8_neg(self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i16x8_neg(self.to_wasm_v128()));
- }
- let a = self.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = a[i].wrapping_neg();
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.neg")]
- pub fn i32x4_neg(self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i32x4_neg(self.to_wasm_v128()));
- }
- let a = self.as_i32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = a[i].wrapping_neg();
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i64x2.neg")]
- pub fn i64x2_neg(self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i64x2_neg(self.to_wasm_v128()));
- }
- let a = self.as_i64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = a[i].wrapping_neg();
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "i8x16.min_s")]
- pub fn i8x16_min_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i8x16_min(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i8x16();
- let b = rhs.as_i8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = if a[i] < b[i] { a[i] } else { b[i] };
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.min_s")]
- pub fn i16x8_min_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i16x8_min(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = if a[i] < b[i] { a[i] } else { b[i] };
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.min_s")]
- pub fn i32x4_min_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i32x4_min(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i32x4();
- let b = rhs.as_i32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] < b[i] { a[i] } else { b[i] };
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i8x16.min_u")]
- pub fn i8x16_min_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u8x16_min(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u8x16();
- let b = rhs.as_u8x16();
- let mut out = [0u8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = if a[i] < b[i] { a[i] } else { b[i] };
- i += 1;
- }
- Self::from_u8x16(out)
- }
-
- #[doc(alias = "i16x8.min_u")]
- pub fn i16x8_min_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u16x8_min(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u16x8();
- let b = rhs.as_u16x8();
- let mut out = [0u16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = if a[i] < b[i] { a[i] } else { b[i] };
- i += 1;
- }
- Self::from_u16x8(out)
- }
-
- #[doc(alias = "i32x4.min_u")]
- pub fn i32x4_min_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u32x4_min(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u32x4();
- let b = rhs.as_u32x4();
- let mut out = [0u32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] < b[i] { a[i] } else { b[i] };
- i += 1;
- }
- Self::from_u32x4(out)
- }
-
- #[doc(alias = "i8x16.max_s")]
- pub fn i8x16_max_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i8x16_max(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i8x16();
- let b = rhs.as_i8x16();
- let mut out = [0i8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = if a[i] > b[i] { a[i] } else { b[i] };
- i += 1;
- }
- Self::from_i8x16(out)
- }
-
- #[doc(alias = "i16x8.max_s")]
- pub fn i16x8_max_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i16x8_max(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i16x8();
- let b = rhs.as_i16x8();
- let mut out = [0i16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = if a[i] > b[i] { a[i] } else { b[i] };
- i += 1;
- }
- Self::from_i16x8(out)
- }
-
- #[doc(alias = "i32x4.max_s")]
- pub fn i32x4_max_s(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::i32x4_max(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_i32x4();
- let b = rhs.as_i32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] > b[i] { a[i] } else { b[i] };
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "i8x16.max_u")]
- pub fn i8x16_max_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u8x16_max(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u8x16();
- let b = rhs.as_u8x16();
- let mut out = [0u8; 16];
- let mut i = 0;
- while i < 16 {
- out[i] = if a[i] > b[i] { a[i] } else { b[i] };
- i += 1;
- }
- Self::from_u8x16(out)
- }
+ simd_cmp_mask!(i8x16_eq, "i8x16.eq", i8x16_eq, i8, 16, as_i8x16, from_i8x16, ==);
+ simd_cmp_mask!(i16x8_eq, "i16x8.eq", i16x8_eq, i16, 8, as_i16x8, from_i16x8, ==);
+ simd_cmp_mask!(i32x4_eq, "i32x4.eq", i32x4_eq, i32, 4, as_i32x4, from_i32x4, ==);
+ simd_cmp_mask!(i64x2_eq, "i64x2.eq", i64x2_eq, i64, 2, as_i64x2, from_i64x2, ==);
+ simd_cmp_mask!(i8x16_ne, "i8x16.ne", i8x16_ne, i8, 16, as_i8x16, from_i8x16, !=);
+ simd_cmp_mask!(i16x8_ne, "i16x8.ne", i16x8_ne, i16, 8, as_i16x8, from_i16x8, !=);
+ simd_cmp_mask!(i32x4_ne, "i32x4.ne", i32x4_ne, i32, 4, as_i32x4, from_i32x4, !=);
+ simd_cmp_mask!(i64x2_ne, "i64x2.ne", i64x2_ne, i64, 2, as_i64x2, from_i64x2, !=);
+ simd_cmp_mask!(i8x16_lt_s, "i8x16.lt_s", i8x16_lt, i8, 16, as_i8x16, from_i8x16, <);
+ simd_cmp_mask!(i16x8_lt_s, "i16x8.lt_s", i16x8_lt, i16, 8, as_i16x8, from_i16x8, <);
+ simd_cmp_mask!(i32x4_lt_s, "i32x4.lt_s", i32x4_lt, i32, 4, as_i32x4, from_i32x4, <);
+ simd_cmp_mask!(i64x2_lt_s, "i64x2.lt_s", i64x2_lt, i64, 2, as_i64x2, from_i64x2, <);
+ simd_cmp_mask!(i8x16_lt_u, "i8x16.lt_u", u8x16_lt, i8, 16, as_u8x16, from_i8x16, <);
+ simd_cmp_mask!(i16x8_lt_u, "i16x8.lt_u", u16x8_lt, i16, 8, as_u16x8, from_i16x8, <);
+ simd_cmp_mask!(i32x4_lt_u, "i32x4.lt_u", u32x4_lt, i32, 4, as_u32x4, from_i32x4, <);
- #[doc(alias = "i16x8.max_u")]
- pub fn i16x8_max_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u16x8_max(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u16x8();
- let b = rhs.as_u16x8();
- let mut out = [0u16; 8];
- let mut i = 0;
- while i < 8 {
- out[i] = if a[i] > b[i] { a[i] } else { b[i] };
- i += 1;
- }
- Self::from_u16x8(out)
- }
+ simd_cmp_delegate!(i8x16_gt_s, "i8x16.gt_s", i8x16_lt_s);
+ simd_cmp_delegate!(i16x8_gt_s, "i16x8.gt_s", i16x8_lt_s);
+ simd_cmp_delegate!(i32x4_gt_s, "i32x4.gt_s", i32x4_lt_s);
+ simd_cmp_delegate!(i64x2_gt_s, "i64x2.gt_s", i64x2_lt_s);
+ simd_cmp_delegate!(i8x16_gt_u, "i8x16.gt_u", i8x16_lt_u);
+ simd_cmp_delegate!(i16x8_gt_u, "i16x8.gt_u", i16x8_lt_u);
+ simd_cmp_delegate!(i32x4_gt_u, "i32x4.gt_u", i32x4_lt_u);
+ simd_cmp_delegate!(i8x16_le_s, "i8x16.le_s", i8x16_ge_s);
+ simd_cmp_delegate!(i16x8_le_s, "i16x8.le_s", i16x8_ge_s);
+ simd_cmp_delegate!(i32x4_le_s, "i32x4.le_s", i32x4_ge_s);
+ simd_cmp_delegate!(i64x2_le_s, "i64x2.le_s", i64x2_ge_s);
+ simd_cmp_delegate!(i8x16_le_u, "i8x16.le_u", i8x16_ge_u);
+ simd_cmp_delegate!(i16x8_le_u, "i16x8.le_u", i16x8_ge_u);
+ simd_cmp_delegate!(i32x4_le_u, "i32x4.le_u", i32x4_ge_u);
- #[doc(alias = "i32x4.max_u")]
- pub fn i32x4_max_u(self, rhs: Self) -> Self {
- #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
- {
- return Self::from_wasm_v128(wasm::u32x4_max(self.to_wasm_v128(), rhs.to_wasm_v128()));
- }
- let a = self.as_u32x4();
- let b = rhs.as_u32x4();
- let mut out = [0u32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] > b[i] { a[i] } else { b[i] };
- i += 1;
- }
- Self::from_u32x4(out)
- }
+ simd_cmp_mask!(i8x16_ge_s, "i8x16.ge_s", i8x16_ge, i8, 16, as_i8x16, from_i8x16, >=);
+ simd_cmp_mask!(i16x8_ge_s, "i16x8.ge_s", i16x8_ge, i16, 8, as_i16x8, from_i16x8, >=);
+ simd_cmp_mask!(i32x4_ge_s, "i32x4.ge_s", i32x4_ge, i32, 4, as_i32x4, from_i32x4, >=);
+ simd_cmp_mask!(i64x2_ge_s, "i64x2.ge_s", i64x2_ge, i64, 2, as_i64x2, from_i64x2, >=);
+ simd_cmp_mask!(i8x16_ge_u, "i8x16.ge_u", u8x16_ge, i8, 16, as_u8x16, from_i8x16, >=);
+ simd_cmp_mask!(i16x8_ge_u, "i16x8.ge_u", u16x8_ge, i16, 8, as_u16x8, from_i16x8, >=);
+ simd_cmp_mask!(i32x4_ge_u, "i32x4.ge_u", u32x4_ge, i32, 4, as_u32x4, from_i32x4, >=);
- #[doc(alias = "f32x4.eq")]
- pub const fn f32x4_eq(self, rhs: Self) -> Self {
- let a = self.as_f32x4();
- let b = rhs.as_f32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] == b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "f64x2.eq")]
- pub const fn f64x2_eq(self, rhs: Self) -> Self {
- let a = self.as_f64x2();
- let b = rhs.as_f64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = if a[i] == b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "f32x4.ne")]
- pub const fn f32x4_ne(self, rhs: Self) -> Self {
- let a = self.as_f32x4();
- let b = rhs.as_f32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] != b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i32x4(out)
- }
+ simd_abs_const!(i8x16_abs, "i8x16.abs", i8, 16, as_i8x16, from_i8x16);
+ simd_abs_const!(i16x8_abs, "i16x8.abs", i16, 8, as_i16x8, from_i16x8);
+ simd_abs_const!(i32x4_abs, "i32x4.abs", i32, 4, as_i32x4, from_i32x4);
+ simd_abs_const!(i64x2_abs, "i64x2.abs", i64, 2, as_i64x2, from_i64x2);
- #[doc(alias = "f64x2.ne")]
- pub const fn f64x2_ne(self, rhs: Self) -> Self {
- let a = self.as_f64x2();
- let b = rhs.as_f64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = if a[i] != b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i64x2(out)
- }
+ simd_neg!(i8x16_neg, "i8x16.neg", i8x16_neg, i8, 16, as_i8x16, from_i8x16);
+ simd_neg!(i16x8_neg, "i16x8.neg", i16x8_neg, i16, 8, as_i16x8, from_i16x8);
+ simd_neg!(i32x4_neg, "i32x4.neg", i32x4_neg, i32, 4, as_i32x4, from_i32x4);
+ simd_neg!(i64x2_neg, "i64x2.neg", i64x2_neg, i64, 2, as_i64x2, from_i64x2);
- #[doc(alias = "f32x4.lt")]
- pub const fn f32x4_lt(self, rhs: Self) -> Self {
- let a = self.as_f32x4();
- let b = rhs.as_f32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] < b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i32x4(out)
- }
+ simd_minmax!(i8x16_min_s, "i8x16.min_s", i8x16_min, i8, 16, as_i8x16, from_i8x16, <);
+ simd_minmax!(i16x8_min_s, "i16x8.min_s", i16x8_min, i16, 8, as_i16x8, from_i16x8, <);
+ simd_minmax!(i32x4_min_s, "i32x4.min_s", i32x4_min, i32, 4, as_i32x4, from_i32x4, <);
+ simd_minmax!(i8x16_min_u, "i8x16.min_u", u8x16_min, u8, 16, as_u8x16, from_u8x16, <);
+ simd_minmax!(i16x8_min_u, "i16x8.min_u", u16x8_min, u16, 8, as_u16x8, from_u16x8, <);
+ simd_minmax!(i32x4_min_u, "i32x4.min_u", u32x4_min, u32, 4, as_u32x4, from_u32x4, <);
+ simd_minmax!(i8x16_max_s, "i8x16.max_s", i8x16_max, i8, 16, as_i8x16, from_i8x16, >);
+ simd_minmax!(i16x8_max_s, "i16x8.max_s", i16x8_max, i16, 8, as_i16x8, from_i16x8, >);
+ simd_minmax!(i32x4_max_s, "i32x4.max_s", i32x4_max, i32, 4, as_i32x4, from_i32x4, >);
+ simd_minmax!(i8x16_max_u, "i8x16.max_u", u8x16_max, u8, 16, as_u8x16, from_u8x16, >);
+ simd_minmax!(i16x8_max_u, "i16x8.max_u", u16x8_max, u16, 8, as_u16x8, from_u16x8, >);
+ simd_minmax!(i32x4_max_u, "i32x4.max_u", u32x4_max, u32, 4, as_u32x4, from_u32x4, >);
- #[doc(alias = "f64x2.lt")]
- pub const fn f64x2_lt(self, rhs: Self) -> Self {
- let a = self.as_f64x2();
- let b = rhs.as_f64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = if a[i] < b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i64x2(out)
- }
+ simd_cmp_mask_const!(f32x4_eq, "f32x4.eq", i32, 4, as_f32x4, from_i32x4, ==);
+ simd_cmp_mask_const!(f64x2_eq, "f64x2.eq", i64, 2, as_f64x2, from_i64x2, ==);
+ simd_cmp_mask_const!(f32x4_ne, "f32x4.ne", i32, 4, as_f32x4, from_i32x4, !=);
+ simd_cmp_mask_const!(f64x2_ne, "f64x2.ne", i64, 2, as_f64x2, from_i64x2, !=);
+ simd_cmp_mask_const!(f32x4_lt, "f32x4.lt", i32, 4, as_f32x4, from_i32x4, <);
+ simd_cmp_mask_const!(f64x2_lt, "f64x2.lt", i64, 2, as_f64x2, from_i64x2, <);
#[doc(alias = "f32x4.gt")]
pub const fn f32x4_gt(self, rhs: Self) -> Self {
@@ -2386,207 +966,46 @@ impl Value128 {
rhs.f64x2_lt(self)
}
- #[doc(alias = "f32x4.le")]
- pub const fn f32x4_le(self, rhs: Self) -> Self {
- let a = self.as_f32x4();
- let b = rhs.as_f32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] <= b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "f64x2.le")]
- pub const fn f64x2_le(self, rhs: Self) -> Self {
- let a = self.as_f64x2();
- let b = rhs.as_f64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = if a[i] <= b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "f32x4.ge")]
- pub const fn f32x4_ge(self, rhs: Self) -> Self {
- let a = self.as_f32x4();
- let b = rhs.as_f32x4();
- let mut out = [0i32; 4];
- let mut i = 0;
- while i < 4 {
- out[i] = if a[i] >= b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i32x4(out)
- }
-
- #[doc(alias = "f64x2.ge")]
- pub const fn f64x2_ge(self, rhs: Self) -> Self {
- let a = self.as_f64x2();
- let b = rhs.as_f64x2();
- let mut out = [0i64; 2];
- let mut i = 0;
- while i < 2 {
- out[i] = if a[i] >= b[i] { -1 } else { 0 };
- i += 1;
- }
- Self::from_i64x2(out)
- }
-
- #[doc(alias = "f32x4.ceil")]
- pub fn f32x4_ceil(self) -> Self {
- self.map_f32x4(|x| canonicalize_simd_f32_nan(x.ceil()))
- }
-
- #[doc(alias = "f64x2.ceil")]
- pub fn f64x2_ceil(self) -> Self {
- self.map_f64x2(|x| canonicalize_simd_f64_nan(x.ceil()))
- }
-
- #[doc(alias = "f32x4.floor")]
- pub fn f32x4_floor(self) -> Self {
- self.map_f32x4(|x| canonicalize_simd_f32_nan(x.floor()))
- }
-
- #[doc(alias = "f64x2.floor")]
- pub fn f64x2_floor(self) -> Self {
- self.map_f64x2(|x| canonicalize_simd_f64_nan(x.floor()))
- }
-
- #[doc(alias = "f32x4.trunc")]
- pub fn f32x4_trunc(self) -> Self {
- self.map_f32x4(|x| canonicalize_simd_f32_nan(x.trunc()))
- }
-
- #[doc(alias = "f64x2.trunc")]
- pub fn f64x2_trunc(self) -> Self {
- self.map_f64x2(|x| canonicalize_simd_f64_nan(x.trunc()))
- }
-
- #[doc(alias = "f32x4.nearest")]
- pub fn f32x4_nearest(self) -> Self {
- self.map_f32x4(|x| canonicalize_simd_f32_nan(TinywasmFloatExt::tw_nearest(x)))
- }
-
- #[doc(alias = "f64x2.nearest")]
- pub fn f64x2_nearest(self) -> Self {
- self.map_f64x2(|x| canonicalize_simd_f64_nan(TinywasmFloatExt::tw_nearest(x)))
- }
-
- #[doc(alias = "f32x4.abs")]
- pub fn f32x4_abs(self) -> Self {
- self.map_f32x4(f32::abs)
- }
-
- #[doc(alias = "f64x2.abs")]
- pub fn f64x2_abs(self) -> Self {
- self.map_f64x2(f64::abs)
- }
-
- #[doc(alias = "f32x4.neg")]
- pub fn f32x4_neg(self) -> Self {
- self.map_f32x4(|x| -x)
- }
-
- #[doc(alias = "f64x2.neg")]
- pub fn f64x2_neg(self) -> Self {
- self.map_f64x2(|x| -x)
- }
-
- #[doc(alias = "f32x4.sqrt")]
- pub fn f32x4_sqrt(self) -> Self {
- self.map_f32x4(|x| canonicalize_simd_f32_nan(x.sqrt()))
- }
-
- #[doc(alias = "f64x2.sqrt")]
- pub fn f64x2_sqrt(self) -> Self {
- self.map_f64x2(|x| canonicalize_simd_f64_nan(x.sqrt()))
- }
-
- #[doc(alias = "f32x4.add")]
- pub fn f32x4_add(self, rhs: Self) -> Self {
- self.zip_f32x4(rhs, |a, b| canonicalize_simd_f32_nan(a + b))
- }
-
- #[doc(alias = "f64x2.add")]
- pub fn f64x2_add(self, rhs: Self) -> Self {
- self.zip_f64x2(rhs, |a, b| canonicalize_simd_f64_nan(a + b))
- }
-
- #[doc(alias = "f32x4.sub")]
- pub fn f32x4_sub(self, rhs: Self) -> Self {
- self.zip_f32x4(rhs, |a, b| canonicalize_simd_f32_nan(a - b))
- }
-
- #[doc(alias = "f64x2.sub")]
- pub fn f64x2_sub(self, rhs: Self) -> Self {
- self.zip_f64x2(rhs, |a, b| canonicalize_simd_f64_nan(a - b))
- }
-
- #[doc(alias = "f32x4.mul")]
- pub fn f32x4_mul(self, rhs: Self) -> Self {
- self.zip_f32x4(rhs, |a, b| canonicalize_simd_f32_nan(a * b))
- }
-
- #[doc(alias = "f64x2.mul")]
- pub fn f64x2_mul(self, rhs: Self) -> Self {
- self.zip_f64x2(rhs, |a, b| canonicalize_simd_f64_nan(a * b))
- }
-
- #[doc(alias = "f32x4.div")]
- pub fn f32x4_div(self, rhs: Self) -> Self {
- self.zip_f32x4(rhs, |a, b| canonicalize_simd_f32_nan(a / b))
- }
-
- #[doc(alias = "f64x2.div")]
- pub fn f64x2_div(self, rhs: Self) -> Self {
- self.zip_f64x2(rhs, |a, b| canonicalize_simd_f64_nan(a / b))
- }
-
- #[doc(alias = "f32x4.min")]
- pub fn f32x4_min(self, rhs: Self) -> Self {
- self.zip_f32x4(rhs, TinywasmFloatExt::tw_minimum)
- }
-
- #[doc(alias = "f64x2.min")]
- pub fn f64x2_min(self, rhs: Self) -> Self {
- self.zip_f64x2(rhs, TinywasmFloatExt::tw_minimum)
- }
+ simd_cmp_mask_const!(f32x4_le, "f32x4.le", i32, 4, as_f32x4, from_i32x4, <=);
+ simd_cmp_mask_const!(f64x2_le, "f64x2.le", i64, 2, as_f64x2, from_i64x2, <=);
+ simd_cmp_mask_const!(f32x4_ge, "f32x4.ge", i32, 4, as_f32x4, from_i32x4, >=);
+ simd_cmp_mask_const!(f64x2_ge, "f64x2.ge", i64, 2, as_f64x2, from_i64x2, >=);
- #[doc(alias = "f32x4.max")]
- pub fn f32x4_max(self, rhs: Self) -> Self {
- self.zip_f32x4(rhs, TinywasmFloatExt::tw_maximum)
- }
-
- #[doc(alias = "f64x2.max")]
- pub fn f64x2_max(self, rhs: Self) -> Self {
- self.zip_f64x2(rhs, TinywasmFloatExt::tw_maximum)
- }
+ simd_float_unary!(f32x4_ceil, "f32x4.ceil", map_f32x4, |x| canonicalize_simd_f32_nan(x.ceil()));
+ simd_float_unary!(f64x2_ceil, "f64x2.ceil", map_f64x2, |x| canonicalize_simd_f64_nan(x.ceil()));
+ simd_float_unary!(f32x4_floor, "f32x4.floor", map_f32x4, |x| canonicalize_simd_f32_nan(x.floor()));
+ simd_float_unary!(f64x2_floor, "f64x2.floor", map_f64x2, |x| canonicalize_simd_f64_nan(x.floor()));
+ simd_float_unary!(f32x4_trunc, "f32x4.trunc", map_f32x4, |x| canonicalize_simd_f32_nan(x.trunc()));
+ simd_float_unary!(f64x2_trunc, "f64x2.trunc", map_f64x2, |x| canonicalize_simd_f64_nan(x.trunc()));
+ simd_float_unary!(f32x4_nearest, "f32x4.nearest", map_f32x4, |x| canonicalize_simd_f32_nan(
+ TinywasmFloatExt::tw_nearest(x)
+ ));
+ simd_float_unary!(f64x2_nearest, "f64x2.nearest", map_f64x2, |x| canonicalize_simd_f64_nan(
+ TinywasmFloatExt::tw_nearest(x)
+ ));
+ simd_float_unary!(f32x4_abs, "f32x4.abs", map_f32x4, f32::abs);
+ simd_float_unary!(f64x2_abs, "f64x2.abs", map_f64x2, f64::abs);
+ simd_float_unary!(f32x4_neg, "f32x4.neg", map_f32x4, |x| -x);
+ simd_float_unary!(f64x2_neg, "f64x2.neg", map_f64x2, |x| -x);
+ simd_float_unary!(f32x4_sqrt, "f32x4.sqrt", map_f32x4, |x| canonicalize_simd_f32_nan(x.sqrt()));
+ simd_float_unary!(f64x2_sqrt, "f64x2.sqrt", map_f64x2, |x| canonicalize_simd_f64_nan(x.sqrt()));
- #[doc(alias = "f32x4.pmin")]
- pub fn f32x4_pmin(self, rhs: Self) -> Self {
- self.zip_f32x4(rhs, |a, b| if b < a { b } else { a })
- }
-
- #[doc(alias = "f64x2.pmin")]
- pub fn f64x2_pmin(self, rhs: Self) -> Self {
- self.zip_f64x2(rhs, |a, b| if b < a { b } else { a })
- }
-
- #[doc(alias = "f32x4.pmax")]
- pub fn f32x4_pmax(self, rhs: Self) -> Self {
- self.zip_f32x4(rhs, |a, b| if b > a { b } else { a })
- }
-
- #[doc(alias = "f64x2.pmax")]
- pub fn f64x2_pmax(self, rhs: Self) -> Self {
- self.zip_f64x2(rhs, |a, b| if b > a { b } else { a })
- }
+ simd_float_binary!(f32x4_add, "f32x4.add", zip_f32x4, |a, b| canonicalize_simd_f32_nan(a + b));
+ simd_float_binary!(f64x2_add, "f64x2.add", zip_f64x2, |a, b| canonicalize_simd_f64_nan(a + b));
+ simd_float_binary!(f32x4_sub, "f32x4.sub", zip_f32x4, |a, b| canonicalize_simd_f32_nan(a - b));
+ simd_float_binary!(f64x2_sub, "f64x2.sub", zip_f64x2, |a, b| canonicalize_simd_f64_nan(a - b));
+ simd_float_binary!(f32x4_mul, "f32x4.mul", zip_f32x4, |a, b| canonicalize_simd_f32_nan(a * b));
+ simd_float_binary!(f64x2_mul, "f64x2.mul", zip_f64x2, |a, b| canonicalize_simd_f64_nan(a * b));
+ simd_float_binary!(f32x4_div, "f32x4.div", zip_f32x4, |a, b| canonicalize_simd_f32_nan(a / b));
+ simd_float_binary!(f64x2_div, "f64x2.div", zip_f64x2, |a, b| canonicalize_simd_f64_nan(a / b));
+ simd_float_binary!(f32x4_min, "f32x4.min", zip_f32x4, TinywasmFloatExt::tw_minimum);
+ simd_float_binary!(f64x2_min, "f64x2.min", zip_f64x2, TinywasmFloatExt::tw_minimum);
+ simd_float_binary!(f32x4_max, "f32x4.max", zip_f32x4, TinywasmFloatExt::tw_maximum);
+ simd_float_binary!(f64x2_max, "f64x2.max", zip_f64x2, TinywasmFloatExt::tw_maximum);
+ simd_float_binary!(f32x4_pmin, "f32x4.pmin", zip_f32x4, |a, b| if b < a { b } else { a });
+ simd_float_binary!(f64x2_pmin, "f64x2.pmin", zip_f64x2, |a, b| if b < a { b } else { a });
+ simd_float_binary!(f32x4_pmax, "f32x4.pmax", zip_f32x4, |a, b| if b > a { b } else { a });
+ simd_float_binary!(f64x2_pmax, "f64x2.pmax", zip_f64x2, |a, b| if b > a { b } else { a });
#[doc(alias = "i32x4.trunc_sat_f32x4_s")]
pub fn i32x4_trunc_sat_f32x4_s(self) -> Self {
@@ -2659,47 +1078,15 @@ impl Value128 {
}
pub const fn splat_i16(src: i16) -> Self {
- let mut result_bytes = [0u8; 16];
- let bytes = src.to_le_bytes();
- let mut i = 0;
- while i < 8 {
- result_bytes[i * 2] = bytes[0];
- result_bytes[i * 2 + 1] = bytes[1];
- i += 1;
- }
- Self::from_le_bytes(result_bytes)
+ Self::from_i16x8([src; 8])
}
pub const fn splat_i32(src: i32) -> Self {
- let mut result_bytes = [0u8; 16];
- let bytes = src.to_le_bytes();
- let mut i = 0;
- while i < 4 {
- result_bytes[i * 4] = bytes[0];
- result_bytes[i * 4 + 1] = bytes[1];
- result_bytes[i * 4 + 2] = bytes[2];
- result_bytes[i * 4 + 3] = bytes[3];
- i += 1;
- }
- Self::from_le_bytes(result_bytes)
+ Self::from_i32x4([src; 4])
}
pub const fn splat_i64(src: i64) -> Self {
- let mut result_bytes = [0u8; 16];
- let bytes = src.to_le_bytes();
- let mut i = 0;
- while i < 2 {
- result_bytes[i * 8] = bytes[0];
- result_bytes[i * 8 + 1] = bytes[1];
- result_bytes[i * 8 + 2] = bytes[2];
- result_bytes[i * 8 + 3] = bytes[3];
- result_bytes[i * 8 + 4] = bytes[4];
- result_bytes[i * 8 + 5] = bytes[5];
- result_bytes[i * 8 + 6] = bytes[6];
- result_bytes[i * 8 + 7] = bytes[7];
- i += 1;
- }
- Self::from_le_bytes(result_bytes)
+ Self::from_i64x2([src; 2])
}
pub const fn splat_f32(src: f32) -> Self {
@@ -2725,44 +1112,19 @@ impl Value128 {
}
pub const fn extract_lane_i16(self, lane: u8) -> i16 {
- debug_assert!(lane < 8);
- let lane = lane as usize;
- let bytes = self.to_le_bytes();
- let start = lane * 2;
- i16::from_le_bytes([bytes[start], bytes[start + 1]])
+ i16::from_le_bytes(self.extract_lane_bytes::<2>(lane, 8))
}
pub const fn extract_lane_u16(self, lane: u8) -> u16 {
- debug_assert!(lane < 8);
- let lane = lane as usize;
- let bytes = self.to_le_bytes();
- let start = lane * 2;
- u16::from_le_bytes([bytes[start], bytes[start + 1]])
+ u16::from_le_bytes(self.extract_lane_bytes::<2>(lane, 8))
}
pub const fn extract_lane_i32(self, lane: u8) -> i32 {
- debug_assert!(lane < 4);
- let lane = lane as usize;
- let bytes = self.to_le_bytes();
- let start = lane * 4;
- i32::from_le_bytes([bytes[start], bytes[start + 1], bytes[start + 2], bytes[start + 3]])
+ i32::from_le_bytes(self.extract_lane_bytes::<4>(lane, 4))
}
pub const fn extract_lane_i64(self, lane: u8) -> i64 {
- debug_assert!(lane < 2);
- let lane = lane as usize;
- let bytes = self.to_le_bytes();
- let start = lane * 8;
- i64::from_le_bytes([
- bytes[start],
- bytes[start + 1],
- bytes[start + 2],
- bytes[start + 3],
- bytes[start + 4],
- bytes[start + 5],
- bytes[start + 6],
- bytes[start + 7],
- ])
+ i64::from_le_bytes(self.extract_lane_bytes::<8>(lane, 2))
}
pub const fn extract_lane_f32(self, lane: u8) -> f32 {
@@ -2773,6 +1135,19 @@ impl Value128 {
f64::from_bits(self.extract_lane_i64(lane) as u64)
}
+ const fn extract_lane_bytes<const LANE_BYTES: usize>(self, lane: u8, lane_count: u8) -> [u8; LANE_BYTES] {
+ debug_assert!(lane < lane_count);
+ let bytes = self.to_le_bytes();
+ let start = lane as usize * LANE_BYTES;
+ let mut out = [0u8; LANE_BYTES];
+ let mut i = 0;
+ while i < LANE_BYTES {
+ out[i] = bytes[start + i];
+ i += 1;
+ }
+ out
+ }
+
const fn replace_lane_bytes<const LANE_BYTES: usize>(
self,
lane: u8,
@@ -2791,46 +1166,6 @@ impl Value128 {
}
}
-impl From<Value128> for i128 {
- fn from(val: Value128) -> Self {
- val.0
- }
-}
-
-impl From<i128> for Value128 {
- fn from(value: i128) -> Self {
- Self(value)
- }
-}
-
-impl core::ops::Not for Value128 {
- type Output = Self;
- fn not(self) -> Self::Output {
- Self(!self.0)
- }
-}
-
-impl core::ops::BitAnd for Value128 {
- type Output = Self;
- fn bitand(self, rhs: Self) -> Self::Output {
- Self(self.0 & rhs.0)
- }
-}
-
-impl core::ops::BitOr for Value128 {
- type Output = Self;
- fn bitor(self, rhs: Self) -> Self::Output {
- Self(self.0 | rhs.0)
- }
-}
-
-impl core::ops::BitXor for Value128 {
- type Output = Self;
- fn bitxor(self, rhs: Self) -> Self::Output {
- Self(self.0 ^ rhs.0)
- }
-}
-
const fn canonicalize_simd_f32_nan(x: f32) -> f32 {
#[cfg(feature = "canonicalize_nans")]
if x.is_nan() {
@@ -2854,85 +1189,67 @@ const fn canonicalize_simd_f64_nan(x: f64) -> f64 {
}
const fn saturate_i16_to_i8(x: i16) -> i8 {
- if x > i8::MAX as i16 {
- i8::MAX
- } else if x < i8::MIN as i16 {
- i8::MIN
- } else {
- x as i8
+ match x {
+ v if v > i8::MAX as i16 => i8::MAX,
+ v if v < i8::MIN as i16 => i8::MIN,
+ v => v as i8,
}
}
const fn saturate_i16_to_u8(x: i16) -> u8 {
- if x <= 0 {
- 0
- } else if x > u8::MAX as i16 {
- u8::MAX
- } else {
- x as u8
+ match x {
+ v if v <= 0 => 0,
+ v if v > u8::MAX as i16 => u8::MAX,
+ v => v as u8,
}
}
const fn saturate_i32_to_i16(x: i32) -> i16 {
- if x > i16::MAX as i32 {
- i16::MAX
- } else if x < i16::MIN as i32 {
- i16::MIN
- } else {
- x as i16
+ match x {
+ v if v > i16::MAX as i32 => i16::MAX,
+ v if v < i16::MIN as i32 => i16::MIN,
+ v => v as i16,
}
}
const fn saturate_i32_to_u16(x: i32) -> u16 {
- if x <= 0 {
- 0
- } else if x > u16::MAX as i32 {
- u16::MAX
- } else {
- x as u16
+ match x {
+ v if v <= 0 => 0,
+ v if v > u16::MAX as i32 => u16::MAX,
+ v => v as u16,
}
}
fn trunc_sat_f32_to_i32(v: f32) -> i32 {
- if v.is_nan() {
- 0
- } else if v <= i32::MIN as f32 - (1 << 8) as f32 {
- i32::MIN
- } else if v >= (i32::MAX as f32 + 1.0) {
- i32::MAX
- } else {
- v.trunc() as i32
+ match v {
+ x if x.is_nan() => 0,
+ x if x <= i32::MIN as f32 - (1 << 8) as f32 => i32::MIN,
+ x if x >= (i32::MAX as f32 + 1.0) => i32::MAX,
+ x => x.trunc() as i32,
}
}
fn trunc_sat_f32_to_u32(v: f32) -> u32 {
- if v.is_nan() || v <= -1.0_f32 {
- 0
- } else if v >= (u32::MAX as f32 + 1.0) {
- u32::MAX
- } else {
- v.trunc() as u32
+ match v {
+ x if x.is_nan() || x <= -1.0_f32 => 0,
+ x if x >= (u32::MAX as f32 + 1.0) => u32::MAX,
+ x => x.trunc() as u32,
}
}
fn trunc_sat_f64_to_i32(v: f64) -> i32 {
- if v.is_nan() {
- 0
- } else if v <= i32::MIN as f64 - 1.0_f64 {
- i32::MIN
- } else if v >= (i32::MAX as f64 + 1.0) {
- i32::MAX
- } else {
- v.trunc() as i32
+ match v {
+ x if x.is_nan() => 0,
+ x if x <= i32::MIN as f64 - 1.0_f64 => i32::MIN,
+ x if x >= (i32::MAX as f64 + 1.0) => i32::MAX,
+ x => x.trunc() as i32,
}
}
fn trunc_sat_f64_to_u32(v: f64) -> u32 {
- if v.is_nan() || v <= -1.0_f64 {
- 0
- } else if v >= (u32::MAX as f64 + 1.0) {
- u32::MAX
- } else {
- v.trunc() as u32
+ match v {
+ x if x.is_nan() || x <= -1.0_f64 => 0,
+ x if x >= (u32::MAX as f64 + 1.0) => u32::MAX,
+ x => x.trunc() as u32,
}
}
diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs
index b57008c..a127cf6 100644
--- a/crates/tinywasm/src/interpreter/values.rs
+++ b/crates/tinywasm/src/interpreter/values.rs
@@ -108,11 +108,11 @@ pub(crate) trait InternalValue: sealed::Sealed + Into<TinyWasmValue> + Copy + De
fn stack_push(stack: &mut ValueStack, value: Self) -> Result<()>;
fn local_get(stack: &ValueStack, frame: &CallFrame, index: LocalAddr) -> Self;
fn local_set(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, value: Self);
- fn replace_top(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result<Self>) -> Result<()>;
- fn stack_calculate(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result<Self>) -> Result<()>;
- fn stack_calculate3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result<Self>) -> Result<()>;
fn stack_pop(stack: &mut ValueStack) -> Self;
fn stack_peek(stack: &ValueStack) -> Self;
+ fn stack_apply1(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result<Self>) -> Result<()>;
+ fn stack_apply2(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result<Self>) -> Result<()>;
+ fn stack_apply3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result<Self>) -> Result<()>;
}
macro_rules! impl_internalvalue {
@@ -153,7 +153,14 @@ macro_rules! impl_internalvalue {
}
#[inline(always)]
- fn stack_calculate(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result<Self>) -> Result<()> {
+ fn stack_apply1(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result<Self>) -> Result<()> {
+ let top = stack.$stack.last_mut();
+ *top = $to_internal(func($to_outer(*top))?);
+ Ok(())
+ }
+
+ #[inline(always)]
+ fn stack_apply2(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result<Self>) -> Result<()> {
let v2 = stack.$stack.pop();
let v1 = stack.$stack.last_mut();
*v1 = $to_internal(func($to_outer(*v1), $to_outer(v2))?);
@@ -161,20 +168,13 @@ macro_rules! impl_internalvalue {
}
#[inline(always)]
- fn stack_calculate3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result<Self>) -> Result<()> {
+ fn stack_apply3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result<Self>) -> Result<()> {
let v3 = stack.$stack.pop();
let v2 = stack.$stack.pop();
let v1 = stack.$stack.last_mut();
*v1 = $to_internal(func($to_outer(*v1), $to_outer(v2), $to_outer(v3))?);
Ok(())
}
-
- #[inline(always)]
- fn replace_top(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result<Self>) -> Result<()> {
- let v = stack.$stack.last_mut();
- *v = $to_internal(func($to_outer(*v))?);
- Ok(())
- }
}
)*
};
diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs
index 5c08ab9..a0c5c69 100644
--- a/crates/tinywasm/src/store/memory.rs
+++ b/crates/tinywasm/src/store/memory.rs
@@ -154,7 +154,7 @@ impl MemoryInstance {
}
/// A trait for types that can be converted to and from static byte arrays
-pub(crate) trait MemValue<const N: usize>: Copy + Sized {
+pub(crate) trait MemValue<const N: usize>: Copy + Default {
/// Store a value in memory
fn to_mem_bytes(self) -> [u8; N];
@@ -168,12 +168,12 @@ macro_rules! impl_mem_traits {
impl MemValue<$size> for $ty {
#[inline(always)]
fn from_mem_bytes(bytes: [u8; $size]) -> Self {
- <$ty>::from_le_bytes(bytes.into())
+ <$ty>::from_le_bytes(bytes)
}
#[inline(always)]
fn to_mem_bytes(self) -> [u8; $size] {
- self.to_le_bytes().into()
+ self.to_le_bytes()
}
}
)*
diff --git a/crates/tinywasm/tests/host_func_signature_check.rs b/crates/tinywasm/tests/host_func_signature_check.rs
index 9389435..3b682b8 100644
--- a/crates/tinywasm/tests/host_func_signature_check.rs
+++ b/crates/tinywasm/tests/host_func_signature_check.rs
@@ -9,69 +9,62 @@ use tinywasm_types::ExternRef;
const VAL_LISTS: &[&[WasmValue]] = &[
&[],
&[WasmValue::I32(0)],
- &[WasmValue::I32(0), WasmValue::I32(0)], // 2 of the same
- &[WasmValue::I32(0), WasmValue::I32(0), WasmValue::F64(0.0)], // add another type
- &[WasmValue::I32(0), WasmValue::F64(0.0), WasmValue::I32(0)], // reorder
- &[WasmValue::RefExtern(ExternRef::null()), WasmValue::F64(0.0), WasmValue::I32(0)], // all different types
+ &[WasmValue::I32(0), WasmValue::I32(0)],
+ &[WasmValue::I32(0), WasmValue::I32(0), WasmValue::F64(0.0)],
+ &[WasmValue::I32(0), WasmValue::F64(0.0), WasmValue::I32(0)],
+ &[WasmValue::RefExtern(ExternRef::null()), WasmValue::F64(0.0), WasmValue::I32(0)],
];
-// (f64, i32, i32) and (f64) can be used to "match_none"
-fn get_type_lists() -> impl Iterator<Item = impl Iterator<Item = ValType> + Clone> + Clone {
- VAL_LISTS.iter().map(|l| l.iter().map(WasmValue::val_type))
+fn value_types(values: &[WasmValue]) -> Box<[ValType]> {
+ values.iter().map(WasmValue::val_type).collect()
}
-fn get_modules() -> Vec<(Module, FuncType, Vec<WasmValue>)> {
- let mut result = Vec::<(Module, FuncType, Vec<WasmValue>)>::new();
- let val_and_tys = get_type_lists().zip(VAL_LISTS);
- for res_types in get_type_lists() {
- for (arg_types, arg_vals) in val_and_tys.clone() {
- let ty = FuncType { results: res_types.clone().collect(), params: arg_types.collect() };
- result.push((proxy_module(&ty), ty, arg_vals.to_vec()));
+
+fn module_cases() -> Vec<(Module, FuncType, Vec<WasmValue>)> {
+ let mut cases = Vec::<(Module, FuncType, Vec<WasmValue>)>::new();
+ for results in VAL_LISTS {
+ for params in VAL_LISTS {
+ let func_ty = FuncType { results: value_types(results), params: value_types(params) };
+ cases.push((proxy_module(&func_ty), func_ty, params.to_vec()));
}
}
- result
+ cases
}
#[test]
fn test_return_invalid_type() -> Result<()> {
- // try to return from host functions types that don't match their signatures
- let mod_list = get_modules();
+ let cases = module_cases();
- for (module, func_ty, test_args) in mod_list {
- for result_to_try in VAL_LISTS {
+ for (module, func_ty, args) in cases {
+ for returned_values in VAL_LISTS {
let mut store = Store::default();
let mut imports = Imports::new();
imports
- .define("host", "hfn", Extern::func(&func_ty, |_: FuncContext<'_>, _| Ok(result_to_try.to_vec())))
+ .define("host", "hfn", Extern::func(&func_ty, |_: FuncContext<'_>, _| Ok(returned_values.to_vec())))
.unwrap();
let instance = module.clone().instantiate(&mut store, Some(imports)).unwrap();
let caller = instance.exported_func_untyped(&store, "call_hfn").unwrap();
- let res_types_returned = result_to_try.iter().map(WasmValue::val_type);
- dbg!(&res_types_returned, &func_ty);
- let res_types_expected = &func_ty.results;
- let should_succeed = res_types_returned.eq(res_types_expected.iter().cloned());
- // Extern::func that returns wrong type(s) can only be detected when it runs
- let call_res = caller.call(&mut store, &test_args);
- dbg!(&call_res);
+ // Return-type mismatch is only observable at call time.
+ let should_succeed = returned_values.iter().map(WasmValue::val_type).eq(func_ty.results.iter().copied());
+ let call_res = caller.call(&mut store, &args);
assert_eq!(call_res.is_ok(), should_succeed);
- println!("this time ok");
}
}
+
Ok(())
}
#[test]
fn test_linking_invalid_untyped_func() -> Result<()> {
- // try to import host functions with function types no matching those expected by modules
- let mod_list = get_modules();
- for (module, actual_func_ty, _) in &mod_list {
- for (_, func_ty_to_try, _) in &mod_list {
+ let cases = module_cases();
+ for (module, expected_func_ty, _) in &cases {
+ for (_, func_ty_to_try, _) in &cases {
let tried_fn = Extern::func(func_ty_to_try, |_: FuncContext<'_>, _| panic!("not intended to be called"));
let mut store = Store::default();
let mut imports = Imports::new();
imports.define("host", "hfn", tried_fn).unwrap();
- let should_succeed = func_ty_to_try == actual_func_ty;
+ let should_succeed = func_ty_to_try == expected_func_ty;
let link_res = module.clone().instantiate(&mut store, Some(imports));
assert_eq!(link_res.is_ok(), should_succeed);
@@ -83,28 +76,27 @@ fn test_linking_invalid_untyped_func() -> Result<()> {
#[test]
fn test_linking_invalid_typed_func() -> Result<()> {
type Existing = (i32, i32, f64);
- type NonMatchingOne = f64;
- type NonMatchingMul = (f64, i32, i32);
+ type NonMatchingSingle = f64;
+ type NonMatchingTuple = (f64, i32, i32);
const DONT_CALL: &str = "not meant to be called";
- // they don't match any signature from get_modules()
- #[rustfmt::skip] // to make it table-like
- let matching_none= &[
- Extern::typed_func(|_, _: NonMatchingMul| -> tinywasm::Result<Existing> { panic!("{DONT_CALL}") } ),
- Extern::typed_func(|_, _: NonMatchingMul| -> tinywasm::Result<()> { panic!("{DONT_CALL}") } ),
- Extern::typed_func(|_, _: NonMatchingOne| -> tinywasm::Result<Existing> { panic!("{DONT_CALL}") } ),
- Extern::typed_func(|_, _: NonMatchingOne| -> tinywasm::Result<()> { panic!("{DONT_CALL}") } ),
- Extern::typed_func(|_, _: Existing | -> tinywasm::Result<NonMatchingMul> { panic!("{DONT_CALL}") } ),
- Extern::typed_func(|_, _: Existing | -> tinywasm::Result<NonMatchingOne> { panic!("{DONT_CALL}") } ),
- Extern::typed_func(|_, _: () | -> tinywasm::Result<NonMatchingOne> { panic!("{DONT_CALL}") } ),
- Extern::typed_func(|_, _: () | -> tinywasm::Result<NonMatchingMul> { panic!("{DONT_CALL}") } ),
- Extern::typed_func(|_, _: NonMatchingOne| -> tinywasm::Result<NonMatchingMul> { panic!("{DONT_CALL}") } ),
- Extern::typed_func(|_, _: NonMatchingOne| -> tinywasm::Result<NonMatchingOne> { panic!("{DONT_CALL}") } ),
+ // None of these typed host signatures are produced by module_cases().
+ let matching_none = vec![
+ Extern::typed_func(|_, _: NonMatchingTuple| -> tinywasm::Result<Existing> { panic!("{DONT_CALL}") }),
+ Extern::typed_func(|_, _: NonMatchingTuple| -> tinywasm::Result<()> { panic!("{DONT_CALL}") }),
+ Extern::typed_func(|_, _: NonMatchingSingle| -> tinywasm::Result<Existing> { panic!("{DONT_CALL}") }),
+ Extern::typed_func(|_, _: NonMatchingSingle| -> tinywasm::Result<()> { panic!("{DONT_CALL}") }),
+ Extern::typed_func(|_, _: Existing| -> tinywasm::Result<NonMatchingTuple> { panic!("{DONT_CALL}") }),
+ Extern::typed_func(|_, _: Existing| -> tinywasm::Result<NonMatchingSingle> { panic!("{DONT_CALL}") }),
+ Extern::typed_func(|_, _: ()| -> tinywasm::Result<NonMatchingSingle> { panic!("{DONT_CALL}") }),
+ Extern::typed_func(|_, _: ()| -> tinywasm::Result<NonMatchingTuple> { panic!("{DONT_CALL}") }),
+ Extern::typed_func(|_, _: NonMatchingSingle| -> tinywasm::Result<NonMatchingTuple> { panic!("{DONT_CALL}") }),
+ Extern::typed_func(|_, _: NonMatchingSingle| -> tinywasm::Result<NonMatchingSingle> { panic!("{DONT_CALL}") }),
];
- let mod_list = get_modules();
- for (module, _, _) in mod_list {
- for typed_fn in matching_none.clone() {
+ let cases = module_cases();
+ for (module, _, _) in cases {
+ for typed_fn in matching_none.iter().cloned() {
let mut store = Store::default();
let mut imports = Imports::new();
imports.define("host", "hfn", typed_fn).unwrap();
@@ -113,7 +105,6 @@ fn test_linking_invalid_typed_func() -> Result<()> {
}
}
- // the valid cases are well-checked in other tests
Ok(())
}
@@ -129,9 +120,6 @@ fn to_name(ty: &ValType) -> &str {
}
}
-// make a module with imported function {module:"host", name:"hfn"} that takes specified results and returns specified params
-// and 2 wasm functions: call_hfn takes params, passes them to hfn and returns it's results
-// and 2 wasm functions: call_hfn_discard takes params, passes them to hfn and drops it's results
fn proxy_module(func_ty: &FuncType) -> Module {
let results = func_ty.results.as_ref();
let params = func_ty.params.as_ref();
@@ -139,7 +127,7 @@ fn proxy_module(func_ty: &FuncType) -> Module {
if list.is_empty() {
return "".to_string();
}
- let step = list.iter().map(|ty| format!("{} ", to_name(ty)).to_string()).collect::<String>();
+ let step = list.iter().map(|ty| format!("{} ", to_name(ty))).collect::<String>();
format!("({keyword} {step})")
};
@@ -151,7 +139,7 @@ fn proxy_module(func_ty: &FuncType) -> Module {
acc
});
- let result_drops = "(drop)\n".repeat(results.len()).to_string();
+ let result_drops = "(drop)\n".repeat(results.len());
let wasm_text = format!(
r#"(module
(import "host" "hfn" (func $host_fn {params_text} {results_text}))
@@ -162,6 +150,7 @@ fn proxy_module(func_ty: &FuncType) -> Module {
(func (export "call_hfn_discard") {params_text}
{params_gets}
(call $host_fn)
+ ;; Keep stack balanced for arbitrary result arity.
{result_drops}
)
)
diff --git a/examples/funcref_callbacks.rs b/examples/funcref_callbacks.rs
index 01f833c..4ee7438 100644
--- a/examples/funcref_callbacks.rs
+++ b/examples/funcref_callbacks.rs
@@ -1,21 +1,17 @@
use eyre::Result;
use tinywasm::{Extern, FuncContext, Imports, Module, Store, types::FuncRef};
+const LHS: i32 = 5;
+const RHS: i32 = 3;
+
fn main() -> Result<()> {
- by_func_ref_passed()?;
- by_func_ref_returned()?;
+ run_passed_funcref_example()?;
+ run_returned_funcref_example()?;
Ok(())
}
-/// Example of passing Wasm functions (as `funcref`) to an imported host function
-/// and the imported host function calling them.
-fn by_func_ref_passed() -> Result<()> {
- // A module with:
- // - Imported function "host.call_this" that accepts a callback.
- // - Exported Wasm function "tell_host_to_call" that calls "host.call_this" with Wasm functions $add and $sub.
- // - Wasm functions $add and $sub and an imported function $mul used as callbacks
- // (just to show that imported functions can be referenced too).
- // - Exported Wasm function "call_binop_by_ref", a proxy used by the host to call func-references of type (i32, i32) -> i32.
+fn run_passed_funcref_example() -> Result<()> {
+ // Host receives funcref and calls it via an exported proxy.
const WASM: &str = r#"
(module
(import "host" "call_this" (func $host_callback_caller (param funcref)))
@@ -30,7 +26,7 @@ fn by_func_ref_passed() -> Result<()> {
(type $binop (func (param i32 i32) (result i32)))
(table 3 funcref)
- (elem (i32.const 0) $add $sub $host_mul) ;; Function can only be referenced if added to a table.
+ (elem (i32.const 0) $add $sub $host_mul)
(func $add (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
@@ -50,51 +46,41 @@ fn by_func_ref_passed() -> Result<()> {
)
"#;
- let wasm = wat::parse_str(WASM).expect("Failed to parse WAT");
+ let wasm = wat::parse_str(WASM).expect("failed to parse wat");
let module = Module::parse_bytes(&wasm)?;
let mut store = Store::default();
let mut imports = Imports::new();
- // Import host function that takes callbacks and calls them.
imports.define(
"host",
"call_this",
- Extern::typed_func(|mut ctx: FuncContext<'_>, fn_ref: FuncRef| -> tinywasm::Result<()> {
- let proxy_caller =
+ Extern::typed_func(|mut ctx: FuncContext<'_>, func_ref: FuncRef| -> tinywasm::Result<()> {
+ // Host cannot call a funcref directly, so it routes through Wasm.
+ let call_by_ref =
ctx.module().exported_func::<(FuncRef, i32, i32), i32>(ctx.store(), "call_binop_by_ref")?;
- // Call the callback we got as an argument using "call_binop_by_ref".
- let res = proxy_caller.call(ctx.store_mut(), (fn_ref, 5, 3))?;
- println!("(funcref {fn_ref:?})(5,3) results in {res}");
+ let result = call_by_ref.call(ctx.store_mut(), (func_ref, LHS, RHS))?;
+ println!("(funcref {func_ref:?})({LHS},{RHS}) results in {result}");
Ok(())
}),
)?;
- // Import host.mul function (one of the functions whose references are taken).
imports.define(
"host",
"mul",
- Extern::typed_func(|_, args: (i32, i32)| -> tinywasm::Result<i32> { Ok(args.0 * args.1) }),
+ Extern::typed_func(|_, (lhs, rhs): (i32, i32)| -> tinywasm::Result<i32> { Ok(lhs * rhs) }),
)?;
let instance = module.instantiate(&mut store, Some(imports))?;
let caller = instance.exported_func::<(), ()>(&store, "tell_host_to_call")?;
- // Call "tell_host_to_call".
caller.call(&mut store, ())?;
- // An interesting detail is that neither $add, $sub, nor $mul were exported,
- // but with a little help from the proxy "call_binop_by_ref", references to them are callable by the host.
+
Ok(())
}
-/// Example of returning a Wasm function as a callback to a host function
-/// and the host function calling it.
-fn by_func_ref_returned() -> Result<()> {
- // A module with:
- // - An exported function "what_should_host_call" that returns 3 `funcref`s.
- // - Wasm functions $add and $sub and an imported function $mul used as callbacks
- // (just to show that imported functions can be referenced too).
- // - Another exported Wasm function "call_binop_by_ref", a proxy used by the host to call func-references of type (i32, i32) -> i32
+fn run_returned_funcref_example() -> Result<()> {
+ // Wasm returns funcref values, host executes them through the same proxy.
const WASM: &str = r#"
(module
(import "host" "mul" (func $host_mul (param $x i32) (param $y i32) (result i32)))
@@ -125,33 +111,30 @@ fn by_func_ref_returned() -> Result<()> {
)
"#;
- let wasm = wat::parse_str(WASM).expect("Failed to parse WAT");
+ let wasm = wat::parse_str(WASM).expect("failed to parse wat");
let module = Module::parse_bytes(&wasm)?;
let mut store = Store::default();
let mut imports = Imports::new();
- // Import host.mul function (one of the possible operations).
imports.define(
"host",
"mul",
- Extern::typed_func(|_, args: (i32, i32)| -> tinywasm::Result<i32> { Ok(args.0 * args.1) }),
+ Extern::typed_func(|_, (lhs, rhs): (i32, i32)| -> tinywasm::Result<i32> { Ok(lhs * rhs) }),
)?;
let instance = module.instantiate(&mut store, Some(imports))?;
- // Ask the module what to call.
- let funcrefs = {
- let address_getter =
+ let (add_ref, sub_ref, mul_ref) = {
+ let get_funcrefs =
instance.exported_func::<(), (FuncRef, FuncRef, FuncRef)>(&store, "what_should_host_call")?;
- address_getter.call(&mut store, ())?
+ get_funcrefs.call(&mut store, ())?
};
- let proxy_caller = instance.exported_func::<(FuncRef, i32, i32), i32>(&store, "call_binop_by_ref")?;
+ let call_by_ref = instance.exported_func::<(FuncRef, i32, i32), i32>(&store, "call_binop_by_ref")?;
- for (idx, func_ref) in [funcrefs.0, funcrefs.1, funcrefs.2].iter().enumerate() {
- // Call those `funcref`s via "call_binop_by_ref".
- let res = proxy_caller.call(&mut store, (*func_ref, 5, 3))?;
- println!("At idx: {idx}, funcref {func_ref:?}(5,3) results in {res}");
+ for (idx, func_ref) in [add_ref, sub_ref, mul_ref].iter().enumerate() {
+ let result = call_by_ref.call(&mut store, (*func_ref, LHS, RHS))?;
+ println!("At idx: {idx}, funcref {func_ref:?}({LHS},{RHS}) results in {result}");
}
Ok(())
}