Merge pull request #1340 from rtfeldman/layout-cleanup

Layout cleanup
This commit is contained in:
Richard Feldman 2021-05-26 20:49:18 -04:00 committed by GitHub
commit 519b4f2a12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 99 additions and 203 deletions

View file

@ -377,16 +377,6 @@ fn lowlevel_spec(
}
fn build_variant_types(
builder: &mut FuncDefBuilder,
layout: &Layout,
) -> Option<Result<Vec<TypeId>>> {
match layout {
Layout::Union(union_layout) => Some(build_variant_types_help(builder, union_layout)),
_ => None,
}
}
fn build_variant_types_help(
builder: &mut FuncDefBuilder,
union_layout: &UnionLayout,
) -> Result<Vec<TypeId>> {
@ -435,7 +425,7 @@ fn expr_spec(
arguments,
} => {
let value_id = build_tuple_value(builder, env, block, arguments)?;
let variant_types = build_variant_types(builder, tag_layout).unwrap()?;
let variant_types = build_variant_types(builder, tag_layout)?;
builder.add_make_union(block, &variant_types, *tag_id as u32, value_id)
}
Struct(fields) => build_tuple_value(builder, env, block, fields),
@ -525,16 +515,14 @@ fn layout_spec(builder: &mut FuncDefBuilder, layout: &Layout) -> Result<TypeId>
match layout {
Builtin(builtin) => builtin_spec(builder, builtin),
PhantomEmptyStruct => todo!(),
Struct(fields) => build_tuple_type(builder, fields),
Union(union_layout) => {
let variant_types = build_variant_types_help(builder, union_layout)?;
let variant_types = build_variant_types(builder, union_layout)?;
builder.add_union_type(&variant_types)
}
RecursivePointer => todo!(),
FunctionPointer(_, _) => todo!(),
Closure(_, _, _) => todo!(),
Pointer(_) => todo!(),
}
}
@ -550,7 +538,7 @@ fn builtin_spec(builder: &mut FuncDefBuilder, builtin: &Builtin) -> Result<TypeI
Str => todo!(),
Dict(_, _) => todo!(),
Set(_) => todo!(),
List(_, _) => {
List(_) => {
// TODO should incorporate the element type into the name
Ok(builder.add_named_type(MOD_LIST, TypeName(b"List")))
}

View file

@ -3,8 +3,8 @@
use self::InProgressProc::*;
use crate::exhaustive::{Ctor, Guard, RenderAs, TagId};
use crate::layout::{
Builtin, ClosureRepresentation, LambdaSet, Layout, LayoutCache, LayoutProblem, MemoryMode,
UnionLayout, WrappedVariant, TAG_SIZE,
Builtin, ClosureRepresentation, LambdaSet, Layout, LayoutCache, LayoutProblem, UnionLayout,
WrappedVariant, TAG_SIZE,
};
use bumpalo::collections::Vec;
use bumpalo::Bump;
@ -1150,7 +1150,7 @@ pub enum Expr<'a> {
Call(Call<'a>),
Tag {
tag_layout: Layout<'a>,
tag_layout: UnionLayout<'a>,
tag_name: TagName,
tag_id: u8,
union_size: u8,
@ -3371,10 +3371,7 @@ pub fn with_hole<'a>(
Stmt::Let(
assigned,
expr,
Layout::Builtin(Builtin::List(
MemoryMode::Refcounted,
env.arena.alloc(elem_layout),
)),
Layout::Builtin(Builtin::List(env.arena.alloc(elem_layout))),
hole,
)
}
@ -3406,12 +3403,10 @@ pub fn with_hole<'a>(
elems: arg_symbols,
};
let mode = MemoryMode::Refcounted;
let stmt = Stmt::Let(
assigned,
expr,
Layout::Builtin(Builtin::List(mode, env.arena.alloc(elem_layout))),
Layout::Builtin(Builtin::List(env.arena.alloc(elem_layout))),
hole,
);
@ -4140,10 +4135,15 @@ fn construct_closure_data<'a>(
tag_symbols.push(tag_id_symbol);
tag_symbols.extend(symbols);
let tag_layout = match lambda_set.runtime_representation() {
Layout::Union(inner) => inner,
_ => unreachable!(),
};
let expr1 = Expr::Literal(Literal::Int(tag_id as i128));
let expr2 = Expr::Tag {
tag_id,
tag_layout: lambda_set.runtime_representation(),
tag_layout,
union_size,
tag_name,
arguments: tag_symbols.into_bump_slice(),
@ -4305,17 +4305,17 @@ fn convert_tag_union<'a>(
}
debug_assert!(layouts.len() > 1);
let layout = Layout::Union(UnionLayout::Recursive(layouts.into_bump_slice()));
let union_layout = UnionLayout::Recursive(layouts.into_bump_slice());
let tag = Expr::Tag {
tag_layout: layout,
tag_layout: union_layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
(tag, Layout::Union(union_layout))
}
NonNullableUnwrapped {
fields,
@ -4333,17 +4333,17 @@ fn convert_tag_union<'a>(
temp.into_bump_slice()
};
let layout = Layout::Union(UnionLayout::NonNullableUnwrapped(fields));
let union_layout = UnionLayout::NonNullableUnwrapped(fields);
let tag = Expr::Tag {
tag_layout: layout,
tag_layout: union_layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
(tag, Layout::Union(union_layout))
}
NonRecursive { sorted_tag_layouts } => {
let tag_id_symbol = env.unique_symbol();
@ -4365,18 +4365,17 @@ fn convert_tag_union<'a>(
layouts.push(arg_layouts);
}
let layout =
Layout::Union(UnionLayout::NonRecursive(layouts.into_bump_slice()));
let union_layout = UnionLayout::NonRecursive(layouts.into_bump_slice());
let tag = Expr::Tag {
tag_layout: layout,
tag_layout: union_layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
(tag, Layout::Union(union_layout))
}
NullableWrapped {
nullable_id,
@ -4402,20 +4401,20 @@ fn convert_tag_union<'a>(
layouts.push(arg_layouts);
}
let layout = Layout::Union(UnionLayout::NullableWrapped {
let union_layout = UnionLayout::NullableWrapped {
nullable_id,
other_tags: layouts.into_bump_slice(),
});
};
let tag = Expr::Tag {
tag_layout: layout,
tag_layout: union_layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
(tag, Layout::Union(union_layout))
}
NullableUnwrapped {
nullable_id,
@ -4437,20 +4436,20 @@ fn convert_tag_union<'a>(
temp.into_bump_slice()
};
let layout = Layout::Union(UnionLayout::NullableUnwrapped {
let union_layout = UnionLayout::NullableUnwrapped {
nullable_id,
other_fields,
});
};
let tag = Expr::Tag {
tag_layout: layout,
tag_layout: union_layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
(tag, Layout::Union(union_layout))
}
};

View file

@ -40,24 +40,19 @@ pub enum Layout<'a> {
/// A layout that is empty (turns into the empty struct in LLVM IR
/// but for our purposes, not zero-sized, so it does not get dropped from data structures
/// this is important for closures that capture zero-sized values
PhantomEmptyStruct,
Struct(&'a [Layout<'a>]),
Union(UnionLayout<'a>),
RecursivePointer,
/// A function. The types of its arguments, then the type of its return value.
FunctionPointer(&'a [Layout<'a>], &'a Layout<'a>),
Closure(&'a [Layout<'a>], LambdaSet<'a>, &'a Layout<'a>),
Pointer(&'a Layout<'a>),
}
impl<'a> Layout<'a> {
pub fn in_place(&self) -> InPlace {
match self {
Layout::Builtin(Builtin::EmptyList) => InPlace::InPlace,
Layout::Builtin(Builtin::List(memory_mode, _)) => match memory_mode {
MemoryMode::Unique => InPlace::InPlace,
MemoryMode::Refcounted => InPlace::Clone,
},
Layout::Builtin(Builtin::List(_)) => InPlace::Clone,
Layout::Builtin(Builtin::EmptyStr) => InPlace::InPlace,
Layout::Builtin(Builtin::Str) => InPlace::Clone,
Layout::Builtin(Builtin::Int1) => InPlace::Clone,
@ -337,12 +332,6 @@ impl<'a> LambdaSet<'a> {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Copy)]
pub enum MemoryMode {
Unique,
Refcounted,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Builtin<'a> {
Int128,
@ -359,7 +348,7 @@ pub enum Builtin<'a> {
Str,
Dict(&'a Layout<'a>, &'a Layout<'a>),
Set(&'a Layout<'a>),
List(MemoryMode, &'a Layout<'a>),
List(&'a Layout<'a>),
EmptyStr,
EmptyList,
EmptyDict,
@ -483,7 +472,6 @@ impl<'a> Layout<'a> {
match self {
Builtin(builtin) => builtin.safe_to_memcpy(),
PhantomEmptyStruct => true,
Struct(fields) => fields
.iter()
.all(|field_layout| field_layout.safe_to_memcpy()),
@ -508,10 +496,6 @@ impl<'a> Layout<'a> {
true
}
Closure(_, closure_layout, _) => closure_layout.safe_to_memcpy(),
Pointer(_) => {
// We cannot memcpy pointers, because then we would have the same pointer in multiple places!
false
}
RecursivePointer => {
// We cannot memcpy pointers, because then we would have the same pointer in multiple places!
false
@ -523,12 +507,7 @@ impl<'a> Layout<'a> {
// For this calculation, we don't need an accurate
// stack size, we just need to know whether it's zero,
// so it's fine to use a pointer size of 1.
if let Layout::PhantomEmptyStruct = self {
false
} else {
// self.stack_size(1) == 0
false
}
false
}
pub fn stack_size(&self, pointer_size: u32) -> u32 {
@ -536,7 +515,6 @@ impl<'a> Layout<'a> {
match self {
Builtin(builtin) => builtin.stack_size(pointer_size),
PhantomEmptyStruct => 0,
Struct(fields) => {
let mut sum = 0;
@ -570,7 +548,6 @@ impl<'a> Layout<'a> {
Closure(_, lambda_set, _) => lambda_set.stack_size(pointer_size),
FunctionPointer(_, _) => pointer_size,
RecursivePointer => pointer_size,
Pointer(_) => pointer_size,
}
}
@ -600,10 +577,8 @@ impl<'a> Layout<'a> {
}
}
Layout::Builtin(builtin) => builtin.alignment_bytes(pointer_size),
Layout::PhantomEmptyStruct => 0,
Layout::RecursivePointer => pointer_size,
Layout::FunctionPointer(_, _) => pointer_size,
Layout::Pointer(_) => pointer_size,
Layout::Closure(_, captured, _) => {
pointer_size.max(captured.alignment_bytes(pointer_size))
}
@ -626,7 +601,7 @@ impl<'a> Layout<'a> {
RecursivePointer => true,
Builtin(List(MemoryMode::Refcounted, _)) | Builtin(Str) => true,
Builtin(List(_)) | Builtin(Str) => true,
_ => false,
}
@ -640,7 +615,6 @@ impl<'a> Layout<'a> {
match self {
Builtin(builtin) => builtin.is_refcounted(),
PhantomEmptyStruct => false,
Struct(fields) => fields.iter().any(|f| f.contains_refcounted()),
Union(variant) => {
use UnionLayout::*;
@ -659,7 +633,7 @@ impl<'a> Layout<'a> {
}
RecursivePointer => true,
Closure(_, closure_layout, _) => closure_layout.contains_refcounted(),
FunctionPointer(_, _) | Pointer(_) => false,
FunctionPointer(_, _) => false,
}
}
@ -673,7 +647,6 @@ impl<'a> Layout<'a> {
match self {
Builtin(builtin) => builtin.to_doc(alloc, parens),
PhantomEmptyStruct => alloc.text("{}"),
Struct(fields) => {
let fields_doc = fields.iter().map(|x| x.to_doc(alloc, parens));
@ -706,7 +679,6 @@ impl<'a> Layout<'a> {
.append(" |} -> ")
.append(result.to_doc(alloc, Parens::InFunction))
}
Pointer(_) => todo!(),
}
}
}
@ -878,7 +850,7 @@ impl<'a> Builtin<'a> {
Str | EmptyStr => Builtin::STR_WORDS * pointer_size,
Dict(_, _) | EmptyDict => Builtin::DICT_WORDS * pointer_size,
Set(_) | EmptySet => Builtin::SET_WORDS * pointer_size,
List(_, _) | EmptyList => Builtin::LIST_WORDS * pointer_size,
List(_) | EmptyList => Builtin::LIST_WORDS * pointer_size,
}
}
@ -904,7 +876,7 @@ impl<'a> Builtin<'a> {
Str | EmptyStr => pointer_size,
Dict(_, _) | EmptyDict => pointer_size,
Set(_) | EmptySet => pointer_size,
List(_, _) | EmptyList => pointer_size,
List(_) | EmptyList => pointer_size,
}
}
@ -914,7 +886,7 @@ impl<'a> Builtin<'a> {
match self {
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Float128 | Float64 | Float32
| Float16 | EmptyStr | EmptyDict | EmptyList | EmptySet => true,
Str | Dict(_, _) | Set(_) | List(_, _) => false,
Str | Dict(_, _) | Set(_) | List(_) => false,
}
}
@ -925,10 +897,7 @@ impl<'a> Builtin<'a> {
match self {
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Float128 | Float64 | Float32
| Float16 | EmptyStr | EmptyDict | EmptyList | EmptySet => false,
List(mode, element_layout) => match mode {
MemoryMode::Refcounted => true,
MemoryMode::Unique => element_layout.contains_refcounted(),
},
List(_) => true,
Str | Dict(_, _) | Set(_) => true,
}
@ -961,7 +930,7 @@ impl<'a> Builtin<'a> {
EmptySet => alloc.text("EmptySet"),
Str => alloc.text("Str"),
List(_, layout) => alloc
List(layout) => alloc
.text("List ")
.append(layout.to_doc(alloc, Parens::InTypeParam)),
Set(layout) => alloc
@ -1901,11 +1870,7 @@ pub fn list_layout_from_elem<'a>(
_ => {
let elem_layout = Layout::from_var(env, elem_var)?;
// This is a normal list.
Ok(Layout::Builtin(Builtin::List(
MemoryMode::Refcounted,
env.arena.alloc(elem_layout),
)))
Ok(Layout::Builtin(Builtin::List(env.arena.alloc(elem_layout))))
}
}
}
@ -1971,7 +1936,7 @@ impl<'a> std::convert::TryFrom<&Layout<'a>> for ListLayout<'a> {
fn try_from(value: &Layout<'a>) -> Result<Self, Self::Error> {
match value {
Layout::Builtin(Builtin::EmptyList) => Ok(ListLayout::EmptyList),
Layout::Builtin(Builtin::List(_, element)) => Ok(ListLayout::List(element)),
Layout::Builtin(Builtin::List(element)) => Ok(ListLayout::List(element)),
_ => Err(()),
}
}