From 610b66e4cbe1405ae130d04c5c730dab4da8fbdd Mon Sep 17 00:00:00 2001 From: Rerumu Date: Wed, 17 Nov 2021 23:48:47 -0500 Subject: [PATCH] Refactor and optimize memory access --- src/backend/mod.rs | 1 + src/backend/translator/level_1.rs | 26 +-- src/backend/translator/level_2.rs | 50 +++--- src/backend/visitor/memory.rs | 45 +++++ src/backend/visitor/mod.rs | 2 + src/backend/visitor/register.rs | 280 ++++++++++++++++++++++++++++++ 6 files changed, 368 insertions(+), 36 deletions(-) create mode 100644 src/backend/visitor/memory.rs create mode 100644 src/backend/visitor/mod.rs create mode 100644 src/backend/visitor/register.rs diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 105bf43..5725e11 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,3 +1,4 @@ pub mod edition; pub mod helper; pub mod translator; +pub mod visitor; diff --git a/src/backend/translator/level_1.rs b/src/backend/translator/level_1.rs index 7c6d770..689d848 100644 --- a/src/backend/translator/level_1.rs +++ b/src/backend/translator/level_1.rs @@ -47,24 +47,24 @@ pub struct Body<'a> { } impl<'a> Body<'a> { - pub fn new(spec: &'a dyn Edition) -> Self { + pub fn new(spec: &'a dyn Edition, base: u32) -> Self { + let mut reg = Register::new(); + + reg.push(base); + Self { spec, + reg, label_list: vec![], table_list: Vec::new(), - reg: Register::new(), } } - pub fn gen(&mut self, index: usize, module: &Module) -> Result> { - let mut w = Vec::new(); - - module.code[index] + pub fn generate(&mut self, index: usize, m: &Module, w: Writer) -> Result<()> { + m.code[index] .inst_list .iter() - .try_for_each(|v| self.gen_inst(index, v, module, &mut w))?; - - Ok(w) + .try_for_each(|v| self.gen_inst(index, v, m, w)) } fn gen_jump(&mut self, up: u32, w: Writer) -> Result<()> { @@ -107,14 +107,14 @@ impl<'a> Body<'a> { self.reg.push(1); - write!(w, "{0} = load.{1}(MEMORY_LIST[0], {0} + {2}) ", reg, t, o) + write!(w, "{0} = load.{1}(memory_at_0, {0} + {2}) ", reg, t, o) } fn gen_store(&mut self, t: &str, o: u32, f: &Code, w: Writer) -> Result<()> { let val = f.var_name_of(self.reg.pop(1)); let reg = f.var_name_of(self.reg.pop(1)); - write!(w, "store.{}(MEMORY_LIST[0], {} + {}, {}) ", t, reg, o, val) + write!(w, "store.{}(memory_at_0, {} + {}, {}) ", t, reg, o, val) } fn gen_const(&mut self, val: T, f: &Code, w: Writer) -> Result<()> { @@ -342,14 +342,14 @@ impl<'a> Body<'a> { Instruction::CurrentMemory(index) => { let reg = func.var_name_of(self.reg.push(1)); - write!(w, "{} = rt.memory.size(MEMORY_LIST[{}])", reg, index) + write!(w, "{} = rt.memory.size(memory_at_{})", reg, index) } Instruction::GrowMemory(index) => { let reg = func.var_name_of(self.reg.pop(1)); self.reg.push(1); - write!(w, "{0} = rt.memory.grow(MEMORY_LIST[{1}], {0})", reg, index) + write!(w, "{0} = rt.memory.grow(memory_at_{1}, {0})", reg, index) } Instruction::I32Const(v) => self.gen_const(v, func, w), Instruction::I64Const(v) => self.gen_const(self.spec.i64(*v), func, w), diff --git a/src/backend/translator/level_2.rs b/src/backend/translator/level_2.rs index 3d8ad87..0416b79 100644 --- a/src/backend/translator/level_2.rs +++ b/src/backend/translator/level_2.rs @@ -1,4 +1,4 @@ -use std::io::{Result, Write}; +use std::{collections::BTreeSet, io::Result}; use parity_wasm::elements::Instruction; @@ -6,6 +6,7 @@ use crate::{ backend::{ edition::data::Edition, helper::writer::{write_ordered, Writer}, + visitor::{memory::visit_for_memory, register::visit_for_register}, }, data::Module, }; @@ -27,49 +28,52 @@ pub fn gen_init_expression(code: &[Instruction], w: Writer) -> Result<()> { } } -fn gen_prelude(num_param: u32, num_local: u32) -> Result> { - let mut w = Vec::new(); +fn gen_prelude(num_stack: u32, num_param: u32, num_local: u32, w: Writer) -> Result<()> { + let num_reg = num_stack - num_param - num_local; write!(w, "function(")?; - write_ordered("param", num_param, &mut w)?; + write_ordered("param", num_param, w)?; write!(w, ")")?; if num_local != 0 { let zero = vec!["0"; num_local as usize].join(", "); write!(w, "local ")?; - write_ordered("var", num_local, &mut w)?; + write_ordered("var", num_local, w)?; write!(w, "= {} ", zero)?; } - Ok(w) -} - -fn gen_reg_list(last: u32, num_param: u32, num_local: u32) -> Result> { - let mut w = Vec::new(); - let num = last - num_local - num_param; - - if num != 0 { + if num_reg != 0 { write!(w, "local ")?; - write_ordered("reg", num, &mut w)?; + write_ordered("reg", num_reg, w)?; write!(w, " ")?; } - Ok(w) + Ok(()) +} + +fn gen_memory(set: BTreeSet, w: Writer) -> Result<()> { + set.into_iter() + .try_for_each(|i| write!(w, "local memory_at_{0} = MEMORY_LIST[{0}]", i)) } pub fn gen_function(spec: &dyn Edition, index: usize, m: &Module, w: Writer) -> Result<()> { - let mut inner = Body::new(spec); + let mem_set = visit_for_memory(m, index); + let num_stack = visit_for_register(m, index); + let num_param = m.in_arity[index].num_param; let num_local = m.code[index].num_local; - inner.reg.push(num_param + num_local); + let mut inner = Body::new(spec, num_param + num_local); - let prelude = gen_prelude(num_param, num_local)?; - let body = inner.gen(index, m)?; - let reg = gen_reg_list(inner.reg.last, num_param, num_local)?; + gen_prelude(num_stack, num_param, num_local, w)?; + gen_memory(mem_set, w)?; + inner.generate(index, m, w)?; - w.write_all(&prelude)?; - w.write_all(®)?; - w.write_all(&body) + assert!( + inner.reg.last == num_stack, + "Mismatched register allocation" + ); + + Ok(()) } diff --git a/src/backend/visitor/memory.rs b/src/backend/visitor/memory.rs new file mode 100644 index 0000000..c41c1a9 --- /dev/null +++ b/src/backend/visitor/memory.rs @@ -0,0 +1,45 @@ +use std::collections::BTreeSet; + +use parity_wasm::elements::Instruction; + +use crate::data::Module; + +pub fn visit_for_memory(m: &Module, index: usize) -> BTreeSet { + let mut result = BTreeSet::new(); + + for i in m.code[index].inst_list { + match i { + Instruction::I32Store(_, _) + | Instruction::I64Store(_, _) + | Instruction::F32Store(_, _) + | Instruction::F64Store(_, _) + | Instruction::I32Store8(_, _) + | Instruction::I32Store16(_, _) + | Instruction::I64Store8(_, _) + | Instruction::I64Store16(_, _) + | Instruction::I64Store32(_, _) + | Instruction::I32Load(_, _) + | Instruction::I64Load(_, _) + | Instruction::F32Load(_, _) + | Instruction::F64Load(_, _) + | Instruction::I32Load8S(_, _) + | Instruction::I32Load8U(_, _) + | Instruction::I32Load16S(_, _) + | Instruction::I32Load16U(_, _) + | Instruction::I64Load8S(_, _) + | Instruction::I64Load8U(_, _) + | Instruction::I64Load16S(_, _) + | Instruction::I64Load16U(_, _) + | Instruction::I64Load32S(_, _) + | Instruction::I64Load32U(_, _) => { + result.insert(0); + } + Instruction::CurrentMemory(index) | Instruction::GrowMemory(index) => { + result.insert(*index); + } + _ => {} + } + } + + result +} diff --git a/src/backend/visitor/mod.rs b/src/backend/visitor/mod.rs new file mode 100644 index 0000000..fcd3026 --- /dev/null +++ b/src/backend/visitor/mod.rs @@ -0,0 +1,2 @@ +pub mod memory; +pub mod register; diff --git a/src/backend/visitor/register.rs b/src/backend/visitor/register.rs new file mode 100644 index 0000000..7b12c82 --- /dev/null +++ b/src/backend/visitor/register.rs @@ -0,0 +1,280 @@ +use parity_wasm::elements::Instruction; + +use crate::{ + backend::helper::register::Register, + data::{Arity, Module}, +}; + +pub fn visit_for_register(m: &Module, index: usize) -> u32 { + let mut reg = Register::new(); + let num_param = m.in_arity[index].num_param; + let num_local = m.code[index].num_local; + + reg.push(num_param + num_local); + + for i in m.code[index].inst_list { + match i { + Instruction::Block(_) | Instruction::Loop(_) => { + reg.save(); + } + Instruction::If(_) => { + reg.pop(1); + reg.save(); + } + Instruction::Else => { + reg.load(); + reg.save(); + } + Instruction::End => { + reg.load(); + } + Instruction::BrIf(_) | Instruction::BrTable(_) => { + reg.pop(1); + } + Instruction::Call(i) => { + let arity = m.arity_of(*i as usize); + + reg.pop(arity.num_param); + reg.push(arity.num_result); + } + Instruction::CallIndirect(i, _) => { + let types = m.parent.type_section().unwrap().types(); + let arity = Arity::from_index(types, *i); + + reg.pop(arity.num_param + 1); + reg.push(arity.num_result); + } + Instruction::Drop => { + reg.pop(1); + } + Instruction::Select => { + reg.pop(3); + reg.push(1); + } + Instruction::GetLocal(_) => { + reg.push(1); + } + Instruction::SetLocal(_) => { + reg.pop(1); + } + Instruction::TeeLocal(_) => { + reg.pop(1); + reg.push(1); + } + Instruction::GetGlobal(_) => { + reg.push(1); + } + Instruction::SetGlobal(_) => { + reg.pop(1); + } + Instruction::I32Load(_, _) + | Instruction::I64Load(_, _) + | Instruction::F32Load(_, _) + | Instruction::F64Load(_, _) + | Instruction::I32Load8S(_, _) + | Instruction::I32Load8U(_, _) + | Instruction::I32Load16S(_, _) + | Instruction::I32Load16U(_, _) + | Instruction::I64Load8S(_, _) + | Instruction::I64Load8U(_, _) + | Instruction::I64Load16S(_, _) + | Instruction::I64Load16U(_, _) + | Instruction::I64Load32S(_, _) + | Instruction::I64Load32U(_, _) => { + reg.pop(1); + reg.push(1); + } + Instruction::I32Store(_, _) + | Instruction::I64Store(_, _) + | Instruction::F32Store(_, _) + | Instruction::F64Store(_, _) + | Instruction::I32Store8(_, _) + | Instruction::I32Store16(_, _) + | Instruction::I64Store8(_, _) + | Instruction::I64Store16(_, _) + | Instruction::I64Store32(_, _) => { + reg.pop(2); + } + Instruction::CurrentMemory(_) => { + reg.push(1); + } + Instruction::GrowMemory(_) => { + reg.pop(1); + reg.push(1); + } + Instruction::I32Const(_) + | Instruction::I64Const(_) + | Instruction::F32Const(_) + | Instruction::F64Const(_) => { + reg.push(1); + } + Instruction::I32Eqz => { + reg.pop(1); + reg.push(1); + } + Instruction::I32Eq + | Instruction::I32Ne + | Instruction::I32LtS + | Instruction::I32LtU + | Instruction::I32GtS + | Instruction::I32GtU + | Instruction::I32LeS + | Instruction::I32LeU + | Instruction::I32GeS + | Instruction::I32GeU => { + reg.pop(2); + reg.push(1); + } + Instruction::I64Eqz => { + reg.pop(1); + reg.push(1); + } + Instruction::I64Eq + | Instruction::I64Ne + | Instruction::I64LtS + | Instruction::I64LtU + | Instruction::I64GtS + | Instruction::I64GtU + | Instruction::I64LeS + | Instruction::I64LeU + | Instruction::I64GeS + | Instruction::I64GeU + | Instruction::F32Eq + | Instruction::F32Ne + | Instruction::F32Lt + | Instruction::F32Gt + | Instruction::F32Le + | Instruction::F32Ge + | Instruction::F64Eq + | Instruction::F64Ne + | Instruction::F64Lt + | Instruction::F64Gt + | Instruction::F64Le + | Instruction::F64Ge => { + reg.pop(2); + reg.push(1); + } + Instruction::I32Clz | Instruction::I32Ctz | Instruction::I32Popcnt => { + reg.pop(1); + reg.push(1); + } + Instruction::I32Add + | Instruction::I32Sub + | Instruction::I32Mul + | Instruction::I32DivS + | Instruction::I32DivU + | Instruction::I32RemS + | Instruction::I32RemU + | Instruction::I32And + | Instruction::I32Or + | Instruction::I32Xor + | Instruction::I32Shl + | Instruction::I32ShrS + | Instruction::I32ShrU + | Instruction::I32Rotl + | Instruction::I32Rotr => { + reg.pop(2); + reg.push(1); + } + Instruction::I64Clz | Instruction::I64Ctz | Instruction::I64Popcnt => { + reg.pop(1); + reg.push(1); + } + Instruction::I64Add + | Instruction::I64Sub + | Instruction::I64Mul + | Instruction::I64DivS + | Instruction::I64DivU + | Instruction::I64RemS + | Instruction::I64RemU + | Instruction::I64And + | Instruction::I64Or + | Instruction::I64Xor + | Instruction::I64Shl + | Instruction::I64ShrS + | Instruction::I64ShrU + | Instruction::I64Rotl + | Instruction::I64Rotr => { + reg.pop(2); + reg.push(1); + } + Instruction::F32Abs + | Instruction::F32Neg + | Instruction::F32Ceil + | Instruction::F32Floor + | Instruction::F32Trunc + | Instruction::F32Nearest + | Instruction::F32Sqrt => { + reg.pop(1); + reg.push(1); + } + Instruction::F32Add + | Instruction::F32Sub + | Instruction::F32Mul + | Instruction::F32Div + | Instruction::F32Min + | Instruction::F32Max => { + reg.pop(2); + reg.push(1); + } + Instruction::F32Copysign => { + reg.pop(1); + reg.push(1); + } + Instruction::F64Abs + | Instruction::F64Neg + | Instruction::F64Ceil + | Instruction::F64Floor + | Instruction::F64Trunc + | Instruction::F64Nearest + | Instruction::F64Sqrt => { + reg.pop(1); + reg.push(1); + } + Instruction::F64Add + | Instruction::F64Sub + | Instruction::F64Mul + | Instruction::F64Div + | Instruction::F64Min + | Instruction::F64Max => { + reg.pop(2); + reg.push(1); + } + Instruction::F64Copysign => { + reg.pop(1); + reg.push(1); + } + Instruction::I32WrapI64 + | Instruction::I32TruncSF32 + | Instruction::I32TruncUF32 + | Instruction::I32TruncSF64 + | Instruction::I32TruncUF64 + | Instruction::I64ExtendSI32 + | Instruction::I64ExtendUI32 + | Instruction::I64TruncSF32 + | Instruction::I64TruncUF32 + | Instruction::I64TruncSF64 + | Instruction::I64TruncUF64 + | Instruction::F32ConvertSI32 + | Instruction::F32ConvertUI32 + | Instruction::F32ConvertSI64 + | Instruction::F32ConvertUI64 + | Instruction::F32DemoteF64 + | Instruction::F64ConvertSI32 + | Instruction::F64ConvertUI32 + | Instruction::F64ConvertSI64 + | Instruction::F64ConvertUI64 + | Instruction::F64PromoteF32 + | Instruction::I32ReinterpretF32 + | Instruction::I64ReinterpretF64 + | Instruction::F32ReinterpretI32 + | Instruction::F64ReinterpretI64 => { + reg.pop(1); + reg.push(1); + } + _ => {} + } + } + + reg.last +}