summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/parser/src/optimize.rs187
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs78
-rw-r--r--crates/types/src/instructions.rs40
3 files changed, 257 insertions, 48 deletions
diff --git a/crates/parser/src/optimize.rs b/crates/parser/src/optimize.rs
index c066c29..7308262 100644
--- a/crates/parser/src/optimize.rs
+++ b/crates/parser/src/optimize.rs
@@ -1,6 +1,37 @@
use crate::ParserOptions;
use alloc::vec::Vec;
-use tinywasm_types::{Instruction, WasmFunctionData};
+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>,
@@ -30,7 +61,7 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) {
{
instructions[read - 2] = Instruction::Nop;
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::I32AddLocals(a, b);
+ instructions[read] = Instruction::AddLocalLocal32(a, b);
}
if read > 0 {
@@ -39,15 +70,15 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) {
if let Instruction::LocalGet32(local) = instructions[read - 2] {
instructions[read - 2] = Instruction::Nop;
instructions[read - 1] = Instruction::LocalGet32(local);
- instructions[read] = Instruction::I32AddConst(c);
+ instructions[read] = Instruction::AddConst32(c);
} else {
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::I32AddConst(c);
+ instructions[read] = Instruction::AddConst32(c);
}
}
Instruction::I32Const(c) => {
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::I32AddConst(c);
+ instructions[read] = Instruction::AddConst32(c);
}
_ => {}
}
@@ -60,7 +91,7 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) {
{
instructions[read - 2] = Instruction::Nop;
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::I64AddLocals(a, b);
+ instructions[read] = Instruction::AddLocalLocal64(a, b);
}
if read > 0 {
@@ -69,15 +100,15 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) {
if let Instruction::LocalGet64(local) = instructions[read - 2] {
instructions[read - 2] = Instruction::Nop;
instructions[read - 1] = Instruction::LocalGet64(local);
- instructions[read] = Instruction::I64AddConst(c);
+ instructions[read] = Instruction::AddConst64(c);
} else {
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::I64AddConst(c);
+ instructions[read] = Instruction::AddConst64(c);
}
}
Instruction::I64Const(c) => {
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::I64AddConst(c);
+ instructions[read] = Instruction::AddConst64(c);
}
_ => {}
}
@@ -90,7 +121,7 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) {
{
instructions[read - 2] = Instruction::Nop;
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::I64XorRotlConst(c);
+ instructions[read] = Instruction::XorRotlConst64(c);
}
}
Instruction::I32Store(memarg) => {
@@ -101,7 +132,7 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) {
{
instructions[read - 2] = Instruction::Nop;
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::I32StoreLocalLocal(memarg, addr_local, value_local);
+ instructions[read] = Instruction::StoreLocalLocal32(memarg, addr_local, value_local);
}
}
Instruction::I64Store(memarg) => {
@@ -112,7 +143,16 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) {
{
instructions[read - 2] = Instruction::Nop;
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::I64StoreLocalLocal(memarg, addr_local, value_local);
+ instructions[read] = Instruction::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);
}
}
Instruction::MemoryFill(mem) => {
@@ -163,12 +203,12 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) {
}
Instruction::I32Const(c) => {
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::LocalSetConst32(dst, c);
+ instructions[read] = Instruction::SetLocalConst32(dst, c);
}
Instruction::F32Const(c) => {
instructions[read - 1] = Instruction::Nop;
instructions[read] =
- Instruction::LocalSetConst32(dst, i32::from_ne_bytes(c.to_bits().to_ne_bytes()));
+ Instruction::SetLocalConst32(dst, i32::from_ne_bytes(c.to_bits().to_ne_bytes()));
}
_ => {}
}
@@ -176,21 +216,29 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) {
if read > 1 {
match (instructions[read - 2], instructions[read - 1]) {
- (Instruction::LocalGet32(src), Instruction::I32AddConst(c)) if src == dst => {
+ (Instruction::LocalGet32(src), Instruction::AddConst32(c)) if src == dst => {
instructions[read - 2] = Instruction::Nop;
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::LocalAddConst32(dst, c);
+ 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::I32LoadLocalSet(memarg, addr, dst);
+ 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);
+ }
}
Instruction::LocalSet64(dst) => {
if read > 0 {
@@ -202,25 +250,25 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) {
}
Instruction::I64Const(c) => {
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::LocalSetConst64(dst, c);
+ instructions[read] = Instruction::SetLocalConst64(dst, c);
}
Instruction::F64Const(c) => {
instructions[read - 1] = Instruction::Nop;
instructions[read] =
- Instruction::LocalSetConst64(dst, i64::from_ne_bytes(c.to_bits().to_ne_bytes()));
+ Instruction::SetLocalConst64(dst, i64::from_ne_bytes(c.to_bits().to_ne_bytes()));
}
_ => {}
}
}
if read > 1
- && let (Instruction::LocalGet64(src), Instruction::I64AddConst(c)) =
+ && 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::LocalAddConst64(dst, c);
+ instructions[read] = Instruction::AddLocalConst64(dst, c);
}
}
Instruction::LocalSet128(dst) => {
@@ -247,16 +295,24 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) {
{
instructions[read - 2] = Instruction::Nop;
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::I32LoadLocalTee(memarg, addr, dst);
+ 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);
}
}
Instruction::LocalTee64(dst) if read > 0 => match instructions[read - 1] {
Instruction::LocalGet64(src) if src == dst => {
instructions[read] = Instruction::Nop;
}
- Instruction::I64XorRotlConst(c) => {
+ Instruction::XorRotlConst64(c) => {
instructions[read - 1] = Instruction::Nop;
- instructions[read] = Instruction::I64XorRotlConstTee(c, dst);
+ instructions[read] = Instruction::XorRotlConstTee64(c, dst);
}
_ => {}
},
@@ -292,6 +348,87 @@ fn rewrite(instructions: &mut [Instruction], self_func_addr: u32) {
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);
+ 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),
+ };
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+ Instruction::JumpIfNonZero(ip) => {
+ if read > 0 && instructions[read - 1] == Instruction::I32Eqz {
+ instructions[read - 1] = Instruction::Nop;
+ instructions[read] = Instruction::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 };
+ }
+ }
+ _ => {}
+ }
+ }
+ }
_ => {}
}
}
@@ -330,6 +467,8 @@ fn dce(instructions: &mut Vec<Instruction>, function_data: &mut WasmFunctionData
Instruction::Jump(ip)
| Instruction::JumpIfZero(ip)
| Instruction::JumpIfNonZero(ip)
+ | Instruction::JumpCmpLocalConst32 { target_ip: ip, .. }
+ | Instruction::JumpCmpLocalLocal32 { target_ip: ip, .. }
| Instruction::BranchTable(ip, _, _) => ip,
_ => return !matches!(instr, Instruction::Nop),
};
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs
index a6052a9..2f59349 100644
--- a/crates/tinywasm/src/interpreter/executor.rs
+++ b/crates/tinywasm/src/interpreter/executor.rs
@@ -148,6 +148,12 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
Jump(ip) => { self.exec_jump(*ip); continue; }
JumpIfZero(ip) => if self.exec_jump_if_zero(*ip) { continue; },
JumpIfNonZero(ip) => if self.exec_jump_if_non_zero(*ip) { continue; },
+ JumpCmpLocalConst32 { target_ip, local, imm, op } => {
+ if self.exec_jump_cmp_local_const_32(*target_ip, *local, *imm, *op) { continue; }
+ }
+ JumpCmpLocalLocal32 { target_ip, left, right, op } => {
+ if self.exec_jump_cmp_local_local_32(*target_ip, *left, *right, *op) { continue; }
+ }
DropKeep { base32, keep32, base64, keep64, base128, keep128 } => {
let mut base = self.cf.stack_base(); base.s32 += *base32 as u32; base.s64 += *base64 as u32; base.s128 += *base128 as u32;
self.store.stack.values.truncate_keep_counts(base, ValueCounts { c32: *keep32 as u16, c64: *keep64 as u16, c128: *keep128 as u16 });
@@ -166,20 +172,21 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
LocalCopy32(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<Value32>(&self.cf, *from)),
LocalCopy64(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<Value64>(&self.cf, *from)),
LocalCopy128(from, to) => self.store.stack.values.local_set(&self.cf, *to, self.store.stack.values.local_get::<Value128>(&self.cf, *from)),
- I32AddLocals(a, b) => self.store.stack.values.push(self.store.stack.values.local_get::<i32>(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::<i32>(&self.cf, *b)))?,
- I64AddLocals(a, b) => self.store.stack.values.push(self.store.stack.values.local_get::<i64>(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::<i64>(&self.cf, *b)))?,
- I32AddConst(c) => stack_op!(unary i32, |v| v.wrapping_add(*c)),
- I64AddConst(c) => stack_op!(unary i64, |v| v.wrapping_add(*c)),
- LocalAddConst32(local_index, c) => self.store.stack.values.local_update::<Value32>(&self.cf, *local_index, |local| *local = local.wrapping_add(*c as u32)),
- LocalAddConst64(local_index, c) => self.store.stack.values.local_update::<Value64>(&self.cf, *local_index, |local| *local = local.wrapping_add(*c as u64)),
- LocalSetConst32(local_index, c) => self.store.stack.values.local_set::<i32>(&self.cf, *local_index, *c),
- LocalSetConst64(local_index, c) => self.store.stack.values.local_set::<i64>(&self.cf, *local_index, *c),
- I32StoreLocalLocal(m, addr_local, value_local) => self.exec_store_local_local::<u32, u32, 4>(*m, *addr_local, *value_local, |v| v)?,
- I64StoreLocalLocal(m, addr_local, value_local) =>self.exec_store_local_local::<i64, i64, 8>(*m, *addr_local, *value_local, |v| v)?,
- I32LoadLocalTee(m, addr_local, dst_local) => self.exec_i32_load_local_tee(*m, *addr_local, *dst_local)?,
- I32LoadLocalSet(m, addr_local, dst_local) => self.exec_i32_load_local_set(*m, *addr_local, *dst_local)?,
- I64XorRotlConst(c) => stack_op!(binary i64, |lhs, rhs| (lhs ^ rhs).rotate_left(*c as u32)),
- I64XorRotlConstTee(c, local_index) => {
+ AddLocalLocal32(a, b) => self.store.stack.values.push(self.store.stack.values.local_get::<i32>(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::<i32>(&self.cf, *b)))?,
+ AddLocalLocal64(a, b) => self.store.stack.values.push(self.store.stack.values.local_get::<i64>(&self.cf, *a).wrapping_add(self.store.stack.values.local_get::<i64>(&self.cf, *b)))?,
+ AddConst32(c) => stack_op!(unary i32, |v| v.wrapping_add(*c)),
+ AddConst64(c) => stack_op!(unary i64, |v| v.wrapping_add(*c)),
+ AddLocalConst32(local_index, c) => self.store.stack.values.local_update::<Value32>(&self.cf, *local_index, |local| *local = local.wrapping_add(*c as u32)),
+ AddLocalConst64(local_index, c) => self.store.stack.values.local_update::<Value64>(&self.cf, *local_index, |local| *local = local.wrapping_add(*c as u64)),
+ SetLocalConst32(local_index, c) => self.store.stack.values.local_set::<i32>(&self.cf, *local_index, *c),
+ SetLocalConst64(local_index, c) => self.store.stack.values.local_set::<i64>(&self.cf, *local_index, *c),
+ StoreLocalLocal32(m, addr_local, value_local) => self.exec_store_local_local::<u32, u32, 4>(*m, *addr_local, *value_local, |v| v)?,
+ StoreLocalLocal64(m, addr_local, value_local) =>self.exec_store_local_local::<i64, i64, 8>(*m, *addr_local, *value_local, |v| v)?,
+ LoadLocal32(m, addr_local) => self.exec_i32_load_local(*m, *addr_local)?,
+ LoadLocalTee32(m, addr_local, dst_local) => self.exec_i32_load_local_tee(*m, *addr_local, *dst_local)?,
+ LoadLocalSet32(m, addr_local, dst_local) => self.exec_i32_load_local_set(*m, *addr_local, *dst_local)?,
+ XorRotlConst64(c) => stack_op!(binary i64, |lhs, rhs| (lhs ^ rhs).rotate_left(*c as u32)),
+ XorRotlConstTee64(c, local_index) => {
stack_op!(binary i64, |lhs, rhs| (lhs ^ rhs).rotate_left(*c as u32));
stack_op!(local_tee i64, local_index);
}
@@ -691,6 +698,27 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
}
#[inline(always)]
+ fn exec_jump_cmp_local_const_32(&mut self, target_ip: u32, local: LocalAddr, imm: i32, op: CmpOp) -> bool {
+ let lhs = self.store.stack.values.local_get::<i32>(&self.cf, local);
+ if cmp_i32(lhs, imm, op) {
+ self.cf.instr_ptr = target_ip;
+ return true;
+ }
+ false
+ }
+
+ #[inline(always)]
+ fn exec_jump_cmp_local_local_32(&mut self, target_ip: u32, left: LocalAddr, right: LocalAddr, op: CmpOp) -> bool {
+ let lhs = self.store.stack.values.local_get::<i32>(&self.cf, left);
+ let rhs = self.store.stack.values.local_get::<i32>(&self.cf, right);
+ if cmp_i32(lhs, rhs, op) {
+ self.cf.instr_ptr = target_ip;
+ return true;
+ }
+ false
+ }
+
+ #[inline(always)]
fn exec_branch_table(&mut self, default_ip: u32, start: u32, len: u32) {
let idx = self.store.stack.values.pop::<i32>();
let target_ip = if idx >= 0 && (idx as u32) < len {
@@ -879,6 +907,12 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
}
#[inline(always)]
+ fn exec_i32_load_local(&mut self, memarg: MemoryArg, addr_local: u8) -> Result<()> {
+ let value = self.exec_i32_load_local_value(memarg, addr_local)?;
+ self.store.stack.values.push(value)
+ }
+
+ #[inline(always)]
fn exec_i32_load_local_tee(&mut self, memarg: MemoryArg, addr_local: u8, dst_local: u8) -> Result<()> {
let value = self.exec_i32_load_local_value(memarg, addr_local)?;
self.store.stack.values.local_set(&self.cf, u16::from(dst_local), value);
@@ -1283,3 +1317,19 @@ impl<'store> Executor<'store, true> {
}
}
}
+
+#[inline(always)]
+fn cmp_i32(lhs: i32, rhs: i32, op: CmpOp) -> bool {
+ match op {
+ CmpOp::Eq => lhs == rhs,
+ CmpOp::Ne => lhs != rhs,
+ CmpOp::LtS => lhs < rhs,
+ CmpOp::LtU => (lhs as u32) < (rhs as u32),
+ CmpOp::GtS => lhs > rhs,
+ CmpOp::GtU => (lhs as u32) > (rhs as u32),
+ CmpOp::LeS => lhs <= rhs,
+ CmpOp::LeU => (lhs as u32) <= (rhs as u32),
+ CmpOp::GeS => lhs >= rhs,
+ CmpOp::GeU => (lhs as u32) >= (rhs as u32),
+ }
+}
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index 7db9f79..8cfb097 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -48,6 +48,23 @@ pub enum ConstInstruction {
I64Mul,
}
+/// An integer comparison operator, currently only used for conditional jumps.
+#[derive(Clone, Copy, PartialEq, Eq)]
+#[cfg_attr(feature = "debug", derive(Debug))]
+#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
+pub enum CmpOp {
+ Eq,
+ Ne,
+ LtS,
+ LtU,
+ GtS,
+ GtU,
+ LeS,
+ LeU,
+ GeS,
+ GeU,
+}
+
/// A WebAssembly Instruction
///
/// These are our own internal bytecode instructions so they may not match the spec exactly.
@@ -60,16 +77,17 @@ pub enum ConstInstruction {
#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
pub enum Instruction {
LocalCopy32(LocalAddr, LocalAddr), LocalCopy64(LocalAddr, LocalAddr), LocalCopy128(LocalAddr, LocalAddr),
- I32AddLocals(LocalAddr, LocalAddr), I64AddLocals(LocalAddr, LocalAddr),
- I32AddConst(i32), I64AddConst(i64),
- LocalAddConst32(LocalAddr, i32), LocalAddConst64(LocalAddr, i64),
- LocalSetConst32(LocalAddr, i32), LocalSetConst64(LocalAddr, i64),
- I32StoreLocalLocal(MemoryArg, u8, u8),
- I64StoreLocalLocal(MemoryArg, u8, u8),
- I32LoadLocalTee(MemoryArg, u8, u8),
- I32LoadLocalSet(MemoryArg, u8, u8),
- I64XorRotlConst(i64),
- I64XorRotlConstTee(i64, LocalAddr),
+ AddLocalLocal32(LocalAddr, LocalAddr), AddLocalLocal64(LocalAddr, LocalAddr),
+ AddConst32(i32), AddConst64(i64),
+ AddLocalConst32(LocalAddr, i32), AddLocalConst64(LocalAddr, i64),
+ SetLocalConst32(LocalAddr, i32), SetLocalConst64(LocalAddr, i64),
+ StoreLocalLocal32(MemoryArg, u8, u8),
+ StoreLocalLocal64(MemoryArg, u8, u8),
+ LoadLocal32(MemoryArg, u8),
+ LoadLocalTee32(MemoryArg, u8, u8),
+ LoadLocalSet32(MemoryArg, u8, u8),
+ XorRotlConst64(i64),
+ XorRotlConstTee64(i64, LocalAddr),
// > Control Instructions (jump-oriented, lowered from structured control during parsing)
// See <https://webassembly.github.io/spec/core/binary/instructions.html#control-instructions>
@@ -78,6 +96,8 @@ pub enum Instruction {
Jump(u32),
JumpIfZero(u32),
JumpIfNonZero(u32),
+ JumpCmpLocalConst32 { target_ip: u32, local: LocalAddr, imm: i32, op: CmpOp },
+ JumpCmpLocalLocal32 { target_ip: u32, left: LocalAddr, right: LocalAddr, op: CmpOp },
DropKeep { base32: u16, keep32: u8, base64: u16, keep64: u8, base128: u16, keep128: u8 },
DropKeep32(u16, u16),
DropKeep64(u16, u16),