Skip to content

Commit

Permalink
various record-related fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
simvux committed Sep 5, 2024
1 parent 4660ed3 commit ea274e3
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 59 deletions.
2 changes: 1 addition & 1 deletion lumina-compiler/src/backend/cranelift/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl lir::Records {
}
}

fn abi_record_fields(
pub(super) fn abi_record_fields(
&self,
triple: &Triple,
mk: MonoTypeKey,
Expand Down
85 changes: 75 additions & 10 deletions lumina-compiler/src/backend/cranelift/ssa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,17 +236,74 @@ impl<'c, 'a, 'f> Translator<'c, 'a, 'f> {
}

fn construct_record(&mut self, key: MonoTypeKey, values: &[lir::Value]) -> VEntry {
let fields = values.iter().map(|v| self.value_to_field(*v)).collect();
let triple = self.ctx.isa.triple();
let abi_types = self.types().abi_record_fields(triple, key);
assert_eq!(abi_types.len(), values.len());

let fields = abi_types
.into_iter()
.zip(values)
.map(|((_, abi), v)| {
let v = self.value_to_entry(*v);
self.map_entry_to_abi_field(abi, v)
})
.collect();

VEntry::Struct(key, fields)
}

fn value_to_field(&mut self, v: lir::Value) -> VField {
match self.value_to_entry(v) {
VEntry::Direct(v) => VField::Direct(v),
VEntry::Struct(_, fields) => VField::Struct(fields),
VEntry::FuncPointer(typing, ptr) => VField::FuncPointer(typing, ptr),
VEntry::SumPayload { largest, ptr } => VField::SumPayload { largest, ptr },
VEntry::ZST => VField::ZST,
fn map_entry_to_abi_field(&mut self, abi: abi::StructField<Type>, v: VEntry) -> VField {
match abi {
abi::StructField::Direct(_) => VField::Direct(v.as_direct()),
abi::StructField::AutoBoxedRecursion(ty, _) => {
let size = self.types().size_of_defined(ty);
assert_eq!(size, self.size_of_entry(&v));
let ptr = self.heap_alloc(size as i128);
let end = self.write_entry_to_ptr(ptr, 0, &v);
assert_eq!(size, end as u32 * 8);
VField::AutoBoxedRecursion(ty, ptr)
}
abi::StructField::Struct(_) => {
match v {
VEntry::Struct(_, vfields) => VField::Struct(vfields),
_ => unreachable!(),
}
// let subfields = fields.values().map(|field| ()).collect();
// VField::Struct(subfields)
}
abi::StructField::FuncPointer(_, _) => match v {
abi::Entry::FuncPointer(typing, ptr) => VField::FuncPointer(typing, ptr),
_ => unreachable!(),
},
abi::StructField::SumPayload { .. } => match v {
abi::Entry::SumPayload { largest, ptr } => VField::SumPayload { largest, ptr },
_ => unreachable!(),
},
abi::StructField::ZST => VField::ZST,
}
}

fn size_of_entry(&self, entry: &VEntry) -> u32 {
match entry {
abi::Entry::Direct(v) => self.f.type_of_value(*v).bits(),
abi::Entry::SumPayload { .. } | abi::Entry::FuncPointer(_, _) => {
self.ctx.pointer_type().bits()
}
abi::Entry::Struct(_, fields) => fields.values().map(|v| self.size_of_field(v)).sum(),
abi::Entry::ZST => 0,
}
}

fn size_of_field(&self, field: &VField) -> u32 {
match field {
abi::StructField::Direct(v) => self.f.type_of_value(*v).bits(),
abi::StructField::SumPayload { .. }
| abi::StructField::FuncPointer(_, _)
| abi::StructField::AutoBoxedRecursion(_, _) => self.ctx.pointer_type().bits(),
abi::StructField::Struct(fields) => {
fields.values().map(|v| self.size_of_field(v)).sum()
}
abi::StructField::ZST => 0,
}
}

Expand Down Expand Up @@ -477,7 +534,11 @@ impl<'c, 'a, 'f> Translator<'c, 'a, 'f> {
match field {
VField::Direct(v) => VEntry::Direct(v),
VField::FuncPointer(typing, ptr) => VEntry::FuncPointer(typing, ptr),
VField::AutoBoxedRecursion(_, _) => todo!("dereference"),
VField::AutoBoxedRecursion(ty, v) => {
let (entry, offset) = self.deref_type(v, BitOffset(0), &ty.into());
assert_eq!(offset.0, self.types().size_of_defined(ty));
entry
}
VField::Struct(fields) => VEntry::Struct(field_type.as_key(), fields),
VField::SumPayload { largest, ptr } => VEntry::SumPayload { largest, ptr },
VField::ZST => VEntry::ZST,
Expand Down Expand Up @@ -514,7 +575,11 @@ impl<'c, 'a, 'f> Translator<'c, 'a, 'f> {
self.ins().store(MemFlags::new(), *v, ptr, offset);
offset + size.bytes() as i32
}
VField::AutoBoxedRecursion(_, _) => todo!(),
VField::AutoBoxedRecursion(_, optr) => {
// TODO: are we meant to flatten it here with dereferences? I don't think we are.
self.ins().store(MemFlags::new(), *optr, ptr, offset);
offset + self.ctx.pointer_type().bytes() as i32
}
VField::Struct(fields) => fields.values().fold(offset, |offset, field| {
self.write_field_to_ptr(ptr, offset, field)
}),
Expand Down
12 changes: 12 additions & 0 deletions lumina-compiler/src/hir/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,18 @@ impl<'s> fmt::Display for Expr<'s> {
Expr::Lit(lit) => write!(f, "{lit:?}"),
Expr::Tuple(elems) => write!(f, "{op}{}{cp}", elems.iter().format(", ")),
Expr::List(elems, _) => write!(f, "[{}]", elems.iter().format(", ")),
Expr::Match(on, branches) if branches.len() == 1 => {
write!(
f,
"{} {} {} {} {} {}",
"let".keyword(),
&branches[0].0,
'='.symbol(),
on,
"in".keyword(),
&branches[0].1,
)
}
Expr::Match(on, branches) => write!(
f,
"{} {} | {}",
Expand Down
4 changes: 2 additions & 2 deletions lumina-compiler/src/lir/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ impl<'a> FuncLower<'a> {

let values = fields
.iter()
.map(|(_, expr)| self.expr_to_value(expr))
.map(|(_, _, expr)| self.expr_to_value(expr))
.collect::<Vec<Value>>();

let sorted = (0..fields.len() as u32)
.map(key::Field)
.map(|field| values[fields.iter().position(|(f, _)| *f == field).unwrap()])
.map(|field| values[fields.iter().position(|(f, _, _)| *f == field).unwrap()])
.collect();

self.ssa().construct(sorted, ty)
Expand Down
2 changes: 1 addition & 1 deletion lumina-compiler/src/lir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ pub fn run<'s>(info: ProjectInfo, target: Target, iquery: &ImplIndex, mut mir: m

let mainfunc = &mir.funcs[info.main].as_done();

let mut mono = mono::MonomorphisedTypes::new(info.closure);
let mut mono = mono::MonomorphisedTypes::new(info.closure, target.int_size() as u32);

fn to_morphization<'a>(
mir: &'a mir::MIR,
Expand Down
47 changes: 31 additions & 16 deletions lumina-compiler/src/lir/mono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@ impl From<MonoTypeKey> for MonoType {
}

#[derive(Deref, DerefMut)]
pub struct Records(Map<MonoTypeKey, MonomorphisedRecord>);
pub struct Records {
#[deref_mut]
#[deref]
types: Map<MonoTypeKey, MonomorphisedRecord>,
pub pointer_size: u32,
}

pub struct MonomorphisedTypes {
resolve: HashMap<(M<key::TypeKind>, Vec<MonoType>), MonoTypeKey>,
Expand Down Expand Up @@ -237,12 +242,12 @@ impl Records {

fn size_of_ty(&self, ty: &MonoType, sum_are_ptrs: bool) -> u32 {
match ty {
MonoType::SumDataCast { .. } if sum_are_ptrs => 64,
MonoType::SumDataCast { .. } if sum_are_ptrs => self.pointer_size,
MonoType::SumDataCast { largest } => *largest,
MonoType::Pointer(_) => 64,
MonoType::Pointer(_) => self.pointer_size,
MonoType::Int(intsize) => intsize.bits() as u32,
MonoType::Float => 64,
MonoType::FnPointer(_, _) => 64,
MonoType::FnPointer(_, _) => self.pointer_size,
MonoType::Unreachable => 0,
MonoType::Monomorphised(key) => self.size_of_defined(*key),
}
Expand Down Expand Up @@ -315,12 +320,12 @@ impl Records {
}

impl MonomorphisedTypes {
pub fn new(closure: M<key::Trait>) -> Self {
pub fn new(closure: M<key::Trait>, pointer_size: u32) -> Self {
let mut types = Self {
closure,
resolve: HashMap::new(),
tuples: HashMap::new(),
types: Records(Map::new()),
types: Records { types: Map::new(), pointer_size },
};
assert_eq!(UNIT, types.get_or_make_tuple(vec![]));
types
Expand Down Expand Up @@ -490,21 +495,31 @@ impl<'a> Monomorphization<'a> {
repr: Repr,
) -> MonomorphisedRecord {
let original = original.map(|k| k.map(Into::into));
let autoboxed = original
.map(|key| {
fields
.iter()
.filter_map(|(field, ty)| {
self.mono.types.field_is_recursive(key, ty).then_some(field)
})
.collect()
})
.unwrap_or_else(HashSet::new);
MonomorphisedRecord {
size: fields.values().map(|ty| self.mono.types.size_of(ty)).sum(),
repr,
autoboxed: original
.map(|key| {
fields
.iter()
.filter_map(|(field, ty)| {
self.mono.types.field_is_recursive(key, ty).then_some(field)
})
.collect()
size: fields
.iter()
.map(|(field, ty)| {
if autoboxed.contains(&field) {
self.mono.types.pointer_size
} else {
self.mono.types.size_of(ty)
}
})
.unwrap_or_else(HashSet::new),
.sum(),
fields,
original,
autoboxed,
}
}

Expand Down
2 changes: 0 additions & 2 deletions lumina-compiler/src/mir/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ impl<'a, 's> Verify<'a, 's> {
);
};

// FOUND IT: The problem is that we're assigning this *before* creating the fields. So; they're never "fixed"

if let Some(bind) = modify.as_deref() {
let ty = self.type_of(*bind).cloned();
let exp = IType::infer(*var).tr(expr.span);
Expand Down
48 changes: 27 additions & 21 deletions lumina-compiler/src/mir/lower/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub enum Expr {
Yield(Callable),

Access(Box<Self>, M<key::Record>, Vec<Type>, key::Field),
Record(M<key::Record>, Vec<Type>, Vec<(key::Field, Self)>),
Record(M<key::Record>, Vec<Type>, Vec<(key::Field, Span, Self)>),

Int(IntSize, i128),
Bool(bool),
Expand Down Expand Up @@ -220,36 +220,42 @@ impl<'a, 's> Lower<'a, 's> {
return Expr::Poison;
};

let mut unordered_fields = fields
.iter()
.filter_map(|(name, expr)| {
let expr = self.lower_expr(expr.as_ref());

match self.fnames[key].find(|n| n == name) {
Some(field) => Some((field, expr)),
None => {
// Should've already errored by type finalization
// self.errors.push(FinError::FieldNotFound(key, *name));
None
let mut unordered_fields = Vec::with_capacity(fields.len());

for (name, expr) in fields {
let expr = self.lower_expr(expr.as_ref());

match self.fnames[key].find(|n| n == name) {
Some(field) => {
match unordered_fields
.iter()
.find_map(|(f, span, _)| (*f == field).then_some(*span))
{
Some(previous) => {
self.errors.push(FinError::DuplicateField(
name.map(str::to_string),
previous,
));
}
None => unordered_fields.push((field, name.span, expr)),
}
}
})
.collect::<Vec<(key::Field, Expr)>>();

let mut missing_fields = vec![];
// Should've already errored by type finalization
None => {}
}
}

for field in self.fnames[key].keys() {
if unordered_fields.iter().all(|(f, _)| *f != field) {
if unordered_fields.iter().all(|(f, _, _)| *f != field) {
match modified {
Some(bind) => {
let object = Expr::bind(**bind);
let expr =
Expr::Access(Box::new(object), key, params.clone(), field);
unordered_fields.push((field, expr));
unordered_fields.push((field, bind.span, expr));
}
None => {
missing_fields.push(field);
unordered_fields.push((field, Expr::Poison));
unordered_fields.push((field, expr.span, Expr::Poison));
}
}
}
Expand Down Expand Up @@ -511,7 +517,7 @@ impl fmt::Display for Expr {
'|'.symbol(),
fields
.iter()
.map(|(k, v)| format!("{k} {} {v}", '='.symbol()))
.map(|(k, _, v)| format!("{k} {} {v}", '='.symbol()))
.format(", "),
),
Expr::Int(intsize, n) => write!(f, "{n} {as_} {intsize}"),
Expand Down
21 changes: 21 additions & 0 deletions lumina-compiler/src/mir/lower/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub enum FinError {
UnreachablePattern(Span),
MissingPatterns(Span, Vec<pat::MissingPattern>),
InvalidCast(Tr<Type>, Type),
DuplicateField(Tr<String>, Span),
}

impl<'a, 's> Lower<'a, 's> {
Expand Down Expand Up @@ -259,6 +260,13 @@ impl<'l, 'a, 's> pat::Merge<'s, key::DecisionTreeTail> for ParamsLower<'l, 'a, '
self.lower.finalizer().transform(&ty)
}

fn err_duplicate_field(&mut self, field: Tr<&'s str>, previous: Span) {
self.lower.errors.push(FinError::DuplicateField(
field.map(str::to_string),
previous,
));
}

fn str_to_ro(&mut self, str: &'s str) -> M<lumina_key::ReadOnly> {
self.lower.str_to_ro(str)
}
Expand Down Expand Up @@ -317,6 +325,13 @@ impl<'l, 'a, 's> pat::Merge<'s, key::DecisionTreeTail> for MatchBranchLower<'l,
self.lower.finalizer().transform(&ty)
}

fn err_duplicate_field(&mut self, field: Tr<&'s str>, previous: Span) {
self.lower.errors.push(FinError::DuplicateField(
field.map(str::to_string),
previous,
));
}

fn str_to_ro(&mut self, str: &'s str) -> M<key::ReadOnly> {
self.lower.str_to_ro(str)
}
Expand Down Expand Up @@ -351,6 +366,12 @@ pub fn emit_fin_error<'s>(
error: FinError,
) {
match error {
FinError::DuplicateField(field, previous) => sources
.error("field assigned twice")
.m(module)
.iline(previous, "first assigned here")
.iline(field.span, "later assigned again here")
.emit(),
FinError::UnreachablePattern(span) => sources
.error("unreachable pattern")
.m(module)
Expand Down
Loading

0 comments on commit ea274e3

Please sign in to comment.