Refactor and optimize memory access

This commit is contained in:
Rerumu 2021-11-17 23:48:47 -05:00
parent f759443802
commit 610b66e4cb
6 changed files with 368 additions and 36 deletions

View File

@ -1,3 +1,4 @@
pub mod edition; pub mod edition;
pub mod helper; pub mod helper;
pub mod translator; pub mod translator;
pub mod visitor;

View File

@ -47,24 +47,24 @@ pub struct Body<'a> {
} }
impl<'a> 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 { Self {
spec, spec,
reg,
label_list: vec![], label_list: vec![],
table_list: Vec::new(), table_list: Vec::new(),
reg: Register::new(),
} }
} }
pub fn gen(&mut self, index: usize, module: &Module) -> Result<Vec<u8>> { pub fn generate(&mut self, index: usize, m: &Module, w: Writer) -> Result<()> {
let mut w = Vec::new(); m.code[index]
module.code[index]
.inst_list .inst_list
.iter() .iter()
.try_for_each(|v| self.gen_inst(index, v, module, &mut w))?; .try_for_each(|v| self.gen_inst(index, v, m, w))
Ok(w)
} }
fn gen_jump(&mut self, up: u32, w: Writer) -> Result<()> { fn gen_jump(&mut self, up: u32, w: Writer) -> Result<()> {
@ -107,14 +107,14 @@ impl<'a> Body<'a> {
self.reg.push(1); 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<()> { 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 val = f.var_name_of(self.reg.pop(1));
let reg = 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<T: Display>(&mut self, val: T, f: &Code, w: Writer) -> Result<()> { fn gen_const<T: Display>(&mut self, val: T, f: &Code, w: Writer) -> Result<()> {
@ -342,14 +342,14 @@ impl<'a> Body<'a> {
Instruction::CurrentMemory(index) => { Instruction::CurrentMemory(index) => {
let reg = func.var_name_of(self.reg.push(1)); 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) => { Instruction::GrowMemory(index) => {
let reg = func.var_name_of(self.reg.pop(1)); let reg = func.var_name_of(self.reg.pop(1));
self.reg.push(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::I32Const(v) => self.gen_const(v, func, w),
Instruction::I64Const(v) => self.gen_const(self.spec.i64(*v), func, w), Instruction::I64Const(v) => self.gen_const(self.spec.i64(*v), func, w),

View File

@ -1,4 +1,4 @@
use std::io::{Result, Write}; use std::{collections::BTreeSet, io::Result};
use parity_wasm::elements::Instruction; use parity_wasm::elements::Instruction;
@ -6,6 +6,7 @@ use crate::{
backend::{ backend::{
edition::data::Edition, edition::data::Edition,
helper::writer::{write_ordered, Writer}, helper::writer::{write_ordered, Writer},
visitor::{memory::visit_for_memory, register::visit_for_register},
}, },
data::Module, 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<Vec<u8>> { fn gen_prelude(num_stack: u32, num_param: u32, num_local: u32, w: Writer) -> Result<()> {
let mut w = Vec::new(); let num_reg = num_stack - num_param - num_local;
write!(w, "function(")?; write!(w, "function(")?;
write_ordered("param", num_param, &mut w)?; write_ordered("param", num_param, w)?;
write!(w, ")")?; write!(w, ")")?;
if num_local != 0 { if num_local != 0 {
let zero = vec!["0"; num_local as usize].join(", "); let zero = vec!["0"; num_local as usize].join(", ");
write!(w, "local ")?; write!(w, "local ")?;
write_ordered("var", num_local, &mut w)?; write_ordered("var", num_local, w)?;
write!(w, "= {} ", zero)?; write!(w, "= {} ", zero)?;
} }
Ok(w) if num_reg != 0 {
}
fn gen_reg_list(last: u32, num_param: u32, num_local: u32) -> Result<Vec<u8>> {
let mut w = Vec::new();
let num = last - num_local - num_param;
if num != 0 {
write!(w, "local ")?; write!(w, "local ")?;
write_ordered("reg", num, &mut w)?; write_ordered("reg", num_reg, w)?;
write!(w, " ")?; write!(w, " ")?;
} }
Ok(w) Ok(())
}
fn gen_memory(set: BTreeSet<u8>, 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<()> { 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_param = m.in_arity[index].num_param;
let num_local = m.code[index].num_local; 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)?; gen_prelude(num_stack, num_param, num_local, w)?;
let body = inner.gen(index, m)?; gen_memory(mem_set, w)?;
let reg = gen_reg_list(inner.reg.last, num_param, num_local)?; inner.generate(index, m, w)?;
w.write_all(&prelude)?; assert!(
w.write_all(&reg)?; inner.reg.last == num_stack,
w.write_all(&body) "Mismatched register allocation"
);
Ok(())
} }

View File

@ -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<u8> {
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
}

View File

@ -0,0 +1,2 @@
pub mod memory;
pub mod register;

View File

@ -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
}