Skip to content

Commit 53bb44f

Browse files
feat: implement I32StoreLocal & I32LocalGetConstAdd
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
1 parent 11271a2 commit 53bb44f

File tree

5 files changed

+63
-20
lines changed

5 files changed

+63
-20
lines changed

BENCHMARKS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ All runtimes are compiled with the following settings:
3636
| ------------ | -------- | ---------- | --------- | -------------------- |
3737
| `fib` | \*\* | ` 43.60µs` | `48.27µs` | ` 44.99µs` |
3838
| `fib-rec` | `0.27ms` | ` 21.13ms` | ` 4.63ms` | ` 0.47ms` |
39-
| `argon2id` | `0.53ms` | ` 99.16ms` | `45.00ms` | ` 4.59ms` |
39+
| `argon2id` | `0.53ms` | ` 86.16ms` | `45.00ms` | ` 4.59ms` |
4040
| `selfhosted` | `0.05ms` | ` 1.84ms` | ` 6.51ms` | `446.48ms` |
4141

4242
_\* Uses tinywasm's internal module format instead of `wasm`. It takes ~5.7ms to parse and validate `tinywasm.wasm`._

crates/parser/src/visit.rs

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
162162
visit_i64_load16_u, I64Load16U,
163163
visit_i64_load32_s, I64Load32S,
164164
visit_i64_load32_u, I64Load32U,
165-
visit_i32_store, I32Store,
165+
// visit_i32_store, I32Store,
166166
visit_i64_store, I64Store,
167167
visit_f32_store, F32Store,
168168
visit_f64_store, F64Store,
@@ -321,6 +321,37 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
321321
visit_i64_trunc_sat_f64_u, Instruction::I64TruncSatF64U
322322
}
323323

324+
fn visit_i32_store(&mut self, memarg: wasmparser::MemArg) -> Self::Output {
325+
let arg = convert_memarg(memarg);
326+
let i32store = Instruction::I32Store { offset: arg.offset, mem_addr: arg.mem_addr };
327+
328+
if self.instructions.len() < 3 {
329+
return self.visit(i32store);
330+
}
331+
332+
#[cold]
333+
fn cold() {}
334+
335+
if arg.mem_addr > 0xFF || arg.offset > 0xFFFF_FFFF {
336+
cold();
337+
return self.visit(i32store);
338+
}
339+
340+
match self.instructions[self.instructions.len() - 2..] {
341+
[Instruction::LocalGet(a), Instruction::I32Const(b)] => {
342+
self.instructions.pop();
343+
self.instructions.pop();
344+
self.visit(Instruction::I32StoreLocal {
345+
local: a,
346+
consti32: b,
347+
offset: arg.offset as u32,
348+
mem_addr: arg.mem_addr as u8,
349+
})
350+
}
351+
_ => self.visit(i32store),
352+
}
353+
}
354+
324355
fn visit_local_get(&mut self, idx: u32) -> Self::Output {
325356
if let Some(instruction) = self.instructions.last_mut() {
326357
match instruction {
@@ -369,19 +400,18 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
369400
}
370401

371402
fn visit_i32_add(&mut self) -> Self::Output {
372-
self.visit(Instruction::I32Add)
373-
// if self.instructions.len() < 2 {
374-
// return self.visit(Instruction::I32Add);
375-
// }
403+
if self.instructions.len() < 2 {
404+
return self.visit(Instruction::I32Add);
405+
}
376406

377-
// match self.instructions[self.instructions.len() - 2..] {
378-
// // [Instruction::LocalGet(a), Instruction::I32Const(b)] => {
379-
// // self.instructions.pop();
380-
// // self.instructions.pop();
381-
// // self.visit(Instruction::I32LocalGetConstAdd(a, b))
382-
// // }
383-
// _ => self.visit(Instruction::I32Add),
384-
// }
407+
match self.instructions[self.instructions.len() - 2..] {
408+
[Instruction::LocalGet(a), Instruction::I32Const(b)] => {
409+
self.instructions.pop();
410+
self.instructions.pop();
411+
self.visit(Instruction::I32LocalGetConstAdd(a, b))
412+
}
413+
_ => self.visit(Instruction::I32Add),
414+
}
385415
}
386416

387417
fn visit_block(&mut self, blockty: wasmparser::BlockType) -> Self::Output {

crates/tinywasm/src/runtime/interpreter/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,21 @@ fn exec_one(cf: &mut CallFrame, stack: &mut Stack, store: &mut Store, module: &M
689689
let res = val ^ mask;
690690
stack.values.push(res.rotate_left(*rotate_by as u32).into());
691691
}
692+
693+
I32LocalGetConstAdd(local, val) => {
694+
let local: i32 = cf.get_local(*local as usize).into();
695+
stack.values.push((local + *val).into());
696+
}
697+
698+
I32StoreLocal { local, consti32, offset, mem_addr } => {
699+
let (mem_addr, offset) = (*mem_addr as u32, *offset as u32);
700+
let mem = store.get_mem(module.resolve_mem_addr(mem_addr) as usize)?;
701+
let val = consti32;
702+
let val = val.to_le_bytes();
703+
let addr: u64 = cf.get_local(*local as usize).into();
704+
mem.borrow_mut().store((offset as u64 + addr) as usize, val.len(), &val)?;
705+
}
706+
692707
i => {
693708
cold();
694709
log::error!("unimplemented instruction: {:?}", i);

crates/types/src/instructions.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,14 @@ pub enum Instruction {
8484
// Custom Instructions
8585
BrLabel(LabelAddr),
8686

87-
// Not implemented yet
8887
// LocalGet + I32Const + I32Add
8988
// One of the most common patterns in the Rust compiler output
90-
// I32LocalGetConstAdd(LocalAddr, i32),
89+
I32LocalGetConstAdd(LocalAddr, i32),
9190

92-
// Not implemented yet
9391
// LocalGet + I32Const + I32Store => I32LocalGetConstStore + I32Const
9492
// Also common, helps us skip the stack entirely.
9593
// Has to be followed by an I32Const instruction
96-
// I32StoreLocal { local: LocalAddr, offset: i32, mem_addr: MemAddr },
94+
I32StoreLocal { local: LocalAddr, consti32: i32, offset: u32, mem_addr: u8 },
9795

9896
// I64Xor + I64Const + I64RotL
9997
// Commonly used by a few crypto libraries

examples/rust/build.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ exclude_wat=("tinywasm")
66
out_dir="./target/wasm32-unknown-unknown/wasm"
77
dest_dir="out"
88

9-
features="+reference-types,+bulk-memory,+mutable-globals,+multivalue"
9+
features="+reference-types,+bulk-memory,+mutable-globals"
1010

1111
# ensure out dir exists
1212
mkdir -p "$dest_dir"
@@ -15,7 +15,7 @@ for bin in "${bins[@]}"; do
1515
RUSTFLAGS="-C target-feature=$features -C panic=abort" cargo build --target wasm32-unknown-unknown --package rust-wasm-examples --profile=wasm --bin "$bin"
1616

1717
cp "$out_dir/$bin.wasm" "$dest_dir/"
18-
wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wasm" -Oz --enable-bulk-memory --enable-multivalue --enable-reference-types --enable-mutable-globals
18+
wasm-opt "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wasm" -Oz --enable-bulk-memory --enable-reference-types --enable-mutable-globals
1919

2020
if [[ ! " ${exclude_wat[@]} " =~ " $bin " ]]; then
2121
wasm2wat "$dest_dir/$bin.wasm" -o "$dest_dir/$bin.wat"

0 commit comments

Comments
 (0)