adding structures

This commit is contained in:
mlokr 2024-05-12 13:13:36 +02:00
parent 80b05779ea
commit f87959aacb
4 changed files with 140 additions and 29 deletions

View file

@ -252,7 +252,7 @@ struct Loop {
struct Struct { struct Struct {
id: Ident, id: Ident,
fields: Vec<(Rc<str>, Type)>, fields: Rc<[(Rc<str>, Type)]>,
} }
pub struct Codegen<'a> { pub struct Codegen<'a> {
@ -305,16 +305,18 @@ impl<'a> Codegen<'a> {
} }
fn size_of(&self, ty: Type) -> u64 { fn size_of(&self, ty: Type) -> u64 {
// TODO: proper alignment match ty {
match TypeKind::from_ty(ty) { bt::INT => 8,
TypeKind::Pointer(_) | TypeKind::Builtin(bt::INT) => 8, bt::BOOL => 1,
TypeKind::Builtin(bt::BOOL) => 1, _ => match TypeKind::from_ty(ty) {
TypeKind::Builtin(_) => unreachable!(), TypeKind::Pointer(_) => 8,
TypeKind::Builtin(e) => unreachable!("{:?}", e),
TypeKind::Struct(ty) => self.records[ty as usize] TypeKind::Struct(ty) => self.records[ty as usize]
.fields .fields
.iter() .iter()
.map(|(_, ty)| self.size_of(*ty)) .map(|(_, ty)| self.size_of(*ty))
.sum(), .sum(),
},
} }
} }
@ -337,7 +339,7 @@ impl<'a> Codegen<'a> {
self.code.encode(instrs::li64(reg.0, imm)); self.code.encode(instrs::li64(reg.0, imm));
reg reg
} }
Loc::Stack(offset) => { Loc::Stack(offset) | Loc::StackRef(offset) => {
let reg = self.gpa.allocate(); let reg = self.gpa.allocate();
self.load_stack(reg.0, offset, 8); self.load_stack(reg.0, offset, 8);
reg reg
@ -391,12 +393,82 @@ impl<'a> Codegen<'a> {
match *expr { match *expr {
E::Ident { name: "int", .. } => bt::INT, E::Ident { name: "int", .. } => bt::INT,
E::Ident { name: "bool", .. } => bt::BOOL, E::Ident { name: "bool", .. } => bt::BOOL,
E::Ident { id, .. } => {
let index = self
.records
.iter()
.position(|r| r.id == id)
.unwrap_or_else(|| {
panic!("type not found: {:?}", id);
});
TypeKind::Struct(index as Type).encode()
}
expr => unimplemented!("type: {:#?}", expr), expr => unimplemented!("type: {:#?}", expr),
} }
} }
fn expr(&mut self, expr: &'a parser::Expr<'a>, expeted: Option<Type>) -> Option<Value> { fn expr(&mut self, expr: &'a parser::Expr<'a>, expeted: Option<Type>) -> Option<Value> {
match *expr { match *expr {
E::Ctor { ty, fields } => {
let ty = self.ty(&ty);
let TypeKind::Struct(idx) = TypeKind::from_ty(ty) else {
panic!("expected struct, got {:?}", ty);
};
let size = self.size_of(ty);
let stack = self.alloc_stack(size as u32);
let mut field_values = fields
.iter()
.map(|(name, field)| (*name, self.expr(field, None).unwrap()))
.collect::<Vec<_>>();
let decl_fields = self.records[idx as usize].fields.clone();
let mut offset = 0;
for (name, ty) in decl_fields.as_ref() {
let index = field_values
.iter()
.position(|(n, _)| *n == name.as_ref())
.unwrap();
let (_, value) = field_values.remove(index);
if value.ty != *ty {
panic!("expected {:?}, got {:?}", ty, value.ty);
}
let reg = self.loc_to_reg(value.loc);
self.store_stack(reg.0, stack + offset, 8);
self.gpa.free(reg);
offset += 8;
}
Some(Value {
ty,
loc: Loc::Stack(stack),
})
}
E::Field { target, field } => {
let target = self.expr(target, None).unwrap();
let TypeKind::Struct(idx) = TypeKind::from_ty(target.ty) else {
panic!("expected struct, got {:?}", target.ty);
};
let decl_fields = self.records[idx as usize].fields.clone();
let index = decl_fields
.iter()
.position(|(name, _)| name.as_ref() == field)
.unwrap();
let size = self.size_of(decl_fields[index].1);
assert_eq!(size, 8, "TODO: implement other sizes");
let value = match target.loc {
Loc::Reg(_) => todo!(),
Loc::RegRef(_) => todo!(),
Loc::Deref(r) => {
self.code.encode(instrs::addi64(r.0, r.0, index as u64 * 8));
Loc::Deref(r)
}
Loc::Imm(_) => todo!(),
Loc::Stack(stack) => Loc::Stack(stack + index as u64 * 8),
Loc::StackRef(stack) => Loc::StackRef(stack + index as u64 * 8),
};
Some(Value {
ty: decl_fields[index].1,
loc: value,
})
}
E::BinOp { E::BinOp {
left: E::Ident { id, .. }, left: E::Ident { id, .. },
op: T::Decl, op: T::Decl,
@ -414,7 +486,7 @@ impl<'a> Codegen<'a> {
} => { } => {
let val = self.expr(val, None).unwrap(); let val = self.expr(val, None).unwrap();
match val.loc { match val.loc {
Loc::Stack(off) => { Loc::StackRef(off) => {
let reg = self.gpa.allocate(); let reg = self.gpa.allocate();
self.stack_relocs.push(StackReloc { self.stack_relocs.push(StackReloc {
offset: self.code.code.len() as u32 + 3, offset: self.code.code.len() as u32 + 3,
@ -489,17 +561,12 @@ impl<'a> Codegen<'a> {
right, right,
} => { } => {
let val = self.expr(right, None).unwrap(); let val = self.expr(right, None).unwrap();
let reg = self.loc_to_reg(val.loc); let loc = self.make_loc_owned(val.loc, val.ty);
let offset = self.alloc_stack(8); let loc = self.ensure_spilled(loc);
self.vars.push(Variable { self.vars.push(Variable {
id: *id, id: *id,
value: Value { value: Value { ty: val.ty, loc },
ty: val.ty,
loc: Loc::Stack(offset),
},
}); });
self.store_stack(reg.0, offset, 8);
self.gpa.free(reg);
None None
} }
E::Call { E::Call {
@ -705,7 +772,7 @@ impl<'a> Codegen<'a> {
self.gpa.free(reg); self.gpa.free(reg);
} }
Loc::RegRef(reg) => self.code.encode(instrs::cp(reg, rhs.0)), Loc::RegRef(reg) => self.code.encode(instrs::cp(reg, rhs.0)),
Loc::Stack(offset) => self.store_stack(rhs.0, offset, 8), Loc::StackRef(offset) => self.store_stack(rhs.0, offset, 8),
_ => unimplemented!(), _ => unimplemented!(),
} }
self.gpa.free(rhs); self.gpa.free(rhs);
@ -797,6 +864,47 @@ impl<'a> Codegen<'a> {
TypeKind::Pointer(ty as Type).encode() TypeKind::Pointer(ty as Type).encode()
} }
fn make_loc_owned(&mut self, loc: Loc, ty: Type) -> Loc {
match loc {
Loc::RegRef(rreg) => {
let reg = self.gpa.allocate();
self.code.encode(instrs::cp(reg.0, rreg));
Loc::Reg(reg)
}
Loc::Imm(imm) => {
let reg = self.gpa.allocate();
self.code.encode(instrs::li64(reg.0, imm));
Loc::Reg(reg)
}
Loc::StackRef(mut off) => {
let size = self.size_of(ty);
assert!(size % 8 == 0, "TODO: implement other sizes");
let stack = self.alloc_stack(size as u32);
let reg = self.gpa.allocate();
while size > 0 {
self.load_stack(reg.0, off, 8);
self.store_stack(reg.0, stack, 8);
off += 8;
}
self.gpa.free(reg);
Loc::Stack(stack)
}
l => l,
}
}
fn ensure_spilled(&mut self, loc: Loc) -> Loc {
match loc {
Loc::Reg(reg) => {
let stack = self.alloc_stack(8);
self.store_stack(reg.0, stack, 8);
self.gpa.free(reg);
Loc::Stack(stack)
}
l => l,
}
}
} }
pub struct Value { pub struct Value {
@ -811,13 +919,14 @@ enum Loc {
Deref(LinReg), Deref(LinReg),
Imm(u64), Imm(u64),
Stack(u64), Stack(u64),
StackRef(u64),
} }
impl Loc { impl Loc {
fn take_ref(&self) -> Loc { fn take_ref(&self) -> Loc {
match self { match self {
Self::Reg(reg) => Self::RegRef(reg.0), Self::Reg(reg) => Self::RegRef(reg.0),
Self::Stack(off) => Self::Stack(*off), Self::Stack(off) => Self::StackRef(*off),
_ => unreachable!(), un => unreachable!("{:?}", un),
} }
} }
} }

View file

@ -239,7 +239,7 @@ impl<'a, 'b> Parser<'a, 'b> {
}), }),
}, },
T::Dot => E::Field { T::Dot => E::Field {
ty: self.arena.alloc(expr), target: self.arena.alloc(expr),
field: { field: {
let token = self.expect_advance(T::Ident); let token = self.expect_advance(T::Ident);
self.lexer.slice(token.range()) self.lexer.slice(token.range())
@ -396,7 +396,7 @@ pub enum Expr<'a> {
fields: &'a [(&'a str, Self)], fields: &'a [(&'a str, Self)],
}, },
Field { Field {
ty: &'a Self, target: &'a Self,
field: &'a str, field: &'a str,
}, },
} }
@ -408,7 +408,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
} }
match *self { match *self {
Self::Field { ty, field } => write!(f, "{}.{}", ty, field), Self::Field { target, field } => write!(f, "{}.{}", target, field),
Self::Struct { fields, .. } => { Self::Struct { fields, .. } => {
write!(f, "struct {{")?; write!(f, "struct {{")?;
let first = &mut true; let first = &mut true;

Binary file not shown.

View file

@ -0,0 +1,2 @@
ret: 3
status: Ok(())