Skip to content

Commit

Permalink
feat: implement I32StoreLocal & I32LocalGetConstAdd
Browse files Browse the repository at this point in the history
Signed-off-by: Henry Gressmann <[email protected]>
  • Loading branch information
explodingcamera committed May 9, 2024
1 parent 11271a2 commit 53bb44f
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 20 deletions.
2 changes: 1 addition & 1 deletion BENCHMARKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`._
Expand Down
56 changes: 43 additions & 13 deletions crates/parser/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
15 changes: 15 additions & 0 deletions crates/tinywasm/src/runtime/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 2 additions & 4 deletions crates/types/src/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions examples/rust/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down

0 comments on commit 53bb44f

Please sign in to comment.