summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorHenry <mail@henrygressmann.de>2026-03-19 21:45:31 +0100
committerHenry <mail@henrygressmann.de>2026-03-19 21:45:31 +0100
commit7db07e03b56577997706adda1358bb43155b2aeb (patch)
tree7f33827ac54d26c824b408294dba0137535898f7 /crates
parent384cb7ecb8e39fc6d4ec371bd753a889dfb83b33 (diff)
feat: add all simd instructions, add stackop macro
Signed-off-by: Henry <mail@henrygressmann.de>
Diffstat (limited to 'crates')
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs877
-rw-r--r--crates/tinywasm/src/interpreter/num_helpers.rs2
-rw-r--r--crates/tinywasm/src/interpreter/stack/value_stack.rs14
-rw-r--r--crates/tinywasm/src/interpreter/value128.rs2212
-rw-r--r--crates/tinywasm/src/store/memory.rs2
-rw-r--r--crates/tinywasm/tests/generated/wasm-simd.csv2
6 files changed, 2632 insertions, 477 deletions
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index c186c01..08089f4 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -44,6 +44,36 @@ impl<'store, 'stack> Executor<'store, 'stack> {
fn exec_next(&mut self) -> ControlFlow<Option<Error>> {
use tinywasm_types::Instruction::*;
+ macro_rules! stack_op {
+ (simd_unary $method:ident) => {
+ self.stack.values.unary_same::<Value128>(|v| Ok(v.$method())).to_cf()?
+ };
+ (simd_binary $method:ident) => {
+ self.stack.values.binary_same::<Value128>(|a, b| Ok(a.$method(b))).to_cf()?
+ };
+ (unary $ty:ty, |$v:ident| $expr:expr) => {
+ self.stack.values.unary_same::<$ty>(|$v| Ok($expr)).to_cf()?
+ };
+ (binary $ty:ty, |$a:ident, $b:ident| $expr:expr) => {
+ self.stack.values.binary_same::<$ty>(|$a, $b| Ok($expr)).to_cf()?
+ };
+ (binary_try $ty:ty, |$a:ident, $b:ident| $expr:expr) => {
+ self.stack.values.binary_same::<$ty>(|$a, $b| $expr).to_cf()?
+ };
+ (unary $from:ty => $to:ty, |$v:ident| $expr:expr) => {
+ self.stack.values.unary::<$from, $to>(|$v| Ok($expr)).to_cf()?
+ };
+ (binary $from:ty => $to:ty, |$a:ident, $b:ident| $expr:expr) => {
+ self.stack.values.binary::<$from, $to>(|$a, $b| Ok($expr)).to_cf()?
+ };
+ (binary $a:ty, $b:ty, |$lhs:ident, $rhs:ident| $expr:expr) => {
+ self.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.stack.values.binary_diff::<$a, $b, $res>(|$lhs, $rhs| Ok($expr)).to_cf()?
+ };
+ }
+
#[rustfmt::skip]
match self.cf.fetch_instr() {
Nop | BrLabel(_) | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {}
@@ -106,6 +136,8 @@ impl<'store, 'stack> Executor<'store, 'stack> {
I64Const(val) => self.exec_const(*val),
F32Const(val) => self.exec_const(*val),
F64Const(val) => self.exec_const(*val),
+
+ // Reference types
RefFunc(func_idx) => self.exec_const::<ValueRef>(Some(*func_idx)),
RefNull(_) => self.exec_const::<ValueRef>(None),
RefIsNull => self.exec_ref_is_null(),
@@ -119,8 +151,17 @@ impl<'store, 'stack> Executor<'store, 'stack> {
MemoryInit(data_idx, mem_idx) => self.exec_memory_init(*data_idx, *mem_idx).to_cf()?,
DataDrop(data_index) => self.exec_data_drop(*data_index),
ElemDrop(elem_index) => self.exec_elem_drop(*elem_index),
+
+ // Table instructions
+ TableGet(table_idx) => self.exec_table_get(*table_idx).to_cf()?,
+ TableSet(table_idx) => self.exec_table_set(*table_idx).to_cf()?,
+ TableSize(table_idx) => self.exec_table_size(*table_idx).to_cf()?,
+ TableInit(elem_idx, table_idx) => self.exec_table_init(*elem_idx, *table_idx).to_cf()?,
+ TableGrow(table_idx) => self.exec_table_grow(*table_idx).to_cf()?,
+ TableFill(table_idx) => self.exec_table_fill(*table_idx).to_cf()?,
TableCopy { from, to } => self.exec_table_copy(*from, *to).to_cf()?,
+ // Core memory load/store operations
I32Store(m) => self.exec_mem_store::<i32, i32, 4>(m.mem_addr(), m.offset(), |v| v)?,
I64Store(m) => self.exec_mem_store::<i64, i64, 8>(m.mem_addr(), m.offset(), |v| v)?,
F32Store(m) => self.exec_mem_store::<f32, f32, 4>(m.mem_addr(), m.offset(), |v| v)?,
@@ -146,138 +187,140 @@ impl<'store, 'stack> Executor<'store, 'stack> {
I64Load32S(m) => self.exec_mem_load::<i32, 4, _>(m.mem_addr(), m.offset(), i64::from)?,
I64Load32U(m) => self.exec_mem_load::<u32, 4, _>(m.mem_addr(), m.offset(), i64::from)?,
- I64Eqz => self.stack.values.replace_top::<i64, _>(|v| Ok(i32::from(v == 0))).to_cf()?,
- I32Eqz => self.stack.values.replace_top_same::<i32>(|v| Ok(i32::from(v == 0))).to_cf()?,
- I32Eq => self.stack.values.calculate_same::<i32>(|a, b| Ok(i32::from(a == b))).to_cf()?,
- I64Eq => self.stack.values.calculate::<i64, _>(|a, b| Ok(i32::from(a == b))).to_cf()?,
- F32Eq => self.stack.values.calculate::<f32, _>(|a, b| Ok(i32::from(a == b))).to_cf()?,
- F64Eq => self.stack.values.calculate::<f64, _>(|a, b| Ok(i32::from(a == b))).to_cf()?,
+ I64Eqz => stack_op!(unary i64 => i32, |v| i32::from(v == 0)),
+ I32Eqz => stack_op!(unary i32, |v| i32::from(v == 0)),
+ I32Eq => stack_op!(binary i32, |a, b| i32::from(a == b)),
+ I64Eq => stack_op!(binary i64 => i32, |a, b| i32::from(a == b)),
+ F32Eq => stack_op!(binary f32 => i32, |a, b| i32::from(a == b)),
+ F64Eq => stack_op!(binary f64 => i32, |a, b| i32::from(a == b)),
- I32Ne => self.stack.values.calculate_same::<i32>(|a, b| Ok(i32::from(a != b))).to_cf()?,
- I64Ne => self.stack.values.calculate::<i64, _>(|a, b| Ok(i32::from(a != b))).to_cf()?,
- F32Ne => self.stack.values.calculate::<f32, _>(|a, b| Ok(i32::from(a != b))).to_cf()?,
- F64Ne => self.stack.values.calculate::<f64, _>(|a, b| Ok(i32::from(a != b))).to_cf()?,
+ I32Ne => stack_op!(binary i32, |a, b| i32::from(a != b)),
+ I64Ne => stack_op!(binary i64 => i32, |a, b| i32::from(a != b)),
+ F32Ne => stack_op!(binary f32 => i32, |a, b| i32::from(a != b)),
+ F64Ne => stack_op!(binary f64 => i32, |a, b| i32::from(a != b)),
- I32LtS => self.stack.values.calculate_same::<i32>(|a, b| Ok(i32::from(a < b))).to_cf()?,
- I64LtS => self.stack.values.calculate::<i64, _>(|a, b| Ok(i32::from(a < b))).to_cf()?,
- I32LtU => self.stack.values.calculate::<u32, _>(|a, b| Ok(i32::from(a < b))).to_cf()?,
- I64LtU => self.stack.values.calculate::<u64, _>(|a, b| Ok(i32::from(a < b))).to_cf()?,
- F32Lt => self.stack.values.calculate::<f32, _>(|a, b| Ok(i32::from(a < b))).to_cf()?,
- F64Lt => self.stack.values.calculate::<f64, _>(|a, b| Ok(i32::from(a < b))).to_cf()?,
+ I32LtS => stack_op!(binary i32, |a, b| i32::from(a < b)),
+ I64LtS => stack_op!(binary i64 => i32, |a, b| i32::from(a < b)),
+ I32LtU => stack_op!(binary u32 => i32, |a, b| i32::from(a < b)),
+ I64LtU => stack_op!(binary u64 => i32, |a, b| i32::from(a < b)),
+ F32Lt => stack_op!(binary f32 => i32, |a, b| i32::from(a < b)),
+ F64Lt => stack_op!(binary f64 => i32, |a, b| i32::from(a < b)),
- I32LeS => self.stack.values.calculate_same::<i32>(|a, b| Ok(i32::from(a <= b))).to_cf()?,
- I64LeS => self.stack.values.calculate::<i64, _>(|a, b| Ok(i32::from(a <= b))).to_cf()?,
- I32LeU => self.stack.values.calculate::<u32, _>(|a, b| Ok(i32::from(a <= b))).to_cf()?,
- I64LeU => self.stack.values.calculate::<u64, _>(|a, b| Ok(i32::from(a <= b))).to_cf()?,
- F32Le => self.stack.values.calculate::<f32, _>(|a, b| Ok(i32::from(a <= b))).to_cf()?,
- F64Le => self.stack.values.calculate::<f64, _>(|a, b| Ok(i32::from(a <= b))).to_cf()?,
+ I32LeS => stack_op!(binary i32, |a, b| i32::from(a <= b)),
+ I64LeS => stack_op!(binary i64 => i32, |a, b| i32::from(a <= b)),
+ I32LeU => stack_op!(binary u32 => i32, |a, b| i32::from(a <= b)),
+ I64LeU => stack_op!(binary u64 => i32, |a, b| i32::from(a <= b)),
+ F32Le => stack_op!(binary f32 => i32, |a, b| i32::from(a <= b)),
+ F64Le => stack_op!(binary f64 => i32, |a, b| i32::from(a <= b)),
- I32GeS => self.stack.values.calculate_same::<i32>(|a, b| Ok(i32::from(a >= b))).to_cf()?,
- I64GeS => self.stack.values.calculate::<i64, _>(|a, b| Ok(i32::from(a >= b))).to_cf()?,
- I32GeU => self.stack.values.calculate::<u32, _>(|a, b| Ok(i32::from(a >= b))).to_cf()?,
- I64GeU => self.stack.values.calculate::<u64, _>(|a, b| Ok(i32::from(a >= b))).to_cf()?,
- F32Ge => self.stack.values.calculate::<f32, _>(|a, b| Ok(i32::from(a >= b))).to_cf()?,
- F64Ge => self.stack.values.calculate::<f64, _>(|a, b| Ok(i32::from(a >= b))).to_cf()?,
+ I32GeS => stack_op!(binary i32, |a, b| i32::from(a >= b)),
+ I64GeS => stack_op!(binary i64 => i32, |a, b| i32::from(a >= b)),
+ I32GeU => stack_op!(binary u32 => i32, |a, b| i32::from(a >= b)),
+ I64GeU => stack_op!(binary u64 => i32, |a, b| i32::from(a >= b)),
+ F32Ge => stack_op!(binary f32 => i32, |a, b| i32::from(a >= b)),
+ F64Ge => stack_op!(binary f64 => i32, |a, b| i32::from(a >= b)),
- I32GtS => self.stack.values.calculate_same::<i32>(|a, b| Ok(i32::from(a > b))).to_cf()?,
- I64GtS => self.stack.values.calculate::<i64, _>(|a, b| Ok(i32::from(a > b))).to_cf()?,
- I32GtU => self.stack.values.calculate::<u32, _>(|a, b| Ok(i32::from(a > b))).to_cf()?,
- I64GtU => self.stack.values.calculate::<u64, _>(|a, b| Ok(i32::from(a > b))).to_cf()?,
- F32Gt => self.stack.values.calculate::<f32, _>(|a, b| Ok(i32::from(a > b))).to_cf()?,
- F64Gt => self.stack.values.calculate::<f64, _>(|a, b| Ok(i32::from(a > b))).to_cf()?,
+ I32GtS => stack_op!(binary i32, |a, b| i32::from(a > b)),
+ I64GtS => stack_op!(binary i64 => i32, |a, b| i32::from(a > b)),
+ I32GtU => stack_op!(binary u32 => i32, |a, b| i32::from(a > b)),
+ I64GtU => stack_op!(binary u64 => i32, |a, b| i32::from(a > b)),
+ F32Gt => stack_op!(binary f32 => i32, |a, b| i32::from(a > b)),
+ F64Gt => stack_op!(binary f64 => i32, |a, b| i32::from(a > b)),
- I32Add => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wrapping_add(b))).to_cf()?,
- I64Add => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wrapping_add(b))).to_cf()?,
- F32Add => self.stack.values.calculate_same::<f32>(|a, b| Ok(a + b)).to_cf()?,
- F64Add => self.stack.values.calculate_same::<f64>(|a, b| Ok(a + b)).to_cf()?,
+ I32Add => stack_op!(binary i32, |a, b| a.wrapping_add(b)),
+ I64Add => stack_op!(binary i64, |a, b| a.wrapping_add(b)),
+ F32Add => stack_op!(binary f32, |a, b| a + b),
+ F64Add => stack_op!(binary f64, |a, b| a + b),
- I32Sub => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wrapping_sub(b))).to_cf()?,
- I64Sub => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wrapping_sub(b))).to_cf()?,
- F32Sub => self.stack.values.calculate_same::<f32>(|a, b| Ok(a - b)).to_cf()?,
- F64Sub => self.stack.values.calculate_same::<f64>(|a, b| Ok(a - b)).to_cf()?,
+ I32Sub => stack_op!(binary i32, |a, b| a.wrapping_sub(b)),
+ I64Sub => stack_op!(binary i64, |a, b| a.wrapping_sub(b)),
+ F32Sub => stack_op!(binary f32, |a, b| a - b),
+ F64Sub => stack_op!(binary f64, |a, b| a - b),
- F32Div => self.stack.values.calculate_same::<f32>(|a, b| Ok(a / b)).to_cf()?,
- F64Div => self.stack.values.calculate_same::<f64>(|a, b| Ok(a / b)).to_cf()?,
+ F32Div => stack_op!(binary f32, |a, b| a / b),
+ F64Div => stack_op!(binary f64, |a, b| a / b),
- I32Mul => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wrapping_mul(b))).to_cf()?,
- I64Mul => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wrapping_mul(b))).to_cf()?,
- F32Mul => self.stack.values.calculate_same::<f32>(|a, b| Ok(a * b)).to_cf()?,
- F64Mul => self.stack.values.calculate_same::<f64>(|a, b| Ok(a * b)).to_cf()?,
+ I32Mul => stack_op!(binary i32, |a, b| a.wrapping_mul(b)),
+ 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 => self.stack.values.calculate_same::<i32>(|a, b| a.wasm_checked_div(b)).to_cf()?,
- I64DivS => self.stack.values.calculate_same::<i64>(|a, b| a.wasm_checked_div(b)).to_cf()?,
- I32DivU => self.stack.values.calculate_same::<u32>(|a, b| a.checked_div(b).ok_or_else(trap_0)).to_cf()?,
- I64DivU => self.stack.values.calculate_same::<u64>(|a, b| a.checked_div(b).ok_or_else(trap_0)).to_cf()?,
- I32RemS => self.stack.values.calculate_same::<i32>(|a, b| a.checked_wrapping_rem(b)).to_cf()?,
- I64RemS => self.stack.values.calculate_same::<i64>(|a, b| a.checked_wrapping_rem(b)).to_cf()?,
- I32RemU => self.stack.values.calculate_same::<u32>(|a, b| a.checked_wrapping_rem(b)).to_cf()?,
- I64RemU => self.stack.values.calculate_same::<u64>(|a, b| a.checked_wrapping_rem(b)).to_cf()?,
+ 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 => self.stack.values.calculate_same::<i32>(|a, b| Ok(a & b)).to_cf()?,
- I64And => self.stack.values.calculate_same::<i64>(|a, b| Ok(a & b)).to_cf()?,
- I32Or => self.stack.values.calculate_same::<i32>(|a, b| Ok(a | b)).to_cf()?,
- I64Or => self.stack.values.calculate_same::<i64>(|a, b| Ok(a | b)).to_cf()?,
- I32Xor => self.stack.values.calculate_same::<i32>(|a, b| Ok(a ^ b)).to_cf()?,
- I64Xor => self.stack.values.calculate_same::<i64>(|a, b| Ok(a ^ b)).to_cf()?,
- I32Shl => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wasm_shl(b))).to_cf()?,
- I64Shl => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wasm_shl(b))).to_cf()?,
- I32ShrS => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wasm_shr(b))).to_cf()?,
- I64ShrS => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wasm_shr(b))).to_cf()?,
- I32ShrU => self.stack.values.calculate_same::<u32>(|a, b| Ok(a.wasm_shr(b))).to_cf()?,
- I64ShrU => self.stack.values.calculate_same::<u64>(|a, b| Ok(a.wasm_shr(b))).to_cf()?,
- I32Rotl => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wasm_rotl(b))).to_cf()?,
- I64Rotl => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wasm_rotl(b))).to_cf()?,
- I32Rotr => self.stack.values.calculate_same::<i32>(|a, b| Ok(a.wasm_rotr(b))).to_cf()?,
- I64Rotr => self.stack.values.calculate_same::<i64>(|a, b| Ok(a.wasm_rotr(b))).to_cf()?,
+ 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),
+ I64Or => stack_op!(binary i64, |a, b| a | b),
+ I32Xor => stack_op!(binary i32, |a, b| a ^ b),
+ I64Xor => stack_op!(binary i64, |a, b| a ^ b),
+ I32Shl => stack_op!(binary i32, |a, b| a.wasm_shl(b)),
+ I64Shl => stack_op!(binary i64, |a, b| a.wasm_shl(b)),
+ I32ShrS => stack_op!(binary i32, |a, b| a.wasm_shr(b)),
+ I64ShrS => stack_op!(binary i64, |a, b| a.wasm_shr(b)),
+ I32ShrU => stack_op!(binary u32, |a, b| a.wasm_shr(b)),
+ I64ShrU => stack_op!(binary u64, |a, b| a.wasm_shr(b)),
+ I32Rotl => stack_op!(binary i32, |a, b| a.wasm_rotl(b)),
+ I64Rotl => stack_op!(binary i64, |a, b| a.wasm_rotl(b)),
+ I32Rotr => stack_op!(binary i32, |a, b| a.wasm_rotr(b)),
+ I64Rotr => stack_op!(binary i64, |a, b| a.wasm_rotr(b)),
- I32Clz => self.stack.values.replace_top_same::<i32>(|v| Ok(v.leading_zeros() as i32)).to_cf()?,
- I64Clz => self.stack.values.replace_top_same::<i64>(|v| Ok(i64::from(v.leading_zeros()))).to_cf()?,
- I32Ctz => self.stack.values.replace_top_same::<i32>(|v| Ok(v.trailing_zeros() as i32)).to_cf()?,
- I64Ctz => self.stack.values.replace_top_same::<i64>(|v| Ok(i64::from(v.trailing_zeros()))).to_cf()?,
- I32Popcnt => self.stack.values.replace_top_same::<i32>(|v| Ok(v.count_ones() as i32)).to_cf()?,
- I64Popcnt => self.stack.values.replace_top_same::<i64>(|v| Ok(i64::from(v.count_ones()))).to_cf()?,
+ I32Clz => stack_op!(unary i32, |v| v.leading_zeros() as i32),
+ I64Clz => stack_op!(unary i64, |v| i64::from(v.leading_zeros())),
+ I32Ctz => stack_op!(unary i32, |v| v.trailing_zeros() as i32),
+ I64Ctz => stack_op!(unary i64, |v| i64::from(v.trailing_zeros())),
+ I32Popcnt => stack_op!(unary i32, |v| v.count_ones() as i32),
+ I64Popcnt => stack_op!(unary i64, |v| i64::from(v.count_ones())),
- F32ConvertI32S => self.stack.values.replace_top::<i32, _>(|v| Ok(v as f32)).to_cf()?,
- F32ConvertI64S => self.stack.values.replace_top::<i64, _>(|v| Ok(v as f32)).to_cf()?,
- F64ConvertI32S => self.stack.values.replace_top::<i32, _>(|v| Ok(f64::from(v))).to_cf()?,
- F64ConvertI64S => self.stack.values.replace_top::<i64, _>(|v| Ok(v as f64)).to_cf()?,
- F32ConvertI32U => self.stack.values.replace_top::<u32, _>(|v| Ok(v as f32)).to_cf()?,
- F32ConvertI64U => self.stack.values.replace_top::<u64, _>(|v| Ok(v as f32)).to_cf()?,
- F64ConvertI32U => self.stack.values.replace_top::<u32, _>(|v| Ok(f64::from(v))).to_cf()?,
- F64ConvertI64U => self.stack.values.replace_top::<u64, _>(|v| Ok(v as f64)).to_cf()?,
+ // Numeric conversion operations
+ F32ConvertI32S => stack_op!(unary i32 => f32, |v| v as f32),
+ F32ConvertI64S => stack_op!(unary i64 => f32, |v| v as f32),
+ F64ConvertI32S => stack_op!(unary i32 => f64, |v| f64::from(v)),
+ F64ConvertI64S => stack_op!(unary i64 => f64, |v| v as f64),
+ F32ConvertI32U => stack_op!(unary u32 => f32, |v| v as f32),
+ F32ConvertI64U => stack_op!(unary u64 => f32, |v| v as f32),
+ F64ConvertI32U => stack_op!(unary u32 => f64, |v| f64::from(v)),
+ F64ConvertI64U => stack_op!(unary u64 => f64, |v| v as f64),
- I32Extend8S => self.stack.values.replace_top_same::<i32>(|v| Ok(i32::from(v as i8))).to_cf()?,
- I32Extend16S => self.stack.values.replace_top_same::<i32>(|v| Ok(i32::from(v as i16))).to_cf()?,
- I64Extend8S => self.stack.values.replace_top_same::<i64>(|v| Ok(i64::from(v as i8))).to_cf()?,
- I64Extend16S => self.stack.values.replace_top_same::<i64>(|v| Ok(i64::from(v as i16))).to_cf()?,
- I64Extend32S => self.stack.values.replace_top_same::<i64>(|v| Ok(i64::from(v as i32))).to_cf()?,
- I64ExtendI32U => self.stack.values.replace_top::<u32, _>(|v| Ok(i64::from(v))).to_cf()?,
- I64ExtendI32S => self.stack.values.replace_top::<i32, _>(|v| Ok(i64::from(v))).to_cf()?,
- I32WrapI64 => self.stack.values.replace_top::<i64, _>(|v| Ok(v as i32)).to_cf()?,
+ // Sign-extension operations
+ I32Extend8S => stack_op!(unary i32, |v| i32::from(v as i8)),
+ I32Extend16S => stack_op!(unary i32, |v| i32::from(v as i16)),
+ I64Extend8S => stack_op!(unary i64, |v| i64::from(v as i8)),
+ I64Extend16S => stack_op!(unary i64, |v| i64::from(v as i16)),
+ I64Extend32S => stack_op!(unary i64, |v| i64::from(v as i32)),
+ I64ExtendI32U => stack_op!(unary u32 => i64, |v| i64::from(v)),
+ I64ExtendI32S => stack_op!(unary i32 => i64, |v| i64::from(v)),
+ I32WrapI64 => stack_op!(unary i64 => i32, |v| v as i32),
- F32DemoteF64 => self.stack.values.replace_top::<f64, _>(|v| Ok(v as f32)).to_cf()?,
- F64PromoteF32 => self.stack.values.replace_top::<f32, _>(|v| Ok(f64::from(v))).to_cf()?,
+ F32DemoteF64 => stack_op!(unary f64 => f32, |v| v as f32),
+ F64PromoteF32 => stack_op!(unary f32 => f64, |v| f64::from(v)),
- F32Abs => self.stack.values.replace_top_same::<f32>(|v| Ok(v.abs())).to_cf()?,
- F64Abs => self.stack.values.replace_top_same::<f64>(|v| Ok(v.abs())).to_cf()?,
- F32Neg => self.stack.values.replace_top_same::<f32>(|v| Ok(-v)).to_cf()?,
- F64Neg => self.stack.values.replace_top_same::<f64>(|v| Ok(-v)).to_cf()?,
- F32Ceil => self.stack.values.replace_top_same::<f32>(|v| Ok(v.ceil())).to_cf()?,
- F64Ceil => self.stack.values.replace_top_same::<f64>(|v| Ok(v.ceil())).to_cf()?,
- F32Floor => self.stack.values.replace_top_same::<f32>(|v| Ok(v.floor())).to_cf()?,
- F64Floor => self.stack.values.replace_top_same::<f64>(|v| Ok(v.floor())).to_cf()?,
- F32Trunc => self.stack.values.replace_top_same::<f32>(|v| Ok(v.trunc())).to_cf()?,
- F64Trunc => self.stack.values.replace_top_same::<f64>(|v| Ok(v.trunc())).to_cf()?,
- F32Nearest => self.stack.values.replace_top_same::<f32>(|v| Ok(v.tw_nearest())).to_cf()?,
- F64Nearest => self.stack.values.replace_top_same::<f64>(|v| Ok(v.tw_nearest())).to_cf()?,
- F32Sqrt => self.stack.values.replace_top_same::<f32>(|v| Ok(v.sqrt())).to_cf()?,
- F64Sqrt => self.stack.values.replace_top_same::<f64>(|v| Ok(v.sqrt())).to_cf()?,
- F32Min => self.stack.values.calculate_same::<f32>(|a, b| Ok(a.tw_minimum(b))).to_cf()?,
- F64Min => self.stack.values.calculate_same::<f64>(|a, b| Ok(a.tw_minimum(b))).to_cf()?,
- F32Max => self.stack.values.calculate_same::<f32>(|a, b| Ok(a.tw_maximum(b))).to_cf()?,
- F64Max => self.stack.values.calculate_same::<f64>(|a, b| Ok(a.tw_maximum(b))).to_cf()?,
- F32Copysign => self.stack.values.calculate_same::<f32>(|a, b| Ok(a.copysign(b))).to_cf()?,
- F64Copysign => self.stack.values.calculate_same::<f64>(|a, b| Ok(a.copysign(b))).to_cf()?,
+ F32Abs => stack_op!(unary f32, |v| v.abs()),
+ F64Abs => stack_op!(unary f64, |v| v.abs()),
+ F32Neg => stack_op!(unary f32, |v| -v),
+ F64Neg => stack_op!(unary f64, |v| -v),
+ F32Ceil => stack_op!(unary f32, |v| v.ceil()),
+ F64Ceil => stack_op!(unary f64, |v| v.ceil()),
+ F32Floor => stack_op!(unary f32, |v| v.floor()),
+ F64Floor => stack_op!(unary f64, |v| v.floor()),
+ F32Trunc => stack_op!(unary f32, |v| v.trunc()),
+ F64Trunc => stack_op!(unary f64, |v| v.trunc()),
+ F32Nearest => stack_op!(unary f32, |v| v.tw_nearest()),
+ F64Nearest => stack_op!(unary f64, |v| v.tw_nearest()),
+ F32Sqrt => stack_op!(unary f32, |v| v.sqrt()),
+ F64Sqrt => stack_op!(unary f64, |v| v.sqrt()),
+ F32Min => stack_op!(binary f32, |a, b| a.tw_minimum(b)),
+ F64Min => stack_op!(binary f64, |a, b| a.tw_minimum(b)),
+ F32Max => stack_op!(binary f32, |a, b| a.tw_maximum(b)),
+ F64Max => stack_op!(binary f64, |a, b| a.tw_maximum(b)),
+ F32Copysign => stack_op!(binary f32, |a, b| a.copysign(b)),
+ F64Copysign => stack_op!(binary f64, |a, b| a.copysign(b)),
I32TruncF32S => checked_conv_float!(f32, i32, self),
I32TruncF64S => checked_conv_float!(f64, i32, self),
@@ -288,408 +331,306 @@ impl<'store, 'stack> Executor<'store, 'stack> {
I64TruncF32U => checked_conv_float!(f32, u64, i64, self),
I64TruncF64U => checked_conv_float!(f64, u64, i64, self),
- TableGet(table_idx) => self.exec_table_get(*table_idx).to_cf()?,
- TableSet(table_idx) => self.exec_table_set(*table_idx).to_cf()?,
- TableSize(table_idx) => self.exec_table_size(*table_idx).to_cf()?,
- TableInit(elem_idx, table_idx) => self.exec_table_init(*elem_idx, *table_idx).to_cf()?,
- TableGrow(table_idx) => self.exec_table_grow(*table_idx).to_cf()?,
- TableFill(table_idx) => self.exec_table_fill(*table_idx).to_cf()?,
-
- I32TruncSatF32S => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as i32)).to_cf()?,
- I32TruncSatF32U => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as u32)).to_cf()?,
- I32TruncSatF64S => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as i32)).to_cf()?,
- I32TruncSatF64U => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as u32)).to_cf()?,
- I64TruncSatF32S => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as i64)).to_cf()?,
- I64TruncSatF32U => self.stack.values.replace_top::<f32, _>(|v| Ok(v.trunc() as u64)).to_cf()?,
- I64TruncSatF64S => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as i64)).to_cf()?,
- I64TruncSatF64U => self.stack.values.replace_top::<f64, _>(|v| Ok(v.trunc() as u64)).to_cf()?,
+ // Non-trapping float-to-int conversions
+ I32TruncSatF32S => stack_op!(unary f32 => i32, |v| v.trunc() as i32),
+ I32TruncSatF32U => stack_op!(unary f32 => u32, |v| v.trunc() as u32),
+ I32TruncSatF64S => stack_op!(unary f64 => i32, |v| v.trunc() as i32),
+ I32TruncSatF64U => stack_op!(unary f64 => u32, |v| v.trunc() as u32),
+ I64TruncSatF32S => stack_op!(unary f32 => i64, |v| v.trunc() as i64),
+ I64TruncSatF32U => stack_op!(unary f32 => u64, |v| v.trunc() as u64),
+ I64TruncSatF64S => stack_op!(unary f64 => i64, |v| v.trunc() as i64),
+ I64TruncSatF64U => stack_op!(unary f64 => u64, |v| v.trunc() as u64),
LocalCopy32(from, to) => self.exec_local_copy::<Value32>(*from, *to),
LocalCopy64(from, to) => self.exec_local_copy::<Value64>(*from, *to),
LocalCopy128(from, to) => self.exec_local_copy::<Value128>(*from, *to),
LocalCopyRef(from, to) => self.exec_local_copy::<ValueRef>(*from, *to),
- V128Not => self.stack.values.replace_top_same::<Value128>(|v| Ok(!v)).to_cf()?,
- V128And => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a & b)).to_cf()?,
- V128AndNot => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a & (!b))).to_cf()?,
- V128Or => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a | b)).to_cf()?,
- V128Xor => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a ^ b)).to_cf()?,
- V128Bitselect => self.stack.values.calculate_same_3::<Value128>(|v1, v2, c| Ok((v1 & c) | (v2 & !c))).to_cf()?,
- V128AnyTrue => self.stack.values.replace_top::<Value128, i32>(|v| Ok((v.reduce_or() != 0) as i32)).to_cf()?,
- I8x16Swizzle => self.stack.values.calculate_same::<Value128>(|a, s| Ok(a.swizzle(s))).to_cf()?,
+ // SIMD extension
+ V128Not => stack_op!(unary Value128, |v| v.v128_not()),
+ V128And => stack_op!(binary Value128, |a, b| a.v128_and(b)),
+ 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.stack.values.ternary_same::<Value128>(|v1, v2, c| Ok(Value128::v128_bitselect(v1, v2, c))).to_cf()?,
+ 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)?,
- V128Load8x8S(arg) => self.exec_mem_load::<i8, 1, Value128>(arg.mem_addr(), arg.offset(), Value128::extend_8_i8)?,
- V128Load8x8U(_arg) => self.exec_mem_load::<u8, 1, Value128>(_arg.mem_addr(), _arg.offset(), Value128::extend_8_u8)?,
- V128Load16x4S(_arg) => self.exec_mem_load::<i16, 2, Value128>(_arg.mem_addr(), _arg.offset(), Value128::extend_4_i16)?,
- V128Load16x4U(_arg) => self.exec_mem_load::<u16, 2, Value128>(_arg.mem_addr(), _arg.offset(), Value128::extend_4_u16)?,
- V128Load32x2S(_arg) => self.exec_mem_load::<i32, 4, Value128>(_arg.mem_addr(), _arg.offset(), Value128::extend_2_i32)?,
- V128Load32x2U(_arg) => self.exec_mem_load::<u32, 4, Value128>(_arg.mem_addr(), _arg.offset(), Value128::extend_2_u32)?,
- V128Load8Splat(_arg) => self.exec_mem_load::<i8, 1, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i8)?,
- V128Load16Splat(_arg) => self.exec_mem_load::<i16, 2, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i16)?,
- V128Load32Splat(_arg) => self.exec_mem_load::<i32, 4, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i32)?,
- V128Load64Splat(_arg) => self.exec_mem_load::<i64, 8, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i64)?,
+ V128Load(arg) => self.exec_mem_load::<Value128, 16, _>(arg.mem_addr(), arg.offset(), |v| v)?,
+ V128Load8x8S(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load8x8_s(v.to_le_bytes()))?,
+ V128Load8x8U(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load8x8_u(v.to_le_bytes()))?,
+ V128Load16x4S(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load16x4_s(v.to_le_bytes()))?,
+ V128Load16x4U(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load16x4_u(v.to_le_bytes()))?,
+ V128Load32x2S(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load32x2_s(v.to_le_bytes()))?,
+ V128Load32x2U(arg) => self.exec_mem_load::<u64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::v128_load32x2_u(v.to_le_bytes()))?,
+ V128Load8Splat(_arg) => self.exec_mem_load::<i8, 1, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i8)?,
+ V128Load16Splat(_arg) => self.exec_mem_load::<i16, 2, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i16)?,
+ V128Load32Splat(_arg) => self.exec_mem_load::<i32, 4, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i32)?,
+ V128Load64Splat(_arg) => self.exec_mem_load::<i64, 8, Value128>(_arg.mem_addr(), _arg.offset(), Value128::splat_i64)?,
- V128Store(arg) => self.exec_mem_store::<Value128, Value128, 16>(arg.mem_addr(), arg.offset(), |v| v)?,
+ V128Store(arg) => self.exec_mem_store::<Value128, Value128, 16>(arg.mem_addr(), arg.offset(), |v| v)?,
- V128Store8Lane(arg, lane) => self.exec_mem_store_lane::<i8, 1>(arg.mem_addr(), arg.offset(), *lane)?,
- V128Store16Lane(arg, lane) => self.exec_mem_store_lane::<i16, 2>(arg.mem_addr(), arg.offset(), *lane)?,
- V128Store32Lane(arg, lane) => self.exec_mem_store_lane::<i32, 4>(arg.mem_addr(), arg.offset(), *lane)?,
- V128Store64Lane(arg, lane) => self.exec_mem_store_lane::<i64, 8>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Store8Lane(arg, lane) => self.exec_mem_store_lane::<i8, 1>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Store16Lane(arg, lane) => self.exec_mem_store_lane::<i16, 2>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Store32Lane(arg, lane) => self.exec_mem_store_lane::<i32, 4>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Store64Lane(arg, lane) => self.exec_mem_store_lane::<i64, 8>(arg.mem_addr(), arg.offset(), *lane)?,
// Load a single 32-bit or 64-bit element into the lowest bits of a v128 vector, and initialize all other bits of the v128 vector to zero.
- V128Load32Zero(arg) => self.exec_mem_load::<i32, 4, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i32x4([v, 0, 0, 0]))?,
- V128Load64Zero(arg) => self.exec_mem_load::<i64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i64x2([v, 0]))?,
+ V128Load32Zero(arg) => self.exec_mem_load::<i32, 4, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i32x4([v, 0, 0, 0]))?,
+ V128Load64Zero(arg) => self.exec_mem_load::<i64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i64x2([v, 0]))?,
- V128Const(arg) => self.exec_const::<Value128>( self.cf.data().v128_constants[*arg as usize].into()),
+ V128Const(arg) => self.exec_const::<Value128>(self.cf.data().v128_constants[*arg as usize].into()),
- I8x16ExtractLaneS(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_i8(*lane) as i32)).to_cf()?,
- I8x16ExtractLaneU(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_u8(*lane) as i32)).to_cf()?,
- I16x8ExtractLaneS(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_i16(*lane) as i32)).to_cf()?,
- I16x8ExtractLaneU(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_u16(*lane) as i32)).to_cf()?,
- I32x4ExtractLane(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_i32(*lane))).to_cf()?,
- I64x2ExtractLane(lane) => self.stack.values.replace_top::<Value128, i64>(|v| Ok(v.extract_lane_i64(*lane))).to_cf()?,
- F32x4ExtractLane(lane) => self.stack.values.replace_top::<Value128, f32>(|v| Ok(v.extract_lane_f32(*lane))).to_cf()?,
- F64x2ExtractLane(lane) => self.stack.values.replace_top::<Value128, f64>(|v| Ok(v.extract_lane_f64(*lane))).to_cf()?,
+ I8x16ExtractLaneS(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_i8(*lane) as i32),
+ I8x16ExtractLaneU(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_u8(*lane) as i32),
+ I16x8ExtractLaneS(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_i16(*lane) as i32),
+ I16x8ExtractLaneU(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_u16(*lane) as i32),
+ I32x4ExtractLane(lane) => stack_op!(unary Value128 => i32, |v| v.extract_lane_i32(*lane)),
+ I64x2ExtractLane(lane) => stack_op!(unary Value128 => i64, |v| v.extract_lane_i64(*lane)),
+ F32x4ExtractLane(lane) => stack_op!(unary Value128 => f32, |v| v.extract_lane_f32(*lane)),
+ F64x2ExtractLane(lane) => stack_op!(unary Value128 => f64, |v| v.extract_lane_f64(*lane)),
- V128Load8Lane(arg, lane) => self.exec_mem_load_lane::<i8, 1>(arg.mem_addr(), arg.offset(), *lane)?,
- V128Load16Lane(arg, lane) => self.exec_mem_load_lane::<i16, 2>(arg.mem_addr(), arg.offset(), *lane)?,
- V128Load32Lane(arg, lane) => self.exec_mem_load_lane::<i32, 4>(arg.mem_addr(), arg.offset(), *lane)?,
- V128Load64Lane(arg, lane) => self.exec_mem_load_lane::<i64, 8>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Load8Lane(arg, lane) => self.exec_mem_load_lane::<i8, 1>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Load16Lane(arg, lane) => self.exec_mem_load_lane::<i16, 2>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Load32Lane(arg, lane) => self.exec_mem_load_lane::<i32, 4>(arg.mem_addr(), arg.offset(), *lane)?,
+ V128Load64Lane(arg, lane) => self.exec_mem_load_lane::<i64, 8>(arg.mem_addr(), arg.offset(), *lane)?,
- // I8x16ReplaceLane(_lane) => unimplemented!(),
- // I16x8ReplaceLane(_lane) => unimplemented!(),
- // I32x4ReplaceLane(_lane) => unimplemented!(),
- // I64x2ReplaceLane(_lane) => unimplemented!(),
- // F32x4ReplaceLane(_lane) => unimplemented!(),
- // F64x2ReplaceLane(_lane) => unimplemented!(),
+ I8x16ReplaceLane(lane) => stack_op!(binary i32, Value128, |value, vec| vec.i8x16_replace_lane(*lane, value as i8)),
+ I16x8ReplaceLane(lane) => stack_op!(binary i32, Value128, |value, vec| vec.i16x8_replace_lane(*lane, value as i16)),
+ I32x4ReplaceLane(lane) => stack_op!(binary i32, Value128, |value, vec| vec.i32x4_replace_lane(*lane, value)),
+ I64x2ReplaceLane(lane) => stack_op!(binary i64, Value128, |value, vec| vec.i64x2_replace_lane(*lane, value)),
+ F32x4ReplaceLane(lane) => stack_op!(binary f32, Value128, |value, vec| vec.f32x4_replace_lane(*lane, value)),
+ F64x2ReplaceLane(lane) => stack_op!(binary f64, Value128, |value, vec| vec.f64x2_replace_lane(*lane, value)),
- I8x16Splat => self.stack.values.replace_top::<i32, Value128>(|v| Ok(Value128::splat_i8(v as i8))).to_cf()?,
- I16x8Splat => self.stack.values.replace_top::<i32, Value128>(|v| Ok(Value128::splat_i16(v as i16))).to_cf()?,
- I32x4Splat => self.stack.values.replace_top::<i32, Value128>(|v| Ok(Value128::splat_i32(v))).to_cf()?,
- I64x2Splat => self.stack.values.replace_top::<i64, Value128>(|v| Ok(Value128::splat_i64(v))).to_cf()?,
- F32x4Splat => self.stack.values.replace_top::<f32, Value128>(|v| Ok(Value128::splat_f32(v))).to_cf()?,
- F64x2Splat => self.stack.values.replace_top::<f64, Value128>(|v| Ok(Value128::splat_f64(v))).to_cf()?,
+ I8x16Splat => stack_op!(unary i32 => Value128, |v| Value128::splat_i8(v as i8)),
+ I16x8Splat => stack_op!(unary i32 => Value128, |v| Value128::splat_i16(v as i16)),
+ I32x4Splat => stack_op!(unary i32 => Value128, |v| Value128::splat_i32(v)),
+ I64x2Splat => stack_op!(unary i64 => Value128, |v| Value128::splat_i64(v)),
+ F32x4Splat => stack_op!(unary f32 => Value128, |v| Value128::splat_f32(v)),
+ F64x2Splat => stack_op!(unary f64 => Value128, |v| Value128::splat_f64(v)),
- // I8x16Eq => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?,
- // I16x8Eq => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?,
- // I32x4Eq => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?,
- // I64x2Eq => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?,
- // F32x4Eq => self.stack.values.calculate::<f32x4, _>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?,
- // F64x2Eq => self.stack.values.calculate::<f64x2, _>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?,
+ I8x16Eq => stack_op!(binary Value128, |a, b| a.i8x16_eq(b)),
+ I16x8Eq => stack_op!(binary Value128, |a, b| a.i16x8_eq(b)),
+ I32x4Eq => stack_op!(binary Value128, |a, b| a.i32x4_eq(b)),
+ I64x2Eq => stack_op!(binary Value128, |a, b| a.i64x2_eq(b)),
+ F32x4Eq => stack_op!(binary Value128, |a, b| a.f32x4_eq(b)),
+ F64x2Eq => stack_op!(binary Value128, |a, b| a.f64x2_eq(b)),
- // I8x16Ne => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?,
- // I16x8Ne => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?,
- // I32x4Ne => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?,
- // I64x2Ne => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?,
- // F32x4Ne => self.stack.values.calculate::<f32x4, _>(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?,
- // F64x2Ne => self.stack.values.calculate::<f64x2, _>(|a, b| Ok(a.simd_ne(b).to_int())).to_cf()?,
+ I8x16Ne => stack_op!(binary Value128, |a, b| a.i8x16_ne(b)),
+ I16x8Ne => stack_op!(binary Value128, |a, b| a.i16x8_ne(b)),
+ I32x4Ne => stack_op!(binary Value128, |a, b| a.i32x4_ne(b)),
+ I64x2Ne => stack_op!(binary Value128, |a, b| a.i64x2_ne(b)),
+ F32x4Ne => stack_op!(binary Value128, |a, b| a.f32x4_ne(b)),
+ F64x2Ne => stack_op!(binary Value128, |a, b| a.f64x2_ne(b)),
- // I8x16LtS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // I16x8LtS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // I32x4LtS => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // I64x2LtS => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // I8x16LtU => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // I16x8LtU => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // I32x4LtU => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // F32x4Lt => self.stack.values.calculate::<f32x4, _>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
- // F64x2Lt => self.stack.values.calculate::<f64x2, _>(|a, b| Ok(a.simd_lt(b).to_int())).to_cf()?,
+ I8x16LtS => stack_op!(binary Value128, |a, b| a.i8x16_lt_s(b)),
+ I16x8LtS => stack_op!(binary Value128, |a, b| a.i16x8_lt_s(b)),
+ I32x4LtS => stack_op!(binary Value128, |a, b| a.i32x4_lt_s(b)),
+ I64x2LtS => stack_op!(binary Value128, |a, b| a.i64x2_lt_s(b)),
+ I8x16LtU => stack_op!(binary Value128, |a, b| a.i8x16_lt_u(b)),
+ I16x8LtU => stack_op!(binary Value128, |a, b| a.i16x8_lt_u(b)),
+ I32x4LtU => stack_op!(binary Value128, |a, b| a.i32x4_lt_u(b)),
+ F32x4Lt => stack_op!(binary Value128, |a, b| a.f32x4_lt(b)),
+ F64x2Lt => stack_op!(binary Value128, |a, b| a.f64x2_lt(b)),
- // F32x4Gt => self.stack.values.calculate::<f32x4, _>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // F64x2Gt => self.stack.values.calculate::<f64x2, _>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
+ F32x4Gt => stack_op!(binary Value128, |a, b| a.f32x4_gt(b)),
+ F64x2Gt => stack_op!(binary Value128, |a, b| a.f64x2_gt(b)),
- // I8x16GtS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // I16x8GtS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // I32x4GtS => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // I64x2GtS => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // I64x2LeS => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
- // F32x4Le => self.stack.values.calculate::<f32x4,_>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
- // F64x2Le => self.stack.values.calculate::<f64x2,_>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
+ I8x16GtS => stack_op!(binary Value128, |a, b| a.i8x16_gt_s(b)),
+ I16x8GtS => stack_op!(binary Value128, |a, b| a.i16x8_gt_s(b)),
+ I32x4GtS => stack_op!(binary Value128, |a, b| a.i32x4_gt_s(b)),
+ I64x2GtS => stack_op!(binary Value128, |a, b| a.i64x2_gt_s(b)),
+ I64x2LeS => stack_op!(binary Value128, |a, b| a.i64x2_le_s(b)),
+ F32x4Le => stack_op!(binary Value128, |a, b| a.f32x4_le(b)),
+ F64x2Le => stack_op!(binary Value128, |a, b| a.f64x2_le(b)),
- // I8x16GtU => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // I16x8GtU => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // I32x4GtU => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_gt(b).to_int())).to_cf()?,
- // F32x4Ge => self.stack.values.calculate::<f32x4,_>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
- // F64x2Ge => self.stack.values.calculate::<f64x2,_>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
+ I8x16GtU => stack_op!(binary Value128, |a, b| a.i8x16_gt_u(b)),
+ I16x8GtU => stack_op!(binary Value128, |a, b| a.i16x8_gt_u(b)),
+ I32x4GtU => stack_op!(binary Value128, |a, b| a.i32x4_gt_u(b)),
+ F32x4Ge => stack_op!(binary Value128, |a, b| a.f32x4_ge(b)),
+ F64x2Ge => stack_op!(binary Value128, |a, b| a.f64x2_ge(b)),
- // I8x16LeS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
- // I16x8LeS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
- // I32x4LeS => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
+ I8x16LeS => stack_op!(binary Value128, |a, b| a.i8x16_le_s(b)),
+ I16x8LeS => stack_op!(binary Value128, |a, b| a.i16x8_le_s(b)),
+ I32x4LeS => stack_op!(binary Value128, |a, b| a.i32x4_le_s(b)),
- // I8x16LeU => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
- // I16x8LeU => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
- // I32x4LeU => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_le(b).to_int())).to_cf()?,
+ I8x16LeU => stack_op!(binary Value128, |a, b| a.i8x16_le_u(b)),
+ I16x8LeU => stack_op!(binary Value128, |a, b| a.i16x8_le_u(b)),
+ I32x4LeU => stack_op!(binary Value128, |a, b| a.i32x4_le_u(b)),
- // I8x16GeS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
- // I16x8GeS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
- // I32x4GeS => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
- // I64x2GeS => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
+ I8x16GeS => stack_op!(binary Value128, |a, b| a.i8x16_ge_s(b)),
+ I16x8GeS => stack_op!(binary Value128, |a, b| a.i16x8_ge_s(b)),
+ I32x4GeS => stack_op!(binary Value128, |a, b| a.i32x4_ge_s(b)),
+ I64x2GeS => stack_op!(binary Value128, |a, b| a.i64x2_ge_s(b)),
- // I8x16GeU => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
- // I16x8GeU => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
- // I32x4GeU => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_ge(b).to_int())).to_cf()?,
+ I8x16GeU => stack_op!(binary Value128, |a, b| a.i8x16_ge_u(b)),
+ I16x8GeU => stack_op!(binary Value128, |a, b| a.i16x8_ge_u(b)),
+ I32x4GeU => stack_op!(binary Value128, |a, b| a.i32x4_ge_u(b)),
- // I8x16Abs => self.stack.values.replace_top_same::<i8x16>(|a| Ok(a.abs())).to_cf()?,
- // I16x8Abs => self.stack.values.replace_top_same::<i16x8>(|a| Ok(a.abs())).to_cf()?,
- // I32x4Abs => self.stack.values.replace_top_same::<i32x4>(|a| Ok(a.abs())).to_cf()?,
- // I64x2Abs => self.stack.values.replace_top_same::<i64x2>(|a| Ok(a.abs())).to_cf()?,
+ I8x16Abs => stack_op!(unary Value128, |a| a.i8x16_abs()),
+ I16x8Abs => stack_op!(unary Value128, |a| a.i16x8_abs()),
+ I32x4Abs => stack_op!(unary Value128, |a| a.i32x4_abs()),
+ I64x2Abs => stack_op!(unary Value128, |a| a.i64x2_abs()),
- // I8x16Neg => self.stack.values.replace_top_same::<i8x16>(|a| Ok(-a)).to_cf()?,
- // I16x8Neg => self.stack.values.replace_top_same::<i16x8>(|a| Ok(-a)).to_cf()?,
- // I32x4Neg => self.stack.values.replace_top_same::<i32x4>(|a| Ok(-a)).to_cf()?,
- // I64x2Neg => self.stack.values.replace_top_same::<i64x2>(|a| Ok(-a)).to_cf()?,
+ I8x16Neg => stack_op!(unary Value128, |a| a.i8x16_neg()),
+ I16x8Neg => stack_op!(unary Value128, |a| a.i16x8_neg()),
+ I32x4Neg => stack_op!(unary Value128, |a| a.i32x4_neg()),
+ I64x2Neg => stack_op!(unary Value128, |a| a.i64x2_neg()),
- // I8x16AllTrue => self.stack.values.replace_top::<i8x16, i32>(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?,
- // I16x8AllTrue => self.stack.values.replace_top::<i16x8, i32>(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?,
- // I32x4AllTrue => self.stack.values.replace_top::<i32x4, i32>(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?,
- // I64x2AllTrue => self.stack.values.replace_top::<i64x2, i32>(|v| Ok((v.simd_ne(Simd::splat(0)).all()) as i32)).to_cf()?,
+ I8x16AllTrue => stack_op!(unary Value128 => i32, |v| v.i8x16_all_true() as i32),
+ I16x8AllTrue => stack_op!(unary Value128 => i32, |v| v.i16x8_all_true() as i32),
+ I32x4AllTrue => stack_op!(unary Value128 => i32, |v| v.i32x4_all_true() as i32),
+ I64x2AllTrue => stack_op!(unary Value128 => i32, |v| v.i64x2_all_true() as i32),
- // I8x16Bitmask => self.stack.values.replace_top::<i8x16, i32>(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?,
- // I16x8Bitmask => self.stack.values.replace_top::<i16x8, i32>(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?,
- // I32x4Bitmask => self.stack.values.replace_top::<i32x4, i32>(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?,
- // I64x2Bitmask => self.stack.values.replace_top::<i64x2, i32>(|v| Ok(v.simd_lt(Simd::splat(0)).to_bitmask() as i32)).to_cf()?,
+ I8x16Bitmask => stack_op!(unary Value128 => i32, |v| v.i8x16_bitmask() as i32),
+ I16x8Bitmask => stack_op!(unary Value128 => i32, |v| v.i16x8_bitmask() as i32),
+ I32x4Bitmask => stack_op!(unary Value128 => i32, |v| v.i32x4_bitmask() as i32),
+ I64x2Bitmask => stack_op!(unary Value128 => i32, |v| v.i64x2_bitmask() as i32),
- // I8x16Shl => self.stack.values.calculate_diff::<i32, i8x16, i8x16>(|a, b| Ok(b.shl(a as i8))).to_cf()?,
- // I16x8Shl => self.stack.values.calculate_diff::<i32, i16x8, i16x8>(|a, b| Ok(b.shl(a as i16))).to_cf()?,
- // I32x4Shl => self.stack.values.calculate_diff::<i32, i32x4, i32x4>(|a, b| Ok(b.shl(a))).to_cf()?,
- // I64x2Shl => self.stack.values.calculate_diff::<i32, i64x2, i64x2>(|a, b| Ok(b.shl(a as i64))).to_cf()?,
+ I8x16Shl => stack_op!(binary i32, Value128, |a, b| b.i8x16_shl(a as u32)),
+ I16x8Shl => stack_op!(binary i32, Value128, |a, b| b.i16x8_shl(a as u32)),
+ I32x4Shl => stack_op!(binary i32, Value128, |a, b| b.i32x4_shl(a as u32)),
+ I64x2Shl => stack_op!(binary i32, Value128, |a, b| b.i64x2_shl(a as u32)),
- // I8x16ShrS => self.stack.values.calculate_diff::<i32, i8x16, i8x16>(|a, b| Ok(b.shr(a as i8))).to_cf()?,
- // I16x8ShrS => self.stack.values.calculate_diff::<i32, i16x8, i16x8>(|a, b| Ok(b.shr(a as i16))).to_cf()?,
- // I32x4ShrS => self.stack.values.calculate_diff::<i32, i32x4, i32x4>(|a, b| Ok(b.shr(a))).to_cf()?,
- // I64x2ShrS => self.stack.values.calculate_diff::<i32, i64x2, i64x2>(|a, b| Ok(b.shr(a as i64))).to_cf()?,
+ I8x16ShrS => stack_op!(binary i32, Value128, |a, b| b.i8x16_shr_s(a as u32)),
+ I16x8ShrS => stack_op!(binary i32, Value128, |a, b| b.i16x8_shr_s(a as u32)),
+ I32x4ShrS => stack_op!(binary i32, Value128, |a, b| b.i32x4_shr_s(a as u32)),
+ I64x2ShrS => stack_op!(binary i32, Value128, |a, b| b.i64x2_shr_s(a as u32)),
- // I8x16ShrU => self.stack.values.calculate_diff::<i32, u8x16, u8x16>(|a, b| Ok(b.shr(a as u8))).to_cf()?,
- // I16x8ShrU => self.stack.values.calculate_diff::<i32, u16x8, u16x8>(|a, b| Ok(b.shr(a as u16))).to_cf()?,
- // I32x4ShrU => self.stack.values.calculate_diff::<i32, u32x4, u32x4>(|a, b| Ok(b.shr(a as u32))).to_cf()?,
- // I64x2ShrU => self.stack.values.calculate_diff::<i32, u64x2, u64x2>(|a, b| Ok(b.shr(a as u64))).to_cf()?,
-
- // I8x16Add => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a + b)).to_cf()?,
- // I16x8Add => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a + b)).to_cf()?,
- // I32x4Add => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a + b)).to_cf()?,
- // I64x2Add => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a + b)).to_cf()?,
-
- // I8x16Sub => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a - b)).to_cf()?,
- // I16x8Sub => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a - b)).to_cf()?,
- // I32x4Sub => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a - b)).to_cf()?,
- // I64x2Sub => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a - b)).to_cf()?,
-
- // I8x16MinS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_min(b))).to_cf()?,
- // I16x8MinS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_min(b))).to_cf()?,
- // I32x4MinS => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_min(b))).to_cf()?,
-
- // I8x16MinU => self.stack.values.calculate_same::<u8x16>(|a, b| Ok(a.simd_min(b))).to_cf()?,
- // I16x8MinU => self.stack.values.calculate_same::<u16x8>(|a, b| Ok(a.simd_min(b))).to_cf()?,
- // I32x4MinU => self.stack.values.calculate_same::<u32x4>(|a, b| Ok(a.simd_min(b))).to_cf()?,
-
- // I8x16MaxS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_max(b))).to_cf()?,
- // I16x8MaxS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_max(b))).to_cf()?,
- // I32x4MaxS => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a.simd_max(b))).to_cf()?,
-
- // I8x16MaxU => self.stack.values.calculate_same::<u8x16>(|a, b| Ok(a.simd_max(b))).to_cf()?,
- // I16x8MaxU => self.stack.values.calculate_same::<u16x8>(|a, b| Ok(a.simd_max(b))).to_cf()?,
- // I32x4MaxU => self.stack.values.calculate_same::<u32x4>(|a, b| Ok(a.simd_max(b))).to_cf()?,
-
- // I64x2Mul => self.stack.values.calculate_same::<i64x2>(|a, b| Ok(a * b)).to_cf()?,
- // I16x8Mul => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a * b)).to_cf()?,
- // I32x4Mul => self.stack.values.calculate_same::<i32x4>(|a, b| Ok(a * b)).to_cf()?,
-
- // I8x16NarrowI16x8S => unimplemented!(),
- // I8x16NarrowI16x8U => unimplemented!(),
- // I16x8NarrowI32x4S => unimplemented!(),
- // I16x8NarrowI32x4U => unimplemented!(),
-
- // I8x16AddSatS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.saturating_add(b))).to_cf()?,
- // I16x8AddSatS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.saturating_add(b))).to_cf()?,
- // I8x16AddSatU => self.stack.values.calculate_same::<u8x16>(|a, b| Ok(a.saturating_add(b))).to_cf()?,
- // I16x8AddSatU => self.stack.values.calculate_same::<u16x8>(|a, b| Ok(a.saturating_add(b))).to_cf()?,
- // I8x16SubSatS => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.saturating_sub(b))).to_cf()?,
- // I16x8SubSatS => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.saturating_sub(b))).to_cf()?,
- // I8x16SubSatU => self.stack.values.calculate_same::<u8x16>(|a, b| Ok(a.saturating_sub(b))).to_cf()?,
- // I16x8SubSatU => self.stack.values.calculate_same::<u16x8>(|a, b| Ok(a.saturating_sub(b))).to_cf()?,
-
- // I8x16AvgrU => unimplemented!(),
- // I16x8AvgrU => unimplemented!(),
-
- // I16x8ExtAddPairwiseI8x16S => unimplemented!(),
- // I16x8ExtAddPairwiseI8x16U => unimplemented!(),
- // I32x4ExtAddPairwiseI16x8S => unimplemented!(),
- // I32x4ExtAddPairwiseI16x8U => unimplemented!(),
-
- // I16x8ExtMulLowI8x16S => unimplemented!(),
- // I16x8ExtMulLowI8x16U => unimplemented!(),
- // I16x8ExtMulHighI8x16S => unimplemented!(),
- // I16x8ExtMulHighI8x16U => unimplemented!(),
- // I32x4ExtMulLowI16x8S => unimplemented!(),
- // I32x4ExtMulLowI16x8U => unimplemented!(),
- // I32x4ExtMulHighI16x8S => unimplemented!(),
- // I32x4ExtMulHighI16x8U => unimplemented!(),
- // I64x2ExtMulLowI32x4S => unimplemented!(),
- // I64x2ExtMulLowI32x4U => unimplemented!(),
- // I64x2ExtMulHighI32x4S => unimplemented!(),
- // I64x2ExtMulHighI32x4U => unimplemented!(),
-
- // I16x8ExtendLowI8x16S => unimplemented!(),
- // I16x8ExtendLowI8x16U => unimplemented!(),
- // I16x8ExtendHighI8x16S => unimplemented!(),
- // I16x8ExtendHighI8x16U => unimplemented!(),
- // I32x4ExtendLowI16x8S => unimplemented!(),
- // I32x4ExtendLowI16x8U => unimplemented!(),
- // I32x4ExtendHighI16x8S => unimplemented!(),
- // I32x4ExtendHighI16x8U => unimplemented!(),
- // I64x2ExtendLowI32x4S => unimplemented!(),
- // I64x2ExtendLowI32x4U => unimplemented!(),
- // I64x2ExtendHighI32x4S => unimplemented!(),
- // I64x2ExtendHighI32x4U => unimplemented!(),
-
- // I8x16Popcnt => self.stack.values.replace_top::<i8x16, _>(|v| Ok(v.count_ones())).to_cf()?,
- // I8x16Shuffle(_idx) => unimplemented!(),
-
- I16x8Q15MulrSatS => self.stack.values.calculate_same::<Value128>(|a, b| {
- let subq15mulr = |a,b| {
- let a = a as i32;
- let b = b as i32;
- let r = (a * b + 0x4000) >> 15;
- if r > i16::MAX as i32 {
- i16::MAX
- } else if r < i16::MIN as i32 {
- i16::MIN
- } else {
- r as i16
- }
- };
- let a = a.as_i16x8();
- let b = b.as_i16x8();
- Ok(Value128::from_i16x8([
- subq15mulr(a[0], b[0]),
- subq15mulr(a[1], b[1]),
- subq15mulr(a[2], b[2]),
- subq15mulr(a[3], b[3]),
- subq15mulr(a[4], b[4]),
- subq15mulr(a[5], b[5]),
- subq15mulr(a[6], b[6]),
- subq15mulr(a[7], b[7]),
- ]))
- }).to_cf()?,
+ I8x16ShrU => stack_op!(binary i32, Value128, |a, b| b.i8x16_shr_u(a as u32)),
+ I16x8ShrU => stack_op!(binary i32, Value128, |a, b| b.i16x8_shr_u(a as u32)),
+ I32x4ShrU => stack_op!(binary i32, Value128, |a, b| b.i32x4_shr_u(a as u32)),
+ I64x2ShrU => stack_op!(binary i32, Value128, |a, b| b.i64x2_shr_u(a as u32)),
+ I8x16Add => stack_op!(binary Value128, |a, b| a.i8x16_add(b)),
+ I16x8Add => stack_op!(binary Value128, |a, b| a.i16x8_add(b)),
+ I32x4Add => stack_op!(binary Value128, |a, b| a.i32x4_add(b)),
+ I64x2Add => stack_op!(binary Value128, |a, b| a.i64x2_add(b)),
- I32x4DotI16x8S => self.stack.values.calculate::<Value128, Value128>(|a, b| {
- let a = a.as_i16x8();
- let b = b.as_i16x8();
- Ok(Value128::from_i32x4([
- i32::from(a[0] * b[0] + a[1] * b[1]),
- i32::from(a[2] * b[2] + a[3] * b[3]),
- i32::from(a[4] * b[4] + a[5] * b[5]),
- i32::from(a[6] * b[6] + a[7] * b[7]),
- ]))
- }).to_cf()?,
+ I8x16Sub => stack_op!(binary Value128, |a, b| a.i8x16_sub(b)),
+ I16x8Sub => stack_op!(binary Value128, |a, b| a.i16x8_sub(b)),
+ I32x4Sub => stack_op!(binary Value128, |a, b| a.i32x4_sub(b)),
+ I64x2Sub => stack_op!(binary Value128, |a, b| a.i64x2_sub(b)),
- // F32x4Ceil => self.stack.values.replace_top_same::<f32x4>(|v| Ok(v.ceil())).to_cf()?,
- // F64x2Ceil => self.stack.values.replace_top_same::<f64x2>(|v| Ok(v.ceil())).to_cf()?,
- // F32x4Floor => self.stack.values.replace_top_same::<f32x4>(|v| Ok(v.floor())).to_cf()?,
- // F64x2Floor => self.stack.values.replace_top_same::<f64x2>(|v| Ok(v.floor())).to_cf()?,
- // F32x4Trunc => self.stack.values.replace_top_same::<f32x4>(|v| Ok(v.trunc())).to_cf()?,
- // F64x2Trunc => self.stack.values.replace_top_same::<f64x2>(|v| Ok(v.trunc())).to_cf()?,
- // F32x4Nearest => self.stack.values.replace_top_same::<f32x4>(|v| Ok(v.round())).to_cf()?,
- // F64x2Nearest => self.stack.values.replace_top_same::<f64x2>(|v| Ok(v.round())).to_cf()?,
- // F32x4Abs => self.stack.values.replace_top_same::<f32x4>(|v| Ok(v.abs())).to_cf()?,
- // F64x2Abs => self.stack.values.replace_top_same::<f64x2>(|v| Ok(v.abs())).to_cf()?,
- // F32x4Neg => self.stack.values.replace_top_same::<f32x4>(|v| Ok(-v)).to_cf()?,
- // F64x2Neg => self.stack.values.replace_top_same::<f64x2>(|v| Ok(-v)).to_cf()?,
- // F32x4Sqrt => self.stack.values.replace_top_same::<f32x4>(|v| Ok(canonicalize_f32x4(v.sqrt()))).to_cf()?,
- // F64x2Sqrt => self.stack.values.replace_top_same::<f64x2>(|v| Ok(canonicalize_f64x2(v.sqrt()))).to_cf()?,
- // F32x4Add => self.stack.values.calculate_same::<f32x4>(|a, b| Ok(canonicalize_f32x4(a + b))).to_cf()?,
- // F64x2Add => self.stack.values.calculate_same::<f64x2>(|a, b| Ok(canonicalize_f64x2(a + b))).to_cf()?,
- // F32x4Sub => self.stack.values.calculate_same::<f32x4>(|a, b| Ok(canonicalize_f32x4(a - b))).to_cf()?,
- // F64x2Sub => self.stack.values.calculate_same::<f64x2>(|a, b| Ok(canonicalize_f64x2(a - b))).to_cf()?,
- // F32x4Mul => self.stack.values.calculate_same::<f32x4>(|a, b| Ok(canonicalize_f32x4(a * b))).to_cf()?,
- // F64x2Mul => self.stack.values.calculate_same::<f64x2>(|a, b| Ok(canonicalize_f64x2(a * b))).to_cf()?,
- // F32x4Div => self.stack.values.calculate_same::<f32x4>(|a, b| Ok(canonicalize_f32x4(a / b))).to_cf()?,
- // F64x2Div => self.stack.values.calculate_same::<f64x2>(|a, b| Ok(canonicalize_f64x2(a / b))).to_cf()?,
+ I8x16MinS => stack_op!(binary Value128, |a, b| a.i8x16_min_s(b)),
+ I16x8MinS => stack_op!(binary Value128, |a, b| a.i16x8_min_s(b)),
+ I32x4MinS => stack_op!(binary Value128, |a, b| a.i32x4_min_s(b)),
- // F32x4Min => self.stack.values.calculate_same::<f32x4>(|a, b| {
- // Ok(Simd::<f32, 4>::from_array([
- // b[0].tw_minimum(a[0]),
- // b[1].tw_minimum(a[1]),
- // b[2].tw_minimum(a[2]),
- // b[3].tw_minimum(a[3]),
- // ]))
- // }).to_cf()?,
+ I8x16MinU => stack_op!(binary Value128, |a, b| a.i8x16_min_u(b)),
+ I16x8MinU => stack_op!(binary Value128, |a, b| a.i16x8_min_u(b)),
+ I32x4MinU => stack_op!(binary Value128, |a, b| a.i32x4_min_u(b)),
+ I8x16MaxS => stack_op!(binary Value128, |a, b| a.i8x16_max_s(b)),
+ I16x8MaxS => stack_op!(binary Value128, |a, b| a.i16x8_max_s(b)),
+ I32x4MaxS => stack_op!(binary Value128, |a, b| a.i32x4_max_s(b)),
- // F64x2Min => self.stack.values.calculate_same::<f64x2>(|a, b| {
- // Ok(Simd::<f64, 2>::from_array([
- // b[0].tw_minimum(a[0]),
- // b[1].tw_minimum(a[1]),
- // ]))
- // }).to_cf()?,
+ I8x16MaxU => stack_op!(binary Value128, |a, b| a.i8x16_max_u(b)),
+ I16x8MaxU => stack_op!(binary Value128, |a, b| a.i16x8_max_u(b)),
+ I32x4MaxU => stack_op!(binary Value128, |a, b| a.i32x4_max_u(b)),
+ I64x2Mul => stack_op!(binary Value128, |a, b| a.i64x2_mul(b)),
+ I16x8Mul => stack_op!(binary Value128, |a, b| a.i16x8_mul(b)),
+ I32x4Mul => stack_op!(binary Value128, |a, b| a.i32x4_mul(b)),
- // F32x4Max => self.stack.values.calculate_same::<f32x4>(|a, b| {
- // Ok(Simd::<f32, 4>::from_array([
- // b[0].tw_maximum(a[0]),
- // b[1].tw_maximum(a[1]),
- // b[2].tw_maximum(a[2]),
- // b[3].tw_maximum(a[3]),
- // ]))
- // }).to_cf()?,
+ I8x16NarrowI16x8S => stack_op!(binary Value128, |a, b| Value128::i8x16_narrow_i16x8_s(a, b)),
+ I8x16NarrowI16x8U => stack_op!(binary Value128, |a, b| Value128::i8x16_narrow_i16x8_u(a, b)),
+ I16x8NarrowI32x4S => stack_op!(binary Value128, |a, b| Value128::i16x8_narrow_i32x4_s(a, b)),
+ I16x8NarrowI32x4U => stack_op!(binary Value128, |a, b| Value128::i16x8_narrow_i32x4_u(a, b)),
+ I8x16AddSatS => stack_op!(binary Value128, |a, b| a.i8x16_add_sat_s(b)),
+ I16x8AddSatS => stack_op!(binary Value128, |a, b| a.i16x8_add_sat_s(b)),
+ I8x16AddSatU => stack_op!(binary Value128, |a, b| a.i8x16_add_sat_u(b)),
+ I16x8AddSatU => stack_op!(binary Value128, |a, b| a.i16x8_add_sat_u(b)),
+ I8x16SubSatS => stack_op!(binary Value128, |a, b| a.i8x16_sub_sat_s(b)),
+ I16x8SubSatS => stack_op!(binary Value128, |a, b| a.i16x8_sub_sat_s(b)),
+ I8x16SubSatU => stack_op!(binary Value128, |a, b| a.i8x16_sub_sat_u(b)),
+ I16x8SubSatU => stack_op!(binary Value128, |a, b| a.i16x8_sub_sat_u(b)),
- // F64x2Max => self.stack.values.calculate_same::<f64x2>(|a, b| {
- // Ok(Simd::<f64, 2>::from_array([
- // b[0].tw_maximum(a[0]),
- // b[1].tw_maximum(a[1]),
- // ]))
- // }).to_cf()?,
+ I8x16AvgrU => stack_op!(binary Value128, |a, b| a.i8x16_avgr_u(b)),
+ I16x8AvgrU => stack_op!(binary Value128, |a, b| a.i16x8_avgr_u(b)),
+ I16x8ExtAddPairwiseI8x16S => stack_op!(unary Value128, |a| a.i16x8_extadd_pairwise_i8x16_s()),
+ I16x8ExtAddPairwiseI8x16U => stack_op!(unary Value128, |a| a.i16x8_extadd_pairwise_i8x16_u()),
+ I32x4ExtAddPairwiseI16x8S => stack_op!(unary Value128, |a| a.i32x4_extadd_pairwise_i16x8_s()),
+ I32x4ExtAddPairwiseI16x8U => stack_op!(unary Value128, |a| a.i32x4_extadd_pairwise_i16x8_u()),
- // F32x4PMin => self.stack.values.calculate_same::<f32x4>(|a, b| {
- // Ok(Simd::<f32, 4>::from_array([
- // if b[0] < a[0] { b[0] } else { a[0]},
- // if b[1] < a[1] { b[1] } else { a[1]},
- // if b[2] < a[2] { b[2] } else { a[2]},
- // if b[3] < a[3] { b[3] } else { a[3]},
- // ]))
- // }).to_cf()?,
+ I16x8ExtMulLowI8x16S => stack_op!(binary Value128, |a, b| a.i16x8_extmul_low_i8x16_s(b)),
+ I16x8ExtMulLowI8x16U => stack_op!(binary Value128, |a, b| a.i16x8_extmul_low_i8x16_u(b)),
+ I16x8ExtMulHighI8x16S => stack_op!(binary Value128, |a, b| a.i16x8_extmul_high_i8x16_s(b)),
+ I16x8ExtMulHighI8x16U => stack_op!(binary Value128, |a, b| a.i16x8_extmul_high_i8x16_u(b)),
+ I32x4ExtMulLowI16x8S => stack_op!(binary Value128, |a, b| a.i32x4_extmul_low_i16x8_s(b)),
+ I32x4ExtMulLowI16x8U => stack_op!(binary Value128, |a, b| a.i32x4_extmul_low_i16x8_u(b)),
+ I32x4ExtMulHighI16x8S => stack_op!(binary Value128, |a, b| a.i32x4_extmul_high_i16x8_s(b)),
+ I32x4ExtMulHighI16x8U => stack_op!(binary Value128, |a, b| a.i32x4_extmul_high_i16x8_u(b)),
+ I64x2ExtMulLowI32x4S => stack_op!(binary Value128, |a, b| a.i64x2_extmul_low_i32x4_s(b)),
+ I64x2ExtMulLowI32x4U => stack_op!(binary Value128, |a, b| a.i64x2_extmul_low_i32x4_u(b)),
+ I64x2ExtMulHighI32x4S => stack_op!(binary Value128, |a, b| a.i64x2_extmul_high_i32x4_s(b)),
+ I64x2ExtMulHighI32x4U => stack_op!(binary Value128, |a, b| a.i64x2_extmul_high_i32x4_u(b)),
+ I16x8ExtendLowI8x16S => stack_op!(unary Value128, |a| a.i16x8_extend_low_i8x16_s()),
+ I16x8ExtendLowI8x16U => stack_op!(unary Value128, |a| a.i16x8_extend_low_i8x16_u()),
+ I16x8ExtendHighI8x16S => stack_op!(unary Value128, |a| a.i16x8_extend_high_i8x16_s()),
+ I16x8ExtendHighI8x16U => stack_op!(unary Value128, |a| a.i16x8_extend_high_i8x16_u()),
+ I32x4ExtendLowI16x8S => stack_op!(unary Value128, |a| a.i32x4_extend_low_i16x8_s()),
+ I32x4ExtendLowI16x8U => stack_op!(unary Value128, |a| a.i32x4_extend_low_i16x8_u()),
+ I32x4ExtendHighI16x8S => stack_op!(unary Value128, |a| a.i32x4_extend_high_i16x8_s()),
+ I32x4ExtendHighI16x8U => stack_op!(unary Value128, |a| a.i32x4_extend_high_i16x8_u()),
+ I64x2ExtendLowI32x4S => stack_op!(unary Value128, |a| a.i64x2_extend_low_i32x4_s()),
+ I64x2ExtendLowI32x4U => stack_op!(unary Value128, |a| a.i64x2_extend_low_i32x4_u()),
+ I64x2ExtendHighI32x4S => stack_op!(unary Value128, |a| a.i64x2_extend_high_i32x4_s()),
+ I64x2ExtendHighI32x4U => stack_op!(unary Value128, |a| a.i64x2_extend_high_i32x4_u()),
- // F32x4PMax => self.stack.values.calculate_same::<f32x4>(|a, b| {
- // Ok(Simd::<f32, 4>::from_array([
- // if b[0] > a[0] { b[0] } else { a[0]},
- // if b[1] > a[1] { b[1] } else { a[1]},
- // if b[2] > a[2] { b[2] } else { a[2]},
- // if b[3] > a[3] { b[3] } else { a[3]},
- // ]))
- // }).to_cf()?,
+ I8x16Popcnt => stack_op!(unary Value128, |v| v.i8x16_popcnt()),
+ I8x16Shuffle(idx) => { let idx = self.cf.data().v128_constants[*idx as usize].to_le_bytes(); stack_op!(binary Value128, |a, b| Value128::i8x16_shuffle(a, b, idx)) }
+ I16x8Q15MulrSatS => stack_op!(binary Value128, |a, b| a.i16x8_q15mulr_sat_s(b)),
- // F64x2PMin => self.stack.values.calculate_same::<f64x2>(|a, b| {
- // Ok(Simd::<f64, 2>::from_array([
- // if b[0] < a[0] { b[0] } else { a[0]},
- // if b[1] < a[1] { b[1] } else { a[1]},
- // ]))
- // }).to_cf()?,
+ I32x4DotI16x8S => stack_op!(binary Value128, |a, b| a.i32x4_dot_i16x8_s(b)),
+ F32x4Ceil => stack_op!(simd_unary f32x4_ceil),
+ F64x2Ceil => stack_op!(simd_unary f64x2_ceil),
+ F32x4Floor => stack_op!(simd_unary f32x4_floor),
+ F64x2Floor => stack_op!(simd_unary f64x2_floor),
+ F32x4Trunc => stack_op!(simd_unary f32x4_trunc),
+ F64x2Trunc => stack_op!(simd_unary f64x2_trunc),
+ F32x4Nearest => stack_op!(simd_unary f32x4_nearest),
+ F64x2Nearest => stack_op!(simd_unary f64x2_nearest),
+ F32x4Abs => stack_op!(simd_unary f32x4_abs),
+ F64x2Abs => stack_op!(simd_unary f64x2_abs),
+ F32x4Neg => stack_op!(simd_unary f32x4_neg),
+ F64x2Neg => stack_op!(simd_unary f64x2_neg),
+ F32x4Sqrt => stack_op!(simd_unary f32x4_sqrt),
+ F64x2Sqrt => stack_op!(simd_unary f64x2_sqrt),
+ F32x4Add => stack_op!(simd_binary f32x4_add),
+ F64x2Add => stack_op!(simd_binary f64x2_add),
+ F32x4Sub => stack_op!(simd_binary f32x4_sub),
+ F64x2Sub => stack_op!(simd_binary f64x2_sub),
+ F32x4Mul => stack_op!(simd_binary f32x4_mul),
+ F64x2Mul => stack_op!(simd_binary f64x2_mul),
+ F32x4Div => stack_op!(simd_binary f32x4_div),
+ F64x2Div => stack_op!(simd_binary f64x2_div),
- // F64x2PMax => self.stack.values.calculate_same::<f64x2>(|a, b| {
- // Ok(Simd::<f64, 2>::from_array([
- // if b[0] > a[0] { b[0] } else { a[0]},
- // if b[1] > a[1] { b[1] } else { a[1]},
- // ]))
- // }).to_cf()?,
+ F32x4Min => stack_op!(simd_binary f32x4_min),
+ F64x2Min => stack_op!(simd_binary f64x2_min),
+ F32x4Max => stack_op!(simd_binary f32x4_max),
+ F64x2Max => stack_op!(simd_binary f64x2_max),
+ F32x4PMin => stack_op!(simd_binary f32x4_pmin),
+ F32x4PMax => stack_op!(simd_binary f32x4_pmax),
+ F64x2PMin => stack_op!(simd_binary f64x2_pmin),
+ F64x2PMax => stack_op!(simd_binary f64x2_pmax),
- // // not correct
- // I32x4TruncSatF32x4S => self.stack.values.replace_top::<f32x4, f32x4>(|v| Ok(v.trunc())).to_cf()?,
- // I32x4TruncSatF32x4U => self.stack.values.replace_top::<f32x4, f32x4>(|v| Ok(v.trunc())).to_cf()?,
- // F32x4ConvertI32x4S => unimplemented!(),
- // F32x4ConvertI32x4U => unimplemented!(),
- // F64x2ConvertLowI32x4S => unimplemented!(),
- // F64x2ConvertLowI32x4U => unimplemented!(),
- // F32x4DemoteF64x2Zero => unimplemented!(),
- // F64x2PromoteLowF32x4 => unimplemented!(),
- // I32x4TruncSatF64x2SZero => unimplemented!(),
- // I32x4TruncSatF64x2UZero => unimplemented!(),
+ I32x4TruncSatF32x4S => stack_op!(unary Value128, |v| v.i32x4_trunc_sat_f32x4_s()),
+ I32x4TruncSatF32x4U => stack_op!(unary Value128, |v| v.i32x4_trunc_sat_f32x4_u()),
+ F32x4ConvertI32x4S => stack_op!(unary Value128, |v| v.f32x4_convert_i32x4_s()),
+ F32x4ConvertI32x4U => stack_op!(unary Value128, |v| v.f32x4_convert_i32x4_u()),
+ F64x2ConvertLowI32x4S => stack_op!(unary Value128, |v| v.f64x2_convert_low_i32x4_s()),
+ F64x2ConvertLowI32x4U => stack_op!(unary Value128, |v| v.f64x2_convert_low_i32x4_u()),
+ F32x4DemoteF64x2Zero => stack_op!(unary Value128, |v| v.f32x4_demote_f64x2_zero()),
+ F64x2PromoteLowF32x4 => stack_op!(unary Value128, |v| v.f64x2_promote_low_f32x4()),
+ I32x4TruncSatF64x2SZero => stack_op!(unary Value128, |v| v.i32x4_trunc_sat_f64x2_s_zero()),
+ I32x4TruncSatF64x2UZero => stack_op!(unary Value128, |v| v.i32x4_trunc_sat_f64x2_u_zero()),
+ // Relaxed SIMD (not yet implemented)
// I8x16RelaxedSwizzle => unimplemented!(),
// I32x4RelaxedTruncF32x4S => unimplemented!(),
// I32x4RelaxedTruncF32x4U => unimplemented!(),
@@ -1094,8 +1035,10 @@ impl<'store, 'stack> Executor<'store, 'stack> {
lane: u8,
) -> ControlFlow<Option<Error>> {
let mem = self.store.get_mem_mut(self.module.resolve_mem_addr(mem_addr));
- let val = self.stack.values.pop::<Value128>().to_mem_bytes();
- let val = val[lane as usize].to_mem_bytes();
+ let bytes = self.stack.values.pop::<Value128>().to_mem_bytes();
+ let lane_offset = lane as usize * N;
+ let mut val = [0u8; N];
+ val.copy_from_slice(&bytes[lane_offset..lane_offset + N]);
let addr = match mem.is_64bit() {
true => self.stack.values.pop::<i64>() as u64,
diff --git a/crates/tinywasm/src/interpreter/num_helpers.rs b/crates/tinywasm/src/interpreter/num_helpers.rs
index 0356403..5b9e7b9 100644
--- a/crates/tinywasm/src/interpreter/num_helpers.rs
+++ b/crates/tinywasm/src/interpreter/num_helpers.rs
@@ -37,7 +37,7 @@ macro_rules! checked_conv_float {
$self
.stack
.values
- .replace_top::<$from, $to>(|v| {
+ .unary::<$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/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs
index 6e02b0f..2850e91 100644
--- a/crates/tinywasm/src/interpreter/stack/value_stack.rs
+++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs
@@ -1,7 +1,7 @@
use alloc::vec::Vec;
use tinywasm_types::{ExternRef, FuncRef, ValType, ValueCounts, ValueCountsSmall, WasmValue};
-use crate::{Result, StackConfig, interpreter::*};
+use crate::{interpreter::*, Result, StackConfig};
use super::Locals;
@@ -63,18 +63,18 @@ impl ValueStack {
}
#[inline]
- pub(crate) fn calculate_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T) -> Result<T>) -> Result<()> {
+ pub(crate) fn binary_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T) -> Result<T>) -> Result<()> {
T::stack_calculate(self, func)
}
#[inline]
#[allow(dead_code)]
- pub(crate) fn calculate_same_3<T: InternalValue>(&mut self, func: impl FnOnce(T, T, T) -> Result<T>) -> Result<()> {
+ pub(crate) fn ternary_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T, T) -> Result<T>) -> Result<()> {
T::stack_calculate3(self, func)
}
#[inline]
- pub(crate) fn calculate<T: InternalValue, U: InternalValue>(
+ pub(crate) fn binary<T: InternalValue, U: InternalValue>(
&mut self,
func: impl FnOnce(T, T) -> Result<U>,
) -> Result<()> {
@@ -86,7 +86,7 @@ impl ValueStack {
#[inline]
#[allow(dead_code)]
- pub(crate) fn calculate_diff<A: InternalValue, B: InternalValue, RES: InternalValue>(
+ pub(crate) fn binary_diff<A: InternalValue, B: InternalValue, RES: InternalValue>(
&mut self,
func: impl FnOnce(A, B) -> Result<RES>,
) -> Result<()> {
@@ -97,7 +97,7 @@ impl ValueStack {
}
#[inline]
- pub(crate) fn replace_top<T: InternalValue, U: InternalValue>(
+ pub(crate) fn unary<T: InternalValue, U: InternalValue>(
&mut self,
func: impl FnOnce(T) -> Result<U>,
) -> Result<()> {
@@ -107,7 +107,7 @@ impl ValueStack {
}
#[inline]
- pub(crate) fn replace_top_same<T: InternalValue>(&mut self, func: impl Fn(T) -> Result<T>) -> Result<()> {
+ pub(crate) fn unary_same<T: InternalValue>(&mut self, func: impl Fn(T) -> Result<T>) -> Result<()> {
T::replace_top(self, func)
}
diff --git a/crates/tinywasm/src/interpreter/value128.rs b/crates/tinywasm/src/interpreter/value128.rs
index fcd208f..6b807c9 100644
--- a/crates/tinywasm/src/interpreter/value128.rs
+++ b/crates/tinywasm/src/interpreter/value128.rs
@@ -1,7 +1,84 @@
+use super::num_helpers::TinywasmFloatExt;
+
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Value128(i128);
impl Value128 {
+ #[inline]
+ fn canonicalize_simd_f32_nan(x: f32) -> f32 {
+ if x.is_nan() {
+ f32::from_bits(0x7fc0_0000)
+ } else {
+ x
+ }
+ }
+
+ #[inline]
+ fn canonicalize_simd_f64_nan(x: f64) -> f64 {
+ if x.is_nan() {
+ f64::from_bits(0x7ff8_0000_0000_0000)
+ } else {
+ x
+ }
+ }
+
+ 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
+ }
+ }
+
+ 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
+ }
+ }
+
+ 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
+ }
+ }
+
+ 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
+ }
+ }
+
+ const fn replace_lane_bytes<const LANE_BYTES: usize>(
+ self,
+ lane: u8,
+ value: [u8; LANE_BYTES],
+ lane_count: u8,
+ ) -> Self {
+ debug_assert!(lane < lane_count);
+ let mut bytes = self.to_le_bytes();
+ let mut i = 0;
+ let start = lane as usize * LANE_BYTES;
+ while i < LANE_BYTES {
+ bytes[start + i] = value[i];
+ i += 1;
+ }
+ Self::from_le_bytes(bytes)
+ }
+
pub const fn from_le_bytes(bytes: [u8; 16]) -> Self {
Self(i128::from_le_bytes(bytes))
}
@@ -119,6 +196,32 @@ impl Value128 {
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])])
+ }
+
+ #[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])])
+ }
+
+ #[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])])
+ }
+
+ #[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])])
+ }
+
pub const fn reduce_or(self) -> u8 {
let mut result = 0u8;
let bytes = self.to_le_bytes();
@@ -130,7 +233,111 @@ impl Value128 {
result
}
+ #[doc(alias = "v128.any_true")]
+ pub const fn v128_any_true(self) -> bool {
+ self.reduce_or() != 0
+ }
+
+ #[doc(alias = "v128.not")]
+ pub const fn v128_not(self) -> Self {
+ Self(!self.0)
+ }
+
+ #[doc(alias = "v128.and")]
+ pub const fn v128_and(self, rhs: Self) -> Self {
+ Self(self.0 & rhs.0)
+ }
+
+ #[doc(alias = "v128.andnot")]
+ pub const fn v128_andnot(self, rhs: Self) -> Self {
+ Self(self.0 & !rhs.0)
+ }
+
+ #[doc(alias = "v128.or")]
+ pub const fn v128_or(self, rhs: Self) -> Self {
+ Self(self.0 | rhs.0)
+ }
+
+ #[doc(alias = "v128.xor")]
+ pub const fn v128_xor(self, rhs: Self) -> Self {
+ Self(self.0 ^ rhs.0)
+ }
+
+ #[doc(alias = "v128.bitselect")]
+ pub const fn v128_bitselect(v1: Self, v2: Self, c: Self) -> Self {
+ Self((v1.0 & c.0) | (v2.0 & !c.0))
+ }
+
pub const 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([
+ src[0] as i8 as i16,
+ src[1] as i8 as i16,
+ src[2] as i8 as i16,
+ src[3] as i8 as i16,
+ src[4] as i8 as i16,
+ src[5] as i8 as i16,
+ src[6] as i8 as i16,
+ src[7] as i8 as i16,
+ ])
+ }
+
+ #[doc(alias = "v128.load8x8_u")]
+ pub const fn v128_load8x8_u(src: [u8; 8]) -> Self {
+ Self::from_u16x8([
+ src[0] as u16,
+ src[1] as u16,
+ src[2] as u16,
+ src[3] as u16,
+ src[4] as u16,
+ src[5] as u16,
+ src[6] as u16,
+ src[7] as u16,
+ ])
+ }
+
+ #[doc(alias = "v128.load16x4_s")]
+ pub const fn v128_load16x4_s(src: [u8; 8]) -> Self {
+ Self::from_i32x4([
+ i16::from_le_bytes([src[0], src[1]]) as i32,
+ i16::from_le_bytes([src[2], src[3]]) as i32,
+ i16::from_le_bytes([src[4], src[5]]) as i32,
+ i16::from_le_bytes([src[6], src[7]]) as i32,
+ ])
+ }
+
+ #[doc(alias = "v128.load16x4_u")]
+ pub const fn v128_load16x4_u(src: [u8; 8]) -> Self {
+ Self::from_u32x4([
+ u16::from_le_bytes([src[0], src[1]]) as u32,
+ u16::from_le_bytes([src[2], src[3]]) as u32,
+ u16::from_le_bytes([src[4], src[5]]) as u32,
+ u16::from_le_bytes([src[6], src[7]]) as u32,
+ ])
+ }
+
+ #[doc(alias = "v128.load32x2_s")]
+ pub const fn v128_load32x2_s(src: [u8; 8]) -> Self {
+ Self::from_i64x2([
+ i32::from_le_bytes([src[0], src[1], src[2], src[3]]) as i64,
+ i32::from_le_bytes([src[4], src[5], src[6], src[7]]) as i64,
+ ])
+ }
+
+ #[doc(alias = "v128.load32x2_u")]
+ pub const fn v128_load32x2_u(src: [u8; 8]) -> Self {
+ Self::from_u64x2([
+ u32::from_le_bytes([src[0], src[1], src[2], src[3]]) as u64,
+ u32::from_le_bytes([src[4], src[5], src[6], src[7]]) as u64,
+ ])
+ }
+
+ #[doc(alias = "i8x16.swizzle")]
+ pub const fn i8x16_swizzle(self, s: Self) -> Self {
let a_bytes = self.to_le_bytes();
let s_bytes = s.to_le_bytes();
let mut result_bytes = [0u8; 16];
@@ -143,6 +350,20 @@ impl Value128 {
Self::from_le_bytes(result_bytes)
}
+ #[doc(alias = "i8x16.shuffle")]
+ pub const fn i8x16_shuffle(a: Self, b: Self, idx: [u8; 16]) -> Self {
+ let a_bytes = a.to_le_bytes();
+ let b_bytes = b.to_le_bytes();
+ let mut result_bytes = [0u8; 16];
+ let mut i = 0;
+ while i < 16 {
+ let index = idx[i] as usize;
+ result_bytes[i] = if index < 16 { a_bytes[index] } else { b_bytes[index - 16] };
+ i += 1;
+ }
+ 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;
@@ -240,6 +461,1949 @@ impl Value128 {
Self::from_le_bytes(result_bytes)
}
+ #[doc(alias = "i8x16.replace_lane")]
+ pub const fn i8x16_replace_lane(self, lane: u8, value: i8) -> Self {
+ self.replace_lane_bytes::<1>(lane, [value as u8], 16)
+ }
+
+ #[doc(alias = "i16x8.replace_lane")]
+ pub const fn i16x8_replace_lane(self, lane: u8, value: i16) -> Self {
+ self.replace_lane_bytes::<2>(lane, value.to_le_bytes(), 8)
+ }
+
+ #[doc(alias = "i32x4.replace_lane")]
+ pub const fn i32x4_replace_lane(self, lane: u8, value: i32) -> Self {
+ self.replace_lane_bytes::<4>(lane, value.to_le_bytes(), 4)
+ }
+
+ #[doc(alias = "i64x2.replace_lane")]
+ pub const fn i64x2_replace_lane(self, lane: u8, value: i64) -> Self {
+ self.replace_lane_bytes::<8>(lane, value.to_le_bytes(), 2)
+ }
+
+ #[doc(alias = "f32x4.replace_lane")]
+ pub const fn f32x4_replace_lane(self, lane: u8, value: f32) -> Self {
+ self.replace_lane_bytes::<4>(lane, value.to_bits().to_le_bytes(), 4)
+ }
+
+ #[doc(alias = "f64x2.replace_lane")]
+ pub const fn f64x2_replace_lane(self, lane: u8, value: f64) -> Self {
+ 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
+ }
+
+ #[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
+ }
+
+ #[doc(alias = "i8x16.popcnt")]
+ pub const fn i8x16_popcnt(self) -> Self {
+ let lanes = self.as_u8x16();
+ let mut out = [0u8; 16];
+ let mut i = 0;
+ while i < 16 {
+ out[i] = lanes[i].count_ones() as u8;
+ i += 1;
+ }
+ 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 const fn i8x16_add(self, rhs: Self) -> Self {
+ 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 const fn i16x8_add(self, rhs: Self) -> Self {
+ 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 const fn i32x4_add(self, rhs: Self) -> Self {
+ 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 const fn i64x2_add(self, rhs: Self) -> Self {
+ 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 const fn i8x16_sub(self, rhs: Self) -> Self {
+ 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 const fn i16x8_sub(self, rhs: Self) -> Self {
+ 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 const fn i32x4_sub(self, rhs: Self) -> Self {
+ 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 const fn i64x2_sub(self, rhs: Self) -> Self {
+ 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 const fn i16x8_mul(self, rhs: Self) -> Self {
+ 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 const fn i32x4_mul(self, rhs: Self) -> Self {
+ 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 const fn i64x2_mul(self, rhs: Self) -> Self {
+ 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 const fn i8x16_add_sat_s(self, rhs: Self) -> Self {
+ 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 const fn i16x8_add_sat_s(self, rhs: Self) -> Self {
+ 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 const fn i8x16_add_sat_u(self, rhs: Self) -> Self {
+ 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 const fn i16x8_add_sat_u(self, rhs: Self) -> Self {
+ 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 const fn i8x16_sub_sat_s(self, rhs: Self) -> Self {
+ 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)
+ }
+
+ #[doc(alias = "i16x8.sub_sat_s")]
+ pub const fn i16x8_sub_sat_s(self, rhs: Self) -> Self {
+ 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)
+ }
+
+ #[doc(alias = "i8x16.sub_sat_u")]
+ pub const fn i8x16_sub_sat_u(self, rhs: Self) -> Self {
+ 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)
+ }
+
+ #[doc(alias = "i16x8.sub_sat_u")]
+ pub const fn i16x8_sub_sat_u(self, rhs: Self) -> Self {
+ 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)
+ }
+
+ #[doc(alias = "i8x16.avgr_u")]
+ pub const fn i8x16_avgr_u(self, rhs: Self) -> Self {
+ 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)
+ }
+
+ #[doc(alias = "i16x8.avgr_u")]
+ pub const fn i16x8_avgr_u(self, rhs: Self) -> Self {
+ 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)
+ }
+
+ #[doc(alias = "i8x16.narrow_i16x8_s")]
+ pub const fn i8x16_narrow_i16x8_s(a: Self, b: Self) -> Self {
+ let av = a.as_i16x8();
+ let bv = b.as_i16x8();
+ let mut out = [0i8; 16];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = Self::saturate_i16_to_i8(av[i]);
+ out[i + 8] = Self::saturate_i16_to_i8(bv[i]);
+ i += 1;
+ }
+ Self::from_i8x16(out)
+ }
+
+ #[doc(alias = "i8x16.narrow_i16x8_u")]
+ pub const fn i8x16_narrow_i16x8_u(a: Self, b: Self) -> Self {
+ let av = a.as_i16x8();
+ let bv = b.as_i16x8();
+ let mut out = [0u8; 16];
+ let mut i = 0;
+ while i < 8 {
+ out[i] = Self::saturate_i16_to_u8(av[i]);
+ out[i + 8] = Self::saturate_i16_to_u8(bv[i]);
+ i += 1;
+ }
+ Self::from_u8x16(out)
+ }
+
+ #[doc(alias = "i16x8.narrow_i32x4_s")]
+ pub const fn i16x8_narrow_i32x4_s(a: Self, b: Self) -> Self {
+ let av = a.as_i32x4();
+ let bv = b.as_i32x4();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = Self::saturate_i32_to_i16(av[i]);
+ out[i + 4] = Self::saturate_i32_to_i16(bv[i]);
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i16x8.narrow_i32x4_u")]
+ pub const fn i16x8_narrow_i32x4_u(a: Self, b: Self) -> Self {
+ let av = a.as_i32x4();
+ let bv = b.as_i32x4();
+ let mut out = [0u16; 8];
+ let mut i = 0;
+ while i < 4 {
+ out[i] = Self::saturate_i32_to_u16(av[i]);
+ out[i + 4] = Self::saturate_i32_to_u16(bv[i]);
+ i += 1;
+ }
+ Self::from_u16x8(out)
+ }
+
+ #[doc(alias = "i16x8.extadd_pairwise_i8x16_s")]
+ pub const fn i16x8_extadd_pairwise_i8x16_s(self) -> Self {
+ let lanes = self.as_i8x16();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ let j = i * 2;
+ out[i] = lanes[j] as i16 + lanes[j + 1] as i16;
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i16x8.extadd_pairwise_i8x16_u")]
+ pub const fn i16x8_extadd_pairwise_i8x16_u(self) -> Self {
+ let lanes = self.as_u8x16();
+ let mut out = [0u16; 8];
+ let mut i = 0;
+ while i < 8 {
+ let j = i * 2;
+ out[i] = lanes[j] as u16 + lanes[j + 1] as u16;
+ i += 1;
+ }
+ Self::from_u16x8(out)
+ }
+
+ #[doc(alias = "i32x4.extadd_pairwise_i16x8_s")]
+ pub const fn i32x4_extadd_pairwise_i16x8_s(self) -> Self {
+ let lanes = self.as_i16x8();
+ let mut out = [0i32; 4];
+ let mut i = 0;
+ while i < 4 {
+ let j = i * 2;
+ out[i] = lanes[j] as i32 + lanes[j + 1] as i32;
+ i += 1;
+ }
+ Self::from_i32x4(out)
+ }
+
+ #[doc(alias = "i32x4.extadd_pairwise_i16x8_u")]
+ pub const fn i32x4_extadd_pairwise_i16x8_u(self) -> Self {
+ let lanes = self.as_u16x8();
+ let mut out = [0u32; 4];
+ let mut i = 0;
+ while i < 4 {
+ let j = i * 2;
+ out[i] = lanes[j] as u32 + lanes[j + 1] as u32;
+ i += 1;
+ }
+ 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)
+ }
+
+ #[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)
+ }
+
+ #[doc(alias = "i16x8.q15mulr_sat_s")]
+ pub const fn i16x8_q15mulr_sat_s(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ let mut out = [0i16; 8];
+ let mut i = 0;
+ while i < 8 {
+ let r = ((a[i] as i32 * b[i] as i32) + 0x4000) >> 15;
+ out[i] = if r > i16::MAX as i32 {
+ i16::MAX
+ } else if r < i16::MIN as i32 {
+ i16::MIN
+ } else {
+ r as i16
+ };
+ i += 1;
+ }
+ Self::from_i16x8(out)
+ }
+
+ #[doc(alias = "i32x4.dot_i16x8_s")]
+ pub const fn i32x4_dot_i16x8_s(self, rhs: Self) -> Self {
+ let a = self.as_i16x8();
+ let b = rhs.as_i16x8();
+ Self::from_i32x4([
+ (a[0] as i32).wrapping_mul(b[0] as i32).wrapping_add((a[1] as i32).wrapping_mul(b[1] as i32)),
+ (a[2] as i32).wrapping_mul(b[2] as i32).wrapping_add((a[3] as i32).wrapping_mul(b[3] as i32)),
+ (a[4] as i32).wrapping_mul(b[4] as i32).wrapping_add((a[5] as i32).wrapping_mul(b[5] as i32)),
+ (a[6] as i32).wrapping_mul(b[6] as i32).wrapping_add((a[7] as i32).wrapping_mul(b[7] as i32)),
+ ])
+ }
+
+ #[doc(alias = "i8x16.eq")]
+ pub const fn i8x16_eq(self, rhs: Self) -> Self {
+ 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 const fn i16x8_eq(self, rhs: Self) -> Self {
+ 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 const fn i32x4_eq(self, rhs: Self) -> Self {
+ 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 const fn i64x2_eq(self, rhs: Self) -> Self {
+ 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 const fn i8x16_ne(self, rhs: Self) -> Self {
+ 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 const fn i16x8_ne(self, rhs: Self) -> Self {
+ 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 const fn i32x4_ne(self, rhs: Self) -> Self {
+ 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 const fn i64x2_ne(self, rhs: Self) -> Self {
+ 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 const fn i8x16_lt_s(self, rhs: Self) -> Self {
+ 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 const fn i16x8_lt_s(self, rhs: Self) -> Self {
+ 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 const fn i32x4_lt_s(self, rhs: Self) -> Self {
+ 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 const fn i64x2_lt_s(self, rhs: Self) -> Self {
+ 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 const fn i8x16_lt_u(self, rhs: Self) -> Self {
+ 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 const fn i16x8_lt_u(self, rhs: Self) -> Self {
+ 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 const fn i32x4_lt_u(self, rhs: Self) -> Self {
+ 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 const fn i8x16_gt_s(self, rhs: Self) -> Self {
+ rhs.i8x16_lt_s(self)
+ }
+
+ #[doc(alias = "i16x8.gt_s")]
+ pub const fn i16x8_gt_s(self, rhs: Self) -> Self {
+ rhs.i16x8_lt_s(self)
+ }
+
+ #[doc(alias = "i32x4.gt_s")]
+ pub const fn i32x4_gt_s(self, rhs: Self) -> Self {
+ rhs.i32x4_lt_s(self)
+ }
+
+ #[doc(alias = "i64x2.gt_s")]
+ pub const fn i64x2_gt_s(self, rhs: Self) -> Self {
+ rhs.i64x2_lt_s(self)
+ }
+
+ #[doc(alias = "i8x16.gt_u")]
+ pub const fn i8x16_gt_u(self, rhs: Self) -> Self {
+ rhs.i8x16_lt_u(self)
+ }
+
+ #[doc(alias = "i16x8.gt_u")]
+ pub const fn i16x8_gt_u(self, rhs: Self) -> Self {
+ rhs.i16x8_lt_u(self)
+ }
+
+ #[doc(alias = "i32x4.gt_u")]
+ pub const fn i32x4_gt_u(self, rhs: Self) -> Self {
+ rhs.i32x4_lt_u(self)
+ }
+
+ #[doc(alias = "i8x16.le_s")]
+ pub const fn i8x16_le_s(self, rhs: Self) -> Self {
+ rhs.i8x16_ge_s(self)
+ }
+
+ #[doc(alias = "i16x8.le_s")]
+ pub const fn i16x8_le_s(self, rhs: Self) -> Self {
+ rhs.i16x8_ge_s(self)
+ }
+
+ #[doc(alias = "i32x4.le_s")]
+ pub const fn i32x4_le_s(self, rhs: Self) -> Self {
+ rhs.i32x4_ge_s(self)
+ }
+
+ #[doc(alias = "i64x2.le_s")]
+ pub const fn i64x2_le_s(self, rhs: Self) -> Self {
+ rhs.i64x2_ge_s(self)
+ }
+
+ #[doc(alias = "i8x16.le_u")]
+ pub const fn i8x16_le_u(self, rhs: Self) -> Self {
+ rhs.i8x16_ge_u(self)
+ }
+
+ #[doc(alias = "i16x8.le_u")]
+ pub const fn i16x8_le_u(self, rhs: Self) -> Self {
+ rhs.i16x8_ge_u(self)
+ }
+
+ #[doc(alias = "i32x4.le_u")]
+ pub const fn i32x4_le_u(self, rhs: Self) -> Self {
+ rhs.i32x4_ge_u(self)
+ }
+
+ #[doc(alias = "i8x16.ge_s")]
+ pub const fn i8x16_ge_s(self, rhs: Self) -> Self {
+ 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 const fn i16x8_ge_s(self, rhs: Self) -> Self {
+ 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 const fn i32x4_ge_s(self, rhs: Self) -> Self {
+ 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 const fn i64x2_ge_s(self, rhs: Self) -> Self {
+ 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 const fn i8x16_ge_u(self, rhs: Self) -> Self {
+ 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 const fn i16x8_ge_u(self, rhs: Self) -> Self {
+ 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 const fn i32x4_ge_u(self, rhs: Self) -> Self {
+ 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 const fn i8x16_neg(self) -> Self {
+ 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 const fn i16x8_neg(self) -> Self {
+ 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 const fn i32x4_neg(self) -> Self {
+ 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 const fn i64x2_neg(self) -> Self {
+ 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 const fn i8x16_min_s(self, rhs: Self) -> Self {
+ 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 const fn i16x8_min_s(self, rhs: Self) -> Self {
+ 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 const fn i32x4_min_s(self, rhs: Self) -> Self {
+ 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 const fn i8x16_min_u(self, rhs: Self) -> Self {
+ 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 const fn i16x8_min_u(self, rhs: Self) -> Self {
+ 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 const fn i32x4_min_u(self, rhs: Self) -> Self {
+ 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 const fn i8x16_max_s(self, rhs: Self) -> Self {
+ 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 const fn i16x8_max_s(self, rhs: Self) -> Self {
+ 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 const fn i32x4_max_s(self, rhs: Self) -> Self {
+ 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 const fn i8x16_max_u(self, rhs: Self) -> Self {
+ 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.max_u")]
+ pub const fn i16x8_max_u(self, rhs: Self) -> Self {
+ 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.max_u")]
+ pub const fn i32x4_max_u(self, rhs: Self) -> Self {
+ 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 = "f32x4.eq")]
+ pub 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 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 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)
+ }
+
+ #[doc(alias = "f64x2.ne")]
+ pub 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)
+ }
+
+ #[doc(alias = "f32x4.lt")]
+ pub 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)
+ }
+
+ #[doc(alias = "f64x2.lt")]
+ pub 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)
+ }
+
+ #[doc(alias = "f32x4.gt")]
+ pub fn f32x4_gt(self, rhs: Self) -> Self {
+ rhs.f32x4_lt(self)
+ }
+
+ #[doc(alias = "f64x2.gt")]
+ pub fn f64x2_gt(self, rhs: Self) -> Self {
+ rhs.f64x2_lt(self)
+ }
+
+ #[doc(alias = "f32x4.le")]
+ pub 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 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 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 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(f32::ceil)
+ }
+
+ #[doc(alias = "f64x2.ceil")]
+ pub fn f64x2_ceil(self) -> Self {
+ self.map_f64x2(f64::ceil)
+ }
+
+ #[doc(alias = "f32x4.floor")]
+ pub fn f32x4_floor(self) -> Self {
+ self.map_f32x4(f32::floor)
+ }
+
+ #[doc(alias = "f64x2.floor")]
+ pub fn f64x2_floor(self) -> Self {
+ self.map_f64x2(f64::floor)
+ }
+
+ #[doc(alias = "f32x4.trunc")]
+ pub fn f32x4_trunc(self) -> Self {
+ self.map_f32x4(f32::trunc)
+ }
+
+ #[doc(alias = "f64x2.trunc")]
+ pub fn f64x2_trunc(self) -> Self {
+ self.map_f64x2(f64::trunc)
+ }
+
+ #[doc(alias = "f32x4.nearest")]
+ pub fn f32x4_nearest(self) -> Self {
+ self.map_f32x4(TinywasmFloatExt::tw_nearest)
+ }
+
+ #[doc(alias = "f64x2.nearest")]
+ pub fn f64x2_nearest(self) -> Self {
+ self.map_f64x2(TinywasmFloatExt::tw_nearest)
+ }
+
+ #[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| Self::canonicalize_simd_f32_nan(x.sqrt()))
+ }
+
+ #[doc(alias = "f64x2.sqrt")]
+ pub fn f64x2_sqrt(self) -> Self {
+ self.map_f64x2(|x| Self::canonicalize_simd_f64_nan(x.sqrt()))
+ }
+
+ #[doc(alias = "f32x4.add")]
+ pub fn f32x4_add(self, rhs: Self) -> Self {
+ self.zip_f32x4(rhs, |a, b| Self::canonicalize_simd_f32_nan(a + b))
+ }
+
+ #[doc(alias = "f64x2.add")]
+ pub fn f64x2_add(self, rhs: Self) -> Self {
+ self.zip_f64x2(rhs, |a, b| Self::canonicalize_simd_f64_nan(a + b))
+ }
+
+ #[doc(alias = "f32x4.sub")]
+ pub fn f32x4_sub(self, rhs: Self) -> Self {
+ self.zip_f32x4(rhs, |a, b| Self::canonicalize_simd_f32_nan(a - b))
+ }
+
+ #[doc(alias = "f64x2.sub")]
+ pub fn f64x2_sub(self, rhs: Self) -> Self {
+ self.zip_f64x2(rhs, |a, b| Self::canonicalize_simd_f64_nan(a - b))
+ }
+
+ #[doc(alias = "f32x4.mul")]
+ pub fn f32x4_mul(self, rhs: Self) -> Self {
+ self.zip_f32x4(rhs, |a, b| Self::canonicalize_simd_f32_nan(a * b))
+ }
+
+ #[doc(alias = "f64x2.mul")]
+ pub fn f64x2_mul(self, rhs: Self) -> Self {
+ self.zip_f64x2(rhs, |a, b| Self::canonicalize_simd_f64_nan(a * b))
+ }
+
+ #[doc(alias = "f32x4.div")]
+ pub fn f32x4_div(self, rhs: Self) -> Self {
+ self.zip_f32x4(rhs, |a, b| Self::canonicalize_simd_f32_nan(a / b))
+ }
+
+ #[doc(alias = "f64x2.div")]
+ pub fn f64x2_div(self, rhs: Self) -> Self {
+ self.zip_f64x2(rhs, |a, b| Self::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)
+ }
+
+ #[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)
+ }
+
+ #[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 })
+ }
+
+ #[doc(alias = "i32x4.trunc_sat_f32x4_s")]
+ pub fn i32x4_trunc_sat_f32x4_s(self) -> Self {
+ let v = self.as_f32x4();
+ Self::from_i32x4([
+ trunc_sat_f32_to_i32(v[0]),
+ trunc_sat_f32_to_i32(v[1]),
+ trunc_sat_f32_to_i32(v[2]),
+ trunc_sat_f32_to_i32(v[3]),
+ ])
+ }
+
+ #[doc(alias = "i32x4.trunc_sat_f32x4_u")]
+ pub fn i32x4_trunc_sat_f32x4_u(self) -> Self {
+ let v = self.as_f32x4();
+ Self::from_u32x4([
+ trunc_sat_f32_to_u32(v[0]),
+ trunc_sat_f32_to_u32(v[1]),
+ trunc_sat_f32_to_u32(v[2]),
+ trunc_sat_f32_to_u32(v[3]),
+ ])
+ }
+
+ #[doc(alias = "i32x4.trunc_sat_f64x2_s_zero")]
+ pub fn i32x4_trunc_sat_f64x2_s_zero(self) -> Self {
+ let v = self.as_f64x2();
+ Self::from_i32x4([trunc_sat_f64_to_i32(v[0]), trunc_sat_f64_to_i32(v[1]), 0, 0])
+ }
+
+ #[doc(alias = "i32x4.trunc_sat_f64x2_u_zero")]
+ pub fn i32x4_trunc_sat_f64x2_u_zero(self) -> Self {
+ let v = self.as_f64x2();
+ Self::from_u32x4([trunc_sat_f64_to_u32(v[0]), trunc_sat_f64_to_u32(v[1]), 0, 0])
+ }
+
+ #[doc(alias = "f32x4.convert_i32x4_s")]
+ pub fn f32x4_convert_i32x4_s(self) -> Self {
+ let v = self.as_i32x4();
+ Self::from_f32x4([v[0] as f32, v[1] as f32, v[2] as f32, v[3] as f32])
+ }
+
+ #[doc(alias = "f32x4.convert_i32x4_u")]
+ pub fn f32x4_convert_i32x4_u(self) -> Self {
+ let v = self.as_u32x4();
+ Self::from_f32x4([v[0] as f32, v[1] as f32, v[2] as f32, v[3] as f32])
+ }
+
+ #[doc(alias = "f64x2.convert_low_i32x4_s")]
+ pub fn f64x2_convert_low_i32x4_s(self) -> Self {
+ let v = self.as_i32x4();
+ Self::from_f64x2([v[0] as f64, v[1] as f64])
+ }
+
+ #[doc(alias = "f64x2.convert_low_i32x4_u")]
+ pub fn f64x2_convert_low_i32x4_u(self) -> Self {
+ let v = self.as_u32x4();
+ Self::from_f64x2([v[0] as f64, v[1] as f64])
+ }
+
+ #[doc(alias = "f32x4.demote_f64x2_zero")]
+ pub fn f32x4_demote_f64x2_zero(self) -> Self {
+ let v = self.as_f64x2();
+ Self::from_f32x4([v[0] as f32, v[1] as f32, 0.0, 0.0])
+ }
+
+ #[doc(alias = "f64x2.promote_low_f32x4")]
+ pub fn f64x2_promote_low_f32x4(self) -> Self {
+ let v = self.as_f32x4();
+ Self::from_f64x2([v[0] as f64, v[1] as f64])
+ }
+
pub const fn splat_i16(src: i16) -> Self {
let mut result_bytes = [0u8; 16];
let bytes = src.to_le_bytes();
@@ -395,3 +2559,51 @@ impl core::ops::BitXor for Value128 {
Self(self.0 ^ rhs.0)
}
}
+
+#[inline]
+fn trunc_sat_f32_to_i32(v: f32) -> i32 {
+ if v.is_nan() {
+ 0
+ } else if v <= -2147483904.0_f32 {
+ i32::MIN
+ } else if v >= 2147483648.0_f32 {
+ i32::MAX
+ } else {
+ v.trunc() as i32
+ }
+}
+
+#[inline]
+fn trunc_sat_f32_to_u32(v: f32) -> u32 {
+ if v.is_nan() || v <= -1.0_f32 {
+ 0
+ } else if v >= 4294967296.0_f32 {
+ u32::MAX
+ } else {
+ v.trunc() as u32
+ }
+}
+
+#[inline]
+fn trunc_sat_f64_to_i32(v: f64) -> i32 {
+ if v.is_nan() {
+ 0
+ } else if v <= -2147483649.0_f64 {
+ i32::MIN
+ } else if v >= 2147483648.0_f64 {
+ i32::MAX
+ } else {
+ v.trunc() as i32
+ }
+}
+
+#[inline]
+fn trunc_sat_f64_to_u32(v: f64) -> u32 {
+ if v.is_nan() || v <= -1.0_f64 {
+ 0
+ } else if v >= 4294967296.0_f64 {
+ u32::MAX
+ } else {
+ v.trunc() as u32
+ }
+}
diff --git a/crates/tinywasm/src/store/memory.rs b/crates/tinywasm/src/store/memory.rs
index 8898212..65c4361 100644
--- a/crates/tinywasm/src/store/memory.rs
+++ b/crates/tinywasm/src/store/memory.rs
@@ -2,7 +2,7 @@ use alloc::vec;
use alloc::vec::Vec;
use tinywasm_types::{MemoryArch, MemoryType, ModuleInstanceAddr};
-use crate::{Error, Result, cold, interpreter::Value128, log};
+use crate::{cold, interpreter::Value128, log, Error, Result};
/// A WebAssembly Memory Instance
///
diff --git a/crates/tinywasm/tests/generated/wasm-simd.csv b/crates/tinywasm/tests/generated/wasm-simd.csv
index 5603ed0..96d9796 100644
--- a/crates/tinywasm/tests/generated/wasm-simd.csv
+++ b/crates/tinywasm/tests/generated/wasm-simd.csv
@@ -1,2 +1,2 @@
0.8.0,1300,24679,[{"name":"simd_address.wast","passed":4,"failed":45},{"name":"simd_align.wast","passed":46,"failed":54},{"name":"simd_bit_shift.wast","passed":39,"failed":213},{"name":"simd_bitwise.wast","passed":28,"failed":141},{"name":"simd_boolean.wast","passed":16,"failed":261},{"name":"simd_const.wast","passed":301,"failed":456},{"name":"simd_conversions.wast","passed":48,"failed":234},{"name":"simd_f32x4.wast","passed":16,"failed":774},{"name":"simd_f32x4_arith.wast","passed":16,"failed":1806},{"name":"simd_f32x4_cmp.wast","passed":24,"failed":2583},{"name":"simd_f32x4_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f32x4_rounding.wast","passed":24,"failed":177},{"name":"simd_f64x2.wast","passed":8,"failed":795},{"name":"simd_f64x2_arith.wast","passed":16,"failed":1809},{"name":"simd_f64x2_cmp.wast","passed":24,"failed":2661},{"name":"simd_f64x2_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f64x2_rounding.wast","passed":24,"failed":177},{"name":"simd_i16x8_arith.wast","passed":11,"failed":183},{"name":"simd_i16x8_arith2.wast","passed":19,"failed":153},{"name":"simd_i16x8_cmp.wast","passed":30,"failed":435},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":4,"failed":17},{"name":"simd_i16x8_extmul_i8x16.wast","passed":12,"failed":105},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":3,"failed":27},{"name":"simd_i16x8_sat_arith.wast","passed":16,"failed":206},{"name":"simd_i32x4_arith.wast","passed":11,"failed":183},{"name":"simd_i32x4_arith2.wast","passed":26,"failed":123},{"name":"simd_i32x4_cmp.wast","passed":40,"failed":435},{"name":"simd_i32x4_dot_i16x8.wast","passed":3,"failed":27},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":4,"failed":17},{"name":"simd_i32x4_extmul_i16x8.wast","passed":12,"failed":105},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":4,"failed":103},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":4,"failed":103},{"name":"simd_i64x2_arith.wast","passed":11,"failed":189},{"name":"simd_i64x2_arith2.wast","passed":2,"failed":23},{"name":"simd_i64x2_cmp.wast","passed":10,"failed":103},{"name":"simd_i64x2_extmul_i32x4.wast","passed":12,"failed":105},{"name":"simd_i8x16_arith.wast","passed":8,"failed":123},{"name":"simd_i8x16_arith2.wast","passed":25,"failed":186},{"name":"simd_i8x16_cmp.wast","passed":30,"failed":415},{"name":"simd_i8x16_sat_arith.wast","passed":24,"failed":190},{"name":"simd_int_to_int_extend.wast","passed":24,"failed":229},{"name":"simd_lane.wast","passed":189,"failed":286},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":8,"failed":31},{"name":"simd_load16_lane.wast","passed":3,"failed":33},{"name":"simd_load32_lane.wast","passed":3,"failed":21},{"name":"simd_load64_lane.wast","passed":3,"failed":13},{"name":"simd_load8_lane.wast","passed":3,"failed":49},{"name":"simd_load_extend.wast","passed":18,"failed":86},{"name":"simd_load_splat.wast","passed":12,"failed":114},{"name":"simd_load_zero.wast","passed":10,"failed":29},{"name":"simd_splat.wast","passed":23,"failed":162},{"name":"simd_store.wast","passed":9,"failed":19},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}]
-0.9.0-alpha.0,2867,23122,[{"name":"simd_address.wast","passed":49,"failed":0},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":41,"failed":211},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":139,"failed":138},{"name":"simd_const.wast","passed":755,"failed":2},{"name":"simd_conversions.wast","passed":50,"failed":232},{"name":"simd_f32x4.wast","passed":18,"failed":772},{"name":"simd_f32x4_arith.wast","passed":19,"failed":1803},{"name":"simd_f32x4_cmp.wast","passed":26,"failed":2581},{"name":"simd_f32x4_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f32x4_rounding.wast","passed":25,"failed":176},{"name":"simd_f64x2.wast","passed":10,"failed":793},{"name":"simd_f64x2_arith.wast","passed":19,"failed":1806},{"name":"simd_f64x2_cmp.wast","passed":26,"failed":2659},{"name":"simd_f64x2_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f64x2_rounding.wast","passed":25,"failed":176},{"name":"simd_i16x8_arith.wast","passed":13,"failed":181},{"name":"simd_i16x8_arith2.wast","passed":21,"failed":151},{"name":"simd_i16x8_cmp.wast","passed":32,"failed":433},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":30,"failed":0},{"name":"simd_i16x8_sat_arith.wast","passed":18,"failed":204},{"name":"simd_i32x4_arith.wast","passed":13,"failed":181},{"name":"simd_i32x4_arith2.wast","passed":28,"failed":121},{"name":"simd_i32x4_cmp.wast","passed":42,"failed":433},{"name":"simd_i32x4_dot_i16x8.wast","passed":14,"failed":18},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":5,"failed":102},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":13,"failed":187},{"name":"simd_i64x2_arith2.wast","passed":4,"failed":21},{"name":"simd_i64x2_cmp.wast","passed":11,"failed":102},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":10,"failed":121},{"name":"simd_i8x16_arith2.wast","passed":27,"failed":184},{"name":"simd_i8x16_cmp.wast","passed":32,"failed":413},{"name":"simd_i8x16_sat_arith.wast","passed":26,"failed":188},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":328,"failed":147},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":30,"failed":9},{"name":"simd_load16_lane.wast","passed":36,"failed":0},{"name":"simd_load32_lane.wast","passed":24,"failed":0},{"name":"simd_load64_lane.wast","passed":16,"failed":0},{"name":"simd_load8_lane.wast","passed":52,"failed":0},{"name":"simd_load_extend.wast","passed":36,"failed":68},{"name":"simd_load_splat.wast","passed":126,"failed":0},{"name":"simd_load_zero.wast","passed":39,"failed":0},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_select.wast","passed":7,"failed":0},{"name":"simd_splat.wast","passed":158,"failed":27},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":4,"failed":32},{"name":"simd_store32_lane.wast","passed":4,"failed":20},{"name":"simd_store64_lane.wast","passed":4,"failed":12},{"name":"simd_store8_lane.wast","passed":52,"failed":0}]
+0.9.0-alpha.0,25964,25,[{"name":"simd_address.wast","passed":49,"failed":0},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":252,"failed":0},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":277,"failed":0},{"name":"simd_const.wast","passed":757,"failed":0},{"name":"simd_conversions.wast","passed":276,"failed":6},{"name":"simd_f32x4.wast","passed":790,"failed":0},{"name":"simd_f32x4_arith.wast","passed":1822,"failed":0},{"name":"simd_f32x4_cmp.wast","passed":2607,"failed":0},{"name":"simd_f32x4_pmin_pmax.wast","passed":3887,"failed":0},{"name":"simd_f32x4_rounding.wast","passed":192,"failed":9},{"name":"simd_f64x2.wast","passed":803,"failed":0},{"name":"simd_f64x2_arith.wast","passed":1824,"failed":1},{"name":"simd_f64x2_cmp.wast","passed":2685,"failed":0},{"name":"simd_f64x2_pmin_pmax.wast","passed":3887,"failed":0},{"name":"simd_f64x2_rounding.wast","passed":192,"failed":9},{"name":"simd_i16x8_arith.wast","passed":194,"failed":0},{"name":"simd_i16x8_arith2.wast","passed":172,"failed":0},{"name":"simd_i16x8_cmp.wast","passed":465,"failed":0},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":21,"failed":0},{"name":"simd_i16x8_extmul_i8x16.wast","passed":117,"failed":0},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":30,"failed":0},{"name":"simd_i16x8_sat_arith.wast","passed":222,"failed":0},{"name":"simd_i32x4_arith.wast","passed":194,"failed":0},{"name":"simd_i32x4_arith2.wast","passed":149,"failed":0},{"name":"simd_i32x4_cmp.wast","passed":475,"failed":0},{"name":"simd_i32x4_dot_i16x8.wast","passed":32,"failed":0},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":21,"failed":0},{"name":"simd_i32x4_extmul_i16x8.wast","passed":117,"failed":0},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":107,"failed":0},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":107,"failed":0},{"name":"simd_i64x2_arith.wast","passed":200,"failed":0},{"name":"simd_i64x2_arith2.wast","passed":25,"failed":0},{"name":"simd_i64x2_cmp.wast","passed":113,"failed":0},{"name":"simd_i64x2_extmul_i32x4.wast","passed":117,"failed":0},{"name":"simd_i8x16_arith.wast","passed":131,"failed":0},{"name":"simd_i8x16_arith2.wast","passed":211,"failed":0},{"name":"simd_i8x16_cmp.wast","passed":445,"failed":0},{"name":"simd_i8x16_sat_arith.wast","passed":214,"failed":0},{"name":"simd_int_to_int_extend.wast","passed":253,"failed":0},{"name":"simd_lane.wast","passed":475,"failed":0},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":39,"failed":0},{"name":"simd_load16_lane.wast","passed":36,"failed":0},{"name":"simd_load32_lane.wast","passed":24,"failed":0},{"name":"simd_load64_lane.wast","passed":16,"failed":0},{"name":"simd_load8_lane.wast","passed":52,"failed":0},{"name":"simd_load_extend.wast","passed":104,"failed":0},{"name":"simd_load_splat.wast","passed":126,"failed":0},{"name":"simd_load_zero.wast","passed":39,"failed":0},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_select.wast","passed":7,"failed":0},{"name":"simd_splat.wast","passed":185,"failed":0},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":36,"failed":0},{"name":"simd_store32_lane.wast","passed":24,"failed":0},{"name":"simd_store64_lane.wast","passed":16,"failed":0},{"name":"simd_store8_lane.wast","passed":52,"failed":0}]