diff --git a/compiler/mono/src/layout_soa.rs b/compiler/mono/src/layout_soa.rs new file mode 100644 index 0000000000..0d0d662a8a --- /dev/null +++ b/compiler/mono/src/layout_soa.rs @@ -0,0 +1,228 @@ +use roc_builtins::bitcode::{FloatWidth, IntWidth}; +use roc_module::symbol::Symbol; +use roc_types::subs::{Content, FlatType, Subs, Variable}; + +#[derive(Clone, Copy)] +struct Index { + index: u32, + _marker: std::marker::PhantomData, +} + +impl Index { + pub const fn new(index: u32) -> Self { + Self { + index, + _marker: Default::default(), + } + } +} + +#[derive(Clone, Copy)] +struct Slice { + start: u32, + length: u16, + _marker: std::marker::PhantomData, +} + +impl Slice { + pub const fn new(start: u32, length: u16) -> Self { + Self { + start, + length, + _marker: Default::default(), + } + } + + pub const fn len(&self) -> usize { + self.length as _ + } + + pub const fn is_empty(&self) -> bool { + self.length == 0 + } + + pub const fn indices(&self) -> std::ops::Range { + self.start as usize..(self.start as usize + self.length as usize) + } +} + +impl Slice { + pub fn reserve(layouts: &mut Layouts, length: usize) -> Self { + let start = layouts.layouts.len() as u32; + + let it = std::iter::repeat(Layout::Reserved).take(length); + layouts.layouts.extend(it); + + Self { + start, + length: length as u16, + _marker: Default::default(), + } + } +} + +impl Slice> { + pub fn reserve(layouts: &mut Layouts, length: usize) -> Self { + let start = layouts.layout_slices.len() as u32; + + let empty: Slice = Slice::new(0, 0); + let it = std::iter::repeat(empty).take(length); + layouts.layout_slices.extend(it); + + Self { + start, + length: length as u16, + _marker: Default::default(), + } + } +} + +type SliceSlice = Slice>; +type LayoutIndex = Index; +type LambdaSetIndex = u32; +type NullableUnionIndex = u32; +type LayoutTuple = u32; +type SymbolSlice = (u32, u16); + +static_assertions::assert_eq_size!([u8; 12], Layout); + +pub struct Layouts { + layouts: Vec, + layout_slices: Vec>, + function_layouts: Vec<(Slice, LambdaSetIndex)>, + lambda_sets: Vec, + symbols: Vec, + nullable_unions: Vec, +} + +struct FunctionLayout { + /// An index into the Layouts.function_layouts array: + /// + /// last element is the result, prior elements the arguments + /// arguments_and_result: Slice, + /// lambda_set: LambdaSetIndex, + index: u32, +} +struct LambdaSet { + representation: LayoutIndex, + set_symbols: SymbolSlice, + set_layouts: SliceSlice, +} + +#[derive(Clone, Copy)] +enum Layout { + // theory: we can zero out memory to reserve space for many layouts + Reserved, + + // Question: where to store signedness information? + Int(IntWidth), + Float(FloatWidth), + Decimal, + + Str, + Dict(LayoutTuple), + Set(LayoutIndex), + List(LayoutIndex), + + Struct(Slice), + + UnionNonRecursive(SliceSlice), + UnionRecursive(SliceSlice), + UnionNonNullableUnwrapped(Slice), + UnionNullableWrapper { + data: NullableUnionIndex, + tag_id: u16, + }, + + UnionNullableUnwrappedTrue(Slice), + UnionNullableUnwrappedFalse(Slice), + + RecursivePointer, +} + +impl Layouts { + const VOID_INDEX: Index = Index::new(0); + const UNIT_INDEX: Index = Index::new(1); +} + +enum LayoutError { + UnresolvedVariable(Variable), + TypeError(()), +} + +impl Layout { + pub const UNIT: Self = Self::Struct(Slice::new(0, 0)); + pub const VOID: Self = Self::UnionNonRecursive(Slice::new(0, 0)); + + pub const EMPTY_LIST: Self = Self::List(Layouts::VOID_INDEX); + + fn from_var(layouts: &mut Layouts, subs: &Subs, var: Variable) -> Result { + let content = &subs.get_ref(var).content; + Self::from_content(layouts, subs, content) + } + + fn from_content( + layouts: &mut Layouts, + subs: &Subs, + content: &Content, + ) -> Result { + match content { + Content::FlexVar(_) => todo!(), + Content::RigidVar(_) => todo!(), + Content::RecursionVar { + structure, + opt_name, + } => todo!(), + Content::Structure(flat_type) => Self::from_flat_type(layouts, subs, flat_type), + Content::Alias(_, _, actual) => { + // at this point we throw away alias information + Self::from_var(layouts, subs, *actual) + } + Content::Error => todo!(), + } + } + + fn from_flat_type( + layouts: &mut Layouts, + subs: &Subs, + flat_type: &FlatType, + ) -> Result { + use LayoutError::*; + + match flat_type { + FlatType::Apply(Symbol::LIST_LIST, arguments) => { + debug_assert_eq!(arguments.len(), 1); + + let element_var = subs.variables[arguments.slice.start as usize]; + match Self::from_var(layouts, subs, element_var) { + Ok(element_layout) => { + let element_index = Index::new(layouts.layouts.len() as _); + layouts.layouts.push(element_layout); + + Ok(Layout::List(element_index)) + } + Err(UnresolvedVariable(_)) => Ok(Layout::EMPTY_LIST), + Err(other) => Err(other), + } + } + + FlatType::Apply(symbol, _) => { + unreachable!("Symbol {:?} does not have a layout", symbol) + } + + FlatType::Func(_arguments, lambda_set, _result) => { + // in this case, a function (pointer) is represented by the environment it + // captures: the lambda set + + Self::from_var(layouts, subs, *lambda_set) + } + FlatType::Record(_, _) => todo!(), + FlatType::TagUnion(_, _) => todo!(), + FlatType::FunctionOrTagUnion(_, _, _) => todo!(), + FlatType::RecursiveTagUnion(_, _, _) => todo!(), + FlatType::Erroneous(_) => todo!(), + FlatType::EmptyRecord => Ok(Layout::UNIT), + FlatType::EmptyTagUnion => Ok(Layout::VOID), + } + } +} diff --git a/compiler/mono/src/lib.rs b/compiler/mono/src/lib.rs index b1986bc2f8..dfd693c55d 100644 --- a/compiler/mono/src/lib.rs +++ b/compiler/mono/src/lib.rs @@ -7,6 +7,7 @@ pub mod borrow; pub mod inc_dec; pub mod ir; pub mod layout; +pub mod layout_soa; pub mod low_level; pub mod reset_reuse; pub mod tail_recursion;