From 4c1f44a79d0e04fb33042c2eabc27040d260dfa5 Mon Sep 17 00:00:00 2001 From: Henry Gressmann Date: Fri, 11 Oct 2024 22:44:29 +0200 Subject: feat: add simd support to the parser --- crates/cli/Cargo.toml | 2 +- crates/parser/Cargo.toml | 4 +- crates/parser/src/conversion.rs | 4 +- crates/parser/src/lib.rs | 3 +- crates/parser/src/module.rs | 21 +- crates/parser/src/visit.rs | 130 ++++++++++--- crates/tinywasm/Cargo.toml | 4 +- crates/tinywasm/src/interpreter/executor.rs | 58 +++--- .../tinywasm/src/interpreter/stack/call_stack.rs | 27 +-- .../tinywasm/src/interpreter/stack/value_stack.rs | 4 +- crates/tinywasm/src/interpreter/values.rs | 46 +++-- crates/tinywasm/tests/generated/wasm-simd.csv | 1 + crates/types/src/instructions.rs | 211 +++++++++++++++------ crates/types/src/lib.rs | 38 ++++ crates/wasm-testsuite/Cargo.toml | 2 +- 15 files changed, 383 insertions(+), 172 deletions(-) (limited to 'crates') diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 51a669d..d5e64a8 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -15,7 +15,7 @@ path="src/bin.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tinywasm={version="0.8.0-alpha.0", path="../tinywasm", features=["std", "parser"]} +tinywasm={version="0.9.0-alpha.0", path="../tinywasm", features=["std", "parser"]} argh="0.1" eyre={workspace=true} log={workspace=true} diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index aa2f589..83bb32b 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -9,9 +9,9 @@ repository.workspace=true rust-version.workspace=true [dependencies] -wasmparser={version="0.218", default-features=false, features=["validate", "features"]} +wasmparser={version="0.219", default-features=false, features=["validate", "features"]} log={workspace=true, optional=true} -tinywasm-types={version="0.8.0-alpha.0", path="../types", default-features=false} +tinywasm-types={version="0.9.0-alpha.0", path="../types", default-features=false} [features] default=["std", "logging"] diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 76099ca..1ebe392 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -203,8 +203,8 @@ pub(crate) fn convert_module_code( } } - let (body, allocations) = process_operators_and_validate(validator, func, local_addr_map)?; - Ok(((body, local_counts), allocations)) + let (body, data, allocations) = process_operators_and_validate(validator, func, local_addr_map)?; + Ok(((body, data, local_counts), allocations)) } pub(crate) fn convert_module_type(ty: wasmparser::RecGroup) -> Result { diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index e736576..2222ffa 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -61,10 +61,11 @@ impl Parser { function_references: true, tail_call: true, multi_memory: true, - memory64: false, simd: true, + memory64: true, custom_page_sizes: true, + wide_arithmetic: false, gc_types: true, stack_switching: false, component_model: false, diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index ff7d109..9b31f9e 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -3,12 +3,12 @@ use crate::{conversion, ParseError, Result}; use alloc::string::ToString; use alloc::{boxed::Box, format, vec::Vec}; use tinywasm_types::{ - Data, Element, Export, FuncType, Global, Import, Instruction, MemoryType, TableType, TinyWasmModule, ValType, - ValueCounts, ValueCountsSmall, WasmFunction, + Data, Element, Export, FuncType, Global, Import, Instruction, MemoryType, TableType, TinyWasmModule, ValueCounts, + ValueCountsSmall, WasmFunction, WasmFunctionData, }; use wasmparser::{FuncValidatorAllocations, Payload, Validator}; -pub(crate) type Code = (Box<[Instruction]>, ValueCounts); +pub(crate) type Code = (Box<[Instruction]>, WasmFunctionData, ValueCounts); #[derive(Default)] pub(crate) struct ModuleReader { @@ -179,7 +179,6 @@ impl ModuleReader { Ok(()) } - #[inline] pub(crate) fn into_module(self) -> Result { if !self.end_reached { return Err(ParseError::EndNotReached); @@ -193,18 +192,10 @@ impl ModuleReader { .code .into_iter() .zip(self.code_type_addrs) - .map(|((instructions, locals), ty_idx)| { - let mut params = ValueCountsSmall::default(); + .map(|((instructions, data, locals), ty_idx)| { let ty = self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone(); - for param in &ty.params { - match param { - ValType::I32 | ValType::F32 => params.c32 += 1, - ValType::I64 | ValType::F64 => params.c64 += 1, - ValType::V128 => params.c128 += 1, - ValType::RefExtern | ValType::RefFunc => params.cref += 1, - } - } - WasmFunction { instructions, locals, params, ty } + let params = ValueCountsSmall::from(&ty.params); + WasmFunction { instructions, data, locals, params, ty } }) .collect::>() .into_boxed_slice(); diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index c9e5eac..2e80d20 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -3,7 +3,7 @@ use crate::Result; use crate::conversion::{convert_heaptype, convert_valtype}; use alloc::string::ToString; use alloc::{boxed::Box, vec::Vec}; -use tinywasm_types::{Instruction, MemoryArg}; +use tinywasm_types::{Instruction, MemoryArg, SimdInstruction, WasmFunctionData}; use wasmparser::{FuncValidator, FuncValidatorAllocations, FunctionBody, VisitOperator, WasmModuleResources}; struct ValidateThenVisit<'a, R: WasmModuleResources>(usize, &'a mut FunctionBuilder); @@ -26,7 +26,7 @@ pub(crate) fn process_operators_and_validate( validator: FuncValidator, body: FunctionBody<'_>, local_addr_map: Vec, -) -> Result<(Box<[Instruction]>, FuncValidatorAllocations)> { +) -> Result<(Box<[Instruction]>, WasmFunctionData, FuncValidatorAllocations)> { let mut reader = body.get_operators_reader()?; let remaining = reader.get_binary_reader().bytes_remaining(); let mut builder = FunctionBuilder::new(remaining, validator, local_addr_map); @@ -40,42 +40,65 @@ pub(crate) fn process_operators_and_validate( return Err(builder.errors.remove(0)); } - Ok((builder.instructions.into_boxed_slice(), builder.validator.into_allocations())) + Ok(( + builder.instructions.into_boxed_slice(), + WasmFunctionData { v128_constants: builder.v128_constants.into_boxed_slice() }, + builder.validator.into_allocations(), + )) } macro_rules! define_operand { - ($name:ident($instr:ident, $ty:ty)) => { + ($name:ident($instr:expr, $ty:ty)) => { fn $name(&mut self, arg: $ty) -> Self::Output { - self.instructions.push(Instruction::$instr(arg)); + self.instructions.push($instr(arg).into()); } }; - ($name:ident($instr:ident, $ty:ty, $ty2:ty)) => { + ($name:ident($instr:expr, $ty:ty, $ty2:ty)) => { fn $name(&mut self, arg: $ty, arg2: $ty2) -> Self::Output { - self.instructions.push(Instruction::$instr(arg, arg2)); + self.instructions.push($instr(arg, arg2).into()); } }; - ($name:ident($instr:ident)) => { + ($name:ident($instr:expr)) => { fn $name(&mut self) -> Self::Output { - self.instructions.push(Instruction::$instr); + self.instructions.push($instr.into()); } }; } macro_rules! define_operands { ($($name:ident($instr:ident $(,$ty:ty)*)),*) => {$( - define_operand!($name($instr $(,$ty)*)); + define_operand!($name(Instruction::$instr $(,$ty)*)); + )*}; +} + +macro_rules! define_operands_simd { + ($($name:ident($instr:ident $(,$ty:ty)*)),*) => {$( + define_operand!($name(SimdInstruction::$instr $(,$ty)*)); )*}; } macro_rules! define_mem_operands { ($($name:ident($instr:ident)),*) => {$( fn $name(&mut self, memarg: wasmparser::MemArg) -> Self::Output { - self.instructions.push(Instruction::$instr { - offset: memarg.offset, - mem_addr: memarg.memory, - }); + self.instructions.push(Instruction::$instr(MemoryArg::new(memarg.offset, memarg.memory))); + } + )*}; +} + +macro_rules! define_mem_operands_simd { + ($($name:ident($instr:ident)),*) => {$( + fn $name(&mut self, memarg: wasmparser::MemArg) -> Self::Output { + self.instructions.push(SimdInstruction::$instr(MemoryArg::new(memarg.offset, memarg.memory)).into()); + } + )*}; +} + +macro_rules! define_mem_operands_simd_lane { + ($($name:ident($instr:ident)),*) => {$( + fn $name(&mut self, memarg: wasmparser::MemArg, lane: u8) -> Self::Output { + self.instructions.push(SimdInstruction::$instr(MemoryArg::new(memarg.offset, memarg.memory), lane).into()); } )*}; } @@ -83,6 +106,7 @@ macro_rules! define_mem_operands { pub(crate) struct FunctionBuilder { validator: FuncValidator, instructions: Vec, + v128_constants: Vec, label_ptrs: Vec, local_addr_map: Vec, errors: Vec, @@ -107,6 +131,7 @@ impl FunctionBuilder { validator, local_addr_map, instructions: Vec::with_capacity(instr_capacity), + v128_constants: Vec::new(), label_ptrs: Vec::with_capacity(256), errors: Vec::new(), } @@ -127,8 +152,8 @@ macro_rules! impl_visit_operator { (@@sign_extension $($rest:tt)* ) => {}; (@@saturating_float_to_int $($rest:tt)* ) => {}; (@@bulk_memory $($rest:tt)* ) => {}; - (@@tail_call $($rest:tt)* ) => {}; - // (@@simd $($rest:tt)* ) => {}; + // (@@tail_call $($rest:tt)* ) => {}; + (@@simd $($rest:tt)* ) => {}; (@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*)) => { #[cold] fn $visit(&mut self $($(,$arg: $argty)*)?) { @@ -142,7 +167,7 @@ impl wasmparser::VisitOperator<'_> for FunctionBuilder wasmparser::VisitOperator<'_> for FunctionBuilder Self::Output { - self.instructions.push(Instruction::ReturnCall(function_index)); + fn visit_i8x16_shuffle(&mut self, lanes: [u8; 16]) -> Self::Output { + self.v128_constants.push(u128::from_le_bytes(lanes)); + self.instructions.push(SimdInstruction::I8x16Shuffle(self.v128_constants.len() as u32 - 1).into()); } - fn visit_return_call_indirect(&mut self, type_index: u32, table_index: u32) -> Self::Output { - self.instructions.push(Instruction::ReturnCallIndirect(type_index, table_index)); + fn visit_v128_const(&mut self, value: wasmparser::V128) -> Self::Output { + self.v128_constants.push(value.i128() as u128); + self.instructions.push(SimdInstruction::V128Const(self.v128_constants.len() as u32 - 1).into()); } + // fn visit_return_call(&mut self, function_index: u32) -> Self::Output { + // self.instructions.push(Instruction::ReturnCall(function_index)); + // } + + // fn visit_return_call_indirect(&mut self, type_index: u32, table_index: u32) -> Self::Output { + // self.instructions.push(Instruction::ReturnCallIndirect(type_index, table_index)); + // } + fn visit_global_set(&mut self, global_index: u32) -> Self::Output { match self.validator.get_operand_type(0) { Some(Some(t)) => self.instructions.push(match t { @@ -206,11 +285,6 @@ impl wasmparser::VisitOperator<'_> for FunctionBuilder self.visit_unreachable(), } } - fn visit_i32_store(&mut self, memarg: wasmparser::MemArg) -> Self::Output { - let arg = MemoryArg { offset: memarg.offset, mem_addr: memarg.memory }; - let i32store = Instruction::I32Store { offset: arg.offset, mem_addr: arg.mem_addr }; - self.instructions.push(i32store); - } fn visit_local_get(&mut self, idx: u32) -> Self::Output { let Ok(resolved_idx) = self.local_addr_map[idx as usize].try_into() else { diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml index 4dc82bb..401e3de 100644 --- a/crates/tinywasm/Cargo.toml +++ b/crates/tinywasm/Cargo.toml @@ -15,8 +15,8 @@ path="src/lib.rs" [dependencies] log={workspace=true, optional=true} -tinywasm-parser={version="0.8.0-alpha.0", path="../parser", default-features=false, optional=true} -tinywasm-types={version="0.8.0-alpha.0", path="../types", default-features=false} +tinywasm-parser={version="0.9.0-alpha.0", path="../parser", default-features=false, optional=true} +tinywasm-types={version="0.9.0-alpha.0", path="../types", default-features=false} libm={version="0.2", default-features=false} [dev-dependencies] diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index c2df82c..2326227 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -26,7 +26,7 @@ impl<'store, 'stack> Executor<'store, 'stack> { Ok(Self { cf: current_frame, module: current_module, stack, store }) } - #[inline] + #[inline(always)] pub(crate) fn run_to_completion(&mut self) -> Result<()> { loop { if let ControlFlow::Break(res) = self.exec_next() { @@ -114,30 +114,30 @@ impl<'store, 'stack> Executor<'store, 'stack> { ElemDrop(elem_index) => self.exec_elem_drop(*elem_index), TableCopy { from, to } => self.exec_table_copy(*from, *to).to_cf()?, - I32Store { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset, |v| v)?, - I64Store { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset, |v| v)?, - F32Store { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset, |v| v)?, - F64Store { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset, |v| v)?, - I32Store8 { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset, |v| v as i8)?, - I32Store16 { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset, |v| v as i16)?, - I64Store8 { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset, |v| v as i8)?, - I64Store16 { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset, |v| v as i16)?, - I64Store32 { mem_addr, offset } => self.exec_mem_store::(*mem_addr, *offset, |v| v as i32)?, - - I32Load { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v)?, - I64Load { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v)?, - F32Load { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v)?, - F64Load { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v)?, - I32Load8S { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v as i32)?, - I32Load8U { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v as i32)?, - I32Load16S { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v as i32)?, - I32Load16U { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v as i32)?, - I64Load8S { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v as i64)?, - I64Load8U { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v as i64)?, - I64Load16S { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v as i64)?, - I64Load16U { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v as i64)?, - I64Load32S { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v as i64)?, - I64Load32U { mem_addr, offset } => self.exec_mem_load::(*mem_addr, *offset, |v| v as i64)?, + I32Store(m) => self.exec_mem_store::(m.mem_addr(), m.offset(), |v| v)?, + I64Store(m) => self.exec_mem_store::(m.mem_addr(), m.offset(), |v| v)?, + F32Store(m) => self.exec_mem_store::(m.mem_addr(), m.offset(), |v| v)?, + F64Store(m) => self.exec_mem_store::(m.mem_addr(), m.offset(), |v| v)?, + I32Store8(m) => self.exec_mem_store::(m.mem_addr(), m.offset(), |v| v as i8)?, + I32Store16(m) => self.exec_mem_store::(m.mem_addr(), m.offset(), |v| v as i16)?, + I64Store8(m) => self.exec_mem_store::(m.mem_addr(), m.offset(), |v| v as i8)?, + I64Store16(m) => self.exec_mem_store::(m.mem_addr(), m.offset(), |v| v as i16)?, + I64Store32(m) => self.exec_mem_store::(m.mem_addr(), m.offset(), |v| v as i32)?, + + I32Load(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v)?, + I64Load(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v)?, + F32Load(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v)?, + F64Load(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v)?, + I32Load8S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i32)?, + I32Load8U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i32)?, + I32Load16S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i32)?, + I32Load16U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i32)?, + I64Load8S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i64)?, + I64Load8U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i64)?, + I64Load16S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i64)?, + I64Load16U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i64)?, + I64Load32S(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i64)?, + I64Load32U(m) => self.exec_mem_load::(m.mem_addr(), m.offset(), |v| v as i64)?, I64Eqz => self.stack.values.replace_top::(|v| Ok(i32::from(v == 0))).to_cf()?, I32Eqz => self.stack.values.replace_top_same::(|v| Ok(i32::from(v == 0))).to_cf()?, @@ -302,6 +302,10 @@ impl<'store, 'stack> Executor<'store, 'stack> { LocalCopy128(from, to) => self.exec_local_copy::(*from, *to), LocalCopyRef(from, to) => self.exec_local_copy::(*from, *to), + Simd(_) => { + unreachable!("unimplemented sidm instruction"); + } + instr => { unreachable!("unimplemented instruction: {:?}", instr); } @@ -585,10 +589,10 @@ impl<'store, 'stack> Executor<'store, 'stack> { mem.store(dst as usize, size as usize, &data[offset as usize..((offset + size) as usize)]) } fn exec_data_drop(&mut self, data_index: u32) { - self.store.get_data_mut(self.module.resolve_data_addr(data_index)).drop() + self.store.get_data_mut(self.module.resolve_data_addr(data_index)).drop(); } fn exec_elem_drop(&mut self, elem_index: u32) { - self.store.get_elem_mut(self.module.resolve_elem_addr(elem_index)).drop() + self.store.get_elem_mut(self.module.resolve_elem_addr(elem_index)).drop(); } fn exec_table_copy(&mut self, from: u32, to: u32) -> Result<()> { let size: i32 = self.stack.values.pop(); diff --git a/crates/tinywasm/src/interpreter/stack/call_stack.rs b/crates/tinywasm/src/interpreter/stack/call_stack.rs index 7c2be9c..f0e8d18 100644 --- a/crates/tinywasm/src/interpreter/stack/call_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/call_stack.rs @@ -22,12 +22,12 @@ impl CallStack { Self { stack: vec![initial_frame] } } - #[inline(always)] + #[inline] pub(crate) fn pop(&mut self) -> Option { self.stack.pop() } - #[inline(always)] + #[inline] pub(crate) fn push(&mut self, call_frame: CallFrame) -> ControlFlow> { if unlikely((self.stack.len() + 1) >= MAX_CALL_STACK_SIZE) { return ControlFlow::Break(Some(Trap::CallStackOverflow.into())); @@ -60,44 +60,47 @@ impl Locals { } pub(crate) fn set(&mut self, local_index: LocalAddr, value: T) { - T::local_set(self, local_index, value) + T::local_set(self, local_index, value); } } impl CallFrame { - #[inline(always)] + #[inline] pub(crate) fn instr_ptr(&self) -> usize { self.instr_ptr } - #[inline(always)] + #[inline] pub(crate) fn incr_instr_ptr(&mut self) { self.instr_ptr += 1; } - #[inline(always)] + #[inline] pub(crate) fn jump(&mut self, offset: usize) { self.instr_ptr += offset; } - #[inline(always)] + #[inline] pub(crate) fn module_addr(&self) -> ModuleInstanceAddr { self.module_addr } - #[inline(always)] + #[inline] pub(crate) fn block_ptr(&self) -> u32 { self.block_ptr } #[inline(always)] pub(crate) fn fetch_instr(&self) -> &Instruction { - &self.func_instance.instructions[self.instr_ptr] + match self.func_instance.instructions.get(self.instr_ptr) { + Some(instr) => instr, + None => unreachable!("Instruction out of bounds, this is a bug"), + } } /// Break to a block at the given index (relative to the current frame) /// Returns `None` if there is no block at the given index (e.g. if we need to return, this is handled by the caller) - #[inline(always)] + #[inline] pub(crate) fn break_to( &mut self, break_to_relative: u32, @@ -140,7 +143,7 @@ impl CallFrame { Some(()) } - #[inline(always)] + #[inline] pub(crate) fn new( wasm_func_inst: Rc, owner: ModuleInstanceAddr, @@ -192,7 +195,7 @@ impl CallFrame { Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, block_ptr, locals } } - #[inline(always)] + #[inline] pub(crate) fn instructions(&self) -> &[Instruction] { &self.func_instance.instructions } diff --git a/crates/tinywasm/src/interpreter/stack/value_stack.rs b/crates/tinywasm/src/interpreter/stack/value_stack.rs index 03c676e..7cbf612 100644 --- a/crates/tinywasm/src/interpreter/stack/value_stack.rs +++ b/crates/tinywasm/src/interpreter/stack/value_stack.rs @@ -48,7 +48,7 @@ impl ValueStack { #[inline] pub(crate) fn push(&mut self, value: T) { - T::stack_push(self, value) + T::stack_push(self, value); } #[inline] @@ -180,7 +180,7 @@ impl ValueStack { pub(crate) fn extend_from_wasmvalues(&mut self, values: &[WasmValue]) { for value in values { - self.push_dyn(value.into()) + self.push_dyn(value.into()); } } } diff --git a/crates/tinywasm/src/interpreter/values.rs b/crates/tinywasm/src/interpreter/values.rs index 7b363a8..99cf443 100644 --- a/crates/tinywasm/src/interpreter/values.rs +++ b/crates/tinywasm/src/interpreter/values.rs @@ -169,7 +169,6 @@ macro_rules! impl_internalvalue { impl sealed::Sealed for $outer {} impl From<$outer> for TinyWasmValue { - #[inline(always)] fn from(value: $outer) -> Self { TinyWasmValue::$variant($to_internal(value)) } @@ -180,44 +179,59 @@ macro_rules! impl_internalvalue { fn stack_push(stack: &mut ValueStack, value: Self) { stack.$stack.push($to_internal(value)); } + #[inline(always)] fn stack_pop(stack: &mut ValueStack) -> Self { - ($to_outer)(stack.$stack.pop().expect("ValueStack underflow, this is a bug")) + match stack.$stack.pop() { + Some(v) => $to_outer(v), + None => unreachable!("ValueStack underflow, this is a bug"), + } } + #[inline(always)] fn stack_peek(stack: &ValueStack) -> Self { - ($to_outer)(*stack.$stack.last().expect("ValueStack underflow, this is a bug")) + match stack.$stack.last() { + Some(v) => $to_outer(*v), + None => unreachable!("ValueStack underflow, this is a bug"), + } } #[inline(always)] fn stack_calculate(stack: &mut ValueStack, func: fn(Self, Self) -> Result) -> Result<()> { let v2 = stack.$stack.pop(); let v1 = stack.$stack.last_mut(); - if let (Some(v1), Some(v2)) = (v1, v2) { - *v1 = $to_internal(func($to_outer(*v1), $to_outer(v2))?); - } else { - unreachable!("ValueStack underflow, this is a bug"); - } - Ok(()) + let (Some(v1), Some(v2)) = (v1, v2) else { + unreachable!("ValueStack underflow, this is a bug"); + }; + + *v1 = $to_internal(func($to_outer(*v1), $to_outer(v2))?); + return Ok(()) } #[inline(always)] fn replace_top(stack: &mut ValueStack, func: fn(Self) -> Result) -> Result<()> { - if let Some(v) = stack.$stack.last_mut() { - *v = $to_internal(func($to_outer(*v))?); - Ok(()) - } else { + let Some(v) = stack.$stack.last_mut() else { unreachable!("ValueStack underflow, this is a bug"); - } + }; + + *v = $to_internal(func($to_outer(*v))?); + Ok(()) } #[inline(always)] fn local_get(locals: &Locals, index: LocalAddr) -> Self { - $to_outer(locals.$locals[index as usize]) + match locals.$locals.get(index as usize) { + Some(v) => $to_outer(*v), + None => unreachable!("Local variable out of bounds, this is a bug"), + } } + #[inline(always)] fn local_set(locals: &mut Locals, index: LocalAddr, value: Self) { - locals.$locals[index as usize] = $to_internal(value); + match locals.$locals.get_mut(index as usize) { + Some(v) => *v = $to_internal(value), + None => unreachable!("Local variable out of bounds, this is a bug"), + } } } )* diff --git a/crates/tinywasm/tests/generated/wasm-simd.csv b/crates/tinywasm/tests/generated/wasm-simd.csv index e9bc8ae..a7fc7ef 100644 --- a/crates/tinywasm/tests/generated/wasm-simd.csv +++ b/crates/tinywasm/tests/generated/wasm-simd.csv @@ -1 +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,1702,24277,[{"name":"simd_address.wast","passed":7,"failed":42},{"name":"simd_align.wast","passed":92,"failed":8},{"name":"simd_bit_shift.wast","passed":41,"failed":211},{"name":"simd_bitwise.wast","passed":30,"failed":139},{"name":"simd_boolean.wast","passed":18,"failed":259},{"name":"simd_const.wast","passed":551,"failed":206},{"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":4,"failed":26},{"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":4,"failed":26},{"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":200,"failed":275},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":22,"failed":17},{"name":"simd_load16_lane.wast","passed":4,"failed":32},{"name":"simd_load32_lane.wast","passed":4,"failed":20},{"name":"simd_load64_lane.wast","passed":4,"failed":12},{"name":"simd_load8_lane.wast","passed":4,"failed":48},{"name":"simd_load_extend.wast","passed":20,"failed":84},{"name":"simd_load_splat.wast","passed":14,"failed":112},{"name":"simd_load_zero.wast","passed":12,"failed":27},{"name":"simd_splat.wast","passed":26,"failed":159},{"name":"simd_store.wast","passed":11,"failed":17},{"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}] diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs index a3c2fee..1edfef7 100644 --- a/crates/types/src/instructions.rs +++ b/crates/types/src/instructions.rs @@ -1,12 +1,27 @@ use super::{FuncAddr, GlobalAddr, LabelAddr, LocalAddr, TableAddr, TypeAddr, ValType}; -use crate::{DataAddr, ElemAddr, MemAddr}; +use crate::{ConstIdx, DataAddr, ElemAddr, MemAddr}; /// Represents a memory immediate in a WebAssembly memory instruction. #[derive(Debug, Copy, Clone, PartialEq)] #[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] -pub struct MemoryArg { - pub offset: u64, - pub mem_addr: MemAddr, + +pub struct MemoryArg([u8; 12]); + +impl MemoryArg { + pub fn new(offset: u64, mem_addr: MemAddr) -> Self { + let mut bytes = [0; 12]; + bytes[0..8].copy_from_slice(&offset.to_le_bytes()); + bytes[8..12].copy_from_slice(&mem_addr.to_le_bytes()); + Self(bytes) + } + + pub fn offset(&self) -> u64 { + u64::from_le_bytes(self.0[0..8].try_into().expect("invalid offset")) + } + + pub fn mem_addr(&self) -> MemAddr { + MemAddr::from_le_bytes(self.0[8..12].try_into().expect("invalid mem_addr")) + } } type BrTableDefault = u32; @@ -42,8 +57,8 @@ pub enum ConstInstruction { // should be kept as small as possible (16 bytes max) #[rustfmt::skip] pub enum Instruction { - LocalCopy32(LocalAddr, LocalAddr), LocalCopy64(LocalAddr, LocalAddr), LocalCopy128(LocalAddr, LocalAddr), LocalCopy128Ref(LocalAddr, LocalAddr), LocalCopyRef(LocalAddr, LocalAddr), - LocalsStore32(LocalAddr, LocalAddr, u32, MemAddr), LocalsStore64(LocalAddr, LocalAddr, u32, MemAddr), LocalsStore128(LocalAddr, LocalAddr, u32, MemAddr), LocalsStoreRef(LocalAddr, LocalAddr, u32, MemAddr), + LocalCopy32(LocalAddr, LocalAddr), LocalCopy64(LocalAddr, LocalAddr), LocalCopy128(LocalAddr, LocalAddr), LocalCopyRef(LocalAddr, LocalAddr), + // LocalsStore32(LocalAddr, LocalAddr, u32, MemAddr), LocalsStore64(LocalAddr, LocalAddr, u32, MemAddr), LocalsStore128(LocalAddr, LocalAddr, u32, MemAddr), LocalsStoreRef(LocalAddr, LocalAddr, u32, MemAddr), // > Control Instructions // See @@ -71,68 +86,48 @@ pub enum Instruction { Return, Call(FuncAddr), CallIndirect(TypeAddr, TableAddr), - ReturnCall(FuncAddr), - ReturnCallIndirect(TypeAddr, TableAddr), + // ReturnCall(FuncAddr), + // ReturnCallIndirect(TypeAddr, TableAddr), // > Parametric Instructions // See - Drop32, - Drop64, - Drop128, - DropRef, - - Select32, - Select64, - Select128, - SelectRef, + Drop32, Select32, + Drop64, Select64, + Drop128, Select128, + DropRef, SelectRef, // > Variable Instructions // See - LocalGet32(LocalAddr), - LocalGet64(LocalAddr), - LocalGet128(LocalAddr), - LocalGetRef(LocalAddr), - - LocalSet32(LocalAddr), - LocalSet64(LocalAddr), - LocalSet128(LocalAddr), - LocalSetRef(LocalAddr), - - LocalTee32(LocalAddr), - LocalTee64(LocalAddr), - LocalTee128(LocalAddr), - LocalTeeRef(LocalAddr), - GlobalGet(GlobalAddr), - GlobalSet32(GlobalAddr), - GlobalSet64(GlobalAddr), - GlobalSet128(GlobalAddr), - GlobalSetRef(GlobalAddr), + LocalGet32(LocalAddr), LocalSet32(LocalAddr), LocalTee32(LocalAddr), GlobalSet32(GlobalAddr), + LocalGet64(LocalAddr), LocalSet64(LocalAddr), LocalTee64(LocalAddr), GlobalSet64(GlobalAddr), + LocalGet128(LocalAddr), LocalSet128(LocalAddr), LocalTee128(LocalAddr), GlobalSet128(GlobalAddr), + LocalGetRef(LocalAddr), LocalSetRef(LocalAddr), LocalTeeRef(LocalAddr), GlobalSetRef(GlobalAddr), // > Memory Instructions - I32Load { offset: u64, mem_addr: MemAddr }, - I64Load { offset: u64, mem_addr: MemAddr }, - F32Load { offset: u64, mem_addr: MemAddr }, - F64Load { offset: u64, mem_addr: MemAddr }, - I32Load8S { offset: u64, mem_addr: MemAddr }, - I32Load8U { offset: u64, mem_addr: MemAddr }, - I32Load16S { offset: u64, mem_addr: MemAddr }, - I32Load16U { offset: u64, mem_addr: MemAddr }, - I64Load8S { offset: u64, mem_addr: MemAddr }, - I64Load8U { offset: u64, mem_addr: MemAddr }, - I64Load16S { offset: u64, mem_addr: MemAddr }, - I64Load16U { offset: u64, mem_addr: MemAddr }, - I64Load32S { offset: u64, mem_addr: MemAddr }, - I64Load32U { offset: u64, mem_addr: MemAddr }, - I32Store { offset: u64, mem_addr: MemAddr }, - I64Store { offset: u64, mem_addr: MemAddr }, - F32Store { offset: u64, mem_addr: MemAddr }, - F64Store { offset: u64, mem_addr: MemAddr }, - I32Store8 { offset: u64, mem_addr: MemAddr }, - I32Store16 { offset: u64, mem_addr: MemAddr }, - I64Store8 { offset: u64, mem_addr: MemAddr }, - I64Store16 { offset: u64, mem_addr: MemAddr }, - I64Store32 { offset: u64, mem_addr: MemAddr }, + I32Load(MemoryArg), + I64Load(MemoryArg), + F32Load(MemoryArg), + F64Load(MemoryArg), + I32Load8S(MemoryArg), + I32Load8U(MemoryArg), + I32Load16S(MemoryArg), + I32Load16U(MemoryArg), + I64Load8S(MemoryArg), + I64Load8U(MemoryArg), + I64Load16S(MemoryArg), + I64Load16U(MemoryArg), + I64Load32S(MemoryArg), + I64Load32U(MemoryArg), + I32Store(MemoryArg), + I64Store(MemoryArg), + F32Store(MemoryArg), + F64Store(MemoryArg), + I32Store8(MemoryArg), + I32Store16(MemoryArg), + I64Store8(MemoryArg), + I64Store16(MemoryArg), + I64Store32(MemoryArg), MemorySize(MemAddr), MemoryGrow(MemAddr), @@ -146,7 +141,7 @@ pub enum Instruction { RefNull(ValType), RefFunc(FuncAddr), RefIsNull, - + // > Numeric Instructions // See I32Eqz, I32Eq, I32Ne, I32LtS, I32LtU, I32GtS, I32GtU, I32LeS, I32LeU, I32GeS, I32GeU, @@ -188,7 +183,97 @@ pub enum Instruction { DataDrop(DataAddr), ElemDrop(ElemAddr), - // // > SIMD Instructions - // V128Load(MemoryArg), V128Load8x8S { offset: u64, mem_addr: MemAddr }, V128Load8x8U { offset: u64, mem_addr: MemAddr }, V128Load16x4S { offset: u64, mem_addr: MemAddr }, V128Load16x4U { offset: u64, mem_addr: MemAddr }, V128Load32x2S { offset: u64, mem_addr: MemAddr }, V128Load32x2U { offset: u64, mem_addr: MemAddr }, V128Load8Splat { offset: u64, mem_addr: MemAddr }, V128Load16Splat { offset: u64, mem_addr: MemAddr }, V128Load32Splat { offset: u64, mem_addr: MemAddr }, V128Load64Splat { offset: u64, mem_addr: MemAddr }, V128Load32Zero { offset: u64, mem_addr: MemAddr }, V128Load64Zero { offset: u64, mem_addr: MemAddr }, - // V128Store { offset: u64, mem_addr: MemAddr }, V128Store8x8 { offset: u64, mem_addr: MemAddr }, V128Store16x4 { offset: u64, mem_addr: MemAddr }, V128Store32x2 { offset: u64, mem_addr: MemAddr }, + // > SIMD Instructions + Simd(SimdInstruction), +} + +impl From for Instruction { + fn from(instr: SimdInstruction) -> Self { + Instruction::Simd(instr) + } +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[rustfmt::skip] +pub enum SimdInstruction { + V128Load(MemoryArg), + V128Load8x8S(MemoryArg), V128Load8x8U(MemoryArg), + V128Load16x4S(MemoryArg), V128Load16x4U(MemoryArg), + V128Load32x2S(MemoryArg), V128Load32x2U(MemoryArg), + + V128Load8Splat(MemoryArg), V128Load16Splat(MemoryArg), V128Load32Splat(MemoryArg), V128Load64Splat(MemoryArg), + V128Load8Lane(MemoryArg, u8), V128Load16Lane(MemoryArg, u8), V128Load32Lane(MemoryArg, u8), V128Load64Lane(MemoryArg, u8), + + V128Load32Zero(MemoryArg), V128Load64Zero(MemoryArg), + + V128Store(MemoryArg), V128Store8Lane(MemoryArg, u8), V128Store16Lane(MemoryArg, u8), V128Store32Lane(MemoryArg, u8), V128Store64Lane(MemoryArg, u8), + + I8x16Shuffle(ConstIdx), + V128Const(ConstIdx), + + I8x16ExtractLaneS(u8), I8x16ExtractLaneU(u8), I8x16ReplaceLane(u8), + I16x8ExtractLaneS(u8), I16x8ExtractLaneU(u8), I16x8ReplaceLane(u8), + I32x4ExtractLane(u8), I32x4ReplaceLane(u8), + I64x2ExtractLane(u8), I64x2ReplaceLane(u8), + F32x4ExtractLane(u8), F32x4ReplaceLane(u8), + F64x2ExtractLane(u8), F64x2ReplaceLane(u8), + + V128Not, V128And, V128AndNot, V128Or, V128Xor, V128Bitselect, V128AnyTrue, + + I8x16Splat, I8x16Swizzle, I8x16Eq, I8x16Ne, I8x16LtS, I8x16LtU, I8x16GtS, I8x16GtU, I8x16LeS, I8x16LeU, I8x16GeS, I8x16GeU, + I16x8Splat, I16x8Eq, I16x8Ne, I16x8LtS, I16x8LtU, I16x8GtS, I16x8GtU, I16x8LeS, I16x8LeU, I16x8GeS, I16x8GeU, + I32x4Splat, I32x4Eq, I32x4Ne, I32x4LtS, I32x4LtU, I32x4GtS, I32x4GtU, I32x4LeS, I32x4LeU, I32x4GeS, I32x4GeU, + I64x2Splat, I64x2Eq, I64x2Ne, I64x2LtS, I64x2GtS, I64x2LeS, I64x2GeS, + F32x4Splat, F32x4Eq, F32x4Ne, F32x4Lt, F32x4Gt, F32x4Le, F32x4Ge, + F64x2Splat, F64x2Eq, F64x2Ne, F64x2Lt, F64x2Gt, F64x2Le, F64x2Ge, + + I8x16Abs, I8x16Neg, I8x16AllTrue, I8x16Bitmask, I8x16Shl, I8x16ShrS, I8x16ShrU, I8x16Add, I8x16Sub, I8x16MinS, I8x16MinU, I8x16MaxS, I8x16MaxU, + I16x8Abs, I16x8Neg, I16x8AllTrue, I16x8Bitmask, I16x8Shl, I16x8ShrS, I16x8ShrU, I16x8Add, I16x8Sub, I16x8MinS, I16x8MinU, I16x8MaxS, I16x8MaxU, + I32x4Abs, I32x4Neg, I32x4AllTrue, I32x4Bitmask, I32x4Shl, I32x4ShrS, I32x4ShrU, I32x4Add, I32x4Sub, I32x4MinS, I32x4MinU, I32x4MaxS, I32x4MaxU, + I64x2Abs, I64x2Neg, I64x2AllTrue, I64x2Bitmask, I64x2Shl, I64x2ShrS, I64x2ShrU, I64x2Add, I64x2Sub, I64x2Mul, + + I8x16NarrowI16x8S, I8x16NarrowI16x8U, I8x16AddSatS, I8x16AddSatU, I8x16SubSatS, I8x16SubSatU, I8x16AvgrU, + I16x8NarrowI32x4S, I16x8NarrowI32x4U, I16x8AddSatS, I16x8AddSatU, I16x8SubSatS, I16x8SubSatU, I16x8AvgrU, + + I16x8ExtAddPairwiseI8x16S, I16x8ExtAddPairwiseI8x16U, I16x8Mul, + I32x4ExtAddPairwiseI16x8S, I32x4ExtAddPairwiseI16x8U, I32x4Mul, + + I16x8ExtMulLowI8x16S, I16x8ExtMulLowI8x16U, I16x8ExtMulHighI8x16S, I16x8ExtMulHighI8x16U, + I32x4ExtMulLowI16x8S, I32x4ExtMulLowI16x8U, I32x4ExtMulHighI16x8S, I32x4ExtMulHighI16x8U, + I64x2ExtMulLowI32x4S, I64x2ExtMulLowI32x4U, I64x2ExtMulHighI32x4S, I64x2ExtMulHighI32x4U, + + I16x8ExtendLowI8x16S, I16x8ExtendLowI8x16U, I16x8ExtendHighI8x16S, I16x8ExtendHighI8x16U, + I32x4ExtendLowI16x8S, I32x4ExtendLowI16x8U, I32x4ExtendHighI16x8S, I32x4ExtendHighI16x8U, + I64x2ExtendLowI32x4S, I64x2ExtendLowI32x4U, I64x2ExtendHighI32x4S, I64x2ExtendHighI32x4U, + + I8x16Popcnt, I16x8Q15MulrSatS, I32x4DotI16x8S, + + F32x4Ceil, F32x4Floor, F32x4Trunc, F32x4Nearest, F32x4Abs, F32x4Neg, F32x4Sqrt, F32x4Add, F32x4Sub, F32x4Mul, F32x4Div, F32x4Min, F32x4Max, F32x4PMin, F32x4PMax, + F64x2Ceil, F64x2Floor, F64x2Trunc, F64x2Nearest, F64x2Abs, F64x2Neg, F64x2Sqrt, F64x2Add, F64x2Sub, F64x2Mul, F64x2Div, F64x2Min, F64x2Max, F64x2PMin, F64x2PMax, + I32x4TruncSatF32x4S, I32x4TruncSatF32x4U, + F32x4ConvertI32x4S, F32x4ConvertI32x4U, + I32x4TruncSatF64x2SZero, I32x4TruncSatF64x2UZero, + F64x2ConvertLowI32x4S, F64x2ConvertLowI32x4U, + F32x4DemoteF64x2Zero, F64x2PromoteLowF32x4, +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[rustfmt::skip] +pub enum RelaxedSimd { + I8x16RelaxedSwizzle, + I32x4RelaxedTruncF32x4S, I32x4RelaxedTruncF32x4U, + I32x4RelaxedTruncF64x2SZero, I32x4RelaxedTruncF64x2UZero, + F32x4RelaxedMadd, F32x4RelaxedNmadd, + F64x2RelaxedMadd, F64x2RelaxedNmadd, + I8x16RelaxedLaneselect, + I16x8RelaxedLaneselect, + I32x4RelaxedLaneselect, + I64x2RelaxedLaneselect, + F32x4RelaxedMin, F32x4RelaxedMax, + F64x2RelaxedMin, F64x2RelaxedMax, + I16x8RelaxedQ15mulrS, + I16x8RelaxedDotI8x16I7x16S, + I32x4RelaxedDotI8x16I7x16AddS } diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 8ee044f..58120fe 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -135,6 +135,7 @@ pub type GlobalAddr = Addr; pub type ElemAddr = Addr; pub type DataAddr = Addr; pub type ExternAddr = Addr; +pub type ConstIdx = Addr; // additional internal addresses pub type TypeAddr = Addr; @@ -203,15 +204,52 @@ pub struct ValueCountsSmall { pub cref: u16, } +impl<'a, T: IntoIterator> From for ValueCounts { + fn from(types: T) -> Self { + let mut counts = ValueCounts::default(); + for ty in types { + match ty { + ValType::I32 | ValType::F32 => counts.c32 += 1, + ValType::I64 | ValType::F64 => counts.c64 += 1, + ValType::V128 => counts.c128 += 1, + ValType::RefExtern | ValType::RefFunc => counts.cref += 1, + } + } + counts + } +} + +impl<'a, T: IntoIterator> From for ValueCountsSmall { + fn from(types: T) -> Self { + let mut counts = ValueCountsSmall::default(); + for ty in types { + match ty { + ValType::I32 | ValType::F32 => counts.c32 += 1, + ValType::I64 | ValType::F64 => counts.c64 += 1, + ValType::V128 => counts.c128 += 1, + ValType::RefExtern | ValType::RefFunc => counts.cref += 1, + } + } + counts + } +} + #[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] pub struct WasmFunction { pub instructions: Box<[Instruction]>, + pub data: WasmFunctionData, pub locals: ValueCounts, pub params: ValueCountsSmall, pub ty: FuncType, } +#[derive(Debug, Clone, PartialEq, Default)] +#[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +pub struct WasmFunctionData { + pub v128_constants: Box<[u128]>, +} + /// A WebAssembly Module Export #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "archive", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] diff --git a/crates/wasm-testsuite/Cargo.toml b/crates/wasm-testsuite/Cargo.toml index 8edcb8a..46df77f 100644 --- a/crates/wasm-testsuite/Cargo.toml +++ b/crates/wasm-testsuite/Cargo.toml @@ -1,6 +1,6 @@ [package] name="wasm-testsuite" -version="0.5.0" +version="0.6.0-alpha.0" description="Mirror of the WebAssembly core testsuite for use in testing WebAssembly implementations" license="Apache-2.0" readme="README.md" -- cgit v1.3.1