painfully, but suddle bugs with pointers are now fixed
This commit is contained in:
parent
9aa5da82c9
commit
d8a922df26
|
@ -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 fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("Stack")
|
||||||
|
.field("offset", &self.offset)
|
||||||
|
.field("size", &self.size)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
fn drop(&mut self) {
|
||||||
if !std::thread::panicking() {
|
self.alloc
|
||||||
panic!("stack leaked: {:x} {:x}", self.offset, self.size);
|
.get_mut()
|
||||||
}
|
.as_mut()
|
||||||
|
.map(|f| f.borrow_mut().free(self.offset, self.size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[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),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
code size: 318
|
code size: 486
|
||||||
ret: 0
|
ret: 0
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
code size: 538
|
code size: 530
|
||||||
ret: 3
|
ret: 3
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
Loading…
Reference in a new issue