mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
Refactor SymbolStorage local_id code, and copy_memory
SymbolStorage had some rather ad-hoc methods for extracting pieces of data. This change makes that more intentional and organised. Also cleaned up the API for the related function copy_memory, as it had lots of positional arguments with the same types. Created a struct for this just to name them and make the code clearer.
This commit is contained in:
parent
6aed70978d
commit
79a4f2bbf7
3 changed files with 217 additions and 183 deletions
|
@ -13,8 +13,8 @@ use roc_mono::layout::{Builtin, Layout};
|
|||
use crate::layout::WasmLayout;
|
||||
use crate::storage::{StackMemoryLocation, SymbolStorage};
|
||||
use crate::{
|
||||
pop_stack_frame, push_stack_frame, round_up_to_alignment, LocalId, MemoryCopy, PTR_SIZE,
|
||||
PTR_TYPE,
|
||||
copy_memory, pop_stack_frame, push_stack_frame, round_up_to_alignment, CopyMemoryConfig,
|
||||
LocalId, PTR_SIZE, PTR_TYPE,
|
||||
};
|
||||
|
||||
// Don't allocate any constant data at address zero or near it. Would be valid, but bug-prone.
|
||||
|
@ -164,7 +164,7 @@ impl<'a> WasmBackend<'a> {
|
|||
wasm_layout: WasmLayout,
|
||||
symbol: Symbol,
|
||||
kind: LocalKind,
|
||||
) -> SymbolStorage {
|
||||
) -> Option<LocalId> {
|
||||
let next_local_id = LocalId((self.arg_types.len() + self.locals.len()) as u32);
|
||||
|
||||
match kind {
|
||||
|
@ -176,32 +176,33 @@ impl<'a> WasmBackend<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
let storage = match wasm_layout {
|
||||
WasmLayout::LocalOnly(value_type, size) => SymbolStorage::Local {
|
||||
local_id: next_local_id,
|
||||
value_type,
|
||||
size,
|
||||
},
|
||||
let (maybe_local_id, storage) = match wasm_layout {
|
||||
WasmLayout::LocalOnly(value_type, size) => (
|
||||
Some(next_local_id),
|
||||
SymbolStorage::Local {
|
||||
local_id: next_local_id,
|
||||
value_type,
|
||||
size,
|
||||
},
|
||||
),
|
||||
|
||||
WasmLayout::HeapMemory => SymbolStorage::Local {
|
||||
local_id: next_local_id,
|
||||
value_type: PTR_TYPE,
|
||||
size: PTR_SIZE,
|
||||
},
|
||||
WasmLayout::HeapMemory => (
|
||||
Some(next_local_id),
|
||||
SymbolStorage::Local {
|
||||
local_id: next_local_id,
|
||||
value_type: PTR_TYPE,
|
||||
size: PTR_SIZE,
|
||||
},
|
||||
),
|
||||
|
||||
WasmLayout::StackMemory {
|
||||
size,
|
||||
alignment_bytes,
|
||||
} => {
|
||||
let location = match kind {
|
||||
LocalKind::Parameter => StackMemoryLocation::ExternalPointer(next_local_id),
|
||||
LocalKind::Parameter => StackMemoryLocation::CallerFrame(next_local_id),
|
||||
|
||||
LocalKind::Variable => {
|
||||
let offset =
|
||||
round_up_to_alignment(self.stack_memory, alignment_bytes as i32);
|
||||
|
||||
self.stack_memory = offset + size as i32;
|
||||
|
||||
match self.stack_frame_pointer {
|
||||
Some(_) => {}
|
||||
None => {
|
||||
|
@ -209,20 +210,29 @@ impl<'a> WasmBackend<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
StackMemoryLocation::InternalOffset(offset as u32)
|
||||
let offset =
|
||||
round_up_to_alignment(self.stack_memory, alignment_bytes as i32);
|
||||
|
||||
self.stack_memory = offset + size as i32;
|
||||
|
||||
StackMemoryLocation::OwnFrame(offset as u32)
|
||||
}
|
||||
};
|
||||
SymbolStorage::StackMemory {
|
||||
location,
|
||||
size,
|
||||
alignment_bytes,
|
||||
}
|
||||
|
||||
(
|
||||
None,
|
||||
SymbolStorage::StackMemory {
|
||||
location,
|
||||
size,
|
||||
alignment_bytes,
|
||||
},
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
self.symbol_storage_map.insert(symbol, storage.clone());
|
||||
self.symbol_storage_map.insert(symbol, storage);
|
||||
|
||||
storage
|
||||
maybe_local_id
|
||||
}
|
||||
|
||||
fn get_symbol_storage(&self, sym: &Symbol) -> &SymbolStorage {
|
||||
|
@ -236,20 +246,42 @@ impl<'a> WasmBackend<'a> {
|
|||
|
||||
fn local_id_from_symbol(&self, sym: &Symbol) -> LocalId {
|
||||
let storage = self.get_symbol_storage(sym);
|
||||
storage.local_id(self.stack_frame_pointer)
|
||||
match storage {
|
||||
SymbolStorage::Local { local_id, .. } => *local_id,
|
||||
_ => {
|
||||
panic!("{:?} does not have a local_id", sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Load a symbol, e.g. for passing to a function call
|
||||
fn load_symbol(&mut self, sym: &Symbol) {
|
||||
let storage = self.get_symbol_storage(sym);
|
||||
let index: u32 = storage.local_id(self.stack_frame_pointer).0;
|
||||
self.instructions.push(GetLocal(index));
|
||||
let storage = self.get_symbol_storage(sym).to_owned();
|
||||
match storage {
|
||||
SymbolStorage::Local { local_id, .. }
|
||||
| SymbolStorage::StackMemory {
|
||||
location: StackMemoryLocation::CallerFrame(local_id),
|
||||
..
|
||||
} => {
|
||||
self.instructions.push(GetLocal(local_id.0));
|
||||
}
|
||||
|
||||
SymbolStorage::StackMemory {
|
||||
location: StackMemoryLocation::OwnFrame(offset),
|
||||
..
|
||||
} => {
|
||||
self.instructions.extend([
|
||||
GetLocal(self.stack_frame_pointer.unwrap().0),
|
||||
I32Const(offset as i32),
|
||||
I32Add,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// start a loop that leaves a value on the stack
|
||||
fn start_loop_with_return(&mut self, value_type: ValueType) {
|
||||
self.block_depth += 1;
|
||||
|
||||
// self.instructions.push(Loop(BlockType::NoResult));
|
||||
self.instructions.push(Loop(BlockType::Value(value_type)));
|
||||
}
|
||||
|
||||
|
@ -276,7 +308,7 @@ impl<'a> WasmBackend<'a> {
|
|||
// Map this symbol to the first argument (pointer into caller's stack)
|
||||
// Saves us from having to copy it later
|
||||
let storage = SymbolStorage::StackMemory {
|
||||
location: StackMemoryLocation::ExternalPointer(LocalId(0)),
|
||||
location: StackMemoryLocation::CallerFrame(LocalId(0)),
|
||||
size,
|
||||
alignment_bytes,
|
||||
};
|
||||
|
@ -289,16 +321,12 @@ impl<'a> WasmBackend<'a> {
|
|||
|
||||
Stmt::Let(sym, expr, layout, following) => {
|
||||
let wasm_layout = WasmLayout::new(layout);
|
||||
let local_id = self
|
||||
.insert_local(wasm_layout, *sym, LocalKind::Variable)
|
||||
.local_id(self.stack_frame_pointer);
|
||||
let maybe_local_id = self.insert_local(wasm_layout, *sym, LocalKind::Variable);
|
||||
|
||||
self.build_expr(sym, expr, layout)?;
|
||||
|
||||
// If this local is shared with the stack frame pointer, it's already assigned
|
||||
match self.stack_frame_pointer {
|
||||
Some(sfp) if sfp == local_id => {}
|
||||
_ => self.instructions.push(SetLocal(local_id.0)),
|
||||
if let Some(local_id) = maybe_local_id {
|
||||
self.instructions.push(SetLocal(local_id.0));
|
||||
}
|
||||
|
||||
self.build_stmt(following, ret_layout)?;
|
||||
|
@ -317,21 +345,23 @@ impl<'a> WasmBackend<'a> {
|
|||
alignment_bytes,
|
||||
} => {
|
||||
let (from_ptr, from_offset) = match location {
|
||||
StackMemoryLocation::ExternalPointer(local_id) => (*local_id, 0),
|
||||
StackMemoryLocation::InternalOffset(offset) => {
|
||||
StackMemoryLocation::CallerFrame(local_id) => (*local_id, 0),
|
||||
StackMemoryLocation::OwnFrame(offset) => {
|
||||
(self.stack_frame_pointer.unwrap(), *offset)
|
||||
}
|
||||
};
|
||||
|
||||
let copy = MemoryCopy {
|
||||
from_ptr,
|
||||
from_offset,
|
||||
to_ptr: LocalId(0),
|
||||
to_offset: 0,
|
||||
size: *size,
|
||||
alignment_bytes: *alignment_bytes,
|
||||
};
|
||||
copy.generate(&mut self.instructions);
|
||||
copy_memory(
|
||||
&mut self.instructions,
|
||||
CopyMemoryConfig {
|
||||
from_ptr,
|
||||
from_offset,
|
||||
to_ptr: LocalId(0),
|
||||
to_offset: 0,
|
||||
size: *size,
|
||||
alignment_bytes: *alignment_bytes,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Local { local_id, .. } => {
|
||||
|
@ -400,11 +430,10 @@ impl<'a> WasmBackend<'a> {
|
|||
let mut jp_parameter_local_ids = std::vec::Vec::with_capacity(parameters.len());
|
||||
for parameter in parameters.iter() {
|
||||
let wasm_layout = WasmLayout::new(¶meter.layout);
|
||||
let local_id = self
|
||||
.insert_local(wasm_layout, parameter.symbol, LocalKind::Variable)
|
||||
.local_id(self.stack_frame_pointer);
|
||||
|
||||
jp_parameter_local_ids.push(local_id);
|
||||
let maybe_local_id =
|
||||
self.insert_local(wasm_layout, parameter.symbol, LocalKind::Variable);
|
||||
let jp_param_id = maybe_local_id.unwrap();
|
||||
jp_parameter_local_ids.push(jp_param_id);
|
||||
}
|
||||
|
||||
self.start_block(BlockType::NoResult);
|
||||
|
@ -526,9 +555,22 @@ impl<'a> WasmBackend<'a> {
|
|||
let storage = self.get_symbol_storage(sym).to_owned();
|
||||
|
||||
if let Layout::Struct(field_layouts) = layout {
|
||||
let (local_id, size) = match storage {
|
||||
SymbolStorage::StackMemory { size, .. } => {
|
||||
(storage.local_id(self.stack_frame_pointer), size)
|
||||
match storage {
|
||||
SymbolStorage::StackMemory { location, size, .. } => {
|
||||
if size > 0 {
|
||||
let (local_id, struct_offset) =
|
||||
location.local_and_offset(self.stack_frame_pointer);
|
||||
let mut field_offset = struct_offset;
|
||||
for (field, _) in fields.iter().zip(field_layouts.iter()) {
|
||||
field_offset += self.copy_symbol_to_pointer_at_offset(
|
||||
local_id,
|
||||
field_offset,
|
||||
field,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return Err(format!("Not supported yet: zero-size struct at {:?}", sym));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(format!(
|
||||
|
@ -537,20 +579,14 @@ impl<'a> WasmBackend<'a> {
|
|||
));
|
||||
}
|
||||
};
|
||||
|
||||
if size > 0 {
|
||||
let mut relative_offset = 0;
|
||||
for (field, _) in fields.iter().zip(field_layouts.iter()) {
|
||||
relative_offset +=
|
||||
self.copy_symbol_to_pointer_at_offset(local_id, relative_offset, field);
|
||||
}
|
||||
} else {
|
||||
return Err(format!("Not supported yet: zero-size struct at {:?}", sym));
|
||||
}
|
||||
} else {
|
||||
// Struct expression but not Struct layout => single element. Copy it.
|
||||
let field_storage = self.get_symbol_storage(&fields[0]).to_owned();
|
||||
self.copy_storage(&storage, &field_storage);
|
||||
storage.copy_from(
|
||||
&field_storage,
|
||||
&mut self.instructions,
|
||||
self.stack_frame_pointer,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -570,30 +606,6 @@ impl<'a> WasmBackend<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
fn copy_storage(&mut self, to: &SymbolStorage, from: &SymbolStorage) {
|
||||
let has_stack_memory = to.has_stack_memory();
|
||||
debug_assert!(from.has_stack_memory() == has_stack_memory);
|
||||
|
||||
if !has_stack_memory {
|
||||
debug_assert!(from.value_type() == to.value_type());
|
||||
self.instructions
|
||||
.push(GetLocal(from.local_id(self.stack_frame_pointer).0));
|
||||
self.instructions
|
||||
.push(SetLocal(to.local_id(self.stack_frame_pointer).0));
|
||||
} else {
|
||||
let (size, alignment_bytes) = from.stack_size_and_alignment();
|
||||
let copy = MemoryCopy {
|
||||
from_ptr: from.local_id(self.stack_frame_pointer),
|
||||
to_ptr: to.local_id(self.stack_frame_pointer),
|
||||
from_offset: from.address_offset().unwrap(),
|
||||
to_offset: to.address_offset().unwrap(),
|
||||
size,
|
||||
alignment_bytes,
|
||||
};
|
||||
copy.generate(&mut self.instructions);
|
||||
}
|
||||
}
|
||||
|
||||
fn build_call_low_level(
|
||||
&mut self,
|
||||
lowlevel: &LowLevel,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue