mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +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,62 +265,71 @@ 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]) {
|
||||||
let storage = self.get_symbol_storage(sym).to_owned();
|
if self.instructions.verify_stack_match(symbols) {
|
||||||
match storage {
|
// The symbols were already at the top of the stack, do nothing!
|
||||||
SymbolStorage::VirtualMachineStack {
|
// This should be quite common due to the structure of the Mono IR
|
||||||
vm_state,
|
return;
|
||||||
value_type,
|
}
|
||||||
size,
|
for sym in symbols.iter() {
|
||||||
} => {
|
let storage = self.get_symbol_storage(sym).to_owned();
|
||||||
let next_local_id = self.get_next_local_id();
|
match storage {
|
||||||
let maybe_next_vm_state =
|
SymbolStorage::VirtualMachineStack {
|
||||||
self.instructions.load_symbol(*sym, vm_state, next_local_id);
|
vm_state,
|
||||||
match maybe_next_vm_state {
|
value_type,
|
||||||
// The act of loading the value changed the VM state, so update it
|
size,
|
||||||
Some(next_vm_state) => {
|
} => {
|
||||||
self.symbol_storage_map.insert(
|
let next_local_id = self.get_next_local_id();
|
||||||
*sym,
|
let maybe_next_vm_state =
|
||||||
SymbolStorage::VirtualMachineStack {
|
self.instructions.load_symbol(*sym, vm_state, next_local_id);
|
||||||
vm_state: next_vm_state,
|
match maybe_next_vm_state {
|
||||||
value_type,
|
// The act of loading the value changed the VM state, so update it
|
||||||
size,
|
Some(next_vm_state) => {
|
||||||
},
|
self.symbol_storage_map.insert(
|
||||||
);
|
*sym,
|
||||||
}
|
SymbolStorage::VirtualMachineStack {
|
||||||
None => {
|
vm_state: next_vm_state,
|
||||||
// Loading the value required creating a new local, because
|
value_type,
|
||||||
// it was not in a convenient position in the VM stack.
|
size,
|
||||||
self.locals.push(Local::new(1, value_type));
|
},
|
||||||
self.symbol_storage_map.insert(
|
);
|
||||||
*sym,
|
}
|
||||||
SymbolStorage::Local {
|
None => {
|
||||||
local_id: next_local_id,
|
// Loading the value required creating a new local, because
|
||||||
value_type,
|
// it was not in a convenient position in the VM stack.
|
||||||
size,
|
self.locals.push(Local::new(1, value_type));
|
||||||
},
|
self.symbol_storage_map.insert(
|
||||||
);
|
*sym,
|
||||||
|
SymbolStorage::Local {
|
||||||
|
local_id: next_local_id,
|
||||||
|
value_type,
|
||||||
|
size,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
SymbolStorage::Local { local_id, .. }
|
||||||
SymbolStorage::Local { local_id, .. }
|
| SymbolStorage::StackMemory {
|
||||||
| SymbolStorage::StackMemory {
|
location: StackMemoryLocation::PointerArg(local_id),
|
||||||
location: StackMemoryLocation::PointerArg(local_id),
|
..
|
||||||
..
|
} => {
|
||||||
} => {
|
self.instructions.push(GetLocal(local_id.0));
|
||||||
self.instructions.push(GetLocal(local_id.0));
|
self.instructions.set_top_symbol(*sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolStorage::StackMemory {
|
SymbolStorage::StackMemory {
|
||||||
location: StackMemoryLocation::FrameOffset(offset),
|
location: StackMemoryLocation::FrameOffset(offset),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
self.instructions.extend(&[
|
self.instructions.extend(&[
|
||||||
GetLocal(self.stack_frame_pointer.unwrap().0),
|
GetLocal(self.stack_frame_pointer.unwrap().0),
|
||||||
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],
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue