diff options
| author | Henry <mail@henrygressmann.de> | 2026-04-17 20:57:17 +0200 |
|---|---|---|
| committer | Henry <mail@henrygressmann.de> | 2026-04-17 21:00:18 +0200 |
| commit | 468a600d029d6aa45447c4346b11c9b9371050ca (patch) | |
| tree | 434c5bbe3d2c71e04a664403dfc1cc21c97f21d5 /crates/parser/src | |
| parent | 4edfbab882948fe3424b76aebdfd02383adfab01 (diff) | |
feat: refactor optimizer + executor, add v128 super instructions
Signed-off-by: Henry <mail@henrygressmann.de>
Diffstat (limited to 'crates/parser/src')
| -rw-r--r-- | crates/parser/src/conversion.rs | 3 | ||||
| -rw-r--r-- | crates/parser/src/error.rs | 3 | ||||
| -rw-r--r-- | crates/parser/src/lib.rs | 16 | ||||
| -rw-r--r-- | crates/parser/src/macros.rs | 220 | ||||
| -rw-r--r-- | crates/parser/src/module.rs | 7 | ||||
| -rw-r--r-- | crates/parser/src/optimize.rs | 611 | ||||
| -rw-r--r-- | crates/parser/src/visit.rs | 175 |
7 files changed, 486 insertions, 549 deletions
diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs index 32f2944..5de3a73 100644 --- a/crates/parser/src/conversion.rs +++ b/crates/parser/src/conversion.rs @@ -1,5 +1,4 @@ -use crate::Result; -use crate::{module::Code, visit::process_operators_and_validate}; +use crate::{Result, module::Code, visit::process_operators_and_validate}; use alloc::{boxed::Box, format, string::ToString, vec::Vec}; use tinywasm_types::*; use wasmparser::{FuncValidator, FuncValidatorAllocations, OperatorsReader, ValidatorResources}; diff --git a/crates/parser/src/error.rs b/crates/parser/src/error.rs index 9ff2f79..22edd39 100644 --- a/crates/parser/src/error.rs +++ b/crates/parser/src/error.rs @@ -1,6 +1,5 @@ -use core::fmt::{Debug, Display}; - use alloc::string::{String, ToString}; +use core::fmt::{Debug, Display}; use wasmparser::Encoding; #[derive(Debug)] diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index 850042c..ad58cc2 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -31,6 +31,7 @@ pub(crate) mod log { mod conversion; mod error; +mod macros; mod module; mod optimize; mod visit; @@ -42,19 +43,8 @@ pub use tinywasm_types::TinyWasmModule; /// Parser optimization and lowering options. #[non_exhaustive] -#[derive(Debug, Clone)] -pub struct ParserOptions { - /// Enable post-lowering DCE pass. - /// Should be enabled by default, since the parser performs some optimizations that can result in dead code. - /// Disabling this may result in larger modules, but faster parsing time. - pub dce: bool, -} - -impl Default for ParserOptions { - fn default() -> Self { - Self { dce: true } - } -} +#[derive(Debug, Clone, Default)] +pub struct ParserOptions {} /// A WebAssembly parser #[derive(Debug, Default)] diff --git a/crates/parser/src/macros.rs b/crates/parser/src/macros.rs new file mode 100644 index 0000000..97f0080 --- /dev/null +++ b/crates/parser/src/macros.rs @@ -0,0 +1,220 @@ +pub(crate) mod visit { + macro_rules! validate_then_visit { + ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {$( + fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output { + self.1.$visit($($($arg.clone()),*)?); + self.1.validator_visitor(self.0).$visit($($($arg),*)?)?; + Ok(()) + } + )*}; + } + + macro_rules! define_operand { + ($name:ident($instr:expr, $ty:ty)) => { + fn $name(&mut self, arg: $ty) -> Self::Output { + self.instructions.push($instr(arg).into()); + } + }; + + ($name:ident($instr:expr, $ty:ty, $ty2:ty)) => { + fn $name(&mut self, arg: $ty, arg2: $ty2) -> Self::Output { + self.instructions.push($instr(arg, arg2).into()); + } + }; + + ($name:ident($instr:expr)) => { + fn $name(&mut self) -> Self::Output { + self.instructions.push($instr.into()); + } + }; + } + + macro_rules! define_operands { + ($($name:ident($instr:ident $(,$ty:ty)*)),*) => {$( + define_operand!($name(Instruction::$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(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(Instruction::$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(Instruction::$instr(MemoryArg::new(memarg.offset, memarg.memory), lane).into()); + } + )*}; + } + + macro_rules! impl_visit_operator { + ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { + $(impl_visit_operator!(@@$proposal $op $({ $($arg: $argty),* })? => $visit ($($ann:tt)*));)* + }; + + (@@mvp $($rest:tt)* ) => {}; + (@@reference_types $($rest:tt)* ) => {}; + (@@sign_extension $($rest:tt)* ) => {}; + (@@saturating_float_to_int $($rest:tt)* ) => {}; + (@@bulk_memory $($rest:tt)* ) => {}; + (@@simd $($rest:tt)* ) => {}; + (@@wide_arithmetic $($rest:tt)* ) => {}; + (@@relaxed_simd $($rest:tt)* ) => {}; + (@@tail_call $($rest:tt)* ) => {}; + + (@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*)) => { + fn $visit(&mut self $($(,_: $argty)*)?) { + self.unsupported(stringify!($visit)) + } + }; + } + + pub(crate) use { + define_mem_operands, define_mem_operands_simd, define_mem_operands_simd_lane, define_operand, define_operands, + impl_visit_operator, validate_then_visit, + }; +} + +pub(crate) mod optimize { + macro_rules! replace { + ($instructions:ident, $read:ident, 1 => [$a:expr $(,)?]) => {{ + $instructions[$read - 1] = Instruction::Nop; + $instructions[$read] = $a; + }}; + ($instructions:ident, $read:ident, 1 => [$a:expr, $b:expr $(,)?]) => {{ + $instructions[$read - 1] = $a; + $instructions[$read] = $b; + }}; + ($instructions:ident, $read:ident, 2 => [$a:expr $(,)?]) => {{ + $instructions[$read - 2] = Instruction::Nop; + $instructions[$read - 1] = Instruction::Nop; + $instructions[$read] = $a; + }}; + ($instructions:ident, $read:ident, 2 => [$a:expr, $b:expr $(,)?]) => {{ + $instructions[$read - 2] = Instruction::Nop; + $instructions[$read - 1] = $a; + $instructions[$read] = $b; + }}; + ($instructions:ident, $read:ident, 2 => [$a:expr, $b:expr, $c:expr $(,)?]) => {{ + $instructions[$read - 2] = $a; + $instructions[$read - 1] = $b; + $instructions[$read] = $c; + }}; + ($instructions:ident, $read:ident, 3 => [$a:expr $(,)?]) => {{ + $instructions[$read - 3] = Instruction::Nop; + $instructions[$read - 2] = Instruction::Nop; + $instructions[$read - 1] = Instruction::Nop; + $instructions[$read] = $a; + }}; + ($instructions:ident, $read:ident, 3 => [$a:expr, $b:expr $(,)?]) => {{ + $instructions[$read - 3] = Instruction::Nop; + $instructions[$read - 2] = Instruction::Nop; + $instructions[$read - 1] = $a; + $instructions[$read] = $b; + }}; + ($instructions:ident, $read:ident, 3 => [$a:expr, $b:expr, $c:expr $(,)?]) => {{ + $instructions[$read - 3] = Instruction::Nop; + $instructions[$read - 2] = $a; + $instructions[$read - 1] = $b; + $instructions[$read] = $c; + }}; + ($instructions:ident, $read:ident, 3 => [$a:expr, $b:expr, $c:expr, $d:expr $(,)?]) => {{ + $instructions[$read - 3] = $a; + $instructions[$read - 2] = $b; + $instructions[$read - 1] = $c; + $instructions[$read] = $d; + }}; + ($instructions:ident, $read:ident, 1 => $out:expr) => { + replace!($instructions, $read, 1 => [$out]); + }; + ($instructions:ident, $read:ident, 2 => $out:expr) => { + replace!($instructions, $read, 2 => [$out]); + }; + ($instructions:ident, $read:ident, 3 => $out:expr) => { + replace!($instructions, $read, 3 => [$out]); + }; + } + + macro_rules! rewrite { + ($instructions:ident, $read:ident, [$a:pat] if ($($guard:tt)+) => [$($out:expr),+ $(,)?]) => { + rewrite!($instructions, $read, [$a] if ($($guard)+) => { replace!($instructions, $read, 1 => [$($out),+]); }) + }; + ($instructions:ident, $read:ident, [$a:pat, $b:pat] if ($($guard:tt)+) => [$($out:expr),+ $(,)?]) => { + rewrite!($instructions, $read, [$a, $b] if ($($guard)+) => { replace!($instructions, $read, 2 => [$($out),+]); }) + }; + ($instructions:ident, $read:ident, [$a:pat, $b:pat, $c:pat] if ($($guard:tt)+) => [$($out:expr),+ $(,)?]) => { + rewrite!($instructions, $read, [$a, $b, $c] if ($($guard)+) => { replace!($instructions, $read, 3 => [$($out),+]); }) + }; + ($instructions:ident, $read:ident, [$a:pat] => [$($out:expr),+ $(,)?]) => { + rewrite!($instructions, $read, [$a] => { replace!($instructions, $read, 1 => [$($out),+]); }) + }; + ($instructions:ident, $read:ident, [$a:pat, $b:pat] => [$($out:expr),+ $(,)?]) => { + rewrite!($instructions, $read, [$a, $b] => { replace!($instructions, $read, 2 => [$($out),+]); }) + }; + ($instructions:ident, $read:ident, [$a:pat, $b:pat, $c:pat] => [$($out:expr),+ $(,)?]) => { + rewrite!($instructions, $read, [$a, $b, $c] => { replace!($instructions, $read, 3 => [$($out),+]); }) + }; + ($instructions:ident, $read:ident, [$a:pat] if ($($guard:tt)+) => $body:block $(,)?) => { + if $read > 0 && let $a = $instructions[$read - 1] && $($guard)+ { + $body + } + }; + ($instructions:ident, $read:ident, [$a:pat, $b:pat] if ($($guard:tt)+) => $body:block $(,)?) => { + if $read > 1 && let ($a, $b) = ($instructions[$read - 2], $instructions[$read - 1]) && $($guard)+ { + $body + } + }; + ($instructions:ident, $read:ident, [$a:pat, $b:pat, $c:pat] if ($($guard:tt)+) => $body:block $(,)?) => { + if $read > 2 && let ($a, $b, $c) = ($instructions[$read - 3], $instructions[$read - 2], $instructions[$read - 1]) && $($guard)+ { + $body + } + }; + ($instructions:ident, $read:ident, [$a:pat] => $body:block $(,)?) => { + if $read > 0 && let $a = $instructions[$read - 1] { + $body + } + }; + ($instructions:ident, $read:ident, [$a:pat, $b:pat] => $body:block $(,)?) => { + if $read > 1 && let ($a, $b) = ($instructions[$read - 2], $instructions[$read - 1]) { + $body + } + }; + ($instructions:ident, $read:ident, [$a:pat, $b:pat, $c:pat] => $body:block $(,)?) => { + if $read > 2 && let ($a, $b, $c) = ($instructions[$read - 3], $instructions[$read - 2], $instructions[$read - 1]) { + $body + } + }; + ($instructions:ident, $read:ident, [$a:pat] if ($($guard:tt)+) => $out:expr $(,)?) => { + rewrite!($instructions, $read, [$a] if ($($guard)+) => { replace!($instructions, $read, 1 => $out); }) + }; + ($instructions:ident, $read:ident, [$a:pat, $b:pat] if ($($guard:tt)+) => $out:expr $(,)?) => { + rewrite!($instructions, $read, [$a, $b] if ($($guard)+) => { replace!($instructions, $read, 2 => $out); }) + }; + ($instructions:ident, $read:ident, [$a:pat, $b:pat, $c:pat] if ($($guard:tt)+) => $out:expr $(,)?) => { + rewrite!($instructions, $read, [$a, $b, $c] if ($($guard)+) => { replace!($instructions, $read, 3 => $out); }) + }; + ($instructions:ident, $read:ident, [$a:pat] => $out:expr $(,)?) => { + rewrite!($instructions, $read, [$a] => { replace!($instructions, $read, 1 => $out); }) + }; + ($instructions:ident, $read:ident, [$a:pat, $b:pat] => $out:expr $(,)?) => { + rewrite!($instructions, $read, [$a, $b] => { replace!($instructions, $read, 2 => $out); }) + }; + ($instructions:ident, $read:ident, [$a:pat, $b:pat, $c:pat] => $out:expr $(,)?) => { + rewrite!($instructions, $read, [$a, $b, $c] => { replace!($instructions, $read, 3 => $out); }) + }; + } + + pub(crate) use {replace, rewrite}; +} diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index 081af2b..461f79f 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -1,7 +1,6 @@ use crate::log::debug; use crate::{ParseError, ParserOptions, Result, conversion, optimize}; -use alloc::string::ToString; -use alloc::{format, vec::Vec}; +use alloc::{format, string::ToString, vec::Vec}; use tinywasm_types::*; use wasmparser::{FuncValidatorAllocations, Payload, Validator}; @@ -168,7 +167,7 @@ impl ModuleReader { Ok(()) } - pub(crate) fn into_module(self, options: &ParserOptions) -> Result<TinyWasmModule> { + pub(crate) fn into_module(self, _options: &ParserOptions) -> Result<TinyWasmModule> { if !self.end_reached { return Err(ParseError::EndNotReached); } @@ -183,7 +182,7 @@ impl ModuleReader { let ty = self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone(); let params = ValueCounts::from_iter(ty.params()); let self_func = (imported_func_count + func_idx) as u32; - let instructions = optimize::optimize_instructions(instructions, &mut data, self_func, options); + let instructions = optimize::optimize_instructions(instructions, &mut data, self_func); WasmFunction { instructions: ArcSlice::from(instructions), data, locals, params, ty } }, ); diff --git a/crates/parser/src/optimize.rs b/crates/parser/src/optimize.rs index 7308262..0539b61 100644 --- a/crates/parser/src/optimize.rs +++ b/crates/parser/src/optimize.rs @@ -1,440 +1,241 @@ -use crate::ParserOptions; +use crate::macros::optimize::*; use alloc::vec::Vec; use tinywasm_types::{CmpOp, Instruction, WasmFunctionData}; -fn cmp_op(instr: Instruction) -> Option<CmpOp> { - Some(match instr { - Instruction::I32Eq => CmpOp::Eq, - Instruction::I32Ne => CmpOp::Ne, - Instruction::I32LtS => CmpOp::LtS, - Instruction::I32LtU => CmpOp::LtU, - Instruction::I32GtS => CmpOp::GtS, - Instruction::I32GtU => CmpOp::GtU, - Instruction::I32LeS => CmpOp::LeS, - Instruction::I32LeU => CmpOp::LeU, - Instruction::I32GeS => CmpOp::GeS, - Instruction::I32GeU => CmpOp::GeU, - _ => return None, - }) -} - -fn inverse_cmp_op(op: CmpOp) -> CmpOp { - match op { - CmpOp::Eq => CmpOp::Ne, - CmpOp::Ne => CmpOp::Eq, - CmpOp::LtS => CmpOp::GeS, - CmpOp::LtU => CmpOp::GeU, - CmpOp::GtS => CmpOp::LeS, - CmpOp::GtU => CmpOp::LeU, - CmpOp::LeS => CmpOp::GtS, - CmpOp::LeU => CmpOp::GtU, - CmpOp::GeS => CmpOp::LtS, - CmpOp::GeU => CmpOp::LtU, - } -} - pub(crate) fn optimize_instructions( mut instructions: Vec<Instruction>, function_data: &mut WasmFunctionData, self_func_addr: u32, - options: &ParserOptions, ) -> Vec<Instruction> { rewrite(&mut instructions, self_func_addr); - if options.dce { - dce(&mut instructions, function_data); - } + remove_nop(&mut instructions, function_data); instructions } -fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) { - for read in 0..instructions.len() { - match instructions[read] { - Instruction::LocalCopy32(a, b) if a == b => instructions[read] = Instruction::Nop, - Instruction::LocalCopy64(a, b) if a == b => instructions[read] = Instruction::Nop, - Instruction::LocalCopy128(a, b) if a == b => instructions[read] = Instruction::Nop, - Instruction::Call(addr) if addr == self_func_addr => instructions[read] = Instruction::CallSelf, - Instruction::ReturnCall(addr) if addr == self_func_addr => instructions[read] = Instruction::ReturnCallSelf, - Instruction::I32Add => { - if read > 1 - && let (Instruction::LocalGet32(a), Instruction::LocalGet32(b)) = - (instructions[read - 2], instructions[read - 1]) - { - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::AddLocalLocal32(a, b); - } - - if read > 0 { - match instructions[read - 1] { - Instruction::I32Const(c) if read > 1 => { - if let Instruction::LocalGet32(local) = instructions[read - 2] { - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::LocalGet32(local); - instructions[read] = Instruction::AddConst32(c); - } else { - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::AddConst32(c); - } - } - Instruction::I32Const(c) => { - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::AddConst32(c); - } - _ => {} - } - } - } - Instruction::I64Add => { - if read > 1 - && let (Instruction::LocalGet64(a), Instruction::LocalGet64(b)) = - (instructions[read - 2], instructions[read - 1]) - { - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::AddLocalLocal64(a, b); - } - - if read > 0 { - match instructions[read - 1] { - Instruction::I64Const(c) if read > 1 => { - if let Instruction::LocalGet64(local) = instructions[read - 2] { - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::LocalGet64(local); - instructions[read] = Instruction::AddConst64(c); - } else { - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::AddConst64(c); - } - } - Instruction::I64Const(c) => { - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::AddConst64(c); - } - _ => {} - } - } +fn rewrite(instrs: &mut [Instruction], self_func_addr: u32) { + use Instruction::*; + for i in 0..instrs.len() { + match instrs[i] { + LocalCopy32(a, b) if a == b => instrs[i] = Nop, + LocalCopy64(a, b) if a == b => instrs[i] = Nop, + LocalCopy128(a, b) if a == b => instrs[i] = Nop, + Call(addr) if addr == self_func_addr => instrs[i] = CallSelf, + ReturnCall(addr) if addr == self_func_addr => instrs[i] = ReturnCallSelf, + I32Add => { + rewrite!(instrs, i, [I32Const(c)] => AddConst32(c)); + rewrite!(instrs, i, [LocalGet32(a), LocalGet32(b)] => AddLocalLocal32(a, b)); + rewrite!(instrs, i, [LocalGet32(local), I32Const(c)] => [ Nop, LocalGet32(local), AddConst32(c)]); } - Instruction::I64Rotl => { - if read > 1 - && let (Instruction::I64Xor, Instruction::I64Const(c)) = - (instructions[read - 2], instructions[read - 1]) - { - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::XorRotlConst64(c); - } + I64Add => { + rewrite!(instrs, i, [I64Const(c)] => AddConst64(c)); + rewrite!(instrs, i, [LocalGet64(a), LocalGet64(b)] => AddLocalLocal64(a, b)); + rewrite!(instrs, i, [LocalGet64(local), I64Const(c)] => [ Nop, LocalGet64(local), AddConst64(c)]); } - Instruction::I32Store(memarg) => { - if read > 1 - && let (Instruction::LocalGet32(addr_local), Instruction::LocalGet32(value_local)) = - (instructions[read - 2], instructions[read - 1]) - && let (Ok(addr_local), Ok(value_local)) = (u8::try_from(addr_local), u8::try_from(value_local)) - { - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::StoreLocalLocal32(memarg, addr_local, value_local); - } + I64Rotl => rewrite!(instrs, i, [I64Xor, I64Const(c)] => XorRotlConst64(c)), + I32Store(memarg) => { + rewrite!(instrs, i, + [LocalGet32(addr_local), LocalGet32(value_local)] if + (let (Ok(addr_local), Ok(value_local)) = (u8::try_from(addr_local), u8::try_from(value_local))) => + StoreLocalLocal32(memarg, addr_local, value_local) + ); } - Instruction::I64Store(memarg) => { - if read > 1 - && let (Instruction::LocalGet32(addr_local), Instruction::LocalGet64(value_local)) = - (instructions[read - 2], instructions[read - 1]) - && let (Ok(addr_local), Ok(value_local)) = (u8::try_from(addr_local), u8::try_from(value_local)) - { - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::StoreLocalLocal64(memarg, addr_local, value_local); - } + I64Store(memarg) => { + rewrite!(instrs, i, + [LocalGet32(addr_local), LocalGet64(value_local)] if + (let (Ok(addr_local), Ok(value_local)) = (u8::try_from(addr_local), u8::try_from(value_local))) => + StoreLocalLocal64(memarg, addr_local, value_local) + ); } - Instruction::I32Load(memarg) => { - if read > 0 - && let Instruction::LocalGet32(addr_local) = instructions[read - 1] - && let Ok(addr_local) = u8::try_from(addr_local) - { - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::LoadLocal32(memarg, addr_local); - } + V128Store(memarg) => { + rewrite!(instrs, i, + [LocalGet32(addr_local), LocalGet128(value_local)] if + (let (Ok(addr_local), Ok(value_local)) = (u8::try_from(addr_local), u8::try_from(value_local))) => + StoreLocalLocal128(memarg, addr_local, value_local) + ); } - Instruction::MemoryFill(mem) => { - if read > 1 - && let (Instruction::I32Const(val), Instruction::I32Const(size)) = - (instructions[read - 2], instructions[read - 1]) - { - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::MemoryFillImm(mem, val as u8, size); - } - } - - Instruction::LocalGet32(dst) => { - if read > 0 - && let Instruction::LocalSet32(src) = instructions[read - 1] - && src == dst - { - instructions[read - 1] = Instruction::LocalTee32(src); - instructions[read] = Instruction::Nop; - } + I32Load(memarg) => { + rewrite!(instrs, i, + [LocalGet32(addr_local)] if (let Ok(addr_local) = u8::try_from(addr_local)) => + LoadLocal32(memarg, addr_local) + ); } - Instruction::LocalGet64(dst) => { - if read > 0 - && let Instruction::LocalSet64(src) = instructions[read - 1] - && src == dst - { - instructions[read - 1] = Instruction::LocalTee64(src); - instructions[read] = Instruction::Nop; - } + MemoryFill(mem) => { + rewrite!(instrs, i, [I32Const(val), I32Const(size)] => MemoryFillImm(mem, val as u8, size)) } - Instruction::LocalGet128(dst) => { - if read > 0 - && let Instruction::LocalSet128(src) = instructions[read - 1] - && src == dst - { - instructions[read - 1] = Instruction::LocalTee128(src); - instructions[read] = Instruction::Nop; - } + LocalGet32(dst) => rewrite!(instrs, i, [LocalSet32(src)] if (src == dst) => [LocalTee32(src), Nop]), + LocalGet64(dst) => rewrite!(instrs, i, [LocalSet64(src)] if (src == dst) => [LocalTee64(src), Nop]), + LocalGet128(dst) => rewrite!(instrs, i, [LocalSet128(src)] if (src == dst) => [LocalTee128(src), Nop]), + LocalSet32(dst) => { + rewrite!(instrs, i, [LocalGet32(src)] => if src == dst { Nop } else { LocalCopy32(src, dst) }); + rewrite!(instrs, i, [I32Const(c)] => SetLocalConst32(dst, c)); + rewrite!(instrs, i, [F32Const(c)] => SetLocalConst32(dst, i32::from_ne_bytes(c.to_bits().to_ne_bytes()))); + rewrite!(instrs, i, [LocalGet32(src), AddConst32(c)] if (src == dst) => AddLocalConst32(dst, c)); + rewrite!(instrs, i, [LoadLocal32(memarg, addr)] if (let Ok(dst) = u8::try_from(dst)) => LoadLocalSet32(memarg, addr, dst)); + rewrite!(instrs, i, + [LocalGet32(addr), I32Load(memarg)] if + (let (Ok(addr), Ok(dst)) = (u8::try_from(addr), u8::try_from(dst))) => + LoadLocalSet32(memarg, addr, dst) + ); } - Instruction::LocalSet32(dst) => { - if read > 0 { - match instructions[read - 1] { - Instruction::LocalGet32(src) => { - instructions[read - 1] = Instruction::Nop; - instructions[read] = - if src == dst { Instruction::Nop } else { Instruction::LocalCopy32(src, dst) }; - } - Instruction::I32Const(c) => { - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::SetLocalConst32(dst, c); - } - Instruction::F32Const(c) => { - instructions[read - 1] = Instruction::Nop; - instructions[read] = - Instruction::SetLocalConst32(dst, i32::from_ne_bytes(c.to_bits().to_ne_bytes())); - } - _ => {} - } - } - - if read > 1 { - match (instructions[read - 2], instructions[read - 1]) { - (Instruction::LocalGet32(src), Instruction::AddConst32(c)) if src == dst => { - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::AddLocalConst32(dst, c); - } - (Instruction::LocalGet32(addr), Instruction::I32Load(memarg)) => { - if let (Ok(addr), Ok(dst)) = (u8::try_from(addr), u8::try_from(dst)) { - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::LoadLocalSet32(memarg, addr, dst); - } - } - _ => {} - } - } - - if read > 0 - && let Instruction::LoadLocal32(memarg, addr) = instructions[read - 1] - && let Ok(dst) = u8::try_from(dst) - { - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::LoadLocalSet32(memarg, addr, dst); - } + LocalSet64(dst) => { + rewrite!(instrs, i, [LocalGet64(src)] => if src == dst { Nop } else { LocalCopy64(src, dst) }); + rewrite!(instrs, i, [I64Const(c)] => SetLocalConst64(dst, c)); + rewrite!(instrs, i, [F64Const(c)] => SetLocalConst64(dst, i64::from_ne_bytes(c.to_bits().to_ne_bytes()))); + rewrite!(instrs, i, + [LocalGet64(src), AddConst64(c)] if (src == dst) => + AddLocalConst64(dst, c) + ); } - Instruction::LocalSet64(dst) => { - if read > 0 { - match instructions[read - 1] { - Instruction::LocalGet64(src) => { - instructions[read - 1] = Instruction::Nop; - instructions[read] = - if src == dst { Instruction::Nop } else { Instruction::LocalCopy64(src, dst) }; - } - Instruction::I64Const(c) => { - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::SetLocalConst64(dst, c); - } - Instruction::F64Const(c) => { - instructions[read - 1] = Instruction::Nop; - instructions[read] = - Instruction::SetLocalConst64(dst, i64::from_ne_bytes(c.to_bits().to_ne_bytes())); - } - _ => {} - } - } - - if read > 1 - && let (Instruction::LocalGet64(src), Instruction::AddConst64(c)) = - (instructions[read - 2], instructions[read - 1]) - && src == dst - { - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::AddLocalConst64(dst, c); - } + LocalSet128(dst) => { + rewrite!(instrs, i, [LocalGet128(src)] => if src == dst { Nop } else { LocalCopy128(src, dst) }); + rewrite!(instrs, i, + [LocalGet32(addr), V128Load(memarg)] if + (let (Ok(addr), Ok(dst)) = (u8::try_from(addr), u8::try_from(dst))) => + LoadLocalSet128(memarg, addr, dst) + ); } - Instruction::LocalSet128(dst) => { - if read > 0 - && let Instruction::LocalGet128(src) = instructions[read - 1] - { - instructions[read - 1] = Instruction::Nop; - instructions[read] = - if src == dst { Instruction::Nop } else { Instruction::LocalCopy128(src, dst) }; - } + LocalTee32(dst) => { + rewrite!(instrs, i, [LocalGet32(src)] if (src == dst) => [LocalGet32(src), Nop]); + rewrite!(instrs, i, [I32Const(c), I32And] => AndConstTee32(c, dst)); + rewrite!(instrs, i, [I32Const(c), I32Sub] => SubConstTee32(c, dst)); + rewrite!(instrs, i, + [LocalGet32(addr), I32Load(memarg)] if + (let (Ok(addr), Ok(dst)) = (u8::try_from(addr), u8::try_from(dst))) => + LoadLocalTee32(memarg, addr, dst) + ); + rewrite!(instrs, i, + [LoadLocal32(memarg, addr)] if (let Ok(dst) = u8::try_from(dst)) => + LoadLocalTee32(memarg, addr, dst) + ); } - Instruction::LocalTee32(dst) => { - if read > 0 - && let Instruction::LocalGet32(src) = instructions[read - 1] - && src == dst - { - instructions[read] = Instruction::Nop; - } - - if read > 1 - && let (Instruction::LocalGet32(addr), Instruction::I32Load(memarg)) = - (instructions[read - 2], instructions[read - 1]) - && let (Ok(addr), Ok(dst)) = (u8::try_from(addr), u8::try_from(dst)) - { - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::LoadLocalTee32(memarg, addr, dst); - } - - if read > 0 - && let Instruction::LoadLocal32(memarg, addr) = instructions[read - 1] - && let Ok(dst) = u8::try_from(dst) - { - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::LoadLocalTee32(memarg, addr, dst); - } + LocalTee64(dst) => { + rewrite!(instrs, i, [LocalGet64(src)] if (src == dst) => [LocalGet64(src), Nop]); + rewrite!(instrs, i, [I64Const(c), I64And] => AndConstTee64(c, dst)); + rewrite!(instrs, i, [I64Const(c), I64Sub] => SubConstTee64(c, dst)); + rewrite!(instrs, i, [XorRotlConst64(c)] => XorRotlConstTee64(c, dst)); } - Instruction::LocalTee64(dst) if read > 0 => match instructions[read - 1] { - Instruction::LocalGet64(src) if src == dst => { - instructions[read] = Instruction::Nop; - } - Instruction::XorRotlConst64(c) => { - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::XorRotlConstTee64(c, dst); - } - _ => {} - }, - Instruction::LocalTee128(dst) => { - if read > 0 - && let Instruction::LocalGet128(src) = instructions[read - 1] - && src == dst - { - instructions[read] = Instruction::Nop; - } + LocalTee128(dst) => { + rewrite!(instrs, i, [LocalGet128(src)] if (src == dst) => [LocalGet128(src), Nop]); + rewrite!(instrs, i, + [LocalGet32(addr), V128Load(memarg)] if + (let (Ok(addr), Ok(dst)) = (u8::try_from(addr), u8::try_from(dst))) => + LoadLocalTee128(memarg, addr, dst) + ); } - Instruction::Drop32 => { - if read > 0 - && let Instruction::LocalTee32(local) = instructions[read - 1] - { - instructions[read - 1] = Instruction::LocalSet32(local); - instructions[read] = Instruction::Nop; - } - } - Instruction::Drop64 => { - if read > 0 - && let Instruction::LocalTee64(local) = instructions[read - 1] - { - instructions[read - 1] = Instruction::LocalSet64(local); - instructions[read] = Instruction::Nop; - } - } - Instruction::Drop128 => { - if read > 0 - && let Instruction::LocalTee128(local) = instructions[read - 1] - { - instructions[read - 1] = Instruction::LocalSet128(local); - instructions[read] = Instruction::Nop; - } - } - Instruction::JumpIfZero(ip) => { - if read > 0 && instructions[read - 1] == Instruction::I32Eqz { - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::JumpIfNonZero(ip); + Drop32 => rewrite!(instrs, i, [LocalTee32(local)] => [LocalSet32(local), Nop]), + Drop64 => rewrite!(instrs, i, [LocalTee64(local)] => [LocalSet64(local), Nop]), + Drop128 => rewrite!(instrs, i, [LocalTee128(local)] => [LocalSet128(local), Nop]), + JumpIfZero(ip) => { + rewrite!(instrs, i, [I32Eqz] => { + replace!(instrs, i, 1 => [Nop, JumpIfNonZero(ip)]); continue; - } - - if read > 2 { - match (instructions[read - 2], instructions[read - 1]) { - (Instruction::I32Const(imm), cmp) => { - if read > 3 - && let Instruction::LocalGet32(local) = instructions[read - 3] - && let Some(op) = cmp_op(cmp) - { - instructions[read - 3] = Instruction::Nop; - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::JumpCmpLocalConst32 { - target_ip: ip, - local, - imm, - op: inverse_cmp_op(op), - }; - } - } - (Instruction::LocalGet32(right), cmp) => { - if read > 3 - && let Instruction::LocalGet32(left) = instructions[read - 3] - && let Some(op) = cmp_op(cmp) - { - instructions[read - 3] = Instruction::Nop; - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::JumpCmpLocalLocal32 { - target_ip: ip, - left, - right, - op: inverse_cmp_op(op), - }; - } - } - _ => {} - } - } + }); + rewrite!(instrs, i, [cmp, I32Const(imm)] if (let Some(op) = cmp_op(cmp)) => + JumpCmpStackConst32 { target_ip: ip, imm, op: inverse_cmp_op(op) } + ); + rewrite!(instrs, i, [cmp, I64Const(imm)] if (let Some(op) = cmp_op_64(cmp)) => + JumpCmpStackConst64 { target_ip: ip, imm, op: inverse_cmp_op(op) } + ); + rewrite!(instrs, i, + [LocalGet32(local), cmp, I32Const(imm)] if (let Some(op) = cmp_op(cmp)) => + JumpCmpLocalConst32 { target_ip: ip, local, imm, op: inverse_cmp_op(op) } + ); + rewrite!(instrs, i, + [LocalGet64(local), cmp, I64Const(imm)] if + (let Some(op) = cmp_op_64(cmp) && let Ok(imm) = i32::try_from(imm)) => + JumpCmpLocalConst64 { target_ip: ip, local, imm, op: inverse_cmp_op(op) } + ); + rewrite!(instrs, i, + [LocalGet32(left), cmp, LocalGet32(right)] if (let Some(op) = cmp_op(cmp)) => + JumpCmpLocalLocal32 { target_ip: ip, left, right, op: inverse_cmp_op(op) } + ); + rewrite!(instrs, i, + [LocalGet64(left), cmp, LocalGet64(right)] if (let Some(op) = cmp_op_64(cmp)) => + JumpCmpLocalLocal64 { target_ip: ip, left, right, op: inverse_cmp_op(op) } + ); } - Instruction::JumpIfNonZero(ip) => { - if read > 0 && instructions[read - 1] == Instruction::I32Eqz { - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::JumpIfZero(ip); + JumpIfNonZero(ip) => { + rewrite!(instrs, i, [I32Eqz] => { + replace!(instrs, i, 1 => [Nop, JumpIfZero(ip)]); continue; - } - - if read > 2 { - match (instructions[read - 2], instructions[read - 1]) { - (Instruction::I32Const(imm), cmp) => { - if read > 3 - && let Instruction::LocalGet32(local) = instructions[read - 3] - && let Some(op) = cmp_op(cmp) - { - instructions[read - 3] = Instruction::Nop; - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = Instruction::JumpCmpLocalConst32 { target_ip: ip, local, imm, op }; - } - } - (Instruction::LocalGet32(right), cmp) => { - if read > 3 - && let Instruction::LocalGet32(left) = instructions[read - 3] - && let Some(op) = cmp_op(cmp) - { - instructions[read - 3] = Instruction::Nop; - instructions[read - 2] = Instruction::Nop; - instructions[read - 1] = Instruction::Nop; - instructions[read] = - Instruction::JumpCmpLocalLocal32 { target_ip: ip, left, right, op }; - } - } - _ => {} - } - } + }); + rewrite!(instrs, i, [cmp, I32Const(imm)] if (let Some(op) = cmp_op(cmp)) => + JumpCmpStackConst32 { target_ip: ip, imm, op } + ); + rewrite!(instrs, i, [cmp, I64Const(imm)] if (let Some(op) = cmp_op_64(cmp)) => + JumpCmpStackConst64 { target_ip: ip, imm, op } + ); + rewrite!(instrs, i, + [LocalGet32(local), cmp, I32Const(imm)] if (let Some(op) = cmp_op(cmp)) => + JumpCmpLocalConst32 { target_ip: ip, local, imm, op } + ); + rewrite!(instrs, i, + [LocalGet64(local), cmp, I64Const(imm)] if + (let Some(op) = cmp_op_64(cmp) && let Ok(imm) = i32::try_from(imm)) => + JumpCmpLocalConst64 { target_ip: ip, local, imm, op } + ); + rewrite!(instrs, i, + [LocalGet32(left), cmp, LocalGet32(right)] if (let Some(op) = cmp_op(cmp)) => + JumpCmpLocalLocal32 { target_ip: ip, left, right, op } + ); + rewrite!(instrs, i, + [LocalGet64(left), cmp, LocalGet64(right)] if (let Some(op) = cmp_op_64(cmp)) => + JumpCmpLocalLocal64 { target_ip: ip, left, right, op } + ); } _ => {} } } } -fn dce(instructions: &mut Vec<Instruction>, function_data: &mut WasmFunctionData) { +fn cmp_op(instr: Instruction) -> Option<CmpOp> { + Some(match instr { + Instruction::I32Eq => CmpOp::Eq, + Instruction::I32Ne => CmpOp::Ne, + Instruction::I32LtS => CmpOp::LtS, + Instruction::I32LtU => CmpOp::LtU, + Instruction::I32GtS => CmpOp::GtS, + Instruction::I32GtU => CmpOp::GtU, + Instruction::I32LeS => CmpOp::LeS, + Instruction::I32LeU => CmpOp::LeU, + Instruction::I32GeS => CmpOp::GeS, + Instruction::I32GeU => CmpOp::GeU, + _ => return None, + }) +} + +fn cmp_op_64(instr: Instruction) -> Option<CmpOp> { + Some(match instr { + Instruction::I64Eq => CmpOp::Eq, + Instruction::I64Ne => CmpOp::Ne, + Instruction::I64LtS => CmpOp::LtS, + Instruction::I64LtU => CmpOp::LtU, + Instruction::I64GtS => CmpOp::GtS, + Instruction::I64GtU => CmpOp::GtU, + Instruction::I64LeS => CmpOp::LeS, + Instruction::I64LeU => CmpOp::LeU, + Instruction::I64GeS => CmpOp::GeS, + Instruction::I64GeU => CmpOp::GeU, + _ => return None, + }) +} + +fn inverse_cmp_op(op: CmpOp) -> CmpOp { + match op { + CmpOp::Eq => CmpOp::Ne, + CmpOp::Ne => CmpOp::Eq, + CmpOp::LtS => CmpOp::GeS, + CmpOp::LtU => CmpOp::GeU, + CmpOp::GtS => CmpOp::LeS, + CmpOp::GtU => CmpOp::LeU, + CmpOp::LeS => CmpOp::GtS, + CmpOp::LeU => CmpOp::GtU, + CmpOp::GeS => CmpOp::LtS, + CmpOp::GeU => CmpOp::LtU, + } +} + +fn remove_nop(instructions: &mut Vec<Instruction>, function_data: &mut WasmFunctionData) { let old_len = instructions.len(); if old_len == 0 { return; @@ -467,8 +268,12 @@ fn dce(instructions: &mut Vec<Instruction>, function_data: &mut WasmFunctionData Instruction::Jump(ip) | Instruction::JumpIfZero(ip) | Instruction::JumpIfNonZero(ip) + | Instruction::JumpCmpStackConst32 { target_ip: ip, .. } + | Instruction::JumpCmpStackConst64 { target_ip: ip, .. } | Instruction::JumpCmpLocalConst32 { target_ip: ip, .. } + | Instruction::JumpCmpLocalConst64 { target_ip: ip, .. } | Instruction::JumpCmpLocalLocal32 { target_ip: ip, .. } + | Instruction::JumpCmpLocalLocal64 { target_ip: ip, .. } | Instruction::BranchTable(ip, _, _) => ip, _ => return !matches!(instr, Instruction::Nop), }; diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs index e6f415b..3000b9b 100644 --- a/crates/parser/src/visit.rs +++ b/crates/parser/src/visit.rs @@ -1,9 +1,6 @@ -use crate::Result; - -use crate::conversion::convert_heaptype; +use crate::{Result, conversion::convert_heaptype, macros::visit::*}; use alloc::string::ToString; -use alloc::vec; -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; use tinywasm_types::{Instruction, MemoryArg, WasmFunctionData}; use wasmparser::{ FrameKind, FuncValidator, FuncValidatorAllocations, FunctionBody, VisitOperator, VisitSimdOperator, @@ -48,16 +45,6 @@ impl FunctionDataBuilder { struct ValidateThenVisit<'a, R: WasmModuleResources>(usize, &'a mut FunctionBuilder<R>); -macro_rules! validate_then_visit { - ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {$( - fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output { - self.1.$visit($($($arg.clone()),*)?); - self.1.validator_visitor(self.0).$visit($($($arg),*)?)?; - Ok(()) - } - )*}; -} - impl<'a, R: WasmModuleResources> VisitOperator<'a> for ValidateThenVisit<'_, R> { type Output = Result<()>; wasmparser::for_each_visit_operator!(validate_then_visit); @@ -92,56 +79,6 @@ pub(crate) fn process_operators_and_validate<R: WasmModuleResources>( Ok((builder.instructions, builder.data.finish(), builder.validator.into_allocations())) } -macro_rules! define_operand { - ($name:ident($instr:expr, $ty:ty)) => { - fn $name(&mut self, arg: $ty) -> Self::Output { - self.instructions.push($instr(arg).into()); - } - }; - - ($name:ident($instr:expr, $ty:ty, $ty2:ty)) => { - fn $name(&mut self, arg: $ty, arg2: $ty2) -> Self::Output { - self.instructions.push($instr(arg, arg2).into()); - } - }; - - ($name:ident($instr:expr)) => { - fn $name(&mut self) -> Self::Output { - self.instructions.push($instr.into()); - } - }; -} - -macro_rules! define_operands { - ($($name:ident($instr:ident $(,$ty:ty)*)),*) => {$( - define_operand!($name(Instruction::$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(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(Instruction::$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(Instruction::$instr(MemoryArg::new(memarg.offset, memarg.memory), lane).into()); - } - )*}; -} - pub(crate) struct FunctionBuilder<R: WasmModuleResources> { validator: FuncValidator<R>, instructions: Vec<Instruction>, @@ -151,28 +88,6 @@ pub(crate) struct FunctionBuilder<R: WasmModuleResources> { errors: Vec<crate::ParseError>, } -macro_rules! impl_visit_operator { - ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => { - $(impl_visit_operator!(@@$proposal $op $({ $($arg: $argty),* })? => $visit ($($ann:tt)*));)* - }; - - (@@mvp $($rest:tt)* ) => {}; - (@@reference_types $($rest:tt)* ) => {}; - (@@sign_extension $($rest:tt)* ) => {}; - (@@saturating_float_to_int $($rest:tt)* ) => {}; - (@@bulk_memory $($rest:tt)* ) => {}; - (@@simd $($rest:tt)* ) => {}; - (@@wide_arithmetic $($rest:tt)* ) => {}; - (@@relaxed_simd $($rest:tt)* ) => {}; - (@@tail_call $($rest:tt)* ) => {}; - - (@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*)) => { - fn $visit(&mut self $($(,_: $argty)*)?) { - self.unsupported(stringify!($visit)) - } - }; -} - impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuilder<R> { type Output = (); wasmparser::for_each_visit_operator!(impl_visit_operator); @@ -182,24 +97,59 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild } define_mem_operands! { - visit_i32_load(I32Load), visit_i64_load(I64Load), visit_f32_load(F32Load), visit_f64_load(F64Load), visit_i32_load8_s(I32Load8S), visit_i32_load8_u(I32Load8U), visit_i32_load16_s(I32Load16S), visit_i32_load16_u(I32Load16U), visit_i64_load8_s(I64Load8S), visit_i64_load8_u(I64Load8U), visit_i64_load16_s(I64Load16S), visit_i64_load16_u(I64Load16U), visit_i64_load32_s(I64Load32S), visit_i64_load32_u(I64Load32U), visit_f32_store(F32Store), visit_f64_store(F64Store), visit_i32_store8(I32Store8), visit_i32_store16(I32Store16), visit_i64_store8(I64Store8), visit_i64_store16(I64Store16), visit_i64_store32(I64Store32), visit_i32_store(I32Store), visit_i64_store(I64Store) + visit_i32_load(I32Load), visit_i64_load(I64Load), visit_f32_load(F32Load), visit_f64_load(F64Load), + visit_i32_load8_s(I32Load8S), visit_i32_load8_u(I32Load8U), visit_i32_load16_s(I32Load16S), + visit_i32_load16_u(I32Load16U), visit_i64_load8_s(I64Load8S), visit_i64_load8_u(I64Load8U), + visit_i64_load16_s(I64Load16S), visit_i64_load16_u(I64Load16U), visit_i64_load32_s(I64Load32S), + visit_i64_load32_u(I64Load32U), visit_f32_store(F32Store), visit_f64_store(F64Store), visit_i32_store8(I32Store8), + visit_i32_store16(I32Store16), visit_i64_store8(I64Store8), visit_i64_store16(I64Store16), + visit_i64_store32(I64Store32), visit_i32_store(I32Store), visit_i64_store(I64Store) } define_operands! { // basic instructions - visit_global_get(GlobalGet, u32), visit_i32_const(I32Const, i32), visit_i64_const(I64Const, i64), visit_call(Call, u32), visit_return_call(ReturnCall, u32), visit_memory_size(MemorySize, u32), visit_memory_grow(MemoryGrow, u32), visit_unreachable(Unreachable), visit_nop(Nop), visit_i32_eqz(I32Eqz), visit_i32_eq(I32Eq), visit_i32_ne(I32Ne), visit_i32_lt_s(I32LtS), visit_i32_lt_u(I32LtU), visit_i32_gt_s(I32GtS), visit_i32_gt_u(I32GtU), visit_i32_le_s(I32LeS), visit_i32_le_u(I32LeU), visit_i32_ge_s(I32GeS), visit_i32_ge_u(I32GeU), visit_i64_eqz(I64Eqz), visit_i64_eq(I64Eq), visit_i64_ne(I64Ne), visit_i64_lt_s(I64LtS), visit_i64_lt_u(I64LtU), visit_i64_gt_s(I64GtS), visit_i64_gt_u(I64GtU), visit_i64_le_s(I64LeS), visit_i64_le_u(I64LeU), visit_i64_ge_s(I64GeS), visit_i64_ge_u(I64GeU), visit_f32_eq(F32Eq), visit_f32_ne(F32Ne), visit_f32_lt(F32Lt), visit_f32_gt(F32Gt), visit_f32_le(F32Le), visit_f32_ge(F32Ge), visit_f64_eq(F64Eq), visit_f64_ne(F64Ne), visit_f64_lt(F64Lt), visit_f64_gt(F64Gt), visit_f64_le(F64Le), visit_f64_ge(F64Ge), visit_i32_clz(I32Clz), visit_i32_ctz(I32Ctz), visit_i32_popcnt(I32Popcnt), visit_i32_sub(I32Sub), visit_i32_mul(I32Mul), visit_i32_div_s(I32DivS), visit_i32_div_u(I32DivU), visit_i32_rem_s(I32RemS), visit_i32_rem_u(I32RemU), visit_i32_and(I32And), visit_i32_or(I32Or), visit_i32_xor(I32Xor), visit_i32_shl(I32Shl), visit_i32_shr_s(I32ShrS), visit_i32_shr_u(I32ShrU), visit_i32_rotl(I32Rotl), visit_i32_rotr(I32Rotr), visit_i64_clz(I64Clz), visit_i64_ctz(I64Ctz), visit_i64_popcnt(I64Popcnt), visit_i64_sub(I64Sub), visit_i64_mul(I64Mul), visit_i64_div_s(I64DivS), visit_i64_div_u(I64DivU), visit_i64_rem_s(I64RemS), visit_i64_rem_u(I64RemU), visit_i64_and(I64And), visit_i64_or(I64Or), visit_i64_xor(I64Xor), visit_i64_shl(I64Shl), visit_i64_shr_s(I64ShrS), visit_i64_shr_u(I64ShrU), visit_i64_rotr(I64Rotr), visit_f32_abs(F32Abs), visit_f32_neg(F32Neg), visit_f32_ceil(F32Ceil), visit_f32_floor(F32Floor), visit_f32_trunc(F32Trunc), visit_f32_nearest(F32Nearest), visit_f32_sqrt(F32Sqrt), visit_f32_add(F32Add), visit_f32_sub(F32Sub), visit_f32_mul(F32Mul), visit_f32_div(F32Div), visit_f32_min(F32Min), visit_f32_max(F32Max), visit_f32_copysign(F32Copysign), visit_f64_abs(F64Abs), visit_f64_neg(F64Neg), visit_f64_ceil(F64Ceil), visit_f64_floor(F64Floor), visit_f64_trunc(F64Trunc), visit_f64_nearest(F64Nearest), visit_f64_sqrt(F64Sqrt), visit_f64_add(F64Add), visit_f64_sub(F64Sub), visit_f64_mul(F64Mul), visit_f64_div(F64Div), visit_f64_min(F64Min), visit_f64_max(F64Max), visit_f64_copysign(F64Copysign), visit_i32_wrap_i64(I32WrapI64), visit_i32_trunc_f32_s(I32TruncF32S), visit_i32_trunc_f32_u(I32TruncF32U), visit_i32_trunc_f64_s(I32TruncF64S), visit_i32_trunc_f64_u(I32TruncF64U), visit_i64_extend_i32_s(I64ExtendI32S), visit_i64_extend_i32_u(I64ExtendI32U), visit_i64_trunc_f32_s(I64TruncF32S), visit_i64_trunc_f32_u(I64TruncF32U), visit_i64_trunc_f64_s(I64TruncF64S), visit_i64_trunc_f64_u(I64TruncF64U), visit_f32_convert_i32_s(F32ConvertI32S), visit_f32_convert_i32_u(F32ConvertI32U), visit_f32_convert_i64_s(F32ConvertI64S), visit_f32_convert_i64_u(F32ConvertI64U), visit_f32_demote_f64(F32DemoteF64), visit_f64_convert_i32_s(F64ConvertI32S), visit_f64_convert_i32_u(F64ConvertI32U), visit_f64_convert_i64_s(F64ConvertI64S), visit_f64_convert_i64_u(F64ConvertI64U), visit_f64_promote_f32(F64PromoteF32), visit_i32_add(I32Add), visit_i64_add(I64Add), visit_i64_rotl(I64Rotl), + visit_global_get(GlobalGet, u32), visit_i32_const(I32Const, i32), visit_i64_const(I64Const, i64), visit_return(Return), + visit_call(Call, u32), visit_call_indirect(CallIndirect, u32, u32), visit_return_call_indirect(ReturnCallIndirect, u32, u32), + visit_return_call(ReturnCall, u32), visit_memory_size(MemorySize, u32), visit_memory_grow(MemoryGrow, u32), visit_unreachable(Unreachable), + visit_nop(Nop), visit_i32_eqz(I32Eqz), visit_i32_eq(I32Eq), visit_i32_ne(I32Ne), visit_i32_lt_s(I32LtS), visit_i32_lt_u(I32LtU), + visit_i32_gt_s(I32GtS), visit_i32_gt_u(I32GtU), visit_i32_le_s(I32LeS), visit_i32_le_u(I32LeU), visit_i32_ge_s(I32GeS), + visit_i32_ge_u(I32GeU), visit_i64_eqz(I64Eqz), visit_i64_eq(I64Eq), visit_i64_ne(I64Ne), visit_i64_lt_s(I64LtS), visit_i64_lt_u(I64LtU), + visit_i64_gt_s(I64GtS), visit_i64_gt_u(I64GtU), visit_i64_le_s(I64LeS), visit_i64_le_u(I64LeU), visit_i64_ge_s(I64GeS), visit_i64_ge_u(I64GeU), + visit_f32_eq(F32Eq), visit_f32_ne(F32Ne), visit_f32_lt(F32Lt), visit_f32_gt(F32Gt), visit_f32_le(F32Le), visit_f32_ge(F32Ge), visit_f64_eq(F64Eq), + visit_f64_ne(F64Ne), visit_f64_lt(F64Lt), visit_f64_gt(F64Gt), visit_f64_le(F64Le), visit_f64_ge(F64Ge), visit_i32_clz(I32Clz), visit_i32_ctz(I32Ctz), + visit_i32_popcnt(I32Popcnt), visit_i32_sub(I32Sub), visit_i32_mul(I32Mul), visit_i32_div_s(I32DivS), visit_i32_div_u(I32DivU), visit_i32_rem_s(I32RemS), + visit_i32_rem_u(I32RemU), visit_i32_and(I32And), visit_i32_or(I32Or), visit_i32_xor(I32Xor), visit_i32_shl(I32Shl), visit_i32_shr_s(I32ShrS), + visit_i32_shr_u(I32ShrU), visit_i32_rotl(I32Rotl), visit_i32_rotr(I32Rotr), visit_i64_clz(I64Clz), visit_i64_ctz(I64Ctz), visit_i64_popcnt(I64Popcnt), + visit_i64_sub(I64Sub), visit_i64_mul(I64Mul), visit_i64_div_s(I64DivS), visit_i64_div_u(I64DivU), visit_i64_rem_s(I64RemS), visit_i64_rem_u(I64RemU), + visit_i64_and(I64And), visit_i64_or(I64Or), visit_i64_xor(I64Xor), visit_i64_shl(I64Shl), visit_i64_shr_s(I64ShrS), visit_i64_shr_u(I64ShrU), + visit_i64_rotr(I64Rotr), visit_f32_abs(F32Abs), visit_f32_neg(F32Neg), visit_f32_ceil(F32Ceil), visit_f32_floor(F32Floor), visit_f32_trunc(F32Trunc), + visit_f32_nearest(F32Nearest), visit_f32_sqrt(F32Sqrt), visit_f32_add(F32Add), visit_f32_sub(F32Sub), visit_f32_mul(F32Mul), visit_f32_div(F32Div), + visit_f32_min(F32Min), visit_f32_max(F32Max), visit_f32_copysign(F32Copysign), visit_f64_abs(F64Abs), visit_f64_neg(F64Neg), visit_f64_ceil(F64Ceil), + visit_f64_floor(F64Floor), visit_f64_trunc(F64Trunc), visit_f64_nearest(F64Nearest), visit_f64_sqrt(F64Sqrt), visit_f64_add(F64Add), visit_f64_sub(F64Sub), + visit_f64_mul(F64Mul), visit_f64_div(F64Div), visit_f64_min(F64Min), visit_f64_max(F64Max), visit_f64_copysign(F64Copysign), visit_i32_wrap_i64(I32WrapI64), + visit_i32_trunc_f32_s(I32TruncF32S), visit_i32_trunc_f32_u(I32TruncF32U), visit_i32_trunc_f64_s(I32TruncF64S), visit_i32_trunc_f64_u(I32TruncF64U), + visit_i64_extend_i32_s(I64ExtendI32S), visit_i64_extend_i32_u(I64ExtendI32U), visit_i64_trunc_f32_s(I64TruncF32S), visit_i64_trunc_f32_u(I64TruncF32U), + visit_i64_trunc_f64_s(I64TruncF64S), visit_i64_trunc_f64_u(I64TruncF64U), visit_f32_convert_i32_s(F32ConvertI32S), visit_f32_convert_i32_u(F32ConvertI32U), + visit_f32_convert_i64_s(F32ConvertI64S), visit_f32_convert_i64_u(F32ConvertI64U), visit_f32_demote_f64(F32DemoteF64), visit_f64_convert_i32_s(F64ConvertI32S), + visit_f64_convert_i32_u(F64ConvertI32U), visit_f64_convert_i64_s(F64ConvertI64S), visit_f64_convert_i64_u(F64ConvertI64U), visit_f64_promote_f32(F64PromoteF32), + visit_i32_add(I32Add), visit_i64_add(I64Add), visit_i64_rotl(I64Rotl), // sign_extension - visit_i32_extend8_s(I32Extend8S), visit_i32_extend16_s(I32Extend16S), visit_i64_extend8_s(I64Extend8S), visit_i64_extend16_s(I64Extend16S), visit_i64_extend32_s(I64Extend32S), + visit_i32_extend8_s(I32Extend8S), visit_i32_extend16_s(I32Extend16S), visit_i64_extend8_s(I64Extend8S), visit_i64_extend16_s(I64Extend16S), + visit_i64_extend32_s(I64Extend32S), // Non-trapping Float-to-int Conversions - visit_i32_trunc_sat_f32_s(I32TruncSatF32S), visit_i32_trunc_sat_f32_u(I32TruncSatF32U), visit_i32_trunc_sat_f64_s(I32TruncSatF64S), visit_i32_trunc_sat_f64_u(I32TruncSatF64U), visit_i64_trunc_sat_f32_s(I64TruncSatF32S), visit_i64_trunc_sat_f32_u(I64TruncSatF32U), visit_i64_trunc_sat_f64_s(I64TruncSatF64S), visit_i64_trunc_sat_f64_u(I64TruncSatF64U), + visit_i32_trunc_sat_f32_s(I32TruncSatF32S), visit_i32_trunc_sat_f32_u(I32TruncSatF32U), visit_i32_trunc_sat_f64_s(I32TruncSatF64S), + visit_i32_trunc_sat_f64_u(I32TruncSatF64U), visit_i64_trunc_sat_f32_s(I64TruncSatF32S), visit_i64_trunc_sat_f32_u(I64TruncSatF32U), + visit_i64_trunc_sat_f64_s(I64TruncSatF64S), visit_i64_trunc_sat_f64_u(I64TruncSatF64U), // Reference Types - visit_ref_func(RefFunc, u32), visit_table_fill(TableFill, u32), visit_table_get(TableGet, u32), visit_table_set(TableSet, u32), visit_table_grow(TableGrow, u32), visit_table_size(TableSize, u32), + visit_ref_func(RefFunc, u32), visit_table_fill(TableFill, u32), visit_table_get(TableGet, u32), visit_table_set(TableSet, u32), + visit_table_grow(TableGrow, u32), visit_table_size(TableSize, u32), visit_ref_is_null(RefIsNull), // Bulk Memory - visit_memory_init(MemoryInit, u32, u32), visit_memory_fill(MemoryFill, u32), visit_table_init(TableInit, u32, u32), visit_data_drop(DataDrop, u32), visit_elem_drop(ElemDrop, u32), + visit_memory_init(MemoryInit, u32, u32), visit_memory_fill(MemoryFill, u32), visit_table_init(TableInit, u32, u32), + visit_data_drop(DataDrop, u32), visit_elem_drop(ElemDrop, u32), // Wide Arithmetic visit_i64_add128(I64Add128), visit_i64_sub128(I64Sub128), visit_i64_mul_wide_s(I64MulWideS), visit_i64_mul_wide_u(I64MulWideU) @@ -238,26 +188,15 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild }; } - fn visit_return(&mut self) -> Self::Output { - self.instructions.push(Instruction::Return); - } - fn visit_local_get(&mut self, idx: u32) -> Self::Output { let resolved_idx = self.local_addr_map[idx as usize]; + use wasmparser::ValType::*; if let Some(t) = self.validator.get_local_type(idx) { match t { - wasmparser::ValType::I32 | wasmparser::ValType::F32 => { - self.instructions.push(Instruction::LocalGet32(resolved_idx)); - } - wasmparser::ValType::I64 | wasmparser::ValType::F64 => { - self.instructions.push(Instruction::LocalGet64(resolved_idx)); - } - wasmparser::ValType::V128 => { - self.instructions.push(Instruction::LocalGet128(resolved_idx)); - } - wasmparser::ValType::Ref(_) => { - self.instructions.push(Instruction::LocalGet32(resolved_idx)); - } + I32 | F32 => self.instructions.push(Instruction::LocalGet32(resolved_idx)), + I64 | F64 => self.instructions.push(Instruction::LocalGet64(resolved_idx)), + V128 => self.instructions.push(Instruction::LocalGet128(resolved_idx)), + Ref(_) => self.instructions.push(Instruction::LocalGet32(resolved_idx)), } } } @@ -309,14 +248,12 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild } fn visit_if(&mut self, _ty: wasmparser::BlockType) -> Self::Output { - let cond_jump_ip = self.instructions.len(); self.instructions.push(Instruction::JumpIfZero(0)); - let start_ip = self.instructions.len(); self.ctx_stack.push(LoweringCtx { kind: BlockKind::If, has_else: false, - start_ip, - branch_jumps: alloc::vec![cond_jump_ip], + start_ip: self.instructions.len(), + branch_jumps: alloc::vec![self.instructions.len() - 1], }); } @@ -422,14 +359,6 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild } } - fn visit_call_indirect(&mut self, ty: u32, table: u32) -> Self::Output { - self.instructions.push(Instruction::CallIndirect(ty, table)); - } - - fn visit_return_call_indirect(&mut self, ty: u32, table: u32) -> Self::Output { - self.instructions.push(Instruction::ReturnCallIndirect(ty, table)); - } - fn visit_f32_const(&mut self, val: wasmparser::Ieee32) -> Self::Output { self.instructions.push(Instruction::F32Const(f32::from_bits(val.bits()))); } @@ -451,10 +380,6 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild self.instructions.push(Instruction::RefNull(convert_heaptype(ty))); } - fn visit_ref_is_null(&mut self) -> Self::Output { - self.instructions.push(Instruction::RefIsNull); - } - fn visit_typed_select_multi(&mut self, tys: Vec<wasmparser::ValType>) -> Self::Output { let (c32, c64, c128) = Self::label_keep_counts(&tys); self.instructions.push(Instruction::SelectMulti(tinywasm_types::ValueCounts { c32, c64, c128 })); |
