Refactor SymbolStorage into two enums instead of one

This commit is contained in:
Brian Carroll 2021-10-02 16:15:06 +01:00
parent ffa6ff0a62
commit 6aed70978d
2 changed files with 78 additions and 149 deletions

View file

@ -11,7 +11,7 @@ use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt};
use roc_mono::layout::{Builtin, Layout}; use roc_mono::layout::{Builtin, Layout};
use crate::layout::WasmLayout; use crate::layout::WasmLayout;
use crate::storage::SymbolStorage; use crate::storage::{StackMemoryLocation, SymbolStorage};
use crate::{ use crate::{
pop_stack_frame, push_stack_frame, round_up_to_alignment, LocalId, MemoryCopy, PTR_SIZE, pop_stack_frame, push_stack_frame, round_up_to_alignment, LocalId, MemoryCopy, PTR_SIZE,
PTR_TYPE, PTR_TYPE,
@ -167,68 +167,55 @@ impl<'a> WasmBackend<'a> {
) -> SymbolStorage { ) -> SymbolStorage {
let next_local_id = LocalId((self.arg_types.len() + self.locals.len()) as u32); let next_local_id = LocalId((self.arg_types.len() + self.locals.len()) as u32);
let storage = match kind { match kind {
LocalKind::Parameter => { LocalKind::Parameter => {
// Already stack-allocated by the caller if needed.
self.arg_types.push(wasm_layout.value_type()); self.arg_types.push(wasm_layout.value_type());
match wasm_layout {
WasmLayout::LocalOnly(value_type, size) => SymbolStorage::ParamPrimitive {
local_id: next_local_id,
value_type,
size,
},
WasmLayout::HeapMemory => SymbolStorage::ParamPrimitive {
local_id: next_local_id,
value_type: PTR_TYPE,
size: PTR_SIZE,
},
WasmLayout::StackMemory {
size,
alignment_bytes,
} => SymbolStorage::ParamStackMemory {
local_id: next_local_id,
size,
alignment_bytes,
},
}
} }
LocalKind::Variable => { LocalKind::Variable => {
self.locals.push(Local::new(1, wasm_layout.value_type())); self.locals.push(Local::new(1, wasm_layout.value_type()));
}
}
match wasm_layout { let storage = match wasm_layout {
WasmLayout::LocalOnly(value_type, size) => SymbolStorage::VarPrimitive { WasmLayout::LocalOnly(value_type, size) => SymbolStorage::Local {
local_id: next_local_id, local_id: next_local_id,
value_type, value_type,
size, size,
}, },
WasmLayout::HeapMemory => SymbolStorage::VarHeapMemory { WasmLayout::HeapMemory => SymbolStorage::Local {
local_id: next_local_id, local_id: next_local_id,
}, value_type: PTR_TYPE,
size: PTR_SIZE,
},
WasmLayout::StackMemory { WasmLayout::StackMemory {
size, size,
alignment_bytes, alignment_bytes,
} => { } => {
let location = match kind {
LocalKind::Parameter => StackMemoryLocation::ExternalPointer(next_local_id),
LocalKind::Variable => {
let offset = let offset =
round_up_to_alignment(self.stack_memory, alignment_bytes as i32); round_up_to_alignment(self.stack_memory, alignment_bytes as i32);
self.stack_memory = offset + size as i32; self.stack_memory = offset + size as i32;
match self.stack_frame_pointer { match self.stack_frame_pointer {
Some(_) => {}
None => { None => {
self.stack_frame_pointer = Some(next_local_id); self.stack_frame_pointer = Some(next_local_id);
} }
Some(_) => {}
}; };
SymbolStorage::VarStackMemory { StackMemoryLocation::InternalOffset(offset as u32)
size,
offset: offset as u32,
alignment_bytes,
}
} }
};
SymbolStorage::StackMemory {
location,
size,
alignment_bytes,
} }
} }
}; };
@ -288,8 +275,8 @@ impl<'a> WasmBackend<'a> {
{ {
// Map this symbol to the first argument (pointer into caller's stack) // Map this symbol to the first argument (pointer into caller's stack)
// Saves us from having to copy it later // Saves us from having to copy it later
let storage = SymbolStorage::ParamStackMemory { let storage = SymbolStorage::StackMemory {
local_id: LocalId(0), location: StackMemoryLocation::ExternalPointer(LocalId(0)),
size, size,
alignment_bytes, alignment_bytes,
}; };
@ -324,14 +311,21 @@ impl<'a> WasmBackend<'a> {
let storage = self.symbol_storage_map.get(sym).unwrap(); let storage = self.symbol_storage_map.get(sym).unwrap();
match storage { match storage {
VarStackMemory { StackMemory {
location,
size, size,
alignment_bytes, alignment_bytes,
offset,
} => { } => {
let (from_ptr, from_offset) = match location {
StackMemoryLocation::ExternalPointer(local_id) => (*local_id, 0),
StackMemoryLocation::InternalOffset(offset) => {
(self.stack_frame_pointer.unwrap(), *offset)
}
};
let copy = MemoryCopy { let copy = MemoryCopy {
from_ptr: self.stack_frame_pointer.unwrap(), from_ptr,
from_offset: *offset, from_offset,
to_ptr: LocalId(0), to_ptr: LocalId(0),
to_offset: 0, to_offset: 0,
size: *size, size: *size,
@ -340,25 +334,7 @@ impl<'a> WasmBackend<'a> {
copy.generate(&mut self.instructions); copy.generate(&mut self.instructions);
} }
ParamStackMemory { Local { local_id, .. } => {
local_id,
size,
alignment_bytes,
} => {
let copy = MemoryCopy {
from_ptr: *local_id,
from_offset: 0,
to_ptr: LocalId(0),
to_offset: 0,
size: *size,
alignment_bytes: *alignment_bytes,
};
copy.generate(&mut self.instructions);
}
ParamPrimitive { local_id, .. }
| VarPrimitive { local_id, .. }
| VarHeapMemory { local_id, .. } => {
self.instructions.push(GetLocal(local_id.0)); self.instructions.push(GetLocal(local_id.0));
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)
} }
@ -551,10 +527,9 @@ impl<'a> WasmBackend<'a> {
if let Layout::Struct(field_layouts) = layout { if let Layout::Struct(field_layouts) = layout {
let (local_id, size) = match storage { let (local_id, size) = match storage {
SymbolStorage::VarStackMemory { size, .. } => { SymbolStorage::StackMemory { size, .. } => {
(self.stack_frame_pointer.unwrap(), size) (storage.local_id(self.stack_frame_pointer), size)
} }
SymbolStorage::ParamStackMemory { local_id, size, .. } => (local_id, size),
_ => { _ => {
return Err(format!( return Err(format!(
"Cannot create struct {:?} with storage {:?}", "Cannot create struct {:?} with storage {:?}",

View file

@ -1,82 +1,66 @@
use crate::{LocalId, MemoryCopy, ALIGN_1, ALIGN_2, ALIGN_4, ALIGN_8}; use crate::{LocalId, MemoryCopy, ALIGN_1, ALIGN_2, ALIGN_4, ALIGN_8};
use parity_wasm::elements::{Instruction, Instruction::*, ValueType}; use parity_wasm::elements::{Instruction, Instruction::*, ValueType};
#[derive(Debug, Clone)]
pub enum StackMemoryLocation {
ExternalPointer(LocalId),
InternalOffset(u32),
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum SymbolStorage { pub enum SymbolStorage {
VarPrimitive { Local {
local_id: LocalId, local_id: LocalId,
value_type: ValueType, value_type: ValueType,
size: u32, size: u32,
}, },
ParamPrimitive { StackMemory {
local_id: LocalId, location: StackMemoryLocation,
value_type: ValueType,
size: u32,
},
VarStackMemory {
size: u32,
offset: u32,
alignment_bytes: u32,
},
ParamStackMemory {
local_id: LocalId,
size: u32, size: u32,
alignment_bytes: u32, alignment_bytes: u32,
}, },
VarHeapMemory {
local_id: LocalId,
},
} }
impl SymbolStorage { impl SymbolStorage {
pub fn local_id(&self, stack_frame_pointer: Option<LocalId>) -> LocalId { pub fn local_id(&self, stack_frame_pointer: Option<LocalId>) -> LocalId {
use StackMemoryLocation::*;
match self { match self {
Self::ParamPrimitive { local_id, .. } => *local_id, Self::Local { local_id, .. } => *local_id,
Self::ParamStackMemory { local_id, .. } => *local_id, Self::StackMemory { location, .. } => match *location {
Self::VarPrimitive { local_id, .. } => *local_id, ExternalPointer(local_id) => local_id,
Self::VarStackMemory { .. } => stack_frame_pointer.unwrap(), InternalOffset(_) => stack_frame_pointer.unwrap(),
Self::VarHeapMemory { local_id, .. } => *local_id, },
} }
} }
pub fn value_type(&self) -> ValueType { pub fn value_type(&self) -> ValueType {
match self { match self {
Self::ParamPrimitive { value_type, .. } => *value_type, Self::Local { value_type, .. } => *value_type,
Self::VarPrimitive { value_type, .. } => *value_type, Self::StackMemory { .. } => ValueType::I32,
Self::ParamStackMemory { .. } => ValueType::I32,
Self::VarStackMemory { .. } => ValueType::I32,
Self::VarHeapMemory { .. } => ValueType::I32,
} }
} }
pub fn has_stack_memory(&self) -> bool { pub fn has_stack_memory(&self) -> bool {
match self { match self {
Self::ParamStackMemory { .. } => true, Self::Local { .. } => false,
Self::VarStackMemory { .. } => true, Self::StackMemory { .. } => true,
Self::ParamPrimitive { .. } => false,
Self::VarPrimitive { .. } => false,
Self::VarHeapMemory { .. } => false,
} }
} }
pub fn address_offset(&self) -> Option<u32> { pub fn address_offset(&self) -> Option<u32> {
use StackMemoryLocation::*;
match self { match self {
Self::ParamStackMemory { .. } => Some(0), Self::Local { .. } => None,
Self::VarStackMemory { offset, .. } => Some(*offset), Self::StackMemory { location, .. } => match *location {
Self::ParamPrimitive { .. } => None, ExternalPointer(_) => Some(0),
Self::VarPrimitive { .. } => None, InternalOffset(offset) => Some(offset),
Self::VarHeapMemory { .. } => None, },
} }
} }
pub fn stack_size_and_alignment(&self) -> (u32, u32) { pub fn stack_size_and_alignment(&self) -> (u32, u32) {
match self { match self {
Self::VarStackMemory { Self::StackMemory {
size,
alignment_bytes,
..
}
| Self::ParamStackMemory {
size, size,
alignment_bytes, alignment_bytes,
.. ..
@ -94,13 +78,7 @@ impl SymbolStorage {
stack_frame_pointer: Option<LocalId>, stack_frame_pointer: Option<LocalId>,
) -> u32 { ) -> u32 {
match self { match self {
Self::ParamPrimitive { Self::Local {
local_id,
value_type,
size,
..
}
| Self::VarPrimitive {
local_id, local_id,
value_type, value_type,
size, size,
@ -123,13 +101,14 @@ impl SymbolStorage {
*size *size
} }
Self::ParamStackMemory { Self::StackMemory {
local_id,
size, size,
alignment_bytes, alignment_bytes,
..
} => { } => {
let local_id = self.local_id(stack_frame_pointer);
let copy = MemoryCopy { let copy = MemoryCopy {
from_ptr: *local_id, from_ptr: local_id,
from_offset: 0, from_offset: 0,
to_ptr: to_pointer, to_ptr: to_pointer,
to_offset, to_offset,
@ -139,31 +118,6 @@ impl SymbolStorage {
copy.generate(instructions); copy.generate(instructions);
*size *size
} }
Self::VarStackMemory {
size,
alignment_bytes,
offset,
..
} => {
let copy = MemoryCopy {
from_ptr: stack_frame_pointer.unwrap(),
from_offset: *offset,
to_ptr: to_pointer,
to_offset,
size: *size,
alignment_bytes: *alignment_bytes,
};
copy.generate(instructions);
*size
}
Self::VarHeapMemory { local_id, .. } => {
instructions.push(GetLocal(to_pointer.0));
instructions.push(GetLocal(local_id.0));
instructions.push(I32Store(ALIGN_4, to_offset));
4
}
} }
} }
} }