mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Get rid of unneeded local.set/get in common cases
This commit is contained in:
parent
d6bba482ee
commit
af823fe5a8
2 changed files with 86 additions and 62 deletions
|
@ -265,8 +265,14 @@ impl<'a> WasmBackend<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Load a symbol, e.g. for passing to a function call
|
||||
fn load_symbol(&mut self, sym: &Symbol) {
|
||||
/// Load symbols to the top of the VM stack
|
||||
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();
|
||||
match storage {
|
||||
SymbolStorage::VirtualMachineStack {
|
||||
|
@ -310,6 +316,7 @@ impl<'a> WasmBackend<'a> {
|
|||
..
|
||||
} => {
|
||||
self.instructions.push(GetLocal(local_id.0));
|
||||
self.instructions.set_top_symbol(*sym);
|
||||
}
|
||||
|
||||
SymbolStorage::StackMemory {
|
||||
|
@ -321,6 +328,8 @@ impl<'a> WasmBackend<'a> {
|
|||
I32Const(offset as i32),
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -541,9 +550,7 @@ impl<'a> WasmBackend<'a> {
|
|||
arguments,
|
||||
}) => match call_type {
|
||||
CallType::ByName { name: func_sym, .. } => {
|
||||
for arg in *arguments {
|
||||
self.load_symbol(arg);
|
||||
}
|
||||
self.load_symbols(*arguments);
|
||||
let function_location = self.proc_symbol_map.get(func_sym).ok_or(format!(
|
||||
"Cannot find function {:?} called from {:?}",
|
||||
func_sym, sym
|
||||
|
@ -691,7 +698,7 @@ impl<'a> WasmBackend<'a> {
|
|||
}
|
||||
};
|
||||
self.instructions.push(GetLocal(to_ptr.0));
|
||||
self.load_symbol(&from_symbol);
|
||||
self.load_symbols(&[from_symbol]);
|
||||
self.instructions.push(store_instruction);
|
||||
size
|
||||
}
|
||||
|
@ -704,9 +711,7 @@ impl<'a> WasmBackend<'a> {
|
|||
args: &'a [Symbol],
|
||||
return_layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
for arg in args {
|
||||
self.load_symbol(arg);
|
||||
}
|
||||
self.load_symbols(args);
|
||||
let wasm_layout = WasmLayout::new(return_layout);
|
||||
self.build_instructions_lowlevel(lowlevel, wasm_layout.value_type())?;
|
||||
Ok(())
|
||||
|
@ -723,7 +728,6 @@ impl<'a> WasmBackend<'a> {
|
|||
// 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.
|
||||
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 {
|
||||
ValueType::I32 => &[I32Add],
|
||||
ValueType::I64 => &[I64Add],
|
||||
|
|
|
@ -133,6 +133,26 @@ impl CodeBuilder {
|
|||
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(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue