finishing structures

This commit is contained in:
mlokr 2024-05-12 20:10:50 +02:00
parent bc59886428
commit d5a5c932e7
4 changed files with 253 additions and 94 deletions

View file

@ -3,7 +3,19 @@ Ty := struct {
b: int, b: int,
} }
main := fn(): int { Ty2 := struct {
inst := Ty.{ a: 1, b: 2 }; ty: Ty,
return inst.a + inst.b; c: int,
}
main := fn(): int {
inst := Ty2.{ ty: Ty.{ a: 4, b: 1 }, c: 3 };
if inst.c == 3 {
return pass(inst.ty);
}
return 0;
}
pass := fn(t: Ty): int {
return t.a - t.b;
} }

View file

@ -1,3 +1,5 @@
use std::ops::Range;
use crate::ident::Ident; use crate::ident::Ident;
use { use {
@ -134,6 +136,13 @@ impl Func {
); );
self.code.extend_from_slice(&instr[..len]); self.code.extend_from_slice(&instr[..len]);
} }
// ---- 0 24 bottom
// | 3
// ---- 8 16
// | 2
// ---- 16 8
// | 1
// ---- 24 0 top
fn push(&mut self, value: Reg, size: usize) { fn push(&mut self, value: Reg, size: usize) {
self.subi64(STACK_PTR, STACK_PTR, size as _); self.subi64(STACK_PTR, STACK_PTR, size as _);
@ -225,6 +234,10 @@ impl RegAlloc {
self.free.push(reg.0); self.free.push(reg.0);
std::mem::forget(reg); std::mem::forget(reg);
} }
fn prepare_call(&mut self) {
self.free.extend((2..=11).rev());
}
} }
struct FnLabel { struct FnLabel {
@ -256,39 +269,37 @@ struct Struct {
} }
pub struct Codegen<'a> { pub struct Codegen<'a> {
path: &'a std::path::Path, path: &'a std::path::Path,
ret: Type, ret: Type,
gpa: RegAlloc, gpa: RegAlloc,
code: Func, code: Func,
temp: Func, temp: Func,
labels: Vec<FnLabel>, labels: Vec<FnLabel>,
stack_size: u64, stack_size: u64,
vars: Vec<Variable>, vars: Vec<Variable>,
stack_relocs: Vec<StackReloc>,
ret_relocs: Vec<RetReloc>, ret_relocs: Vec<RetReloc>,
loops: Vec<Loop>, loops: Vec<Loop>,
records: Vec<Struct>, records: Vec<Struct>,
pointers: Vec<Type>, pointers: Vec<Type>,
main: Option<LabelId>, main: Option<LabelId>,
} }
impl<'a> Codegen<'a> { impl<'a> Codegen<'a> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
path: std::path::Path::new(""), path: std::path::Path::new(""),
ret: bt::VOID, ret: bt::VOID,
gpa: Default::default(), gpa: Default::default(),
code: Default::default(), code: Default::default(),
temp: Default::default(), temp: Default::default(),
labels: Default::default(), labels: Default::default(),
stack_size: 0, stack_size: 0,
vars: Default::default(), vars: Default::default(),
stack_relocs: Default::default(),
ret_relocs: Default::default(), ret_relocs: Default::default(),
loops: Default::default(), loops: Default::default(),
records: Default::default(), records: Default::default(),
pointers: Default::default(), pointers: Default::default(),
main: None, main: None,
} }
} }
@ -334,6 +345,11 @@ impl<'a> Codegen<'a> {
self.gpa.free(dreg); self.gpa.free(dreg);
reg reg
} }
Loc::DerefRef(dreg) => {
let reg = self.gpa.allocate();
self.code.encode(instrs::ld(reg.0, dreg, 0, 8));
reg
}
Loc::Imm(imm) => { Loc::Imm(imm) => {
let reg = self.gpa.allocate(); let reg = self.gpa.allocate();
self.code.encode(instrs::li64(reg.0, imm)); self.code.encode(instrs::li64(reg.0, imm));
@ -349,35 +365,19 @@ impl<'a> Codegen<'a> {
fn alloc_stack(&mut self, size: u32) -> u64 { fn alloc_stack(&mut self, size: u32) -> u64 {
let offset = self.stack_size; let offset = self.stack_size;
log::dbg!("alloc_stack: {} {}", offset, size);
self.stack_size += size as u64; self.stack_size += size as u64;
offset offset
} }
fn store_stack(&mut self, reg: Reg, offset: u64, size: u16) { fn store_stack(&mut self, reg: Reg, offset: u64, size: u16) {
self.stack_relocs.push(StackReloc {
offset: self.code.code.len() as u32 + 3,
size,
});
self.code.encode(instrs::st(reg, STACK_PTR, offset, size)); self.code.encode(instrs::st(reg, STACK_PTR, offset, size));
} }
fn load_stack(&mut self, reg: Reg, offset: u64, size: u16) { fn load_stack(&mut self, reg: Reg, offset: u64, size: u16) {
self.stack_relocs.push(StackReloc {
offset: self.code.code.len() as u32 + 3,
size,
});
self.code.encode(instrs::ld(reg, STACK_PTR, offset, size)); self.code.encode(instrs::ld(reg, STACK_PTR, offset, size));
} }
fn reloc_stack(&mut self) {
for reloc in self.stack_relocs.drain(..) {
let dest = &mut self.code.code[reloc.offset as usize..][..reloc.size as usize];
let value = u64::from_ne_bytes(dest.try_into().unwrap());
let offset = self.stack_size - value;
dest.copy_from_slice(&offset.to_ne_bytes());
}
}
fn reloc_rets(&mut self) { fn reloc_rets(&mut self) {
let len = self.code.code.len() as i32; let len = self.code.code.len() as i32;
for reloc in self.ret_relocs.drain(..) { for reloc in self.ret_relocs.drain(..) {
@ -411,18 +411,24 @@ impl<'a> Codegen<'a> {
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::Bool { value, .. } => Some(Value {
ty: bt::BOOL,
loc: Loc::Imm(value as u64),
}),
E::Ctor { ty, fields } => { E::Ctor { ty, fields } => {
let ty = self.ty(&ty); let ty = self.ty(&ty);
let TypeKind::Struct(idx) = TypeKind::from_ty(ty) else { let TypeKind::Struct(idx) = TypeKind::from_ty(ty) else {
panic!("expected struct, got {:?}", ty); panic!("expected struct, got {:?}", ty);
}; };
let size = self.size_of(ty);
let stack = self.alloc_stack(size as u32);
let mut field_values = fields let mut field_values = fields
.iter() .iter()
.map(|(name, field)| self.expr(field, None).map(|v| (*name, v))) .map(|(name, field)| self.expr(field, None).map(|v| (*name, v)))
.collect::<Option<Vec<_>>>()?; .collect::<Option<Vec<_>>>()?;
let size = self.size_of(ty);
let stack = self.alloc_stack(size as u32);
let decl_fields = self.records[idx as usize].fields.clone(); let decl_fields = self.records[idx as usize].fields.clone();
let mut offset = 0; let mut offset = 0;
for (name, ty) in decl_fields.as_ref() { for (name, ty) in decl_fields.as_ref() {
@ -434,10 +440,15 @@ impl<'a> Codegen<'a> {
if value.ty != *ty { if value.ty != *ty {
panic!("expected {:?}, got {:?}", ty, value.ty); panic!("expected {:?}, got {:?}", ty, value.ty);
} }
let reg = self.loc_to_reg(value.loc); log::dbg!("ctor: {} {} {:?}", stack, offset, value.loc);
self.store_stack(reg.0, stack + offset, 8); self.assign(
self.gpa.free(reg); Value {
offset += 8; ty: value.ty,
loc: Loc::Stack(stack + offset),
},
value,
);
offset += self.size_of(*ty);
} }
Some(Value { Some(Value {
ty, ty,
@ -454,18 +465,25 @@ impl<'a> Codegen<'a> {
.iter() .iter()
.position(|(name, _)| name.as_ref() == field) .position(|(name, _)| name.as_ref() == field)
.unwrap(); .unwrap();
let size = self.size_of(decl_fields[index].1); let offset = decl_fields[..index]
assert_eq!(size, 8, "TODO: implement other sizes"); .iter()
.map(|(_, ty)| self.size_of(*ty))
.sum::<u64>();
let value = match target.loc { let value = match target.loc {
Loc::Reg(_) => todo!(), Loc::Reg(_) => todo!(),
Loc::RegRef(_) => todo!(), Loc::RegRef(_) => todo!(),
Loc::Deref(r) => { Loc::Deref(r) => {
self.code.encode(instrs::addi64(r.0, r.0, index as u64 * 8)); self.code.encode(instrs::addi64(r.0, r.0, offset));
Loc::Deref(r) Loc::Deref(r)
} }
Loc::DerefRef(r) => {
let reg = self.gpa.allocate();
self.code.encode(instrs::addi64(reg.0, r, offset));
Loc::Deref(reg)
}
Loc::Imm(_) => todo!(), Loc::Imm(_) => todo!(),
Loc::Stack(stack) => Loc::Stack(stack + index as u64 * 8), Loc::Stack(stack) => Loc::Stack(stack + offset),
Loc::StackRef(stack) => Loc::StackRef(stack + index as u64 * 8), Loc::StackRef(stack) => Loc::StackRef(stack + offset),
}; };
Some(Value { Some(Value {
ty: decl_fields[index].1, ty: decl_fields[index].1,
@ -491,10 +509,6 @@ impl<'a> Codegen<'a> {
match val.loc { match val.loc {
Loc::StackRef(off) => { Loc::StackRef(off) => {
let reg = self.gpa.allocate(); let reg = self.gpa.allocate();
self.stack_relocs.push(StackReloc {
offset: self.code.code.len() as u32 + 3,
size: 8,
});
self.code.encode(instrs::addi64(reg.0, STACK_PTR, off)); self.code.encode(instrs::addi64(reg.0, STACK_PTR, off));
Some(Value { Some(Value {
ty: self.alloc_pointer(val.ty), ty: self.alloc_pointer(val.ty),
@ -529,35 +543,36 @@ impl<'a> Codegen<'a> {
if *name == "main" { if *name == "main" {
self.main = Some(frame.label); self.main = Some(frame.label);
} }
log::dbg!("fn-args"); log::dbg!("fn-args");
for (i, arg) in args.iter().enumerate() { let mut parama = 2..12;
let offset = self.alloc_stack(8); for arg in args.iter() {
let ty = self.ty(&arg.ty); let ty = self.ty(&arg.ty);
let loc = self.load_arg(ty, &mut parama);
self.vars.push(Variable { self.vars.push(Variable {
id: arg.id, id: arg.id,
value: Value { value: Value { ty, loc },
ty,
loc: Loc::Stack(offset),
},
}); });
self.store_stack(i as Reg + 2, offset, 8);
} }
self.gpa.init_callee(); self.gpa.init_callee();
self.ret = self.ty(ret); self.ret = self.ty(ret);
log::dbg!("fn-body"); log::dbg!("fn-body");
if self.expr(body, None).is_some() { if self.expr(body, None).is_some() {
panic!("expected all paths in the fucntion {name} to return"); panic!("expected all paths in the fucntion {name} to return");
} }
self.vars.clear(); self.vars.clear();
log::dbg!("fn-prelude, stack: {:x}", self.stack_size);
log::dbg!("fn-relocs"); log::dbg!("fn-relocs");
self.reloc_stack();
log::dbg!("fn-prelude");
self.write_fn_prelude(frame); self.write_fn_prelude(frame);
log::dbg!("fn-ret"); log::dbg!("fn-ret");
self.reloc_rets(); self.reloc_rets();
self.ret(); self.ret();
self.stack_size = 0; self.stack_size = 0;
self.vars.clear();
Some(Value::VOID) Some(Value::VOID)
} }
E::BinOp { E::BinOp {
@ -578,11 +593,10 @@ impl<'a> Codegen<'a> {
func: E::Ident { id, .. }, func: E::Ident { id, .. },
args, args,
} => { } => {
for (i, arg) in args.iter().enumerate() { let mut parama = 2..12;
for arg in args.iter() {
let arg = self.expr(arg, None)?; let arg = self.expr(arg, None)?;
let reg = self.loc_to_reg(arg.loc); self.pass_arg(arg, &mut parama);
self.code.encode(instrs::cp(i as Reg + 2, reg.0));
self.gpa.free(reg);
} }
let func = self.get_or_reserve_label(*id); let func = self.get_or_reserve_label(*id);
self.code.call(func); self.code.call(func);
@ -784,21 +798,60 @@ impl<'a> Codegen<'a> {
} }
} }
fn assign(&mut self, left: Value, right: Value) -> Option<Value> { fn assign(&mut self, right: Value, left: Value) -> Option<Value> {
let rhs = self.loc_to_reg(right.loc); let size = self.size_of(left.ty);
match left.loc {
Loc::Deref(reg) => { match size {
self.code.encode(instrs::st(rhs.0, reg.0, 0, 8)); 8 => {
self.gpa.free(reg); let lhs = self.loc_to_reg(left.loc);
match right.loc {
Loc::Deref(reg) => {
self.code.encode(instrs::st(lhs.0, reg.0, 0, 8));
self.gpa.free(reg);
}
Loc::RegRef(reg) => self.code.encode(instrs::cp(reg, lhs.0)),
Loc::StackRef(offset) | Loc::Stack(offset) => {
self.store_stack(lhs.0, offset, 8)
}
l => unimplemented!("{:?}", l),
}
self.gpa.free(lhs);
} }
Loc::RegRef(reg) => self.code.encode(instrs::cp(reg, rhs.0)), 16..=u64::MAX => {
Loc::StackRef(offset) => self.store_stack(rhs.0, offset, 8), let rhs = self.loc_to_ptr(right.loc);
_ => unimplemented!(), let lhs = self.loc_to_ptr(left.loc);
let cp = self.gpa.allocate();
for offset in (0..size).step_by(8) {
self.code.encode(instrs::ld(cp.0, lhs.0, offset, 8));
self.code.encode(instrs::st(cp.0, rhs.0, offset, 8));
}
self.gpa.free(rhs);
self.gpa.free(lhs);
self.gpa.free(cp);
}
s => unimplemented!("size: {}", s),
} }
self.gpa.free(rhs);
Some(Value::VOID) Some(Value::VOID)
} }
fn loc_to_ptr(&mut self, loc: Loc) -> LinReg {
match loc {
Loc::Deref(reg) => reg,
Loc::DerefRef(reg) => {
let dreg = self.gpa.allocate();
self.code.encode(instrs::cp(dreg.0, reg));
dreg
}
Loc::Stack(offset) | Loc::StackRef(offset) => {
let reg = self.gpa.allocate();
self.code.encode(instrs::addi64(reg.0, STACK_PTR, offset));
reg
}
l => panic!("expected stack location, got {:?}", l),
}
}
fn get_or_reserve_label(&mut self, name: Ident) -> LabelId { fn get_or_reserve_label(&mut self, name: Ident) -> LabelId {
if let Some(label) = self.labels.iter().position(|l| l.name == name) { if let Some(label) = self.labels.iter().position(|l| l.name == name) {
label as u32 label as u32
@ -897,23 +950,94 @@ impl<'a> Codegen<'a> {
self.code.encode(instrs::li64(reg.0, imm)); self.code.encode(instrs::li64(reg.0, imm));
Loc::Reg(reg) Loc::Reg(reg)
} }
Loc::StackRef(mut off) => { Loc::StackRef(off) => {
let size = self.size_of(ty); let size = self.size_of(ty);
assert!(size % 8 == 0, "TODO: implement other sizes");
let stack = self.alloc_stack(size as u32); let stack = self.alloc_stack(size as u32);
let reg = self.gpa.allocate(); self.assign(
while size > 0 { Value {
self.load_stack(reg.0, off, 8); ty,
self.store_stack(reg.0, stack, 8); loc: Loc::Stack(stack),
off += 8; },
} Value {
self.gpa.free(reg); ty,
loc: Loc::StackRef(off),
},
);
Loc::Stack(stack) Loc::Stack(stack)
} }
l => l, l => l,
} }
} }
fn pass_arg(&mut self, value: Value, parama: &mut Range<u8>) {
let size = self.size_of(value.ty);
let p = parama.next().unwrap() as Reg;
if size > 16 {
let (Loc::Stack(stack) | Loc::StackRef(stack)) = value.loc else {
panic!("expected stack location, got {:?}", value.loc);
};
self.code.encode(instrs::addi64(p, STACK_PTR, stack));
}
match value.loc {
Loc::Reg(reg) => {
self.code.encode(instrs::cp(p, reg.0));
self.gpa.free(reg);
}
Loc::RegRef(reg) => {
self.code.encode(instrs::cp(p, reg));
}
Loc::Deref(reg) => {
self.code.encode(instrs::ld(p, reg.0, 0, size as _));
self.gpa.free(reg);
}
Loc::DerefRef(reg) => {
self.code.encode(instrs::ld(p, reg, 0, size as _));
}
Loc::Imm(imm) => {
self.code.encode(instrs::li64(p, imm));
}
Loc::Stack(stack) | Loc::StackRef(stack) => {
self.load_stack(p, stack, size as _);
self.load_stack(parama.next().unwrap(), stack + 8, size as _);
}
}
}
fn load_arg(&mut self, ty: Type, parama: &mut Range<u8>) -> Loc {
let size = self.size_of(ty);
match size {
8 => {
let stack = self.alloc_stack(8);
self.store_stack(parama.next().unwrap(), stack, 8);
Loc::Stack(stack)
}
16 => {
let stack = self.alloc_stack(16);
self.store_stack(parama.next().unwrap(), stack, 8);
self.store_stack(parama.next().unwrap(), stack + 8, 8);
Loc::Stack(stack)
}
24..=u64::MAX => {
let ptr = parama.next().unwrap();
let stack = self.alloc_stack(size as u32);
self.assign(
Value {
ty,
loc: Loc::StackRef(stack),
},
Value {
ty,
loc: Loc::DerefRef(ptr),
},
);
Loc::Stack(stack)
}
blah => todo!("{blah:?}"),
}
}
fn ensure_spilled(&mut self, loc: Loc) -> Loc { fn ensure_spilled(&mut self, loc: Loc) -> Loc {
match loc { match loc {
Loc::Reg(reg) => { Loc::Reg(reg) => {
@ -944,6 +1068,7 @@ enum Loc {
Reg(LinReg), Reg(LinReg),
RegRef(Reg), RegRef(Reg),
Deref(LinReg), Deref(LinReg),
DerefRef(Reg),
Imm(u64), Imm(u64),
Stack(u64), Stack(u64),
StackRef(u64), StackRef(u64),
@ -976,7 +1101,7 @@ mod tests {
"read: {:x} {} {:?}", "read: {:x} {} {:?}",
addr.get(), addr.get(),
count, count,
core::slice::from_raw_parts(target, count) core::slice::from_raw_parts(addr.get() as *const u8, count)
.iter() .iter()
.rev() .rev()
.skip_while(|&&b| b == 0) .skip_while(|&&b| b == 0)
@ -994,7 +1119,17 @@ mod tests {
source: *const u8, source: *const u8,
count: usize, count: usize,
) -> Result<(), hbvm::mem::StoreError> { ) -> Result<(), hbvm::mem::StoreError> {
log::dbg!("write: {:x} {}", addr.get(), count); log::dbg!(
"write: {:x} {} {:?}",
addr.get(),
count,
core::slice::from_raw_parts(source, count)
.iter()
.rev()
.skip_while(|&&b| b == 0)
.map(|&b| format!("{:02x}", b))
.collect::<String>()
);
unsafe { core::ptr::copy(source, addr.get() as *mut u8, count) } unsafe { core::ptr::copy(source, addr.get() as *mut u8, count) }
Ok(()) Ok(())
} }

View file

@ -92,6 +92,7 @@ gen_token_kind! {
Continue = b"continue", Continue = b"continue",
Fn = b"fn", Fn = b"fn",
Struct = b"struct", Struct = b"struct",
True = b"true",
#[punkt] #[punkt]
LParen = "(", LParen = "(",
RParen = ")", RParen = ")",

View file

@ -96,6 +96,8 @@ impl<'a, 'b> Parser<'a, 'b> {
Some(match name { Some(match name {
"int" => bt::INT, "int" => bt::INT,
"bool" => bt::BOOL, "bool" => bt::BOOL,
"void" => bt::VOID,
"never" => bt::NEVER,
_ => return None, _ => return None,
}) })
} }
@ -139,6 +141,10 @@ impl<'a, 'b> Parser<'a, 'b> {
let frame = self.idents.len(); let frame = self.idents.len();
let token = self.next(); let token = self.next();
let mut expr = match token.kind { let mut expr = match token.kind {
T::True => E::Bool {
pos: token.start,
value: true,
},
T::Struct => E::Struct { T::Struct => E::Struct {
pos: token.start, pos: token.start,
fields: { fields: {
@ -399,6 +405,10 @@ pub enum Expr<'a> {
target: &'a Self, target: &'a Self,
field: &'a str, field: &'a str,
}, },
Bool {
pos: u32,
value: bool,
},
} }
impl<'a> std::fmt::Display for Expr<'a> { impl<'a> std::fmt::Display for Expr<'a> {
@ -488,6 +498,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
res res
} }
Self::Number { value, .. } => write!(f, "{}", value), Self::Number { value, .. } => write!(f, "{}", value),
Self::Bool { value, .. } => write!(f, "{}", value),
Self::BinOp { left, right, op } => { Self::BinOp { left, right, op } => {
let display_branch = |f: &mut std::fmt::Formatter, expr: &Self| { let display_branch = |f: &mut std::fmt::Formatter, expr: &Self| {
if let Self::BinOp { op: lop, .. } = expr if let Self::BinOp { op: lop, .. } = expr