Get rid of unneeded local.set/get in common cases

This commit is contained in:
Brian Carroll 2021-10-06 20:07:20 +01:00
parent d6bba482ee
commit af823fe5a8
2 changed files with 86 additions and 62 deletions

View file

@ -265,8 +265,14 @@ impl<'a> WasmBackend<'a> {
} }
} }
/// Load a symbol, e.g. for passing to a function call /// Load symbols to the top of the VM stack
fn load_symbol(&mut self, sym: &Symbol) { fn load_symbols(&mut self, symbols: &[Symbol]) {
if self.instructions.verify_stack_match(symbols) {
// The symbols were already at the top of the stack, do nothing!
// This should be quite common due to the structure of the Mono IR
return;
}
for sym in symbols.iter() {
let storage = self.get_symbol_storage(sym).to_owned(); let storage = self.get_symbol_storage(sym).to_owned();
match storage { match storage {
SymbolStorage::VirtualMachineStack { SymbolStorage::VirtualMachineStack {
@ -310,6 +316,7 @@ impl<'a> WasmBackend<'a> {
.. ..
} => { } => {
self.instructions.push(GetLocal(local_id.0)); self.instructions.push(GetLocal(local_id.0));
self.instructions.set_top_symbol(*sym);
} }
SymbolStorage::StackMemory { SymbolStorage::StackMemory {
@ -321,6 +328,8 @@ impl<'a> WasmBackend<'a> {
I32Const(offset as i32), I32Const(offset as i32),
I32Add, I32Add,
]); ]);
self.instructions.set_top_symbol(*sym);
}
} }
} }
} }
@ -415,7 +424,7 @@ impl<'a> WasmBackend<'a> {
} }
_ => { _ => {
self.load_symbol(sym); self.load_symbols(&[*sym]);
self.instructions.push(Br(self.block_depth)); // jump to end of function (for stack frame pop) self.instructions.push(Br(self.block_depth)); // jump to end of function (for stack frame pop)
} }
} }
@ -541,9 +550,7 @@ impl<'a> WasmBackend<'a> {
arguments, arguments,
}) => match call_type { }) => match call_type {
CallType::ByName { name: func_sym, .. } => { CallType::ByName { name: func_sym, .. } => {
for arg in *arguments { self.load_symbols(*arguments);
self.load_symbol(arg);
}
let function_location = self.proc_symbol_map.get(func_sym).ok_or(format!( let function_location = self.proc_symbol_map.get(func_sym).ok_or(format!(
"Cannot find function {:?} called from {:?}", "Cannot find function {:?} called from {:?}",
func_sym, sym func_sym, sym
@ -691,7 +698,7 @@ impl<'a> WasmBackend<'a> {
} }
}; };
self.instructions.push(GetLocal(to_ptr.0)); self.instructions.push(GetLocal(to_ptr.0));
self.load_symbol(&from_symbol); self.load_symbols(&[from_symbol]);
self.instructions.push(store_instruction); self.instructions.push(store_instruction);
size size
} }
@ -704,9 +711,7 @@ impl<'a> WasmBackend<'a> {
args: &'a [Symbol], args: &'a [Symbol],
return_layout: &Layout<'a>, return_layout: &Layout<'a>,
) -> Result<(), String> { ) -> Result<(), String> {
for arg in args { self.load_symbols(args);
self.load_symbol(arg);
}
let wasm_layout = WasmLayout::new(return_layout); let wasm_layout = WasmLayout::new(return_layout);
self.build_instructions_lowlevel(lowlevel, wasm_layout.value_type())?; self.build_instructions_lowlevel(lowlevel, wasm_layout.value_type())?;
Ok(()) Ok(())
@ -723,7 +728,6 @@ impl<'a> WasmBackend<'a> {
// For those, we'll need to pre-process each argument before the main op, // For those, we'll need to pre-process each argument before the main op,
// so simple arrays of instructions won't work. But there are common patterns. // so simple arrays of instructions won't work. But there are common patterns.
let instructions: &[Instruction] = match lowlevel { let instructions: &[Instruction] = match lowlevel {
// Wasm type might not be enough, may need to sign-extend i8 etc. Maybe in load_symbol?
LowLevel::NumAdd => match return_value_type { LowLevel::NumAdd => match return_value_type {
ValueType::I32 => &[I32Add], ValueType::I32 => &[I32Add],
ValueType::I64 => &[I64Add], ValueType::I64 => &[I64Add],

View file

@ -133,6 +133,26 @@ impl CodeBuilder {
VirtualMachineSymbolState::Pushed { pushed_at } VirtualMachineSymbolState::Pushed { pushed_at }
} }
/// Verify if a sequence of symbols is at the top of the stack
pub fn verify_stack_match(&self, symbols: &[Symbol]) -> bool {
let n_symbols = symbols.len();
let stack_depth = self.vm_stack.len();
if n_symbols > stack_depth {
return false;
}
let offset = stack_depth - n_symbols;
for (i, sym) in symbols.iter().enumerate() {
match self.vm_stack[offset + i] {
Some(stack_symbol) if stack_symbol == *sym => {}
_ => {
return false;
}
}
}
true
}
pub fn load_symbol( pub fn load_symbol(
&mut self, &mut self,
symbol: Symbol, symbol: Symbol,