diff options
| author | Henry <mail@henrygressmann.de> | 2026-04-01 20:39:33 +0200 |
|---|---|---|
| committer | Henry <mail@henrygressmann.de> | 2026-04-01 20:39:33 +0200 |
| commit | c3b1f582f44747cb4343b51ffb208334c973c67c (patch) | |
| tree | 5a390555e495849110520a463e992dd2a390d7b5 | |
| parent | 0ed3e1d29dca7d27e0d3aa1780f7cacc9481aa46 (diff) | |
chore: cleanup + add wasm intrinsics
Signed-off-by: Henry <mail@henrygressmann.de>
| -rw-r--r-- | .cargo/config.toml | 3 | ||||
| -rw-r--r-- | crates/parser/src/visit.rs | 7 | ||||
| -rw-r--r-- | crates/tinywasm/benches/argon2id.rs | 2 | ||||
| -rw-r--r-- | crates/tinywasm/benches/fibonacci.rs | 2 | ||||
| -rw-r--r-- | crates/tinywasm/benches/tinywasm.rs | 2 | ||||
| -rw-r--r-- | crates/tinywasm/src/func.rs | 15 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/executor.rs | 65 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/stack/call_stack.rs | 44 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/stack/value_stack.rs | 74 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/value128.rs | 507 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/values.rs | 51 | ||||
| -rw-r--r-- | crates/tinywasm/tests/wasm-custom/loop-boundary-superinstructions.wast | 26 | ||||
| -rw-r--r-- | crates/tinywasm/tests/wasm-custom/select-multi-reference-types.wast | 17 | ||||
| -rw-r--r-- | crates/types/src/instructions.rs | 28 | ||||
| -rw-r--r-- | examples/rust/Cargo.toml | 2 | ||||
| -rwxr-xr-x | examples/rust/build.sh | 11 | ||||
| -rw-r--r-- | examples/wasm-rust.rs | 10 |
17 files changed, 600 insertions, 266 deletions
diff --git a/.cargo/config.toml b/.cargo/config.toml index e702802..0190999 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -5,3 +5,6 @@ test-wasm-2="test --package tinywasm --test test-wasm-2 --release" test-wasm-3="test --package tinywasm --test test-wasm-3 --release" test-wast="test --package tinywasm --test test-wast" test-wasm-custom="test --package tinywasm --test test-wasm-custom --release" + +[target.x86_64-unknown-linux-gnu] +rustflags=["-C", "target-cpu=x86-64-v3"] diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index b71185e..7eefa1c 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -657,6 +657,9 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild } fn visit_loop(&mut self, _ty: wasmparser::BlockType) -> Self::Output { + if !matches!(self.instructions.last(), Some(Instruction::Nop)) { + self.instructions.push(Instruction::Nop); // add nop to ensure that no superinstruction can be merged across block boundaries + } let start_ip = self.instructions.len(); self.ctx_stack.push(LoweringCtx { kind: BlockKind::Loop, has_else: false, start_ip, branch_jumps: Vec::new() }); } @@ -683,7 +686,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild ctx.branch_jumps.push(jump_ip); self.patch_jump_if_zero(cond_jump_ip, self.instructions.len()); if !matches!(self.instructions.last(), Some(Instruction::Nop)) { - self.instructions.push(Instruction::Nop); + self.instructions.push(Instruction::Nop); // add nop to ensure that no superinstruction can be merged across block boundaries } }; }; @@ -693,7 +696,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild if let Some(ctx) = self.ctx_stack.pop() { self.patch_end_jumps(ctx, self.instructions.len()); if !matches!(self.instructions.last(), Some(Instruction::Nop)) { - self.instructions.push(Instruction::Nop); + self.instructions.push(Instruction::Nop); // add nop to ensure that no superinstruction can be merged across block boundaries } } else { self.instructions.push(Instruction::Return); diff --git a/crates/tinywasm/benches/argon2id.rs b/crates/tinywasm/benches/argon2id.rs index ca08378..4521722 100644 --- a/crates/tinywasm/benches/argon2id.rs +++ b/crates/tinywasm/benches/argon2id.rs @@ -3,7 +3,7 @@ use eyre::Result; use tinywasm::{ModuleInstance, Store, types}; use types::TinyWasmModule; -const WASM: &[u8] = include_bytes!("../../../examples/rust/out/argon2id.opt.wasm"); +const WASM: &[u8] = include_bytes!("../../../examples/rust/out/argon2id.wasm"); fn argon2id_parse() -> Result<TinyWasmModule> { let parser = tinywasm_parser::Parser::new(); diff --git a/crates/tinywasm/benches/fibonacci.rs b/crates/tinywasm/benches/fibonacci.rs index eea28c4..ba1b318 100644 --- a/crates/tinywasm/benches/fibonacci.rs +++ b/crates/tinywasm/benches/fibonacci.rs @@ -3,7 +3,7 @@ use eyre::Result; use tinywasm::{ModuleInstance, Store, types}; use types::TinyWasmModule; -const WASM: &[u8] = include_bytes!("../../../examples/rust/out/fibonacci.opt.wasm"); +const WASM: &[u8] = include_bytes!("../../../examples/rust/out/fibonacci.wasm"); fn fibonacci_parse() -> Result<TinyWasmModule> { let parser = tinywasm_parser::Parser::new(); diff --git a/crates/tinywasm/benches/tinywasm.rs b/crates/tinywasm/benches/tinywasm.rs index a949b52..82a3878 100644 --- a/crates/tinywasm/benches/tinywasm.rs +++ b/crates/tinywasm/benches/tinywasm.rs @@ -3,7 +3,7 @@ use eyre::Result; use tinywasm::{Extern, FuncContext, Imports, ModuleInstance, Store, types}; use types::TinyWasmModule; -const WASM: &[u8] = include_bytes!("../../../examples/rust/out/tinywasm.opt.wasm"); +const WASM: &[u8] = include_bytes!("../../../examples/rust/out/tinywasm.wasm"); fn tinywasm_parse() -> Result<TinyWasmModule> { let parser = tinywasm_parser::Parser::new(); diff --git a/crates/tinywasm/src/func.rs b/crates/tinywasm/src/func.rs index 0e42dd7..69d6dd2 100644 --- a/crates/tinywasm/src/func.rs +++ b/crates/tinywasm/src/func.rs @@ -1,6 +1,6 @@ use crate::interpreter::stack::CallFrame; use crate::{Error, FuncContext, InterpreterRuntime, Result, Store}; -use crate::{Function, log, unlikely}; +use crate::{Function, unlikely}; use alloc::{boxed::Box, format, string::ToString, vec, vec::Vec}; use tinywasm_types::{ExternRef, FuncRef, FuncType, ModuleInstanceAddr, ValType, WasmValue}; @@ -34,23 +34,14 @@ impl FuncHandle { } // 5. For each value type and the corresponding value, check if types match - if !(func_ty.params.iter().zip(params).enumerate().all(|(_i, (ty, param))| { - if ty == ¶m.val_type() { - true - } else { - log::error!("param type mismatch at index {_i}: expected {ty:?}, got {param:?}"); - false - } - })) { + if !(func_ty.params.iter().zip(params).all(|(ty, param)| ty == ¶m.val_type())) { return Err(Error::Other("Type mismatch".into())); } let func_inst = store.state.get_func(self.addr); let wasm_func = match &func_inst.func { Function::Host(host_func) => { - let host_func = host_func.clone(); - let ctx = FuncContext { store, module_addr: self.module_addr }; - return host_func.call(ctx, params); + return host_func.clone().call(FuncContext { store, module_addr: self.module_addr }, params); } Function::Wasm(wasm_func) => wasm_func.clone(), }; diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index 1da799e..91234cc 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -3,7 +3,7 @@ use super::no_std_floats::NoStdFloatExt; use alloc::boxed::Box; -use alloc::{format, rc::Rc, string::ToString}; +use alloc::{rc::Rc, string::ToString}; use core::ops::ControlFlow; use interpreter::stack::CallFrame; @@ -78,7 +78,7 @@ impl<'store> Executor<'store> { }}; } - let next = match self.func.instructions.0.get(self.cf.instr_ptr) { + let next = match self.func.instructions.0.get(self.cf.instr_ptr as usize) { Some(instr) => instr, None => unreachable!( "Instruction pointer out of bounds: {} ({} instructions)", @@ -89,7 +89,7 @@ impl<'store> Executor<'store> { #[rustfmt::skip] match next { - Nop | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {} + Nop | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 | BranchTableTarget {..} => {} Unreachable => return ControlFlow::Break(Some(Trap::Unreachable.into())), Drop32 => self.store.stack.values.drop::<Value32>(), Drop64 => self.store.stack.values.drop::<Value64>(), @@ -107,66 +107,66 @@ impl<'store> Executor<'store> { ReturnCallSelf => return self.exec_call_self::<true>(), ReturnCallIndirect(ty, table) => return self.exec_call_indirect::<true>(*ty, *table), Jump(ip) => { - self.cf.instr_ptr = *ip as usize; + self.cf.instr_ptr = *ip; return ControlFlow::Continue(()); } JumpIfZero(ip) => { let cond = self.store.stack.values.pop::<i32>(); if cond == 0 { - self.cf.instr_ptr = *ip as usize; + self.cf.instr_ptr = *ip; } else { self.cf.incr_instr_ptr(); } return ControlFlow::Continue(()); } DropKeepSmall { base32, keep32, base64, keep64, base128, keep128, base_ref, keep_ref } => { - let b32 = self.cf.stack_base().s32 + *base32 as usize; + let b32 = self.cf.stack_base().s32 + *base32 as u32; let k32 = *keep32 as usize; - self.store.stack.values.stack_32.truncate_keep(b32, k32); - let b64 = self.cf.stack_base().s64 + *base64 as usize; + self.store.stack.values.stack_32.truncate_keep(b32 as usize, k32); + let b64 = self.cf.stack_base().s64 + *base64 as u32; let k64 = *keep64 as usize; - self.store.stack.values.stack_64.truncate_keep(b64, k64); - let b128 = self.cf.stack_base().s128 + *base128 as usize; + self.store.stack.values.stack_64.truncate_keep(b64 as usize, k64); + let b128 = self.cf.stack_base().s128 + *base128 as u32; let k128 = *keep128 as usize; - self.store.stack.values.stack_128.truncate_keep(b128, k128); - let bref = self.cf.stack_base().sref + *base_ref as usize; + self.store.stack.values.stack_128.truncate_keep(b128 as usize, k128); + let bref = self.cf.stack_base().sref + *base_ref as u32; let kref = *keep_ref as usize; - self.store.stack.values.stack_ref.truncate_keep(bref, kref); + self.store.stack.values.stack_ref.truncate_keep(bref as usize, kref); } DropKeep32(base, keep) => { - let b = self.cf.stack_base().s32 + *base as usize; + let b = self.cf.stack_base().s32 + *base as u32; let k = *keep as usize; - self.store.stack.values.stack_32.truncate_keep(b, k); + self.store.stack.values.stack_32.truncate_keep(b as usize, k); } DropKeep64(base, keep) => { - let b = self.cf.stack_base().s64 + *base as usize; + let b = self.cf.stack_base().s64 + *base as u32; let k = *keep as usize; - self.store.stack.values.stack_64.truncate_keep(b, k); + self.store.stack.values.stack_64.truncate_keep(b as usize, k); } DropKeep128(base, keep) => { - let b = self.cf.stack_base().s128 + *base as usize; + let b = self.cf.stack_base().s128 + *base as u32; let k = *keep as usize; - self.store.stack.values.stack_128.truncate_keep(b, k); + self.store.stack.values.stack_128.truncate_keep(b as usize, k); } DropKeepRef(base, keep) => { - let b = self.cf.stack_base().sref + *base as usize; + let b = self.cf.stack_base().sref + *base as u32; let k = *keep as usize; - self.store.stack.values.stack_ref.truncate_keep(b, k); + self.store.stack.values.stack_ref.truncate_keep(b as usize, k); } BranchTable(default_ip, len) => { let idx = self.store.stack.values.pop::<i32>(); let start = self.cf.instr_ptr + 1; let target_ip = if idx >= 0 && (idx as u32) < *len { - match self.func.instructions.0.get(start + idx as usize) { + match self.func.instructions.0.get((start + idx as u32) as usize) { Some(Instruction::BranchTableTarget(ip)) => *ip, _ => *default_ip, } } else { *default_ip }; - self.cf.instr_ptr = target_ip as usize; + self.cf.instr_ptr = target_ip; return ControlFlow::Continue(()); } Return => return self.exec_return(), @@ -434,10 +434,10 @@ impl<'store> Executor<'store> { 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)?, + 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)?, 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)?, @@ -655,9 +655,6 @@ impl<'store> Executor<'store> { 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()), - - #[allow(unreachable_patterns)] - i => return ControlFlow::Break(Some(Error::UnsupportedFeature(format!("unimplemented opcode: {i:?}")))), }; self.cf.incr_instr_ptr(); @@ -670,10 +667,6 @@ impl<'store> Executor<'store> { func_addr: FuncAddr, owner: ModuleInstanceAddr, ) -> ControlFlow<Option<Error>> { - if !IS_RETURN_CALL && self.store.stack.call_stack.is_full() { - return ControlFlow::Break(Some(Trap::CallStackOverflow.into())); - } - if !Rc::ptr_eq(&self.func, &wasm_func) { self.func = wasm_func.clone(); } @@ -726,10 +719,6 @@ impl<'store> Executor<'store> { } fn exec_call_self<const IS_RETURN_CALL: bool>(&mut self) -> ControlFlow<Option<Error>> { - if !IS_RETURN_CALL && self.store.stack.call_stack.is_full() { - return ControlFlow::Break(Some(Trap::CallStackOverflow.into())); - } - let params = self.func.params; let locals = self.func.locals; diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs index 2409d88..1b8117c 100644 --- a/crates/tinywasm/src/interpreter/stack/call_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs @@ -6,47 +6,35 @@ use tinywasm_types::{FuncAddr, ModuleInstanceAddr, ValueCountsSmall}; #[derive(Debug)] pub(crate) struct CallStack { stack: Vec<CallFrame>, - len: usize, } impl CallStack { pub(crate) fn new(config: &crate::engine::Config) -> Self { - let mut stack = Vec::with_capacity(config.call_stack_size); - stack.resize_with(config.call_stack_size, CallFrame::default); - Self { stack, len: 0 } + Self { stack: Vec::with_capacity(config.call_stack_size) } } pub(crate) fn clear(&mut self) { - self.len = 0; + self.stack.clear(); } + #[inline(always)] pub(crate) fn pop(&mut self) -> Option<CallFrame> { - if self.len == 0 { - return None; - } - - self.len -= 1; - Some(self.stack[self.len]) - } - - pub(crate) fn is_full(&self) -> bool { - self.len >= self.stack.len() + self.stack.pop() } + #[inline(always)] pub(crate) fn push(&mut self, call_frame: CallFrame) -> Result<()> { - if unlikely(self.is_full()) { + if unlikely(self.stack.len() == self.stack.capacity()) { return Err(Trap::CallStackOverflow.into()); } - - self.stack[self.len] = call_frame; - self.len += 1; + self.stack.push(call_frame); Ok(()) } } #[derive(Debug, Clone, Copy, Default)] pub(crate) struct CallFrame { - pub(crate) instr_ptr: usize, + pub(crate) instr_ptr: u32, pub(crate) module_addr: ModuleInstanceAddr, pub(crate) func_addr: FuncAddr, pub(crate) locals_base: StackBase, @@ -55,10 +43,10 @@ pub(crate) struct CallFrame { #[derive(Debug, Clone, Copy, Default)] pub(crate) struct StackBase { - pub(crate) s32: usize, - pub(crate) s64: usize, - pub(crate) s128: usize, - pub(crate) sref: usize, + pub(crate) s32: u32, + pub(crate) s64: u32, + pub(crate) s128: u32, + pub(crate) sref: u32, } impl CallFrame { @@ -74,10 +62,10 @@ impl CallFrame { #[inline] pub(crate) fn stack_base(&self) -> StackBase { StackBase { - s32: self.locals_base.s32 + self.stack_offset.c32 as usize, - s64: self.locals_base.s64 + self.stack_offset.c64 as usize, - s128: self.locals_base.s128 + self.stack_offset.c128 as usize, - sref: self.locals_base.sref + self.stack_offset.cref as usize, + s32: self.locals_base.s32 + self.stack_offset.c32 as u32, + s64: self.locals_base.s64 + self.stack_offset.c64 as u32, + s128: self.locals_base.s128 + self.stack_offset.c128 as u32, + sref: self.locals_base.sref + self.stack_offset.cref as u32, } } diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs index b461f7a..81a5c5d 100644 --- a/crates/tinywasm/src/interpreter/stack/value_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs @@ -2,7 +2,7 @@ use alloc::boxed::Box; use alloc::vec::Vec; use tinywasm_types::{ExternRef, FuncRef, LocalAddr, ValType, ValueCounts, ValueCountsSmall, WasmValue}; -use crate::{Result, Trap, engine::Config, interpreter::*}; +use crate::{Result, Trap, engine::Config, interpreter::*, unlikely}; use super::{CallFrame, StackBase}; @@ -15,7 +15,7 @@ pub(crate) struct ValueStack { } #[derive(Debug)] -pub(crate) struct Stack<T> { +pub(crate) struct Stack<T: Copy + Default> { data: Box<[T]>, len: usize, } @@ -27,33 +27,30 @@ impl<T: Copy + Default> Stack<T> { Self { data: data.into_boxed_slice(), len: 0 } } - pub(crate) fn len(&self) -> usize { - self.len - } - pub(crate) fn clear(&mut self) { self.len = 0; } + #[inline(always)] pub(crate) fn push(&mut self, value: T) -> Result<()> { - if self.len >= self.data.len() { + if unlikely(self.len >= self.data.len()) { return Err(Trap::ValueStackOverflow.into()); } - self.data[self.len] = value; self.len += 1; Ok(()) } + #[inline(always)] pub(crate) fn pop(&mut self) -> T { if self.len == 0 { unreachable!("ValueStack underflow, this is a bug"); } - self.len -= 1; self.data[self.len] } + #[inline(always)] pub(crate) fn last(&self) -> &T { if self.len == 0 { unreachable!("ValueStack underflow, this is a bug"); @@ -61,6 +58,7 @@ impl<T: Copy + Default> Stack<T> { &self.data[self.len - 1] } + #[inline(always)] pub(crate) fn last_mut(&mut self) -> &mut T { if self.len == 0 { unreachable!("ValueStack underflow, this is a bug"); @@ -68,6 +66,7 @@ impl<T: Copy + Default> Stack<T> { &mut self.data[self.len - 1] } + #[inline(always)] pub(crate) fn get(&self, index: usize) -> T { match self.data.get(index) { Some(v) => *v, @@ -75,6 +74,7 @@ impl<T: Copy + Default> Stack<T> { } } + #[inline(always)] pub(crate) fn set(&mut self, index: usize, value: T) { match self.data.get_mut(index) { Some(v) => *v = value, @@ -83,35 +83,34 @@ impl<T: Copy + Default> Stack<T> { } pub(crate) fn truncate_keep(&mut self, n: usize, end_keep: usize) { - if self.len <= n { + debug_assert!(n <= self.len); + if n >= self.len { return; } - let keep_tail = end_keep.min(self.len - n); - - if keep_tail == 0 { - self.len = n; - return; + let keep = (self.len - n).min(end_keep); + if keep != 0 { + let src = self.len - keep; + self.data.copy_within(src..self.len, n); } - let tail_start = self.len - keep_tail; - self.data.copy_within(tail_start..self.len, n); - self.len = n + keep_tail; + self.len = n + keep; } - pub(crate) fn enter_locals(&mut self, param_count: usize, local_count: usize) -> Result<(usize, usize)> { - debug_assert!(param_count <= local_count, "param count exceeds local count"); - let start = - self.len.checked_sub(param_count).unwrap_or_else(|| unreachable!("value stack underflow, this is a bug")); - + pub(crate) fn enter_locals(&mut self, param_count: usize, local_count: usize) -> Result<(u32, u32)> { + debug_assert!(param_count <= local_count); + let start = self.len - param_count; let end = start + local_count; - if end > self.data.len() { + + if unlikely(end > self.data.len()) { return Err(Trap::ValueStackOverflow.into()); } - self.data[(start + param_count)..end].fill(T::default()); + let init_start = start + param_count; + self.data[init_start..end].fill(T::default()); self.len = end; - Ok((start, end)) + + Ok((start as u32, end as u32)) } pub(crate) fn select_many(&mut self, count: usize, condition: bool) { @@ -148,26 +147,32 @@ impl ValueStack { self.stack_ref.clear(); } + #[inline(always)] pub(crate) fn len(&self) -> usize { - self.stack_32.len() + self.stack_64.len() + self.stack_128.len() + self.stack_ref.len() + self.stack_32.len + self.stack_64.len + self.stack_128.len + self.stack_ref.len } + #[inline(always)] pub(crate) fn peek<T: InternalValue>(&self) -> T { T::stack_peek(self) } + #[inline(always)] pub(crate) fn pop<T: InternalValue>(&mut self) -> T { T::stack_pop(self) } + #[inline(always)] pub(crate) fn push<T: InternalValue>(&mut self, value: T) -> Result<()> { T::stack_push(self, value) } + #[inline(always)] pub(crate) fn drop<T: InternalValue>(&mut self) { T::stack_pop(self); } + #[inline] pub(crate) fn select<T: InternalValue>(&mut self) -> Result<()> { let cond: i32 = self.pop(); let val2: T = self.pop(); @@ -178,6 +183,7 @@ impl ValueStack { Ok(()) } + #[inline] pub(crate) fn select_multi(&mut self, counts: ValueCountsSmall) { let condition = self.pop::<i32>() != 0; self.stack_32.select_many(counts.c32 as usize, condition); @@ -186,14 +192,17 @@ impl ValueStack { self.stack_ref.select_many(counts.cref as usize, condition); } + #[inline] pub(crate) fn binary_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T) -> Result<T>) -> Result<()> { T::stack_calculate(self, func) } + #[inline] pub(crate) fn ternary_same<T: InternalValue>(&mut self, func: impl FnOnce(T, T, T) -> Result<T>) -> Result<()> { T::stack_calculate3(self, func) } + #[inline] pub(crate) fn binary<T: InternalValue, U: InternalValue>( &mut self, func: impl FnOnce(T, T) -> Result<U>, @@ -204,6 +213,7 @@ impl ValueStack { Ok(()) } + #[inline] pub(crate) fn binary_diff<A: InternalValue, B: InternalValue, RES: InternalValue>( &mut self, func: impl FnOnce(A, B) -> Result<RES>, @@ -214,6 +224,7 @@ impl ValueStack { Ok(()) } + #[inline] pub(crate) fn unary<T: InternalValue, U: InternalValue>( &mut self, func: impl FnOnce(T) -> Result<U>, @@ -223,6 +234,7 @@ impl ValueStack { Ok(()) } + #[inline] pub(crate) fn unary_same<T: InternalValue>(&mut self, func: impl Fn(T) -> Result<T>) -> Result<()> { T::replace_top(self, func) } @@ -261,10 +273,10 @@ impl ValueStack { } pub(crate) fn truncate_keep_counts(&mut self, base: StackBase, keep: ValueCountsSmall) { - self.stack_32.truncate_keep(base.s32, keep.c32 as usize); - self.stack_64.truncate_keep(base.s64, keep.c64 as usize); - self.stack_128.truncate_keep(base.s128, keep.c128 as usize); - self.stack_ref.truncate_keep(base.sref, keep.cref as usize); + self.stack_32.truncate_keep(base.s32 as usize, keep.c32 as usize); + self.stack_64.truncate_keep(base.s64 as usize, keep.c64 as usize); + self.stack_128.truncate_keep(base.s128 as usize, keep.c128 as usize); + self.stack_ref.truncate_keep(base.sref as usize, keep.cref as usize); } #[inline] diff --git a/crates/tinywasm/src/interpreter/value128.rs b/crates/tinywasm/src/interpreter/value128.rs index edcf50a..bb2c686 100644 --- a/crates/tinywasm/src/interpreter/value128.rs +++ b/crates/tinywasm/src/interpreter/value128.rs @@ -2,148 +2,207 @@ use super::num_helpers::TinywasmFloatExt; #[cfg(not(feature = "std"))] use super::no_std_floats::NoStdFloatExt; +#[cfg(target_arch = "wasm32")] +use core::arch::wasm32 as wasm; +#[cfg(target_arch = "wasm64")] +use core::arch::wasm64 as wasm; #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub struct Value128(i128); +#[cfg_attr(any(target_arch = "wasm32", target_arch = "wasm64"), allow(unreachable_code))] impl Value128 { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + #[inline(always)] + fn to_wasm_v128(self) -> wasm::v128 { + let b = self.to_le_bytes(); + wasm::u8x16( + b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], + ) + } + + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + #[inline(always)] + fn from_wasm_v128(value: wasm::v128) -> Self { + Self::from_le_bytes([ + wasm::u8x16_extract_lane::<0>(value), + wasm::u8x16_extract_lane::<1>(value), + wasm::u8x16_extract_lane::<2>(value), + wasm::u8x16_extract_lane::<3>(value), + wasm::u8x16_extract_lane::<4>(value), + wasm::u8x16_extract_lane::<5>(value), + wasm::u8x16_extract_lane::<6>(value), + wasm::u8x16_extract_lane::<7>(value), + wasm::u8x16_extract_lane::<8>(value), + wasm::u8x16_extract_lane::<9>(value), + wasm::u8x16_extract_lane::<10>(value), + wasm::u8x16_extract_lane::<11>(value), + wasm::u8x16_extract_lane::<12>(value), + wasm::u8x16_extract_lane::<13>(value), + wasm::u8x16_extract_lane::<14>(value), + wasm::u8x16_extract_lane::<15>(value), + ]) + } + + #[inline] pub const fn from_le_bytes(bytes: [u8; 16]) -> Self { Self(i128::from_le_bytes(bytes)) } + #[inline] pub const fn to_le_bytes(self) -> [u8; 16] { self.0.to_le_bytes() } #[rustfmt::skip] + #[inline] pub const fn as_i8x16(self) -> [i8; 16] { let b = self.to_le_bytes(); [b[0] as i8, b[1] as i8, b[2] as i8, b[3] as i8, b[4] as i8, b[5] as i8, b[6] as i8, b[7] as i8, b[8] as i8, b[9] as i8, b[10] as i8, b[11] as i8, b[12] as i8, b[13] as i8, b[14] as i8, b[15] as i8] } #[rustfmt::skip] + #[inline] pub const fn as_u8x16(self) -> [u8; 16] { self.to_le_bytes() } #[rustfmt::skip] + #[inline] pub const fn from_i8x16(x: [i8; 16]) -> Self { Self::from_le_bytes([x[0] as u8, x[1] as u8, x[2] as u8, x[3] as u8, x[4] as u8, x[5] as u8, x[6] as u8, x[7] as u8, x[8] as u8, x[9] as u8, x[10] as u8, x[11] as u8, x[12] as u8, x[13] as u8, x[14] as u8, x[15] as u8]) } #[rustfmt::skip] + #[inline] pub const fn from_u8x16(x: [u8; 16]) -> Self { Self::from_le_bytes(x) } #[rustfmt::skip] + #[inline] pub const fn as_i16x8(self) -> [i16; 8] { let b = self.to_le_bytes(); [i16::from_le_bytes([b[0], b[1]]), i16::from_le_bytes([b[2], b[3]]), i16::from_le_bytes([b[4], b[5]]), i16::from_le_bytes([b[6], b[7]]), i16::from_le_bytes([b[8], b[9]]), i16::from_le_bytes([b[10], b[11]]), i16::from_le_bytes([b[12], b[13]]), i16::from_le_bytes([b[14], b[15]])] } #[rustfmt::skip] + #[inline] pub const fn as_u16x8(self) -> [u16; 8] { let b = self.to_le_bytes(); [u16::from_le_bytes([b[0], b[1]]), u16::from_le_bytes([b[2], b[3]]), u16::from_le_bytes([b[4], b[5]]), u16::from_le_bytes([b[6], b[7]]), u16::from_le_bytes([b[8], b[9]]), u16::from_le_bytes([b[10], b[11]]), u16::from_le_bytes([b[12], b[13]]), u16::from_le_bytes([b[14], b[15]])] } #[rustfmt::skip] + #[inline] pub const fn from_i16x8(x: [i16; 8]) -> Self { Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[4].to_le_bytes()[0], x[4].to_le_bytes()[1], x[5].to_le_bytes()[0], x[5].to_le_bytes()[1], x[6].to_le_bytes()[0], x[6].to_le_bytes()[1], x[7].to_le_bytes()[0], x[7].to_le_bytes()[1]]) } #[rustfmt::skip] + #[inline] pub const fn from_u16x8(x: [u16; 8]) -> Self { Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[4].to_le_bytes()[0], x[4].to_le_bytes()[1], x[5].to_le_bytes()[0], x[5].to_le_bytes()[1], x[6].to_le_bytes()[0], x[6].to_le_bytes()[1], x[7].to_le_bytes()[0], x[7].to_le_bytes()[1]]) } #[rustfmt::skip] + #[inline] pub const fn as_i32x4(self) -> [i32; 4] { let b = self.to_le_bytes(); [i32::from_le_bytes([b[0], b[1], b[2], b[3]]), i32::from_le_bytes([b[4], b[5], b[6], b[7]]), i32::from_le_bytes([b[8], b[9], b[10], b[11]]), i32::from_le_bytes([b[12], b[13], b[14], b[15]])] } #[rustfmt::skip] + #[inline] pub const fn as_u32x4(self) -> [u32; 4] { let b = self.to_le_bytes(); [u32::from_le_bytes([b[0], b[1], b[2], b[3]]), u32::from_le_bytes([b[4], b[5], b[6], b[7]]), u32::from_le_bytes([b[8], b[9], b[10], b[11]]), u32::from_le_bytes([b[12], b[13], b[14], b[15]])] } #[rustfmt::skip] + #[inline] pub const fn as_f32x4(self) -> [f32; 4] { let b = self.to_le_bytes(); [f32::from_bits(u32::from_le_bytes([b[0], b[1], b[2], b[3]])), f32::from_bits(u32::from_le_bytes([b[4], b[5], b[6], b[7]])), f32::from_bits(u32::from_le_bytes([b[8], b[9], b[10], b[11]])), f32::from_bits(u32::from_le_bytes([b[12], b[13], b[14], b[15]]))] } #[rustfmt::skip] + #[inline] pub const fn from_i32x4(x: [i32; 4]) -> Self { Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[2].to_le_bytes()[2], x[2].to_le_bytes()[3], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[3].to_le_bytes()[2], x[3].to_le_bytes()[3]]) } #[rustfmt::skip] + #[inline] pub const fn from_u32x4(x: [u32; 4]) -> Self { Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[2].to_le_bytes()[2], x[2].to_le_bytes()[3], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[3].to_le_bytes()[2], x[3].to_le_bytes()[3]]) } #[rustfmt::skip] + #[inline] pub const fn from_f32x4(x: [f32; 4]) -> Self { Self::from_le_bytes([x[0].to_bits().to_le_bytes()[0], x[0].to_bits().to_le_bytes()[1], x[0].to_bits().to_le_bytes()[2], x[0].to_bits().to_le_bytes()[3], x[1].to_bits().to_le_bytes()[0], x[1].to_bits().to_le_bytes()[1], x[1].to_bits().to_le_bytes()[2], x[1].to_bits().to_le_bytes()[3], x[2].to_bits().to_le_bytes()[0], x[2].to_bits().to_le_bytes()[1], x[2].to_bits().to_le_bytes()[2], x[2].to_bits().to_le_bytes()[3], x[3].to_bits().to_le_bytes()[0], x[3].to_bits().to_le_bytes()[1], x[3].to_bits().to_le_bytes()[2], x[3].to_bits().to_le_bytes()[3]]) } #[rustfmt::skip] + #[inline] pub const fn as_i64x2(self) -> [i64; 2] { let b = self.to_le_bytes(); [i64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]), i64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]])] } #[rustfmt::skip] + #[inline] pub const fn as_u64x2(self) -> [u64; 2] { let b = self.to_le_bytes(); [u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]), u64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]])] } #[rustfmt::skip] + #[inline] pub const fn as_f64x2(self) -> [f64; 2] { let b = self.to_le_bytes(); [f64::from_bits(u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])), f64::from_bits(u64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]]))] } #[rustfmt::skip] + #[inline] pub const fn from_i64x2(x: [i64; 2]) -> Self { Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[0].to_le_bytes()[4], x[0].to_le_bytes()[5], x[0].to_le_bytes()[6], x[0].to_le_bytes()[7], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[1].to_le_bytes()[4], x[1].to_le_bytes()[5], x[1].to_le_bytes()[6], x[1].to_le_bytes()[7]]) } #[rustfmt::skip] + #[inline] pub const fn from_u64x2(x: [u64; 2]) -> Self { Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[0].to_le_bytes()[4], x[0].to_le_bytes()[5], x[0].to_le_bytes()[6], x[0].to_le_bytes()[7], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[1].to_le_bytes()[4], x[1].to_le_bytes()[5], x[1].to_le_bytes()[6], x[1].to_le_bytes()[7]]) } #[rustfmt::skip] + #[inline] pub const fn from_f64x2(x: [f64; 2]) -> Self { 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(always)] + #[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(always)] + #[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(always)] + #[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(always)] + #[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(); @@ -163,41 +222,69 @@ impl Value128 { } #[doc(alias = "v128.any_true")] - pub const fn v128_any_true(self) -> bool { + pub fn v128_any_true(self) -> bool { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return wasm::v128_any_true(self.to_wasm_v128()); + } self.reduce_or() != 0 } #[doc(alias = "v128.not")] - pub const fn v128_not(self) -> Self { + pub fn v128_not(self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::v128_not(self.to_wasm_v128())); + } Self(!self.0) } #[doc(alias = "v128.and")] - pub const fn v128_and(self, rhs: Self) -> Self { + pub fn v128_and(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::v128_and(self.to_wasm_v128(), rhs.to_wasm_v128())); + } Self(self.0 & rhs.0) } #[doc(alias = "v128.andnot")] - pub const fn v128_andnot(self, rhs: Self) -> Self { + pub fn v128_andnot(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::v128_andnot(self.to_wasm_v128(), rhs.to_wasm_v128())); + } Self(self.0 & !rhs.0) } #[doc(alias = "v128.or")] - pub const fn v128_or(self, rhs: Self) -> Self { + pub fn v128_or(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::v128_or(self.to_wasm_v128(), rhs.to_wasm_v128())); + } Self(self.0 | rhs.0) } #[doc(alias = "v128.xor")] - pub const fn v128_xor(self, rhs: Self) -> Self { + pub fn v128_xor(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::v128_xor(self.to_wasm_v128(), rhs.to_wasm_v128())); + } Self(self.0 ^ rhs.0) } #[doc(alias = "v128.bitselect")] - pub const fn v128_bitselect(v1: Self, v2: Self, c: Self) -> Self { + pub fn v128_bitselect(v1: Self, v2: Self, c: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::v128_bitselect(v1.to_wasm_v128(), v2.to_wasm_v128(), c.to_wasm_v128())); + } Self((v1.0 & c.0) | (v2.0 & !c.0)) } - pub const fn swizzle(self, s: Self) -> Self { + pub fn swizzle(self, s: Self) -> Self { self.i8x16_swizzle(s) } @@ -266,7 +353,11 @@ impl Value128 { } #[doc(alias = "i8x16.swizzle")] - pub const fn i8x16_swizzle(self, s: Self) -> Self { + pub fn i8x16_swizzle(self, s: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i8x16_swizzle(self.to_wasm_v128(), s.to_wasm_v128())); + } let a_bytes = self.to_le_bytes(); let s_bytes = s.to_le_bytes(); let mut result_bytes = [0u8; 16]; @@ -280,15 +371,13 @@ impl Value128 { } #[doc(alias = "i8x16.shuffle")] - pub const fn i8x16_shuffle(a: Self, b: Self, idx: [u8; 16]) -> Self { + pub 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; + for i in 0..16 { + let index = (idx[i] & 31) as usize; result_bytes[i] = if index < 16 { a_bytes[index] } else { b_bytes[index - 16] }; - i += 1; } Self::from_le_bytes(result_bytes) } @@ -689,7 +778,11 @@ impl Value128 { } #[doc(alias = "i8x16.add")] - pub const fn i8x16_add(self, rhs: Self) -> Self { + pub fn i8x16_add(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i8x16_add(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i8x16(); let b = rhs.as_i8x16(); let mut out = [0i8; 16]; @@ -702,7 +795,11 @@ impl Value128 { } #[doc(alias = "i16x8.add")] - pub const fn i16x8_add(self, rhs: Self) -> Self { + pub fn i16x8_add(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i16x8_add(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i16x8(); let b = rhs.as_i16x8(); let mut out = [0i16; 8]; @@ -715,7 +812,11 @@ impl Value128 { } #[doc(alias = "i32x4.add")] - pub const fn i32x4_add(self, rhs: Self) -> Self { + pub fn i32x4_add(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i32x4_add(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i32x4(); let b = rhs.as_i32x4(); let mut out = [0i32; 4]; @@ -728,7 +829,11 @@ impl Value128 { } #[doc(alias = "i64x2.add")] - pub const fn i64x2_add(self, rhs: Self) -> Self { + pub fn i64x2_add(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i64x2_add(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i64x2(); let b = rhs.as_i64x2(); let mut out = [0i64; 2]; @@ -741,7 +846,11 @@ impl Value128 { } #[doc(alias = "i8x16.sub")] - pub const fn i8x16_sub(self, rhs: Self) -> Self { + pub fn i8x16_sub(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i8x16_sub(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i8x16(); let b = rhs.as_i8x16(); let mut out = [0i8; 16]; @@ -754,7 +863,11 @@ impl Value128 { } #[doc(alias = "i16x8.sub")] - pub const fn i16x8_sub(self, rhs: Self) -> Self { + pub fn i16x8_sub(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i16x8_sub(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i16x8(); let b = rhs.as_i16x8(); let mut out = [0i16; 8]; @@ -767,7 +880,11 @@ impl Value128 { } #[doc(alias = "i32x4.sub")] - pub const fn i32x4_sub(self, rhs: Self) -> Self { + pub fn i32x4_sub(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i32x4_sub(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i32x4(); let b = rhs.as_i32x4(); let mut out = [0i32; 4]; @@ -780,7 +897,11 @@ impl Value128 { } #[doc(alias = "i64x2.sub")] - pub const fn i64x2_sub(self, rhs: Self) -> Self { + pub fn i64x2_sub(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i64x2_sub(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i64x2(); let b = rhs.as_i64x2(); let mut out = [0i64; 2]; @@ -793,7 +914,11 @@ impl Value128 { } #[doc(alias = "i16x8.mul")] - pub const fn i16x8_mul(self, rhs: Self) -> Self { + pub fn i16x8_mul(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i16x8_mul(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i16x8(); let b = rhs.as_i16x8(); let mut out = [0i16; 8]; @@ -806,7 +931,11 @@ impl Value128 { } #[doc(alias = "i32x4.mul")] - pub const fn i32x4_mul(self, rhs: Self) -> Self { + pub fn i32x4_mul(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i32x4_mul(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i32x4(); let b = rhs.as_i32x4(); let mut out = [0i32; 4]; @@ -819,7 +948,11 @@ impl Value128 { } #[doc(alias = "i64x2.mul")] - pub const fn i64x2_mul(self, rhs: Self) -> Self { + pub fn i64x2_mul(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i64x2_mul(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i64x2(); let b = rhs.as_i64x2(); let mut out = [0i64; 2]; @@ -832,7 +965,11 @@ impl Value128 { } #[doc(alias = "i8x16.add_sat_s")] - pub const fn i8x16_add_sat_s(self, rhs: Self) -> Self { + pub fn i8x16_add_sat_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i8x16_add_sat(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i8x16(); let b = rhs.as_i8x16(); let mut out = [0i8; 16]; @@ -845,7 +982,11 @@ impl Value128 { } #[doc(alias = "i16x8.add_sat_s")] - pub const fn i16x8_add_sat_s(self, rhs: Self) -> Self { + pub fn i16x8_add_sat_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i16x8_add_sat(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i16x8(); let b = rhs.as_i16x8(); let mut out = [0i16; 8]; @@ -858,7 +999,11 @@ impl Value128 { } #[doc(alias = "i8x16.add_sat_u")] - pub const fn i8x16_add_sat_u(self, rhs: Self) -> Self { + pub fn i8x16_add_sat_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u8x16_add_sat(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u8x16(); let b = rhs.as_u8x16(); let mut out = [0u8; 16]; @@ -871,7 +1016,11 @@ impl Value128 { } #[doc(alias = "i16x8.add_sat_u")] - pub const fn i16x8_add_sat_u(self, rhs: Self) -> Self { + pub fn i16x8_add_sat_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u16x8_add_sat(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u16x8(); let b = rhs.as_u16x8(); let mut out = [0u16; 8]; @@ -884,7 +1033,11 @@ impl Value128 { } #[doc(alias = "i8x16.sub_sat_s")] - pub const fn i8x16_sub_sat_s(self, rhs: Self) -> Self { + pub fn i8x16_sub_sat_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i8x16_sub_sat(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i8x16(); let b = rhs.as_i8x16(); let mut out = [0i8; 16]; @@ -897,7 +1050,11 @@ impl Value128 { } #[doc(alias = "i16x8.sub_sat_s")] - pub const fn i16x8_sub_sat_s(self, rhs: Self) -> Self { + pub fn i16x8_sub_sat_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i16x8_sub_sat(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i16x8(); let b = rhs.as_i16x8(); let mut out = [0i16; 8]; @@ -910,7 +1067,11 @@ impl Value128 { } #[doc(alias = "i8x16.sub_sat_u")] - pub const fn i8x16_sub_sat_u(self, rhs: Self) -> Self { + pub fn i8x16_sub_sat_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u8x16_sub_sat(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u8x16(); let b = rhs.as_u8x16(); let mut out = [0u8; 16]; @@ -923,7 +1084,11 @@ impl Value128 { } #[doc(alias = "i16x8.sub_sat_u")] - pub const fn i16x8_sub_sat_u(self, rhs: Self) -> Self { + pub fn i16x8_sub_sat_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u16x8_sub_sat(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u16x8(); let b = rhs.as_u16x8(); let mut out = [0u16; 8]; @@ -936,7 +1101,11 @@ impl Value128 { } #[doc(alias = "i8x16.avgr_u")] - pub const fn i8x16_avgr_u(self, rhs: Self) -> Self { + pub fn i8x16_avgr_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u8x16_avgr(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u8x16(); let b = rhs.as_u8x16(); let mut out = [0u8; 16]; @@ -949,7 +1118,11 @@ impl Value128 { } #[doc(alias = "i16x8.avgr_u")] - pub const fn i16x8_avgr_u(self, rhs: Self) -> Self { + pub fn i16x8_avgr_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u16x8_avgr(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u16x8(); let b = rhs.as_u16x8(); let mut out = [0u16; 8]; @@ -1366,7 +1539,11 @@ impl Value128 { } #[doc(alias = "i8x16.eq")] - pub const fn i8x16_eq(self, rhs: Self) -> Self { + pub fn i8x16_eq(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i8x16_eq(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i8x16(); let b = rhs.as_i8x16(); let mut out = [0i8; 16]; @@ -1379,7 +1556,11 @@ impl Value128 { } #[doc(alias = "i16x8.eq")] - pub const fn i16x8_eq(self, rhs: Self) -> Self { + pub fn i16x8_eq(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i16x8_eq(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i16x8(); let b = rhs.as_i16x8(); let mut out = [0i16; 8]; @@ -1392,7 +1573,11 @@ impl Value128 { } #[doc(alias = "i32x4.eq")] - pub const fn i32x4_eq(self, rhs: Self) -> Self { + pub fn i32x4_eq(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i32x4_eq(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i32x4(); let b = rhs.as_i32x4(); let mut out = [0i32; 4]; @@ -1405,7 +1590,11 @@ impl Value128 { } #[doc(alias = "i64x2.eq")] - pub const fn i64x2_eq(self, rhs: Self) -> Self { + pub fn i64x2_eq(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i64x2_eq(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i64x2(); let b = rhs.as_i64x2(); let mut out = [0i64; 2]; @@ -1418,7 +1607,11 @@ impl Value128 { } #[doc(alias = "i8x16.ne")] - pub const fn i8x16_ne(self, rhs: Self) -> Self { + pub fn i8x16_ne(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i8x16_ne(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i8x16(); let b = rhs.as_i8x16(); let mut out = [0i8; 16]; @@ -1431,7 +1624,11 @@ impl Value128 { } #[doc(alias = "i16x8.ne")] - pub const fn i16x8_ne(self, rhs: Self) -> Self { + pub fn i16x8_ne(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i16x8_ne(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i16x8(); let b = rhs.as_i16x8(); let mut out = [0i16; 8]; @@ -1444,7 +1641,11 @@ impl Value128 { } #[doc(alias = "i32x4.ne")] - pub const fn i32x4_ne(self, rhs: Self) -> Self { + pub fn i32x4_ne(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i32x4_ne(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i32x4(); let b = rhs.as_i32x4(); let mut out = [0i32; 4]; @@ -1457,7 +1658,11 @@ impl Value128 { } #[doc(alias = "i64x2.ne")] - pub const fn i64x2_ne(self, rhs: Self) -> Self { + pub fn i64x2_ne(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i64x2_ne(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i64x2(); let b = rhs.as_i64x2(); let mut out = [0i64; 2]; @@ -1470,7 +1675,11 @@ impl Value128 { } #[doc(alias = "i8x16.lt_s")] - pub const fn i8x16_lt_s(self, rhs: Self) -> Self { + pub fn i8x16_lt_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i8x16_lt(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i8x16(); let b = rhs.as_i8x16(); let mut out = [0i8; 16]; @@ -1483,7 +1692,11 @@ impl Value128 { } #[doc(alias = "i16x8.lt_s")] - pub const fn i16x8_lt_s(self, rhs: Self) -> Self { + pub fn i16x8_lt_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i16x8_lt(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i16x8(); let b = rhs.as_i16x8(); let mut out = [0i16; 8]; @@ -1496,7 +1709,11 @@ impl Value128 { } #[doc(alias = "i32x4.lt_s")] - pub const fn i32x4_lt_s(self, rhs: Self) -> Self { + pub fn i32x4_lt_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i32x4_lt(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i32x4(); let b = rhs.as_i32x4(); let mut out = [0i32; 4]; @@ -1509,7 +1726,11 @@ impl Value128 { } #[doc(alias = "i64x2.lt_s")] - pub const fn i64x2_lt_s(self, rhs: Self) -> Self { + pub fn i64x2_lt_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i64x2_lt(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i64x2(); let b = rhs.as_i64x2(); let mut out = [0i64; 2]; @@ -1522,7 +1743,11 @@ impl Value128 { } #[doc(alias = "i8x16.lt_u")] - pub const fn i8x16_lt_u(self, rhs: Self) -> Self { + pub fn i8x16_lt_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u8x16_lt(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u8x16(); let b = rhs.as_u8x16(); let mut out = [0i8; 16]; @@ -1535,7 +1760,11 @@ impl Value128 { } #[doc(alias = "i16x8.lt_u")] - pub const fn i16x8_lt_u(self, rhs: Self) -> Self { + pub fn i16x8_lt_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u16x8_lt(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u16x8(); let b = rhs.as_u16x8(); let mut out = [0i16; 8]; @@ -1548,7 +1777,11 @@ impl Value128 { } #[doc(alias = "i32x4.lt_u")] - pub const fn i32x4_lt_u(self, rhs: Self) -> Self { + pub fn i32x4_lt_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u32x4_lt(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u32x4(); let b = rhs.as_u32x4(); let mut out = [0i32; 4]; @@ -1561,77 +1794,81 @@ impl Value128 { } #[doc(alias = "i8x16.gt_s")] - pub const fn i8x16_gt_s(self, rhs: Self) -> Self { + pub 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 { + pub 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 { + pub 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 { + pub 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 { + pub 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 { + pub 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 { + pub 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 { + pub 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 { + pub 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 { + pub 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 { + pub 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 { + pub 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 { + pub 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 { + pub 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 { + pub fn i8x16_ge_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i8x16_ge(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i8x16(); let b = rhs.as_i8x16(); let mut out = [0i8; 16]; @@ -1644,7 +1881,11 @@ impl Value128 { } #[doc(alias = "i16x8.ge_s")] - pub const fn i16x8_ge_s(self, rhs: Self) -> Self { + pub fn i16x8_ge_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i16x8_ge(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i16x8(); let b = rhs.as_i16x8(); let mut out = [0i16; 8]; @@ -1657,7 +1898,11 @@ impl Value128 { } #[doc(alias = "i32x4.ge_s")] - pub const fn i32x4_ge_s(self, rhs: Self) -> Self { + pub fn i32x4_ge_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i32x4_ge(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i32x4(); let b = rhs.as_i32x4(); let mut out = [0i32; 4]; @@ -1670,7 +1915,11 @@ impl Value128 { } #[doc(alias = "i64x2.ge_s")] - pub const fn i64x2_ge_s(self, rhs: Self) -> Self { + pub fn i64x2_ge_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i64x2_ge(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i64x2(); let b = rhs.as_i64x2(); let mut out = [0i64; 2]; @@ -1683,7 +1932,11 @@ impl Value128 { } #[doc(alias = "i8x16.ge_u")] - pub const fn i8x16_ge_u(self, rhs: Self) -> Self { + pub fn i8x16_ge_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u8x16_ge(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u8x16(); let b = rhs.as_u8x16(); let mut out = [0i8; 16]; @@ -1696,7 +1949,11 @@ impl Value128 { } #[doc(alias = "i16x8.ge_u")] - pub const fn i16x8_ge_u(self, rhs: Self) -> Self { + pub fn i16x8_ge_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u16x8_ge(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u16x8(); let b = rhs.as_u16x8(); let mut out = [0i16; 8]; @@ -1709,7 +1966,11 @@ impl Value128 { } #[doc(alias = "i32x4.ge_u")] - pub const fn i32x4_ge_u(self, rhs: Self) -> Self { + pub fn i32x4_ge_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u32x4_ge(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u32x4(); let b = rhs.as_u32x4(); let mut out = [0i32; 4]; @@ -1770,7 +2031,11 @@ impl Value128 { } #[doc(alias = "i8x16.neg")] - pub const fn i8x16_neg(self) -> Self { + pub fn i8x16_neg(self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i8x16_neg(self.to_wasm_v128())); + } let a = self.as_i8x16(); let mut out = [0i8; 16]; let mut i = 0; @@ -1782,7 +2047,11 @@ impl Value128 { } #[doc(alias = "i16x8.neg")] - pub const fn i16x8_neg(self) -> Self { + pub fn i16x8_neg(self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i16x8_neg(self.to_wasm_v128())); + } let a = self.as_i16x8(); let mut out = [0i16; 8]; let mut i = 0; @@ -1794,7 +2063,11 @@ impl Value128 { } #[doc(alias = "i32x4.neg")] - pub const fn i32x4_neg(self) -> Self { + pub fn i32x4_neg(self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i32x4_neg(self.to_wasm_v128())); + } let a = self.as_i32x4(); let mut out = [0i32; 4]; let mut i = 0; @@ -1806,7 +2079,11 @@ impl Value128 { } #[doc(alias = "i64x2.neg")] - pub const fn i64x2_neg(self) -> Self { + pub fn i64x2_neg(self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i64x2_neg(self.to_wasm_v128())); + } let a = self.as_i64x2(); let mut out = [0i64; 2]; let mut i = 0; @@ -1818,7 +2095,11 @@ impl Value128 { } #[doc(alias = "i8x16.min_s")] - pub const fn i8x16_min_s(self, rhs: Self) -> Self { + pub fn i8x16_min_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i8x16_min(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i8x16(); let b = rhs.as_i8x16(); let mut out = [0i8; 16]; @@ -1831,7 +2112,11 @@ impl Value128 { } #[doc(alias = "i16x8.min_s")] - pub const fn i16x8_min_s(self, rhs: Self) -> Self { + pub fn i16x8_min_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i16x8_min(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i16x8(); let b = rhs.as_i16x8(); let mut out = [0i16; 8]; @@ -1844,7 +2129,11 @@ impl Value128 { } #[doc(alias = "i32x4.min_s")] - pub const fn i32x4_min_s(self, rhs: Self) -> Self { + pub fn i32x4_min_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i32x4_min(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i32x4(); let b = rhs.as_i32x4(); let mut out = [0i32; 4]; @@ -1857,7 +2146,11 @@ impl Value128 { } #[doc(alias = "i8x16.min_u")] - pub const fn i8x16_min_u(self, rhs: Self) -> Self { + pub fn i8x16_min_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u8x16_min(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u8x16(); let b = rhs.as_u8x16(); let mut out = [0u8; 16]; @@ -1870,7 +2163,11 @@ impl Value128 { } #[doc(alias = "i16x8.min_u")] - pub const fn i16x8_min_u(self, rhs: Self) -> Self { + pub fn i16x8_min_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u16x8_min(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u16x8(); let b = rhs.as_u16x8(); let mut out = [0u16; 8]; @@ -1883,7 +2180,11 @@ impl Value128 { } #[doc(alias = "i32x4.min_u")] - pub const fn i32x4_min_u(self, rhs: Self) -> Self { + pub fn i32x4_min_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u32x4_min(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u32x4(); let b = rhs.as_u32x4(); let mut out = [0u32; 4]; @@ -1896,7 +2197,11 @@ impl Value128 { } #[doc(alias = "i8x16.max_s")] - pub const fn i8x16_max_s(self, rhs: Self) -> Self { + pub fn i8x16_max_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i8x16_max(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i8x16(); let b = rhs.as_i8x16(); let mut out = [0i8; 16]; @@ -1909,7 +2214,11 @@ impl Value128 { } #[doc(alias = "i16x8.max_s")] - pub const fn i16x8_max_s(self, rhs: Self) -> Self { + pub fn i16x8_max_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i16x8_max(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i16x8(); let b = rhs.as_i16x8(); let mut out = [0i16; 8]; @@ -1922,7 +2231,11 @@ impl Value128 { } #[doc(alias = "i32x4.max_s")] - pub const fn i32x4_max_s(self, rhs: Self) -> Self { + pub fn i32x4_max_s(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::i32x4_max(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_i32x4(); let b = rhs.as_i32x4(); let mut out = [0i32; 4]; @@ -1935,7 +2248,11 @@ impl Value128 { } #[doc(alias = "i8x16.max_u")] - pub const fn i8x16_max_u(self, rhs: Self) -> Self { + pub fn i8x16_max_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u8x16_max(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u8x16(); let b = rhs.as_u8x16(); let mut out = [0u8; 16]; @@ -1948,7 +2265,11 @@ impl Value128 { } #[doc(alias = "i16x8.max_u")] - pub const fn i16x8_max_u(self, rhs: Self) -> Self { + pub fn i16x8_max_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u16x8_max(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u16x8(); let b = rhs.as_u16x8(); let mut out = [0u16; 8]; @@ -1961,7 +2282,11 @@ impl Value128 { } #[doc(alias = "i32x4.max_u")] - pub const fn i32x4_max_u(self, rhs: Self) -> Self { + pub fn i32x4_max_u(self, rhs: Self) -> Self { + #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] + { + return Self::from_wasm_v128(wasm::u32x4_max(self.to_wasm_v128(), rhs.to_wasm_v128())); + } let a = self.as_u32x4(); let b = rhs.as_u32x4(); let mut out = [0u32; 4]; diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs index 9b6e2c1..b57008c 100644 --- a/crates/tinywasm/src/interpreter/values.rs +++ b/crates/tinywasm/src/interpreter/values.rs @@ -104,30 +104,15 @@ mod sealed { pub trait Sealed {} } -pub(crate) trait InternalValue: sealed::Sealed + Into<TinyWasmValue> { +pub(crate) trait InternalValue: sealed::Sealed + Into<TinyWasmValue> + Copy + Default { fn stack_push(stack: &mut ValueStack, value: Self) -> Result<()>; - fn local_get(stack: &ValueStack, frame: &CallFrame, index: LocalAddr) -> Self - where - Self: Sized; - fn local_set(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, value: Self) - where - Self: Sized; - fn replace_top(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result<Self>) -> Result<()> - where - Self: Sized; - fn stack_calculate(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result<Self>) -> Result<()> - where - Self: Sized; - fn stack_calculate3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result<Self>) -> Result<()> - where - Self: Sized; - - fn stack_pop(stack: &mut ValueStack) -> Self - where - Self: Sized; - fn stack_peek(stack: &ValueStack) -> Self - where - Self: Sized; + fn local_get(stack: &ValueStack, frame: &CallFrame, index: LocalAddr) -> Self; + fn local_set(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, value: Self); + fn replace_top(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result<Self>) -> Result<()>; + fn stack_calculate(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result<Self>) -> Result<()>; + fn stack_calculate3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result<Self>) -> Result<()>; + fn stack_pop(stack: &mut ValueStack) -> Self; + fn stack_peek(stack: &ValueStack) -> Self; } macro_rules! impl_internalvalue { @@ -142,32 +127,32 @@ macro_rules! impl_internalvalue { } impl InternalValue for $outer { - #[inline] + #[inline(always)] fn stack_push(stack: &mut ValueStack, value: Self) -> Result<()> { stack.$stack.push($to_internal(value)) } - #[inline] + #[inline(always)] fn local_get(stack: &ValueStack, frame: &CallFrame, index: LocalAddr) -> Self { - $to_outer(stack.$stack.get(frame.locals_base.$stack_base + index as usize)) + $to_outer(stack.$stack.get(frame.locals_base.$stack_base as usize + index as usize)) } - #[inline] + #[inline(always)] fn local_set(stack: &mut ValueStack, frame: &CallFrame, index: LocalAddr, value: Self) { - stack.$stack.set(frame.locals_base.$stack_base + index as usize, $to_internal(value)); + stack.$stack.set(frame.locals_base.$stack_base as usize + index as usize, $to_internal(value)); } - #[inline] + #[inline(always)] fn stack_pop(stack: &mut ValueStack) -> Self { $to_outer(stack.$stack.pop()) } - #[inline] + #[inline(always)] fn stack_peek(stack: &ValueStack) -> Self { $to_outer(*stack.$stack.last()) } - #[inline] + #[inline(always)] fn stack_calculate(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result<Self>) -> Result<()> { let v2 = stack.$stack.pop(); let v1 = stack.$stack.last_mut(); @@ -175,7 +160,7 @@ macro_rules! impl_internalvalue { Ok(()) } - #[inline] + #[inline(always)] fn stack_calculate3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result<Self>) -> Result<()> { let v3 = stack.$stack.pop(); let v2 = stack.$stack.pop(); @@ -184,7 +169,7 @@ macro_rules! impl_internalvalue { Ok(()) } - #[inline] + #[inline(always)] fn replace_top(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result<Self>) -> Result<()> { let v = stack.$stack.last_mut(); *v = $to_internal(func($to_outer(*v))?); diff --git a/crates/tinywasm/tests/wasm-custom/loop-boundary-superinstructions.wast b/crates/tinywasm/tests/wasm-custom/loop-boundary-superinstructions.wast new file mode 100644 index 0000000..8647163 --- /dev/null +++ b/crates/tinywasm/tests/wasm-custom/loop-boundary-superinstructions.wast @@ -0,0 +1,26 @@ +(module + (func (export "i32-add-locals-across-loop-boundary") (param i32) (result i32) + (block (result i32) + (local.get 0) + (loop (param i32) (result i32) + (local.get 0) + (i32.add) + (br 1) + ) + ) + ) + + (func (export "i64-add-locals-across-loop-boundary") (param i64) (result i64) + (block (result i64) + (local.get 0) + (loop (param i64) (result i64) + (local.get 0) + (i64.add) + (br 1) + ) + ) + ) +) + +(assert_return (invoke "i32-add-locals-across-loop-boundary" (i32.const 7)) (i32.const 14)) +(assert_return (invoke "i64-add-locals-across-loop-boundary" (i64.const 9)) (i64.const 18)) diff --git a/crates/tinywasm/tests/wasm-custom/select-multi-reference-types.wast b/crates/tinywasm/tests/wasm-custom/select-multi-reference-types.wast new file mode 100644 index 0000000..6f55b15 --- /dev/null +++ b/crates/tinywasm/tests/wasm-custom/select-multi-reference-types.wast @@ -0,0 +1,17 @@ +(module + (table 1 funcref) + (func $f) + (elem (i32.const 0) func $f) + + (func (export "select-funcref") (param i32) (result i32) + (ref.null func) + (i32.const 0) + (table.get 0) + (local.get 0) + (select (result funcref)) + (ref.is_null) + ) +) + +(assert_return (invoke "select-funcref" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "select-funcref" (i32.const 0)) (i32.const 0)) diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index 7f0cef5..29c9cab 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -234,18 +234,18 @@ pub enum Instruction { F32x4DemoteF64x2Zero, F64x2PromoteLowF32x4, // > Relaxed SIMD - I8x16RelaxedSwizzle, - I32x4RelaxedTruncF32x4S, I32x4RelaxedTruncF32x4U, - I32x4RelaxedTruncF64x2SZero, I32x4RelaxedTruncF64x2UZero, - F32x4RelaxedMadd, F32x4RelaxedNmadd, - F64x2RelaxedMadd, F64x2RelaxedNmadd, - I8x16RelaxedLaneselect, - I16x8RelaxedLaneselect, - I32x4RelaxedLaneselect, - I64x2RelaxedLaneselect, - F32x4RelaxedMin, F32x4RelaxedMax, - F64x2RelaxedMin, F64x2RelaxedMax, - I16x8RelaxedQ15mulrS, - I16x8RelaxedDotI8x16I7x16S, - I32x4RelaxedDotI8x16I7x16AddS + // I8x16RelaxedSwizzle, + // I32x4RelaxedTruncF32x4S, I32x4RelaxedTruncF32x4U, + // I32x4RelaxedTruncF64x2SZero, I32x4RelaxedTruncF64x2UZero, + // F32x4RelaxedMadd, F32x4RelaxedNmadd, + // F64x2RelaxedMadd, F64x2RelaxedNmadd, + // I8x16RelaxedLaneselect, + // I16x8RelaxedLaneselect, + // I32x4RelaxedLaneselect, + // I64x2RelaxedLaneselect, + // F32x4RelaxedMin, F32x4RelaxedMax, + // F64x2RelaxedMin, F64x2RelaxedMax, + // I16x8RelaxedQ15mulrS, + // I16x8RelaxedDotI8x16I7x16S, + // I32x4RelaxedDotI8x16I7x16AddS } diff --git a/examples/rust/Cargo.toml b/examples/rust/Cargo.toml index da238ad..430bcad 100644 --- a/examples/rust/Cargo.toml +++ b/examples/rust/Cargo.toml @@ -48,7 +48,7 @@ path="src/argon2id.rs" [profile.wasm] opt-level=3 -lto="thin" +lto="fat" codegen-units=1 panic="abort" inherits="release" diff --git a/examples/rust/build.sh b/examples/rust/build.sh index 567ed56..9df5447 100755 --- a/examples/rust/build.sh +++ b/examples/rust/build.sh @@ -2,12 +2,11 @@ cd "$(dirname "$0")" || exit bins=("host_fn" "hello" "fibonacci" "print" "tinywasm" "argon2id") -exclude_wat=("tinywasm") out_dir="./target/wasm32-unknown-unknown/wasm" dest_dir="out" -rust_features="+simd128,+reference-types,+bulk-memory,+mutable-globals,+multivalue,+sign-ext,+nontrapping-fptoint" -wasmopt_features="--enable-simd --enable-reference-types --enable-bulk-memory --enable-mutable-globals --enable-multivalue --enable-sign-ext --enable-nontrapping-float-to-int" +rust_features="+sign-ext,+simd128,+reference-types,+bulk-memory,+bulk-memory-opt,+multimemory,+call-indirect-overlong,+mutable-globals,+multivalue,+sign-ext,+nontrapping-fptoint,+extended-const,+tail-call" +# wasmopt_features="--enable-reference-types --enable-bulk-memory --enable-mutable-globals --enable-multivalue --enable-sign-ext --enable-nontrapping-float-to-int" # ensure out dir exists mkdir -p "$dest_dir" @@ -20,9 +19,5 @@ for bin in "${bins[@]}"; do RUSTFLAGS="-C target-feature=$rust_features -C panic=abort" cargo build --target wasm32-unknown-unknown --package rust-wasm-examples --profile=wasm --bin "$bin" cp "$out_dir/$bin.wasm" "$dest_dir/" - wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.opt.wasm" -O3 $wasmopt_features - - if [[ ! " ${exclude_wat[@]} " =~ " $bin " ]]; then - wasm2wat "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wat" - fi + # wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.opt.wasm" -O3 $wasmopt_features done diff --git a/examples/wasm-rust.rs b/examples/wasm-rust.rs index 82d5c93..4d8cdf4 100644 --- a/examples/wasm-rust.rs +++ b/examples/wasm-rust.rs @@ -72,7 +72,7 @@ fn main() -> Result<()> { } fn tinywasm() -> Result<()> { - let module = Module::parse_file("./examples/rust/out/tinywasm.opt.wasm")?; + let module = Module::parse_file("./examples/rust/out/tinywasm.wasm")?; let mut store = Store::default(); let mut imports = Imports::new(); @@ -102,7 +102,7 @@ fn tinywasm_no_std() -> Result<()> { } fn hello() -> Result<()> { - let module = Module::parse_file("./examples/rust/out/hello.opt.wasm")?; + let module = Module::parse_file("./examples/rust/out/hello.wasm")?; let mut store = Store::default(); let mut imports = Imports::new(); @@ -151,7 +151,7 @@ fn host_fn() -> Result<()> { } fn printi32() -> Result<()> { - let module = Module::parse_file("./examples/rust/out/print.opt.wasm")?; + let module = Module::parse_file("./examples/rust/out/print.wasm")?; let mut store = Store::default(); let mut imports = Imports::new(); @@ -172,7 +172,7 @@ fn printi32() -> Result<()> { } fn fibonacci() -> Result<()> { - let module = Module::parse_file("./examples/rust/out/fibonacci.opt.wasm")?; + let module = Module::parse_file("./examples/rust/out/fibonacci.wasm")?; let mut store = Store::default(); let instance = module.instantiate(&mut store, None)?; @@ -185,7 +185,7 @@ fn fibonacci() -> Result<()> { } fn argon2id() -> Result<()> { - let module = Module::parse_file("./examples/rust/out/argon2id.opt.wasm")?; + let module = Module::parse_file("./examples/rust/out/argon2id.wasm")?; let mut store = Store::default(); let instance = module.instantiate(&mut store, None)?; |
