summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry Gressmann <mail@henrygressmann.de>2024-05-09 22:36:14 +0200
committerHenry Gressmann <mail@henrygressmann.de>2024-05-09 22:36:14 +0200
commit53bb44f45cfda750250e0835425307e3a1d763bc (patch)
tree4085c249714d76b82157c7a888baa2151fe8f190
parent11271a201633d3b07adacd07e407ac8d07e5fce3 (diff)
feat: implement I32StoreLocal & I32LocalGetConstAdd
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
-rw-r--r--BENCHMARKS.md2
-rw-r--r--crates/parser/src/visit.rs56
-rw-r--r--crates/tinywasm/src/runtime/interpreter/mod.rs15
-rw-r--r--crates/types/src/instructions.rs6
-rwxr-xr-xexamples/rust/build.sh4
5 files changed, 63 insertions, 20 deletions
diff --git a/BENCHMARKS.md b/BENCHMARKS.md
index c34e16c..746c585 100644
--- a/BENCHMARKS.md
+++ b/BENCHMARKS.md
@@ -36,7 +36,7 @@ All runtimes are compiled with the following settings:
| ------------ | -------- | ---------- | --------- | -------------------- |
| `fib` | \*\* | ` 43.60µs` | `48.27µs` | ` 44.99µs` |
| `fib-rec` | `0.27ms` | ` 21.13ms` | ` 4.63ms` | ` 0.47ms` |
-| `argon2id` | `0.53ms` | ` 99.16ms` | `45.00ms` | ` 4.59ms` |
+| `argon2id` | `0.53ms` | ` 86.16ms` | `45.00ms` | ` 4.59ms` |
| `selfhosted` | `0.05ms` | ` 1.84ms` | ` 6.51ms` | `446.48ms` |
_\* Uses tinywasm's internal module format instead of `wasm`. It takes ~5.7ms to parse and validate `tinywasm.wasm`._
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index 80dc789..48eba30 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -162,7 +162,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
visit_i64_load16_u, I64Load16U,
visit_i64_load32_s, I64Load32S,
visit_i64_load32_u, I64Load32U,
- visit_i32_store, I32Store,
+ // visit_i32_store, I32Store,
visit_i64_store, I64Store,
visit_f32_store, F32Store,
visit_f64_store, F64Store,
@@ -321,6 +321,37 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
visit_i64_trunc_sat_f64_u, Instruction::I64TruncSatF64U
}
+ fn visit_i32_store(&mut self, memarg: wasmparser::MemArg) -> Self::Output {
+ let arg = convert_memarg(memarg);
+ let i32store = Instruction::I32Store { offset: arg.offset, mem_addr: arg.mem_addr };
+
+ if self.instructions.len() < 3 {
+ return self.visit(i32store);
+ }
+
+ #[cold]
+ fn cold() {}
+
+ if arg.mem_addr > 0xFF || arg.offset > 0xFFFF_FFFF {
+ cold();
+ return self.visit(i32store);
+ }
+
+ match self.instructions[self.instructions.len() - 2..] {
+ [Instruction::LocalGet(a), Instruction::I32Const(b)] => {
+ self.instructions.pop();
+ self.instructions.pop();
+ self.visit(Instruction::I32StoreLocal {
+ local: a,
+ consti32: b,
+ offset: arg.offset as u32,
+ mem_addr: arg.mem_addr as u8,
+ })
+ }
+ _ => self.visit(i32store),
+ }
+ }
+
fn visit_local_get(&mut self, idx: u32) -> Self::Output {
if let Some(instruction) = self.instructions.last_mut() {
match instruction {
@@ -369,19 +400,18 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
}
fn visit_i32_add(&mut self) -> Self::Output {
- self.visit(Instruction::I32Add)
- // if self.instructions.len() < 2 {
- // return self.visit(Instruction::I32Add);
- // }
+ if self.instructions.len() < 2 {
+ return self.visit(Instruction::I32Add);
+ }
- // match self.instructions[self.instructions.len() - 2..] {
- // // [Instruction::LocalGet(a), Instruction::I32Const(b)] => {
- // // self.instructions.pop();
- // // self.instructions.pop();
- // // self.visit(Instruction::I32LocalGetConstAdd(a, b))
- // // }
- // _ => self.visit(Instruction::I32Add),
- // }
+ match self.instructions[self.instructions.len() - 2..] {
+ [Instruction::LocalGet(a), Instruction::I32Const(b)] => {
+ self.instructions.pop();
+ self.instructions.pop();
+ self.visit(Instruction::I32LocalGetConstAdd(a, b))
+ }
+ _ => self.visit(Instruction::I32Add),
+ }
}
fn visit_block(&mut self, blockty: wasmparser::BlockType) -> Self::Output {
diff --git a/crates/tinywasm/src/runtime/interpreter/mod.rs b/crates/tinywasm/src/runtime/interpreter/mod.rs
index 2f0328b..6ff7be1 100644
--- a/crates/tinywasm/src/runtime/interpreter/mod.rs
+++ b/crates/tinywasm/src/runtime/interpreter/mod.rs
@@ -689,6 +689,21 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
let res = val ^ mask;
stack.values.push(res.rotate_left(*rotate_by as u32).into());
}
+
+ I32LocalGetConstAdd(local, val) => {
+ let local: i32 = cf.get_local(*local as usize).into();
+ stack.values.push((local + *val).into());
+ }
+
+ I32StoreLocal { local, consti32, offset, mem_addr } => {
+ let (mem_addr, offset) = (*mem_addr as u32, *offset as u32);
+ let mem = store.get_mem(module.resolve_mem_addr(mem_addr) as usize)?;
+ let val = consti32;
+ let val = val.to_le_bytes();
+ let addr: u64 = cf.get_local(*local as usize).into();
+ mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?;
+ }
+
i => {
cold();
log::error!("unimplemented instruction: {:?}", i);
diff --git a/crates/types/src/instructions.rs b/crates/types/src/instructions.rs
index 402cc9a..fc6fba2 100644
--- a/crates/types/src/instructions.rs
+++ b/crates/types/src/instructions.rs
@@ -84,16 +84,14 @@ pub enum Instruction {
// Custom Instructions
BrLabel(LabelAddr),
- // Not implemented yet
// LocalGet + I32Const + I32Add
// One of the most common patterns in the Rust compiler output
- // I32LocalGetConstAdd(LocalAddr, i32),
+ I32LocalGetConstAdd(LocalAddr, i32),
- // Not implemented yet
// LocalGet + I32Const + I32Store => I32LocalGetConstStore + I32Const
// Also common, helps us skip the stack entirely.
// Has to be followed by an I32Const instruction
- // I32StoreLocal { local: LocalAddr, offset: i32, mem_addr: MemAddr },
+ I32StoreLocal { local: LocalAddr, consti32: i32, offset: u32, mem_addr: u8 },
// I64Xor + I64Const + I64RotL
// Commonly used by a few crypto libraries
diff --git a/examples/rust/build.sh b/examples/rust/build.sh
index 744f9d0..5028741 100755
--- a/examples/rust/build.sh
+++ b/examples/rust/build.sh
@@ -6,7 +6,7 @@ exclude_wat=("tinywasm")
out_dir="./target/wasm32-unknown-unknown/wasm"
dest_dir="out"
-features="+reference-types,+bulk-memory,+mutable-globals,+multivalue"
+features="+reference-types,+bulk-memory,+mutable-globals"
# ensure out dir exists
mkdir -p "$dest_dir"
@@ -15,7 +15,7 @@ for bin in "${bins[@]}"; do
RUSTFLAGS="-C target-feature=$features -C panic=abort" cargo build --target wasm32-unknown-unknown --package rust-wasm-examples --profile=wasm --bin "$bin"
cp "$out_dir/$bin.wasm" "$dest_dir/"
- wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wasm" -Oz --enable-bulk-memory --enable-multivalue --enable-reference-types --enable-mutable-globals
+ wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wasm" -Oz --enable-bulk-memory --enable-reference-types --enable-mutable-globals
if [[ ! " ${exclude_wat[@]} " =~ " $bin " ]]; then
wasm2wat "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wat"