painfully, but suddle bugs with pointers are now fixed

This commit is contained in:
mlokr 2024-05-14 15:03:36 +02:00
parent 9aa5da82c9
commit d8a922df26
3 changed files with 148 additions and 145 deletions

View file

@ -1,4 +1,7 @@
use std::{cell::Cell, ops::Range}; use std::{
cell::{Cell, RefCell},
ops::Range,
};
use crate::ident::{self, Ident}; use crate::ident::{self, Ident};
@ -22,39 +25,61 @@ fn align_up(value: u64, align: u64) -> u64 {
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
struct LinReg(Reg); struct LinReg(Reg, Rc<RefCell<RegAlloc>>);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
impl Drop for LinReg { impl Drop for LinReg {
fn drop(&mut self) { fn drop(&mut self) {
if !std::thread::panicking() { self.1.borrow_mut().free(self.0);
panic!("reg leaked: {:x}", self.0);
}
} }
} }
#[derive(Debug, PartialEq, Eq)] struct Stack {
struct LinStack {
offset: u64, offset: u64,
size: u64, size: u64,
alloc: Cell<Option<Rc<RefCell<StackAlloc>>>>,
} }
impl Drop for LinStack { impl std::fmt::Debug for Stack {
fn drop(&mut self) { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if !std::thread::panicking() { f.debug_struct("Stack")
panic!("stack leaked: {:x} {:x}", self.offset, self.size); .field("offset", &self.offset)
} .field("size", &self.size)
.finish()
} }
} }
#[derive(Default)] impl PartialEq for Stack {
fn eq(&self, other: &Self) -> bool {
self.offset == other.offset && self.size == other.size
}
}
impl Eq for Stack {}
impl Stack {
fn leak(&self) {
self.alloc.set(None);
}
}
impl Drop for Stack {
fn drop(&mut self) {
self.alloc
.get_mut()
.as_mut()
.map(|f| f.borrow_mut().free(self.offset, self.size));
}
}
#[derive(Default, PartialEq, Eq, Debug)]
struct StackAlloc { struct StackAlloc {
ranges: Vec<Range<u64>>, ranges: Vec<Range<u64>>,
height: u64, height: u64,
} }
impl StackAlloc { impl StackAlloc {
fn alloc(&mut self, size: u64) -> LinStack { fn alloc(&mut self, size: u64) -> (u64, u64) {
if let Some((index, range)) = self if let Some((index, range)) = self
.ranges .ranges
.iter_mut() .iter_mut()
@ -67,17 +92,15 @@ impl StackAlloc {
if range.start == range.end { if range.start == range.end {
self.ranges.swap_remove(index); self.ranges.swap_remove(index);
} }
return LinStack { offset, size }; return (offset, size);
} }
let offset = self.height; let offset = self.height;
self.height += size; self.height += size;
LinStack { offset, size } (offset, size)
} }
fn free(&mut self, l @ LinStack { offset, size }: LinStack) { fn free(&mut self, offset: u64, size: u64) {
std::mem::forget(l);
let range = offset..offset + size; let range = offset..offset + size;
// FIXME: we do more wor then we need to, rather we keep the sequence sorted and only scan // FIXME: we do more wor then we need to, rather we keep the sequence sorted and only scan
// element before and after the modified range // element before and after the modified range
@ -339,7 +362,7 @@ impl Func {
} }
} }
#[derive(Default)] #[derive(Default, PartialEq, Eq, Debug)]
pub struct RegAlloc { pub struct RegAlloc {
free: Vec<Reg>, free: Vec<Reg>,
max_used: Reg, max_used: Reg,
@ -352,15 +375,14 @@ impl RegAlloc {
self.max_used = RET_ADDR; self.max_used = RET_ADDR;
} }
fn allocate(&mut self) -> LinReg { fn allocate(&mut self) -> Reg {
let reg = self.free.pop().expect("TODO: we need to spill"); let reg = self.free.pop().expect("TODO: we need to spill");
self.max_used = self.max_used.max(reg); self.max_used = self.max_used.max(reg);
LinReg(reg) reg
} }
fn free(&mut self, reg: LinReg) { fn free(&mut self, reg: Reg) {
self.free.push(reg.0); self.free.push(reg);
std::mem::forget(reg);
} }
fn pushed_size(&self) -> usize { fn pushed_size(&self) -> usize {
@ -445,8 +467,8 @@ pub struct Codegen<'a> {
path: &'a str, path: &'a str,
input: &'a [u8], input: &'a [u8],
ret: Type, ret: Type,
gpa: RegAlloc, gpa: Rc<RefCell<RegAlloc>>,
sa: StackAlloc, sa: Rc<RefCell<StackAlloc>>,
code: Func, code: Func,
temp: Func, temp: Func,
labels: Vec<FnLabel>, labels: Vec<FnLabel>,
@ -530,18 +552,16 @@ impl<'a> Codegen<'a> {
}); });
} }
self.gpa.init_callee(); self.gpa.borrow_mut().init_callee();
self.ret = fn_label.ret; self.ret = fn_label.ret;
log::dbg!("fn-body"); log::dbg!("fn-body");
if self.expr(body).is_some() { if self.expr(body).is_some() {
self.report(body.pos(), "expected all paths in the fucntion to return"); self.report(body.pos(), "expected all paths in the fucntion to return");
} }
for var in std::mem::take(&mut self.vars) { self.vars.clear();
self.free_loc(var.value.loc);
}
log::dbg!("fn-prelude, stack: {:x}", self.sa.height); log::dbg!("fn-prelude, stack: {:x}", self.sa.borrow().height);
log::dbg!("fn-relocs"); log::dbg!("fn-relocs");
self.write_fn_prelude(frame); self.write_fn_prelude(frame);
@ -549,7 +569,7 @@ impl<'a> Codegen<'a> {
log::dbg!("fn-ret"); log::dbg!("fn-ret");
self.reloc_rets(); self.reloc_rets();
self.ret(); self.ret();
self.sa.clear(); self.sa.borrow_mut().clear();
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -626,35 +646,47 @@ impl<'a> Codegen<'a> {
} }
} }
fn alloc_reg(&mut self) -> LinReg {
LinReg(self.gpa.borrow_mut().allocate(), self.gpa.clone()).into()
}
fn alloc_stack(&mut self, size: u64) -> Rc<Stack> {
let (offset, size) = self.sa.borrow_mut().alloc(size);
Stack {
offset,
size,
alloc: Cell::new(Some(self.sa.clone())),
}
.into()
}
fn loc_to_reg(&mut self, loc: Loc, size: u64) -> LinReg { fn loc_to_reg(&mut self, loc: Loc, size: u64) -> LinReg {
match loc { match loc {
Loc::RegRef(rr) => { Loc::RegRef(rr) => {
let reg = self.gpa.allocate(); let reg = self.alloc_reg();
self.code.encode(instrs::cp(reg.0, rr)); self.code.encode(instrs::cp(reg.0, rr));
reg reg
} }
Loc::Reg(reg) => reg, Loc::Reg(reg) => reg,
Loc::Deref(dreg, offset) => { Loc::Deref(dreg, .., offset) => {
let reg = self.gpa.allocate(); let reg = self.alloc_reg();
self.code self.code
.encode(instrs::ld(reg.0, dreg.0, offset, size as _)); .encode(instrs::ld(reg.0, dreg.0, offset, size as _));
self.free_reg(dreg);
reg reg
} }
Loc::DerefRef(dreg, offset) => { Loc::DerefRef(dreg, .., offset) => {
let reg = self.gpa.allocate(); let reg = self.alloc_reg();
self.code.encode(instrs::ld(reg.0, dreg, offset, size as _)); self.code.encode(instrs::ld(reg.0, dreg, offset, size as _));
reg reg
} }
Loc::Imm(imm) => { Loc::Imm(imm) => {
let reg = self.gpa.allocate(); let reg = self.alloc_reg();
self.code.encode(instrs::li64(reg.0, imm)); self.code.encode(instrs::li64(reg.0, imm));
reg reg
} }
Loc::Stack(stack, off) => { Loc::Stack(stack, off) => {
let reg = self.gpa.allocate(); let reg = self.alloc_reg();
self.load_stack(reg.0, stack.offset + off, size as _); self.load_stack(reg.0, stack.offset + off, size as _);
self.sa.free(stack);
reg reg
} }
} }
@ -718,7 +750,7 @@ impl<'a> Codegen<'a> {
let loc = match ctx { let loc = match ctx {
Ctx::Dest(dest) => dest.loc, Ctx::Dest(dest) => dest.loc,
_ => Loc::Stack(self.sa.alloc(size), 0), _ => Loc::Stack(self.alloc_stack(size), 0),
}; };
let stuct = self.unwrap_struct(ty, pos, "struct literal"); let stuct = self.unwrap_struct(ty, pos, "struct literal");
@ -743,9 +775,12 @@ impl<'a> Codegen<'a> {
if let TypeKind::Pointer(ty) = TypeKind::from_ty(tal.ty) { if let TypeKind::Pointer(ty) = TypeKind::from_ty(tal.ty) {
tal.ty = self.pointers[ty as usize]; tal.ty = self.pointers[ty as usize];
tal.loc = match tal.loc { tal.loc = match tal.loc {
Loc::Reg(r) => Loc::Deref(r, 0), Loc::Reg(r) => Loc::Deref(r, None, 0),
Loc::RegRef(r) => Loc::DerefRef(r, 0), Loc::RegRef(r) => Loc::DerefRef(r, None, 0),
l => Loc::Deref(self.loc_to_reg(l, 8), 0), l => {
let ptr = self.loc_to_reg(l, 8);
Loc::Deref(ptr, None, 0)
}
}; };
} }
let (offset, ty) = self.offset_of(target.pos(), tal.ty, Ok(field)); let (offset, ty) = self.offset_of(target.pos(), tal.ty, Ok(field));
@ -759,20 +794,22 @@ impl<'a> Codegen<'a> {
} => { } => {
let val = self.expr(val)?; let val = self.expr(val)?;
let loc = match val.loc { let loc = match val.loc {
Loc::Deref(r, off) => { Loc::Deref(r, stack, off) => {
stack.map(|stack| stack.leak());
self.code.addi64(r.0, r.0, off); self.code.addi64(r.0, r.0, off);
Loc::Reg(r) Loc::Reg(r)
} }
Loc::DerefRef(r, off) => { Loc::DerefRef(r, stack, off) => {
let reg = self.gpa.allocate(); stack.map(|stack| stack.leak());
let reg = self.alloc_reg();
self.code.addi64(reg.0, r, off); self.code.addi64(reg.0, r, off);
Loc::Reg(reg) Loc::Reg(reg)
} }
Loc::Stack(stack, off) => { Loc::Stack(stack, off) => {
let reg = self.gpa.allocate(); stack.leak();
let reg = self.alloc_reg();
self.code self.code
.encode(instrs::addi64(reg.0, STACK_PTR, stack.offset + off)); .encode(instrs::addi64(reg.0, STACK_PTR, stack.offset + off));
std::mem::forget(stack); // TODO: we might be able to do better
Loc::Reg(reg) Loc::Reg(reg)
} }
l => self.report( l => self.report(
@ -791,11 +828,10 @@ impl<'a> Codegen<'a> {
pos, pos,
} => { } => {
let val = self.expr(val)?; let val = self.expr(val)?;
let reg = self.loc_to_reg(val.loc, self.size_of(val.ty));
match TypeKind::from_ty(val.ty) { match TypeKind::from_ty(val.ty) {
TypeKind::Pointer(ty) => Some(Value { TypeKind::Pointer(ty) => Some(Value {
ty: self.pointers[ty as usize], ty: self.pointers[ty as usize],
loc: Loc::Deref(reg, 0), loc: Loc::Deref(self.loc_to_reg(val.loc, self.size_of(val.ty)), None, 0),
}), }),
_ => self.report( _ => self.report(
pos, pos,
@ -813,9 +849,8 @@ impl<'a> Codegen<'a> {
let loc = match loc { let loc = match loc {
Loc::Reg(r) => { Loc::Reg(r) => {
let size = self.size_of(val.ty); let size = self.size_of(val.ty);
let stack = self.sa.alloc(size); let stack = self.alloc_stack(size);
self.store_stack(r.0, stack.offset, size as _); self.store_stack(r.0, stack.offset, size as _);
self.free_reg(r);
Loc::Stack(stack, 0) Loc::Stack(stack, 0)
} }
l => l, l => l,
@ -841,10 +876,7 @@ impl<'a> Codegen<'a> {
self.pass_arg(&arg, &mut parama); self.pass_arg(&arg, &mut parama);
values.push(arg.loc); values.push(arg.loc);
} }
drop(values);
for value in values {
self.free_loc(value);
}
let size = self.size_of(fn_label.ret); let size = self.size_of(fn_label.ret);
let loc = match size { let loc = match size {
@ -852,12 +884,12 @@ impl<'a> Codegen<'a> {
..=8 => Loc::RegRef(1), ..=8 => Loc::RegRef(1),
..=16 => match ctx { ..=16 => match ctx {
Ctx::Dest(dest) => dest.loc, Ctx::Dest(dest) => dest.loc,
_ => Loc::Stack(self.sa.alloc(size), 0), _ => Loc::Stack(self.alloc_stack(size), 0),
}, },
..=u64::MAX => { ..=u64::MAX => {
let val = match ctx { let val = match ctx {
Ctx::Dest(dest) => dest.loc, Ctx::Dest(dest) => dest.loc,
_ => Loc::Stack(self.sa.alloc(size), 0), _ => Loc::Stack(self.alloc_stack(size), 0),
}; };
let (ptr, off) = val.ref_to_ptr(); let (ptr, off) = val.ref_to_ptr();
self.code.encode(instrs::cp(1, ptr)); self.code.encode(instrs::cp(1, ptr));
@ -910,7 +942,7 @@ impl<'a> Codegen<'a> {
let loc = match size { let loc = match size {
0 => Loc::Imm(0), 0 => Loc::Imm(0),
..=16 => Loc::RegRef(1), ..=16 => Loc::RegRef(1),
_ => Loc::DerefRef(1, 0), _ => Loc::DerefRef(1, None, 0),
}; };
self.expr_ctx(val, Ctx::Dest(Value { loc, ty: self.ret }))?; self.expr_ctx(val, Ctx::Dest(Value { loc, ty: self.ret }))?;
} }
@ -924,9 +956,7 @@ impl<'a> Codegen<'a> {
} }
E::Block { stmts, .. } => { E::Block { stmts, .. } => {
for stmt in stmts { for stmt in stmts {
if let Loc::Reg(reg) = self.expr(stmt)?.loc { self.expr(stmt)?;
self.free_reg(reg);
}
} }
Some(Value::VOID) Some(Value::VOID)
} }
@ -942,7 +972,6 @@ impl<'a> Codegen<'a> {
let reg = self.loc_to_reg(cond.loc, 1); let reg = self.loc_to_reg(cond.loc, 1);
let jump_offset = self.code.code.len() as u32; let jump_offset = self.code.code.len() as u32;
self.code.encode(instrs::jeq(reg.0, 0, 0)); self.code.encode(instrs::jeq(reg.0, 0, 0));
self.free_reg(reg);
log::dbg!("if-then"); log::dbg!("if-then");
let then_unreachable = self.expr(then).is_none(); let then_unreachable = self.expr(then).is_none();
@ -1007,13 +1036,7 @@ impl<'a> Codegen<'a> {
dest.copy_from_slice(&offset.to_ne_bytes()); dest.copy_from_slice(&offset.to_ne_bytes());
} }
for var in self self.vars.drain(loop_.var_count as usize..);
.vars
.drain(loop_.var_count as usize..)
.collect::<Vec<_>>()
{
self.free_loc(var.value.loc);
}
if is_unreachable { if is_unreachable {
log::dbg!("infinite loop"); log::dbg!("infinite loop");
@ -1100,7 +1123,6 @@ impl<'a> Codegen<'a> {
if let Some(op) = Self::math_op(op, signed, size) { if let Some(op) = Self::math_op(op, signed, size) {
self.code.encode(op(lhs.0, lhs.0, rhs.0)); self.code.encode(op(lhs.0, lhs.0, rhs.0));
self.free_reg(rhs);
break 'ops Some(Value { break 'ops Some(Value {
ty, ty,
@ -1118,7 +1140,6 @@ impl<'a> Codegen<'a> {
let op_fn = if signed { i::cmps } else { i::cmpu }; let op_fn = if signed { i::cmps } else { i::cmpu };
self.code.encode(op_fn(lhs.0, lhs.0, rhs.0)); self.code.encode(op_fn(lhs.0, lhs.0, rhs.0));
self.free_reg(rhs);
self.code.encode(instrs::cmpui(lhs.0, lhs.0, against)); self.code.encode(instrs::cmpui(lhs.0, lhs.0, against));
if matches!(op, T::Eq | T::Lt | T::Gt) { if matches!(op, T::Eq | T::Lt | T::Gt) {
self.code.encode(instrs::not(lhs.0, lhs.0)); self.code.encode(instrs::not(lhs.0, lhs.0));
@ -1143,10 +1164,6 @@ impl<'a> Codegen<'a> {
} }
} }
fn free_reg(&mut self, reg: LinReg) {
self.gpa.free(reg);
}
fn math_op( fn math_op(
op: T, op: T,
signed: bool, signed: bool,
@ -1175,20 +1192,11 @@ impl<'a> Codegen<'a> {
) )
} }
fn free_loc(&mut self, loc: Loc) {
match loc {
Loc::Reg(reg) => self.free_reg(reg),
Loc::Deref(reg, ..) => self.free_reg(reg),
Loc::Stack(stack, ..) => self.sa.free(stack),
_ => {}
}
}
fn struct_op(&mut self, op: T, ty: Type, ctx: Ctx, left: Loc, right: Loc) -> Option<Value> { fn struct_op(&mut self, op: T, ty: Type, ctx: Ctx, left: Loc, right: Loc) -> Option<Value> {
if let TypeKind::Struct(stuct) = TypeKind::from_ty(ty) { if let TypeKind::Struct(stuct) = TypeKind::from_ty(ty) {
let dst = match ctx { let dst = match ctx {
Ctx::Dest(dest) => dest.loc, Ctx::Dest(dest) => dest.loc,
_ => Loc::Stack(self.sa.alloc(self.size_of(ty)), 0), _ => Loc::Stack(self.alloc_stack(self.size_of(ty)), 0),
}; };
let mut offset = 0; let mut offset = 0;
for &(_, ty) in self.records[stuct as usize].fields.clone().iter() { for &(_, ty) in self.records[stuct as usize].fields.clone().iter() {
@ -1198,14 +1206,10 @@ impl<'a> Codegen<'a> {
let ctx = Ctx::Dest(Value::new(ty, dst.offset_ref(offset))); let ctx = Ctx::Dest(Value::new(ty, dst.offset_ref(offset)));
let left = left.offset_ref(offset); let left = left.offset_ref(offset);
let right = right.offset_ref(offset); let right = right.offset_ref(offset);
let value = self.struct_op(op, ty, ctx, left, right)?; self.struct_op(op, ty, ctx, left, right)?;
self.free_loc(value.loc);
offset += size; offset += size;
} }
self.free_loc(left);
self.free_loc(right);
return Some(Value { ty, loc: dst }); return Some(Value { ty, loc: dst });
} }
@ -1216,7 +1220,6 @@ impl<'a> Codegen<'a> {
if let Some(op) = Self::math_op(op, signed, size) { if let Some(op) = Self::math_op(op, signed, size) {
self.code.encode(op(lhs, lhs, rhs.0)); self.code.encode(op(lhs, lhs, rhs.0));
self.free_reg(rhs);
return if let Ctx::Dest(dest) = ctx { return if let Ctx::Dest(dest) = ctx {
self.assign(dest.ty, dest.loc, owned.map_or(Loc::RegRef(lhs), Loc::Reg)); self.assign(dest.ty, dest.loc, owned.map_or(Loc::RegRef(lhs), Loc::Reg));
Some(Value::VOID) Some(Value::VOID)
@ -1231,19 +1234,19 @@ impl<'a> Codegen<'a> {
fn loc_to_reg_ref(&mut self, loc: &Loc, size: u64) -> (u8, Option<LinReg>) { fn loc_to_reg_ref(&mut self, loc: &Loc, size: u64) -> (u8, Option<LinReg>) {
match *loc { match *loc {
Loc::RegRef(reg) => (reg, None), Loc::RegRef(reg) => (reg, None),
Loc::Reg(LinReg(reg)) => (reg, None), Loc::Reg(LinReg(reg, ..)) => (reg, None),
Loc::Deref(LinReg(reg), off) | Loc::DerefRef(reg, off) => { Loc::Deref(LinReg(reg, ..), .., off) | Loc::DerefRef(reg, .., off) => {
let new = self.gpa.allocate(); let new = self.alloc_reg();
self.code.encode(instrs::ld(new.0, reg, off, size as _)); self.code.encode(instrs::ld(new.0, reg, off, size as _));
(new.0, Some(new)) (new.0, Some(new))
} }
Loc::Stack(ref stack, off) => { Loc::Stack(ref stack, off) => {
let new = self.gpa.allocate(); let new = self.alloc_reg();
self.load_stack(new.0, stack.offset + off, size as _); self.load_stack(new.0, stack.offset + off, size as _);
(new.0, Some(new)) (new.0, Some(new))
} }
Loc::Imm(imm) => { Loc::Imm(imm) => {
let new = self.gpa.allocate(); let new = self.alloc_reg();
self.code.encode(instrs::li64(new.0, imm)); self.code.encode(instrs::li64(new.0, imm));
(new.0, Some(new)) (new.0, Some(new))
} }
@ -1279,34 +1282,27 @@ impl<'a> Codegen<'a> {
let lhs = self.loc_to_reg(left, size); let lhs = self.loc_to_reg(left, size);
match right { match right {
Loc::RegRef(reg) => self.code.encode(instrs::cp(reg, lhs.0)), Loc::RegRef(reg) => self.code.encode(instrs::cp(reg, lhs.0)),
Loc::Deref(reg, off) => { Loc::Deref(reg, .., off) => {
self.code.encode(instrs::st(lhs.0, reg.0, off, size as _)); self.code.encode(instrs::st(lhs.0, reg.0, off, size as _));
self.free_reg(reg);
} }
Loc::DerefRef(reg, off) => { Loc::DerefRef(reg, .., off) => {
self.code.encode(instrs::st(lhs.0, reg, off, size as _)); self.code.encode(instrs::st(lhs.0, reg, off, size as _));
} }
Loc::Stack(stack, off) => { Loc::Stack(stack, off) => {
self.store_stack(lhs.0, stack.offset + off, size as _); self.store_stack(lhs.0, stack.offset + off, size as _);
self.sa.free(stack);
} }
l => unimplemented!("{:?}", l), l => unimplemented!("{:?}", l),
} }
self.free_reg(lhs);
} }
..=16 if matches!(right, Loc::RegRef(1)) => { ..=16 if matches!(right, Loc::RegRef(1)) => {
let (lhs, loff) = left.ref_to_ptr(); let (lhs, loff) = left.ref_to_ptr();
self.code.encode(instrs::st(1, lhs, loff, 16)); self.code.encode(instrs::st(1, lhs, loff, 16));
self.free_loc(left);
} }
..=u64::MAX => { ..=u64::MAX => {
let rhs = self.to_ptr(right); let rhs = self.to_ptr(right);
let lhs = self.to_ptr(left); let lhs = self.to_ptr(left);
self.code self.code
.encode(instrs::bmc(lhs.0, rhs.0, size.try_into().unwrap())); .encode(instrs::bmc(lhs.0, rhs.0, size.try_into().unwrap()));
self.free_reg(lhs);
self.free_reg(rhs);
} }
} }
@ -1315,19 +1311,18 @@ impl<'a> Codegen<'a> {
fn to_ptr(&mut self, loc: Loc) -> LinReg { fn to_ptr(&mut self, loc: Loc) -> LinReg {
match loc { match loc {
Loc::Deref(reg, off) => { Loc::Deref(reg, .., off) => {
self.code.addi64(reg.0, reg.0, off); self.code.addi64(reg.0, reg.0, off);
reg reg
} }
Loc::DerefRef(reg, off) => { Loc::DerefRef(reg, .., off) => {
let new = self.gpa.allocate(); let new = self.alloc_reg();
self.code.addi64(new.0, reg, off); self.code.addi64(new.0, reg, off);
new new
} }
Loc::Stack(stack, off) => { Loc::Stack(stack, off) => {
let reg = self.gpa.allocate(); let reg = self.alloc_reg();
self.code.addi64(reg.0, STACK_PTR, stack.offset + off); self.code.addi64(reg.0, STACK_PTR, stack.offset + off);
self.sa.free(stack);
reg reg
} }
l => unreachable!("{:?}", l), l => unreachable!("{:?}", l),
@ -1337,14 +1332,14 @@ impl<'a> Codegen<'a> {
fn ensure_owned(&mut self, loc: Loc, ty: Type) -> Loc { fn ensure_owned(&mut self, loc: Loc, ty: Type) -> Loc {
match loc { match loc {
Loc::RegRef(reg) => { Loc::RegRef(reg) => {
let new = self.gpa.allocate(); let new = self.alloc_reg();
self.code.encode(instrs::cp(new.0, reg)); self.code.encode(instrs::cp(new.0, reg));
Loc::Reg(new) Loc::Reg(new)
} }
l => { l => {
let size = self.size_of(ty); let size = self.size_of(ty);
let stack = self.sa.alloc(size); let stack = self.alloc_stack(size);
self.assign(ty, Loc::DerefRef(STACK_PTR, stack.offset), l); self.assign(ty, Loc::DerefRef(STACK_PTR, None, stack.offset), l);
Loc::Stack(stack, 0) Loc::Stack(stack, 0)
} }
} }
@ -1376,8 +1371,9 @@ impl<'a> Codegen<'a> {
} }
fn write_fn_prelude(&mut self, frame: Frame) { fn write_fn_prelude(&mut self, frame: Frame) {
self.temp.push(RET_ADDR, self.gpa.pushed_size()); self.temp.push(RET_ADDR, self.gpa.borrow().pushed_size());
self.temp.subi64(STACK_PTR, STACK_PTR, self.sa.height); self.temp
.subi64(STACK_PTR, STACK_PTR, self.sa.borrow().height);
for reloc in &mut self.code.relocs[frame.prev_relocs..] { for reloc in &mut self.code.relocs[frame.prev_relocs..] {
reloc.offset += self.temp.code.len() as u32; reloc.offset += self.temp.code.len() as u32;
@ -1394,9 +1390,12 @@ impl<'a> Codegen<'a> {
} }
fn ret(&mut self) { fn ret(&mut self) {
self.code self.code.encode(instrs::addi64(
.encode(instrs::addi64(STACK_PTR, STACK_PTR, self.sa.height)); STACK_PTR,
self.code.pop(RET_ADDR, self.gpa.pushed_size()); STACK_PTR,
self.sa.borrow().height,
));
self.code.pop(RET_ADDR, self.gpa.borrow().pushed_size());
self.code.ret(); self.code.ret();
} }
@ -1426,19 +1425,19 @@ impl<'a> Codegen<'a> {
fn make_loc_owned(&mut self, loc: Loc, ty: Type) -> Loc { fn make_loc_owned(&mut self, loc: Loc, ty: Type) -> Loc {
match loc { match loc {
Loc::RegRef(rreg) => { Loc::RegRef(rreg) => {
let reg = self.gpa.allocate(); let reg = self.alloc_reg();
self.code.encode(instrs::cp(reg.0, rreg)); self.code.encode(instrs::cp(reg.0, rreg));
Loc::Reg(reg) Loc::Reg(reg)
} }
Loc::Imm(imm) => { Loc::Imm(imm) => {
let reg = self.gpa.allocate(); let reg = self.alloc_reg();
self.code.encode(instrs::li64(reg.0, imm)); self.code.encode(instrs::li64(reg.0, imm));
Loc::Reg(reg) Loc::Reg(reg)
} }
l @ (Loc::DerefRef(..) | Loc::Deref(..)) => { l @ (Loc::DerefRef(..) | Loc::Deref(..)) => {
let size = self.size_of(ty); let size = self.size_of(ty);
let stack = self.sa.alloc(size); let stack = self.alloc_stack(size);
self.assign(ty, Loc::DerefRef(STACK_PTR, stack.offset), l); self.assign(ty, Loc::DerefRef(STACK_PTR, None, stack.offset), l);
Loc::Stack(stack, 0) Loc::Stack(stack, 0)
} }
l => l, l => l,
@ -1462,10 +1461,10 @@ impl<'a> Codegen<'a> {
Loc::RegRef(reg) => { Loc::RegRef(reg) => {
self.code.encode(instrs::cp(p, reg)); self.code.encode(instrs::cp(p, reg));
} }
Loc::Deref(ref reg, off) => { Loc::Deref(ref reg, .., off) => {
self.code.encode(instrs::ld(p, reg.0, off, size as _)); self.code.encode(instrs::ld(p, reg.0, off, size as _));
} }
Loc::DerefRef(reg, off) => { Loc::DerefRef(reg, .., off) => {
self.code.encode(instrs::ld(p, reg, off, size as _)); self.code.encode(instrs::ld(p, reg, off, size as _));
} }
Loc::Imm(imm) => { Loc::Imm(imm) => {
@ -1483,23 +1482,23 @@ impl<'a> Codegen<'a> {
match size { match size {
0 => Loc::Imm(0), 0 => Loc::Imm(0),
..=8 => { ..=8 => {
let stack = self.sa.alloc(size as _); let stack = self.alloc_stack(size as _);
self.store_stack(parama.next().unwrap(), stack.offset, size as _); self.store_stack(parama.next().unwrap(), stack.offset, size as _);
Loc::Stack(stack, 0) Loc::Stack(stack, 0)
} }
..=16 => { ..=16 => {
let stack = self.sa.alloc(size); let stack = self.alloc_stack(size);
self.store_stack(parama.next().unwrap(), stack.offset, size as _); self.store_stack(parama.next().unwrap(), stack.offset, size as _);
parama.next().unwrap(); parama.next().unwrap();
Loc::Stack(stack, 0) Loc::Stack(stack, 0)
} }
..=u64::MAX => { ..=u64::MAX => {
let ptr = parama.next().unwrap(); let ptr = parama.next().unwrap();
let stack = self.sa.alloc(size); let stack = self.alloc_stack(size);
self.assign( self.assign(
ty, ty,
Loc::DerefRef(STACK_PTR, stack.offset), Loc::DerefRef(STACK_PTR, None, stack.offset),
Loc::DerefRef(ptr, 0), Loc::DerefRef(ptr, None, 0),
); );
Loc::Stack(stack, 0) Loc::Stack(stack, 0)
} }
@ -1545,25 +1544,29 @@ impl Value {
enum Loc { enum Loc {
Reg(LinReg), Reg(LinReg),
RegRef(Reg), RegRef(Reg),
Deref(LinReg, u64), Deref(LinReg, Option<Rc<Stack>>, u64),
DerefRef(Reg, u64), DerefRef(Reg, Option<Rc<Stack>>, u64),
Imm(u64), Imm(u64),
Stack(LinStack, u64), Stack(Rc<Stack>, u64),
} }
impl Loc { impl Loc {
fn take_ref(&self) -> Loc { fn take_ref(&self) -> Loc {
match *self { match *self {
Self::Reg(LinReg(reg)) | Self::RegRef(reg) => Self::RegRef(reg), Self::Reg(LinReg(reg, ..), ..) | Self::RegRef(reg) => Self::RegRef(reg),
Self::Deref(LinReg(reg), off) | Self::DerefRef(reg, off) => Self::DerefRef(reg, off), Self::Deref(LinReg(reg, ..), ref st, off) | Self::DerefRef(reg, ref st, off) => {
Self::Stack(ref stack, off) => Self::DerefRef(STACK_PTR, stack.offset + off), Self::DerefRef(reg, st.clone(), off)
}
Self::Stack(ref stack, off) => {
Self::DerefRef(STACK_PTR, Some(stack.clone()), stack.offset + off)
}
ref un => unreachable!("{:?}", un), ref un => unreachable!("{:?}", un),
} }
} }
fn ref_to_ptr(&self) -> (Reg, u64) { fn ref_to_ptr(&self) -> (Reg, u64) {
match *self { match *self {
Loc::Deref(LinReg(reg), off) => (reg, off), Loc::Deref(LinReg(reg, ..), _, off) => (reg, off),
Loc::DerefRef(reg, off) => (reg, off), Loc::DerefRef(reg, _, off) => (reg, off),
Loc::Stack(ref stack, off) => (STACK_PTR, stack.offset + off), Loc::Stack(ref stack, off) => (STACK_PTR, stack.offset + off),
ref l => panic!("expected stack location, got {:?}", l), ref l => panic!("expected stack location, got {:?}", l),
} }
@ -1575,8 +1578,8 @@ impl Loc {
fn offset(self, offset: u64) -> Loc { fn offset(self, offset: u64) -> Loc {
match self { match self {
Loc::Deref(r, off) => Loc::Deref(r, off + offset), Loc::Deref(r, stack, off) => Loc::Deref(r, stack, off + offset),
Loc::DerefRef(r, off) => Loc::DerefRef(r, off + offset), Loc::DerefRef(r, stack, off) => Loc::DerefRef(r, stack, off + offset),
Loc::Stack(s, off) => Loc::Stack(s, off + offset), Loc::Stack(s, off) => Loc::Stack(s, off + offset),
l => unreachable!("{:?}", l), l => unreachable!("{:?}", l),
} }

View file

@ -1,3 +1,3 @@
code size: 318 code size: 486
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file

@ -1,3 +1,3 @@
code size: 538 code size: 530
ret: 3 ret: 3
status: Ok(()) status: Ok(())