summaryrefslogtreecommitdiff
path: root/crates/parser/src
diff options
context:
space:
mode:
authorHenry <mail@henrygressmann.de>2026-04-17 20:57:17 +0200
committerHenry <mail@henrygressmann.de>2026-04-17 21:00:18 +0200
commit468a600d029d6aa45447c4346b11c9b9371050ca (patch)
tree434c5bbe3d2c71e04a664403dfc1cc21c97f21d5 /crates/parser/src
parent4edfbab882948fe3424b76aebdfd02383adfab01 (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.rs3
-rw-r--r--crates/parser/src/error.rs3
-rw-r--r--crates/parser/src/lib.rs16
-rw-r--r--crates/parser/src/macros.rs220
-rw-r--r--crates/parser/src/module.rs7
-rw-r--r--crates/parser/src/optimize.rs611
-rw-r--r--crates/parser/src/visit.rs175
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 }));