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/parser/src/visit.rs | 130 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 102 insertions(+), 28 deletions(-) (limited to 'crates/parser/src/visit.rs') 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 { -- cgit v1.3.1