summaryrefslogtreecommitdiff
path: root/crates/parser/src/optimize.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src/optimize.rs')
-rw-r--r--crates/parser/src/optimize.rs64
1 files changed, 29 insertions, 35 deletions
diff --git a/crates/parser/src/optimize.rs b/crates/parser/src/optimize.rs
index a5b793e..5882fea 100644
--- a/crates/parser/src/optimize.rs
+++ b/crates/parser/src/optimize.rs
@@ -1,7 +1,7 @@
use crate::ParserOptions;
use crate::macros::optimize::*;
use alloc::vec::Vec;
-use tinywasm_types::{BinOp, BinOp128, CmpOp, ConstIdx, Instruction, WasmFunctionData};
+use tinywasm_types::{BinOp, BinOp128, CmpOp, ConstIdx, Instruction, ValueCounts, WasmFunctionData};
pub(crate) struct OptimizeResult {
pub(crate) instructions: Vec<Instruction>,
@@ -12,12 +12,13 @@ pub(crate) fn optimize_instructions(
mut instructions: Vec<Instruction>,
function_data: &mut WasmFunctionData,
options: &ParserOptions,
+ function_results: ValueCounts,
self_func_addr: u32,
imported_memory_count: u32,
track_local_memory_usage: bool,
) -> OptimizeResult {
let uses_local_memory = if options.optimize_rewrite() {
- rewrite(&mut instructions, self_func_addr, imported_memory_count, track_local_memory_usage)
+ rewrite(&mut instructions, function_results, self_func_addr, imported_memory_count, track_local_memory_usage)
} else {
track_local_memory_usage
&& instructions.iter().any(|instr| instr.memory_addr().is_some_and(|mem| mem >= imported_memory_count))
@@ -31,12 +32,20 @@ pub(crate) fn optimize_instructions(
fn rewrite(
instrs: &mut [Instruction],
+ function_results: ValueCounts,
self_func_addr: u32,
imported_memory_count: u32,
track_local_memory_usage: bool,
) -> bool {
use Instruction::*;
let mut uses_local_memory = false;
+ let return_instr = match function_results {
+ ValueCounts { c32: 0, c64: 0, c128: 0 } => Some(ReturnVoid),
+ ValueCounts { c32: 1, c64: 0, c128: 0 } => Some(Return32),
+ ValueCounts { c32: 0, c64: 1, c128: 0 } => Some(Return64),
+ ValueCounts { c32: 0, c64: 0, c128: 1 } => Some(Return128),
+ _ => None,
+ };
for i in 0..instrs.len() {
match instrs[i] {
@@ -45,6 +54,7 @@ fn rewrite(
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,
+ Return if let Some(return_instr) = return_instr => instrs[i] = return_instr,
instr @ (I32Add | I32Mul | I32And | I32Or | I32Xor) => {
let Some(op) = int_bin_op_32(instr) else { unreachable!() };
rewrite!(instrs, i, [LocalGet32(a), LocalGet32(b)] => BinOpLocalLocal32(op, a, b));
@@ -370,11 +380,7 @@ fn rewrite(
),
Jump(ip) => {
let target = resolve_jump_target(instrs, ip);
- if target == next_non_nop(instrs, i + 1) as u32 {
- instrs[i] = Nop;
- } else if target != ip {
- instrs[i] = Jump(target);
- }
+ canonicalize_jump_like_with_target(instrs, i, target);
}
JumpIfZero(ip) => {
let target = resolve_jump_target(instrs, ip);
@@ -430,10 +436,7 @@ fn rewrite(
(0, CmpOp::Ne) => JumpIfNonZero64(target),
(imm, op) => JumpCmpStackConst64 { target_ip: target, imm, op },
});
- canonicalize_jump_like(instrs, i);
- if let JumpIfZero(current) = &mut instrs[i] {
- *current = target;
- }
+ canonicalize_jump_like_with_target(instrs, i, target);
}
JumpIfNonZero(ip) => {
let target = resolve_jump_target(instrs, ip);
@@ -489,42 +492,27 @@ fn rewrite(
(0, CmpOp::Ne) => JumpIfNonZero64(target),
(imm, op) => JumpCmpStackConst64 { target_ip: target, imm, op },
});
- canonicalize_jump_like(instrs, i);
- if let JumpIfNonZero(current) = &mut instrs[i] {
- *current = target;
- }
+ canonicalize_jump_like_with_target(instrs, i, target);
}
JumpIfZero32(ip) => {
let target = resolve_jump_target(instrs, ip);
rewrite!(instrs, i, [LocalGet32(local)] => JumpIfLocalZero32 { target_ip: target, local });
- canonicalize_jump_like(instrs, i);
- if let JumpIfZero32(current) = &mut instrs[i] {
- *current = target;
- }
+ canonicalize_jump_like_with_target(instrs, i, target);
}
JumpIfNonZero32(ip) => {
let target = resolve_jump_target(instrs, ip);
rewrite!(instrs, i, [LocalGet32(local)] => JumpIfLocalNonZero32 { target_ip: target, local });
- canonicalize_jump_like(instrs, i);
- if let JumpIfNonZero32(current) = &mut instrs[i] {
- *current = target;
- }
+ canonicalize_jump_like_with_target(instrs, i, target);
}
JumpIfZero64(ip) => {
let target = resolve_jump_target(instrs, ip);
rewrite!(instrs, i, [LocalGet64(local)] => JumpIfLocalZero64 { target_ip: target, local });
- canonicalize_jump_like(instrs, i);
- if let JumpIfZero64(current) = &mut instrs[i] {
- *current = target;
- }
+ canonicalize_jump_like_with_target(instrs, i, target);
}
JumpIfNonZero64(ip) => {
let target = resolve_jump_target(instrs, ip);
rewrite!(instrs, i, [LocalGet64(local)] => JumpIfLocalNonZero64 { target_ip: target, local });
- canonicalize_jump_like(instrs, i);
- if let JumpIfNonZero64(current) = &mut instrs[i] {
- *current = target;
- }
+ canonicalize_jump_like_with_target(instrs, i, target);
}
JumpCmpStackConst32 { target_ip, imm: 0, op } => {
match op {
@@ -573,8 +561,8 @@ fn rewrite(
_ => {}
}
- if track_local_memory_usage {
- uses_local_memory |= instrs[i].memory_addr().is_some_and(|mem| mem >= imported_memory_count);
+ if track_local_memory_usage && !uses_local_memory {
+ uses_local_memory = instrs[i].memory_addr().is_some_and(|mem| mem >= imported_memory_count);
}
}
@@ -766,11 +754,14 @@ fn inverse_cmp_op(op: CmpOp) -> CmpOp {
}
}
+const PREVIOUS_NON_NOP_BACKTRACK_LIMIT: usize = 32;
+
fn previous_non_nop<const N: usize>(instrs: &[Instruction], read: usize) -> Option<[(usize, Instruction); N]> {
let mut out = [(0usize, Instruction::Nop); N];
let mut filled = 0usize;
+ let start = read.saturating_sub(PREVIOUS_NON_NOP_BACKTRACK_LIMIT);
- for idx in (0..read).rev() {
+ for idx in (start..read).rev() {
let instr = instrs[idx];
if matches!(instr, Instruction::MergeBarrier) {
return None;
@@ -864,7 +855,10 @@ fn canonicalize_jump_like(instrs: &mut [Instruction], idx: usize) {
return;
};
- let target = resolve_jump_target(instrs, target);
+ canonicalize_jump_like_with_target(instrs, idx, resolve_jump_target(instrs, target));
+}
+
+fn canonicalize_jump_like_with_target(instrs: &mut [Instruction], idx: usize, target: u32) {
if matches!(instrs[idx], Instruction::Jump(_)) && target == next_non_nop(instrs, idx + 1) as u32 {
instrs[idx] = Instruction::Nop;
} else {