2024-05-12 04:52:58 -05:00
|
|
|
use crate::ident::Ident;
|
|
|
|
|
2024-05-10 14:33:42 -05:00
|
|
|
use {
|
2024-05-10 15:54:12 -05:00
|
|
|
crate::{
|
2024-05-11 15:22:08 -05:00
|
|
|
instrs, lexer, log,
|
2024-05-12 04:52:58 -05:00
|
|
|
parser::{self},
|
2024-05-10 15:54:12 -05:00
|
|
|
},
|
2024-05-10 14:33:42 -05:00
|
|
|
std::rc::Rc,
|
|
|
|
};
|
2024-05-09 11:16:01 -05:00
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
use {lexer::TokenKind as T, parser::Expr as E};
|
|
|
|
|
2024-05-10 14:33:42 -05:00
|
|
|
type LabelId = u32;
|
2024-05-10 08:29:11 -05:00
|
|
|
type Reg = u8;
|
|
|
|
type MaskElem = u64;
|
2024-05-11 15:22:08 -05:00
|
|
|
type Type = u32;
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct LinReg(Reg);
|
|
|
|
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
impl Drop for LinReg {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
if !std::thread::panicking() {
|
|
|
|
panic!("reg leaked");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub mod bt {
|
2024-05-11 15:22:08 -05:00
|
|
|
use super::*;
|
|
|
|
|
|
|
|
const fn builtin_type(id: u32) -> Type {
|
|
|
|
Type::MAX - id
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! builtin_type {
|
|
|
|
($($name:ident;)*) => {$(
|
2024-05-12 04:52:58 -05:00
|
|
|
pub const $name: Type = TypeKind::Builtin(${index(0)}).encode();
|
2024-05-11 15:22:08 -05:00
|
|
|
)*};
|
|
|
|
}
|
|
|
|
|
|
|
|
builtin_type! {
|
2024-05-12 04:52:58 -05:00
|
|
|
VOID;
|
|
|
|
UNREACHABLE;
|
2024-05-11 15:22:08 -05:00
|
|
|
INT;
|
|
|
|
BOOL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
#[derive(Debug)]
|
2024-05-11 15:22:08 -05:00
|
|
|
enum TypeKind {
|
|
|
|
Builtin(Type),
|
|
|
|
Struct(Type),
|
2024-05-12 04:52:58 -05:00
|
|
|
Pointer(Type),
|
2024-05-11 15:22:08 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeKind {
|
2024-05-12 04:52:58 -05:00
|
|
|
const fn from_ty(ty: Type) -> Self {
|
|
|
|
let (flag, index) = (ty & 0b11, ty >> 2);
|
|
|
|
match flag {
|
|
|
|
0 => Self::Builtin(index),
|
|
|
|
1 => Self::Pointer(index),
|
|
|
|
2 => Self::Struct(index),
|
|
|
|
_ => unreachable!(),
|
2024-05-11 15:22:08 -05:00
|
|
|
}
|
|
|
|
}
|
2024-05-12 04:52:58 -05:00
|
|
|
|
|
|
|
const fn encode(self) -> Type {
|
|
|
|
let (index, flag) = match self {
|
|
|
|
Self::Builtin(index) => (index, 0),
|
|
|
|
Self::Pointer(index) => (index, 1),
|
|
|
|
Self::Struct(index) => (index, 2),
|
|
|
|
};
|
|
|
|
index << 2 | flag
|
|
|
|
}
|
2024-05-11 15:22:08 -05:00
|
|
|
}
|
2024-05-10 08:29:11 -05:00
|
|
|
|
|
|
|
const STACK_PTR: Reg = 254;
|
|
|
|
const ZERO: Reg = 0;
|
|
|
|
const RET_ADDR: Reg = 31;
|
|
|
|
const ELEM_WIDTH: usize = std::mem::size_of::<MaskElem>() * 8;
|
|
|
|
|
2024-05-10 14:33:42 -05:00
|
|
|
struct Frame {
|
|
|
|
label: LabelId,
|
|
|
|
prev_relocs: usize,
|
|
|
|
offset: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Reloc {
|
2024-05-11 09:04:13 -05:00
|
|
|
id: LabelId,
|
2024-05-10 14:33:42 -05:00
|
|
|
offset: u32,
|
2024-05-11 09:04:13 -05:00
|
|
|
instr_offset: u16,
|
|
|
|
size: u16,
|
2024-05-10 14:33:42 -05:00
|
|
|
}
|
|
|
|
|
2024-05-11 05:51:32 -05:00
|
|
|
struct StackReloc {
|
|
|
|
offset: u32,
|
|
|
|
size: u16,
|
|
|
|
}
|
|
|
|
|
2024-05-10 14:33:42 -05:00
|
|
|
#[derive(Default)]
|
|
|
|
pub struct Func {
|
|
|
|
code: Vec<u8>,
|
|
|
|
relocs: Vec<Reloc>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Func {
|
|
|
|
pub fn extend(&mut self, bytes: &[u8]) {
|
|
|
|
self.code.extend_from_slice(bytes);
|
|
|
|
}
|
|
|
|
|
2024-05-11 09:04:13 -05:00
|
|
|
pub fn offset(&mut self, id: LabelId, instr_offset: u16, size: u16) {
|
2024-05-10 14:33:42 -05:00
|
|
|
self.relocs.push(Reloc {
|
|
|
|
id,
|
2024-05-11 09:04:13 -05:00
|
|
|
offset: self.code.len() as u32,
|
|
|
|
instr_offset,
|
2024-05-10 14:33:42 -05:00
|
|
|
size,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-05-11 05:51:32 -05:00
|
|
|
fn encode(&mut self, (len, instr): (usize, [u8; instrs::MAX_SIZE])) {
|
2024-05-11 10:05:22 -05:00
|
|
|
let name = instrs::NAMES[instr[0] as usize];
|
2024-05-11 15:22:08 -05:00
|
|
|
log::dbg!(
|
2024-05-11 10:05:22 -05:00
|
|
|
"{:08x}: {}: {}",
|
|
|
|
self.code.len(),
|
|
|
|
name,
|
|
|
|
instr
|
|
|
|
.iter()
|
|
|
|
.take(len)
|
|
|
|
.skip(1)
|
|
|
|
.map(|b| format!("{:02x}", b))
|
|
|
|
.collect::<String>()
|
|
|
|
);
|
2024-05-11 05:51:32 -05:00
|
|
|
self.code.extend_from_slice(&instr[..len]);
|
|
|
|
}
|
|
|
|
|
2024-05-10 14:33:42 -05:00
|
|
|
fn push(&mut self, value: Reg, size: usize) {
|
2024-05-11 05:51:32 -05:00
|
|
|
self.subi64(STACK_PTR, STACK_PTR, size as _);
|
|
|
|
self.encode(instrs::st(value, STACK_PTR, 0, size as _));
|
2024-05-10 14:33:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn pop(&mut self, value: Reg, size: usize) {
|
2024-05-11 05:51:32 -05:00
|
|
|
self.encode(instrs::ld(value, STACK_PTR, 0, size as _));
|
|
|
|
self.encode(instrs::addi64(STACK_PTR, STACK_PTR, size as _));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn subi64(&mut self, dest: Reg, src: Reg, imm: u64) {
|
|
|
|
self.encode(instrs::addi64(dest, src, imm.wrapping_neg()));
|
2024-05-10 14:33:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn call(&mut self, func: LabelId) {
|
2024-05-11 05:51:32 -05:00
|
|
|
self.offset(func, 3, 4);
|
|
|
|
self.encode(instrs::jal(RET_ADDR, ZERO, 0));
|
2024-05-10 14:33:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn ret(&mut self) {
|
2024-05-11 05:51:32 -05:00
|
|
|
self.pop(RET_ADDR, 8);
|
|
|
|
self.encode(instrs::jala(ZERO, RET_ADDR, 0));
|
2024-05-10 14:33:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn prelude(&mut self, entry: LabelId) {
|
|
|
|
self.call(entry);
|
2024-05-11 05:51:32 -05:00
|
|
|
self.encode(instrs::tx());
|
2024-05-10 15:54:12 -05:00
|
|
|
}
|
|
|
|
|
2024-05-11 09:04:13 -05:00
|
|
|
fn relocate(&mut self, labels: &[FnLabel], shift: i64) {
|
2024-05-10 14:33:42 -05:00
|
|
|
for reloc in self.relocs.drain(..) {
|
|
|
|
let label = &labels[reloc.id as usize];
|
|
|
|
let offset = if reloc.size == 8 {
|
|
|
|
reloc.offset as i64
|
|
|
|
} else {
|
|
|
|
label.offset as i64 - reloc.offset as i64
|
|
|
|
} + shift;
|
|
|
|
|
2024-05-11 15:22:08 -05:00
|
|
|
log::dbg!(
|
2024-05-12 04:52:58 -05:00
|
|
|
label.name,
|
2024-05-11 09:04:13 -05:00
|
|
|
offset,
|
|
|
|
reloc.size,
|
|
|
|
reloc.instr_offset,
|
|
|
|
reloc.offset,
|
|
|
|
shift,
|
|
|
|
label.offset
|
|
|
|
);
|
|
|
|
|
|
|
|
let dest = &mut self.code[reloc.offset as usize + reloc.instr_offset as usize..]
|
|
|
|
[..reloc.size as usize];
|
2024-05-10 14:33:42 -05:00
|
|
|
match reloc.size {
|
|
|
|
2 => dest.copy_from_slice(&(offset as i16).to_le_bytes()),
|
|
|
|
4 => dest.copy_from_slice(&(offset as i32).to_le_bytes()),
|
|
|
|
8 => dest.copy_from_slice(&(offset as i64).to_le_bytes()),
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-10 08:29:11 -05:00
|
|
|
#[derive(Default)]
|
|
|
|
pub struct RegAlloc {
|
|
|
|
free: Vec<Reg>,
|
|
|
|
// TODO:use 256 bit mask instead
|
2024-05-10 14:33:42 -05:00
|
|
|
used: Vec<Reg>,
|
2024-05-10 08:29:11 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RegAlloc {
|
2024-05-11 09:04:13 -05:00
|
|
|
fn init_callee(&mut self) {
|
2024-05-10 14:33:42 -05:00
|
|
|
self.clear();
|
2024-05-11 09:04:13 -05:00
|
|
|
self.free.extend(32..=253);
|
2024-05-10 14:33:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn clear(&mut self) {
|
|
|
|
self.free.clear();
|
|
|
|
self.used.clear();
|
2024-05-10 08:29:11 -05:00
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
fn allocate(&mut self) -> LinReg {
|
2024-05-10 08:29:11 -05:00
|
|
|
let reg = self.free.pop().expect("TODO: we need to spill");
|
2024-05-10 14:33:42 -05:00
|
|
|
if self.used.binary_search_by_key(&!reg, |&r| !r).is_err() {
|
|
|
|
self.used.push(reg);
|
2024-05-10 08:29:11 -05:00
|
|
|
}
|
2024-05-12 04:52:58 -05:00
|
|
|
LinReg(reg)
|
2024-05-10 08:29:11 -05:00
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
fn free(&mut self, reg: LinReg) {
|
|
|
|
self.free.push(reg.0);
|
|
|
|
std::mem::forget(reg);
|
2024-05-10 08:29:11 -05:00
|
|
|
}
|
|
|
|
}
|
2024-05-09 11:16:01 -05:00
|
|
|
|
2024-05-11 09:04:13 -05:00
|
|
|
struct FnLabel {
|
2024-05-10 14:33:42 -05:00
|
|
|
offset: u32,
|
|
|
|
// TODO: use different stile of identifier that does not allocate, eg. index + length into a
|
|
|
|
// file
|
2024-05-12 04:52:58 -05:00
|
|
|
name: Ident,
|
2024-05-10 14:33:42 -05:00
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
struct Variable {
|
|
|
|
id: Ident,
|
|
|
|
value: Value,
|
2024-05-11 05:51:32 -05:00
|
|
|
}
|
|
|
|
|
2024-05-11 09:04:13 -05:00
|
|
|
struct RetReloc {
|
|
|
|
offset: u32,
|
|
|
|
instr_offset: u16,
|
|
|
|
size: u16,
|
|
|
|
}
|
|
|
|
|
2024-05-11 11:16:27 -05:00
|
|
|
struct Loop {
|
|
|
|
offset: u32,
|
|
|
|
relocs: Vec<RetReloc>,
|
|
|
|
}
|
|
|
|
|
2024-05-11 15:22:08 -05:00
|
|
|
struct Struct {
|
|
|
|
name: Rc<str>,
|
|
|
|
fields: Vec<(Rc<str>, Type)>,
|
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
pub struct Codegen<'a> {
|
2024-05-11 09:04:13 -05:00
|
|
|
path: &'a std::path::Path,
|
2024-05-12 04:52:58 -05:00
|
|
|
ret: Type,
|
2024-05-11 09:04:13 -05:00
|
|
|
gpa: RegAlloc,
|
|
|
|
code: Func,
|
|
|
|
temp: Func,
|
|
|
|
labels: Vec<FnLabel>,
|
2024-05-11 05:51:32 -05:00
|
|
|
stack_size: u64,
|
2024-05-12 04:52:58 -05:00
|
|
|
vars: Vec<Variable>,
|
2024-05-11 05:51:32 -05:00
|
|
|
stack_relocs: Vec<StackReloc>,
|
2024-05-11 09:04:13 -05:00
|
|
|
ret_relocs: Vec<RetReloc>,
|
2024-05-11 11:16:27 -05:00
|
|
|
loops: Vec<Loop>,
|
2024-05-11 15:22:08 -05:00
|
|
|
records: Vec<Struct>,
|
2024-05-12 04:52:58 -05:00
|
|
|
pointers: Vec<Type>,
|
|
|
|
main: Option<LabelId>,
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
impl<'a> Codegen<'a> {
|
2024-05-10 08:29:11 -05:00
|
|
|
pub fn new() -> Self {
|
2024-05-09 11:16:01 -05:00
|
|
|
Self {
|
2024-05-12 04:52:58 -05:00
|
|
|
path: std::path::Path::new(""),
|
|
|
|
ret: bt::VOID,
|
|
|
|
gpa: Default::default(),
|
|
|
|
code: Default::default(),
|
|
|
|
temp: Default::default(),
|
|
|
|
labels: Default::default(),
|
2024-05-11 05:51:32 -05:00
|
|
|
stack_size: 0,
|
2024-05-12 04:52:58 -05:00
|
|
|
vars: Default::default(),
|
2024-05-11 05:51:32 -05:00
|
|
|
stack_relocs: Default::default(),
|
2024-05-12 04:52:58 -05:00
|
|
|
ret_relocs: Default::default(),
|
|
|
|
loops: Default::default(),
|
|
|
|
records: Default::default(),
|
|
|
|
pointers: Default::default(),
|
|
|
|
main: None,
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-10 14:33:42 -05:00
|
|
|
pub fn file(
|
|
|
|
&mut self,
|
|
|
|
path: &'a std::path::Path,
|
|
|
|
exprs: &'a [parser::Expr<'a>],
|
|
|
|
) -> std::fmt::Result {
|
2024-05-10 08:29:11 -05:00
|
|
|
self.path = path;
|
2024-05-09 16:41:59 -05:00
|
|
|
for expr in exprs {
|
2024-05-10 14:33:42 -05:00
|
|
|
self.expr(expr, None);
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
2024-05-09 16:41:59 -05:00
|
|
|
Ok(())
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
fn size_of(&self, ty: Type) -> u64 {
|
|
|
|
// TODO: proper alignment
|
|
|
|
match TypeKind::from_ty(ty) {
|
|
|
|
TypeKind::Pointer(_) | TypeKind::Builtin(bt::INT) => 8,
|
|
|
|
TypeKind::Builtin(bt::BOOL) => 1,
|
|
|
|
TypeKind::Builtin(_) => unreachable!(),
|
|
|
|
TypeKind::Struct(ty) => self.records[ty as usize]
|
|
|
|
.fields
|
|
|
|
.iter()
|
|
|
|
.map(|(_, ty)| self.size_of(*ty))
|
|
|
|
.sum(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn loc_to_reg(&mut self, loc: Loc) -> LinReg {
|
2024-05-11 05:51:32 -05:00
|
|
|
match loc {
|
2024-05-12 04:52:58 -05:00
|
|
|
Loc::RegRef(rr) => {
|
|
|
|
let reg = self.gpa.allocate();
|
|
|
|
self.code.encode(instrs::cp(reg.0, rr));
|
|
|
|
reg
|
|
|
|
}
|
2024-05-11 05:51:32 -05:00
|
|
|
Loc::Reg(reg) => reg,
|
2024-05-12 04:52:58 -05:00
|
|
|
Loc::Deref(dreg) => {
|
|
|
|
let reg = self.gpa.allocate();
|
|
|
|
self.code.encode(instrs::ld(reg.0, dreg.0, 0, 8));
|
|
|
|
self.gpa.free(dreg);
|
|
|
|
reg
|
|
|
|
}
|
2024-05-11 05:51:32 -05:00
|
|
|
Loc::Imm(imm) => {
|
|
|
|
let reg = self.gpa.allocate();
|
2024-05-12 04:52:58 -05:00
|
|
|
self.code.encode(instrs::li64(reg.0, imm));
|
2024-05-11 05:51:32 -05:00
|
|
|
reg
|
|
|
|
}
|
|
|
|
Loc::Stack(offset) => {
|
|
|
|
let reg = self.gpa.allocate();
|
2024-05-12 04:52:58 -05:00
|
|
|
self.load_stack(reg.0, offset, 8);
|
2024-05-11 05:51:32 -05:00
|
|
|
reg
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn alloc_stack(&mut self, size: u32) -> u64 {
|
|
|
|
let offset = self.stack_size;
|
|
|
|
self.stack_size += size as u64;
|
|
|
|
offset
|
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
fn reloc_stack(&mut self) {
|
2024-05-11 05:51:32 -05:00
|
|
|
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());
|
2024-05-12 04:52:58 -05:00
|
|
|
let offset = self.stack_size - value;
|
2024-05-11 05:51:32 -05:00
|
|
|
dest.copy_from_slice(&offset.to_ne_bytes());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-11 09:04:13 -05:00
|
|
|
fn reloc_rets(&mut self) {
|
|
|
|
let len = self.code.code.len() as i32;
|
|
|
|
for reloc in self.ret_relocs.drain(..) {
|
|
|
|
let dest = &mut self.code.code[reloc.offset as usize + reloc.instr_offset as usize..]
|
|
|
|
[..reloc.size as usize];
|
|
|
|
debug_assert!(dest.iter().all(|&b| b == 0));
|
|
|
|
let offset = len - reloc.offset as i32;
|
|
|
|
dest.copy_from_slice(&offset.to_ne_bytes());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
fn ty(&mut self, expr: &parser::Expr<'a>) -> Type {
|
2024-05-10 08:29:11 -05:00
|
|
|
match *expr {
|
2024-05-12 04:52:58 -05:00
|
|
|
E::Ident { name: "int", .. } => bt::INT,
|
|
|
|
E::Ident { name: "bool", .. } => bt::BOOL,
|
|
|
|
expr => unimplemented!("type: {:#?}", expr),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn expr(&mut self, expr: &'a parser::Expr<'a>, expeted: Option<Type>) -> Option<Value> {
|
|
|
|
match *expr {
|
|
|
|
E::UnOp {
|
|
|
|
op: T::Amp, val, ..
|
|
|
|
} => {
|
|
|
|
let val = self.expr(val, None).unwrap();
|
|
|
|
match val.loc {
|
|
|
|
Loc::Stack(off) => {
|
|
|
|
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));
|
|
|
|
Some(Value {
|
|
|
|
ty: self.alloc_pointer(val.ty),
|
|
|
|
loc: Loc::Reg(reg),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
l => panic!("cant take pointer of {:?}", l),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
E::UnOp {
|
|
|
|
op: T::Star, val, ..
|
|
|
|
} => {
|
|
|
|
let val = self.expr(val, None).unwrap();
|
|
|
|
let reg = self.loc_to_reg(val.loc);
|
|
|
|
match TypeKind::from_ty(val.ty) {
|
|
|
|
TypeKind::Pointer(ty) => Some(Value {
|
|
|
|
ty: self.pointers[ty as usize],
|
|
|
|
loc: Loc::Deref(reg),
|
|
|
|
}),
|
|
|
|
_ => panic!("cant deref {:?}", val.ty),
|
|
|
|
}
|
|
|
|
}
|
2024-05-11 15:22:08 -05:00
|
|
|
E::BinOp {
|
2024-05-12 04:52:58 -05:00
|
|
|
left: E::Ident { name, id, .. },
|
2024-05-11 15:22:08 -05:00
|
|
|
op: T::Decl,
|
|
|
|
right: E::Closure {
|
|
|
|
ret, body, args, ..
|
|
|
|
},
|
2024-05-09 16:41:59 -05:00
|
|
|
} => {
|
2024-05-12 04:52:58 -05:00
|
|
|
log::dbg!("fn: {}", name);
|
|
|
|
let frame = self.add_label(*id);
|
|
|
|
if *name == "main" {
|
|
|
|
self.main = Some(frame.label);
|
|
|
|
}
|
|
|
|
log::dbg!("fn-args");
|
|
|
|
for (i, arg) in args.iter().enumerate() {
|
2024-05-11 09:04:13 -05:00
|
|
|
let offset = self.alloc_stack(8);
|
2024-05-12 04:52:58 -05:00
|
|
|
let ty = self.ty(&arg.ty);
|
|
|
|
self.vars.push(Variable {
|
|
|
|
id: arg.id,
|
|
|
|
value: Value {
|
|
|
|
ty,
|
|
|
|
loc: Loc::Stack(offset),
|
|
|
|
},
|
|
|
|
});
|
2024-05-11 09:04:13 -05:00
|
|
|
self.store_stack(i as Reg + 2, offset, 8);
|
|
|
|
}
|
|
|
|
self.gpa.init_callee();
|
2024-05-12 04:52:58 -05:00
|
|
|
self.ret = self.ty(ret);
|
|
|
|
log::dbg!("fn-body");
|
2024-05-10 14:33:42 -05:00
|
|
|
self.expr(body, None);
|
2024-05-11 09:04:13 -05:00
|
|
|
self.vars.clear();
|
2024-05-12 04:52:58 -05:00
|
|
|
log::dbg!("fn-relocs");
|
|
|
|
self.reloc_stack();
|
|
|
|
log::dbg!("fn-prelude");
|
2024-05-10 14:33:42 -05:00
|
|
|
self.write_fn_prelude(frame);
|
2024-05-12 04:52:58 -05:00
|
|
|
log::dbg!("fn-ret");
|
2024-05-11 09:04:13 -05:00
|
|
|
self.reloc_rets();
|
|
|
|
self.ret();
|
2024-05-12 04:52:58 -05:00
|
|
|
self.stack_size = 0;
|
|
|
|
self.vars.clear();
|
2024-05-10 14:33:42 -05:00
|
|
|
None
|
|
|
|
}
|
2024-05-11 15:22:08 -05:00
|
|
|
E::BinOp {
|
2024-05-12 04:52:58 -05:00
|
|
|
left: E::Ident { id, .. },
|
2024-05-11 15:22:08 -05:00
|
|
|
op: T::Decl,
|
|
|
|
right,
|
|
|
|
} => {
|
|
|
|
let val = self.expr(right, None).unwrap();
|
|
|
|
let reg = self.loc_to_reg(val.loc);
|
|
|
|
let offset = self.alloc_stack(8);
|
2024-05-12 04:52:58 -05:00
|
|
|
self.vars.push(Variable {
|
|
|
|
id: *id,
|
|
|
|
value: Value {
|
|
|
|
ty: val.ty,
|
|
|
|
loc: Loc::Stack(offset),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
self.store_stack(reg.0, offset, 8);
|
|
|
|
self.gpa.free(reg);
|
2024-05-11 15:22:08 -05:00
|
|
|
None
|
|
|
|
}
|
2024-05-11 09:04:13 -05:00
|
|
|
E::Call {
|
2024-05-12 04:52:58 -05:00
|
|
|
func: E::Ident { id, .. },
|
2024-05-11 09:04:13 -05:00
|
|
|
args,
|
|
|
|
} => {
|
|
|
|
for (i, arg) in args.iter().enumerate() {
|
|
|
|
let arg = self.expr(arg, None).unwrap();
|
|
|
|
let reg = self.loc_to_reg(arg.loc);
|
2024-05-12 04:52:58 -05:00
|
|
|
self.code.encode(instrs::cp(i as Reg + 2, reg.0));
|
|
|
|
self.gpa.free(reg);
|
2024-05-11 09:04:13 -05:00
|
|
|
}
|
2024-05-12 04:52:58 -05:00
|
|
|
let func = self.get_or_reserve_label(*id);
|
2024-05-11 09:04:13 -05:00
|
|
|
self.code.call(func);
|
|
|
|
let reg = self.gpa.allocate();
|
2024-05-12 04:52:58 -05:00
|
|
|
self.code.encode(instrs::cp(reg.0, 1));
|
2024-05-11 09:04:13 -05:00
|
|
|
Some(Value {
|
|
|
|
ty: self.ret,
|
|
|
|
loc: Loc::Reg(reg),
|
|
|
|
})
|
|
|
|
}
|
2024-05-12 04:52:58 -05:00
|
|
|
E::Ident { name, id, .. } => {
|
|
|
|
let var = self
|
|
|
|
.vars
|
|
|
|
.iter()
|
|
|
|
.find(|v| v.id == id)
|
|
|
|
.unwrap_or_else(|| panic!("variable not found: {:?}", name));
|
2024-05-11 05:51:32 -05:00
|
|
|
Some(Value {
|
2024-05-12 04:52:58 -05:00
|
|
|
ty: var.value.ty,
|
|
|
|
loc: var.value.loc.take_ref(),
|
2024-05-11 05:51:32 -05:00
|
|
|
})
|
|
|
|
}
|
2024-05-11 15:22:08 -05:00
|
|
|
E::Return { val, .. } => {
|
2024-05-10 14:33:42 -05:00
|
|
|
if let Some(val) = val {
|
|
|
|
let val = self.expr(val, Some(self.ret)).unwrap();
|
|
|
|
if val.ty != self.ret {
|
2024-05-12 04:52:58 -05:00
|
|
|
panic!("expected {:?}, got {:?}", self.ret, val.ty);
|
2024-05-10 14:33:42 -05:00
|
|
|
}
|
2024-05-11 05:51:32 -05:00
|
|
|
self.assign(
|
|
|
|
Value {
|
|
|
|
ty: self.ret,
|
2024-05-12 04:52:58 -05:00
|
|
|
loc: Loc::RegRef(1),
|
2024-05-11 05:51:32 -05:00
|
|
|
},
|
|
|
|
val,
|
|
|
|
);
|
2024-05-10 14:33:42 -05:00
|
|
|
}
|
2024-05-11 09:04:13 -05:00
|
|
|
self.ret_relocs.push(RetReloc {
|
|
|
|
offset: self.code.code.len() as u32,
|
|
|
|
instr_offset: 1,
|
|
|
|
size: 4,
|
|
|
|
});
|
|
|
|
self.code.encode(instrs::jmp(0));
|
2024-05-10 14:33:42 -05:00
|
|
|
None
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
2024-05-11 15:22:08 -05:00
|
|
|
E::Block { stmts, .. } => {
|
2024-05-09 16:41:59 -05:00
|
|
|
for stmt in stmts {
|
2024-05-12 04:52:58 -05:00
|
|
|
if let Some(Loc::Reg(reg)) = self.expr(stmt, None).map(|v| v.loc) {
|
|
|
|
self.gpa.free(reg);
|
|
|
|
}
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
2024-05-10 14:33:42 -05:00
|
|
|
None
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
2024-05-11 15:22:08 -05:00
|
|
|
E::Number { value, .. } => Some(Value {
|
2024-05-12 04:52:58 -05:00
|
|
|
ty: expeted.unwrap_or(bt::INT),
|
2024-05-10 14:33:42 -05:00
|
|
|
loc: Loc::Imm(value),
|
|
|
|
}),
|
2024-05-11 15:22:08 -05:00
|
|
|
E::If {
|
|
|
|
cond, then, else_, ..
|
|
|
|
} => {
|
2024-05-12 04:52:58 -05:00
|
|
|
log::dbg!("if-cond");
|
|
|
|
let cond = self.expr(cond, Some(bt::BOOL)).unwrap();
|
2024-05-11 10:05:22 -05:00
|
|
|
let reg = self.loc_to_reg(cond.loc);
|
|
|
|
let jump_offset = self.code.code.len() as u32;
|
2024-05-12 04:52:58 -05:00
|
|
|
self.code.encode(instrs::jeq(reg.0, 0, 0));
|
2024-05-11 10:05:22 -05:00
|
|
|
self.gpa.free(reg);
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
log::dbg!("if-then");
|
2024-05-11 10:05:22 -05:00
|
|
|
self.expr(then, None);
|
2024-05-11 11:16:27 -05:00
|
|
|
|
|
|
|
let jump;
|
|
|
|
|
|
|
|
if let Some(else_) = else_ {
|
2024-05-12 04:52:58 -05:00
|
|
|
log::dbg!("if-else");
|
2024-05-11 11:16:27 -05:00
|
|
|
let else_jump_offset = self.code.code.len() as u32;
|
|
|
|
self.code.encode(instrs::jmp(0));
|
|
|
|
|
|
|
|
jump = self.code.code.len() as i16 - jump_offset as i16;
|
|
|
|
|
|
|
|
self.expr(else_, None);
|
|
|
|
|
|
|
|
let jump = self.code.code.len() as i32 - else_jump_offset as i32;
|
2024-05-12 04:52:58 -05:00
|
|
|
log::dbg!("if-else-jump: {}", jump);
|
2024-05-11 11:16:27 -05:00
|
|
|
self.code.code[else_jump_offset as usize + 1..][..4]
|
|
|
|
.copy_from_slice(&jump.to_ne_bytes());
|
|
|
|
} else {
|
|
|
|
jump = self.code.code.len() as i16 - jump_offset as i16;
|
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
log::dbg!("if-then-jump: {}", jump);
|
2024-05-11 10:05:22 -05:00
|
|
|
self.code.code[jump_offset as usize + 3..][..2]
|
|
|
|
.copy_from_slice(&jump.to_ne_bytes());
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
2024-05-11 15:22:08 -05:00
|
|
|
E::Loop { body, .. } => {
|
2024-05-12 04:52:58 -05:00
|
|
|
log::dbg!("loop");
|
2024-05-11 11:16:27 -05:00
|
|
|
let loop_start = self.code.code.len() as u32;
|
|
|
|
self.loops.push(Loop {
|
|
|
|
offset: loop_start,
|
|
|
|
relocs: Default::default(),
|
|
|
|
});
|
|
|
|
self.expr(body, None);
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
log::dbg!("loop-end");
|
2024-05-11 11:16:27 -05:00
|
|
|
let loop_end = self.code.code.len();
|
|
|
|
self.code
|
|
|
|
.encode(instrs::jmp(loop_start as i32 - loop_end as i32));
|
|
|
|
let loop_end = self.code.code.len() as u32;
|
|
|
|
|
|
|
|
let loop_ = self.loops.pop().unwrap();
|
|
|
|
for reloc in loop_.relocs {
|
|
|
|
let dest = &mut self.code.code
|
|
|
|
[reloc.offset as usize + reloc.instr_offset as usize..]
|
|
|
|
[..reloc.size as usize];
|
|
|
|
let offset = loop_end as i32 - reloc.offset as i32;
|
|
|
|
dest.copy_from_slice(&offset.to_ne_bytes());
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
2024-05-11 15:22:08 -05:00
|
|
|
E::Break { .. } => {
|
2024-05-11 11:16:27 -05:00
|
|
|
let loop_ = self.loops.last_mut().unwrap();
|
|
|
|
let offset = self.code.code.len() as u32;
|
|
|
|
self.code.encode(instrs::jmp(0));
|
|
|
|
loop_.relocs.push(RetReloc {
|
|
|
|
offset,
|
|
|
|
instr_offset: 1,
|
|
|
|
size: 4,
|
|
|
|
});
|
|
|
|
None
|
|
|
|
}
|
2024-05-11 15:22:08 -05:00
|
|
|
E::Continue { .. } => {
|
2024-05-11 11:16:27 -05:00
|
|
|
let loop_ = self.loops.last().unwrap();
|
|
|
|
let offset = self.code.code.len() as u32;
|
|
|
|
self.code
|
|
|
|
.encode(instrs::jmp(loop_.offset as i32 - offset as i32));
|
|
|
|
None
|
|
|
|
}
|
2024-05-10 15:54:12 -05:00
|
|
|
E::BinOp { left, op, right } => {
|
|
|
|
let left = self.expr(left, expeted).unwrap();
|
|
|
|
let right = self.expr(right, Some(left.ty)).unwrap();
|
2024-05-12 04:52:58 -05:00
|
|
|
if op == T::Assign {
|
|
|
|
return self.assign(left, right);
|
|
|
|
}
|
2024-05-10 15:54:12 -05:00
|
|
|
|
2024-05-11 10:05:22 -05:00
|
|
|
let lhs = self.loc_to_reg(left.loc);
|
|
|
|
let rhs = self.loc_to_reg(right.loc);
|
|
|
|
|
2024-05-10 15:54:12 -05:00
|
|
|
let op = match op {
|
2024-05-11 05:51:32 -05:00
|
|
|
T::Plus => instrs::add64,
|
|
|
|
T::Minus => instrs::sub64,
|
|
|
|
T::Star => instrs::mul64,
|
2024-05-11 10:05:22 -05:00
|
|
|
T::Le => {
|
2024-05-12 04:52:58 -05:00
|
|
|
self.code.encode(instrs::cmpu(lhs.0, lhs.0, rhs.0));
|
2024-05-11 10:05:22 -05:00
|
|
|
self.gpa.free(rhs);
|
2024-05-12 04:52:58 -05:00
|
|
|
self.code.encode(instrs::cmpui(lhs.0, lhs.0, 1));
|
2024-05-11 10:05:22 -05:00
|
|
|
return Some(Value {
|
2024-05-12 04:52:58 -05:00
|
|
|
ty: bt::BOOL,
|
2024-05-11 10:05:22 -05:00
|
|
|
loc: Loc::Reg(lhs),
|
|
|
|
});
|
|
|
|
}
|
2024-05-11 11:16:27 -05:00
|
|
|
T::Eq => {
|
2024-05-12 04:52:58 -05:00
|
|
|
self.code.encode(instrs::cmpu(lhs.0, lhs.0, rhs.0));
|
2024-05-11 11:16:27 -05:00
|
|
|
self.gpa.free(rhs);
|
2024-05-12 04:52:58 -05:00
|
|
|
self.code.encode(instrs::cmpui(lhs.0, lhs.0, 0));
|
|
|
|
self.code.encode(instrs::not(lhs.0, lhs.0));
|
2024-05-11 11:16:27 -05:00
|
|
|
return Some(Value {
|
2024-05-12 04:52:58 -05:00
|
|
|
ty: bt::BOOL,
|
2024-05-11 11:16:27 -05:00
|
|
|
loc: Loc::Reg(lhs),
|
|
|
|
});
|
|
|
|
}
|
2024-05-11 05:51:32 -05:00
|
|
|
T::FSlash => |reg0, reg1, reg2| instrs::diru64(reg0, ZERO, reg1, reg2),
|
2024-05-10 15:54:12 -05:00
|
|
|
_ => unimplemented!("{:#?}", op),
|
|
|
|
};
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
self.code.encode(op(lhs.0, lhs.0, rhs.0));
|
2024-05-10 15:54:12 -05:00
|
|
|
self.gpa.free(rhs);
|
|
|
|
|
|
|
|
Some(Value {
|
|
|
|
ty: left.ty,
|
|
|
|
loc: Loc::Reg(lhs),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
ast => unimplemented!("{:#?}", ast),
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
fn assign(&mut self, left: Value, right: Value) -> Option<Value> {
|
2024-05-11 05:51:32 -05:00
|
|
|
let rhs = self.loc_to_reg(right.loc);
|
|
|
|
match left.loc {
|
2024-05-12 04:52:58 -05:00
|
|
|
Loc::Deref(reg) => {
|
|
|
|
self.code.encode(instrs::st(rhs.0, reg.0, 0, 8));
|
|
|
|
self.gpa.free(reg);
|
|
|
|
}
|
|
|
|
Loc::RegRef(reg) => self.code.encode(instrs::cp(reg, rhs.0)),
|
|
|
|
Loc::Stack(offset) => self.store_stack(rhs.0, offset, 8),
|
2024-05-11 05:51:32 -05:00
|
|
|
_ => unimplemented!(),
|
|
|
|
}
|
|
|
|
self.gpa.free(rhs);
|
2024-05-12 04:52:58 -05:00
|
|
|
None
|
2024-05-11 05:51:32 -05:00
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
fn get_or_reserve_label(&mut self, name: Ident) -> LabelId {
|
|
|
|
if let Some(label) = self.labels.iter().position(|l| l.name == name) {
|
2024-05-10 14:33:42 -05:00
|
|
|
label as u32
|
|
|
|
} else {
|
2024-05-12 04:52:58 -05:00
|
|
|
self.labels.push(FnLabel { offset: 0, name });
|
2024-05-10 14:33:42 -05:00
|
|
|
self.labels.len() as u32 - 1
|
2024-05-10 08:29:11 -05:00
|
|
|
}
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
fn add_label(&mut self, name: Ident) -> Frame {
|
2024-05-10 14:33:42 -05:00
|
|
|
let offset = self.code.code.len() as u32;
|
2024-05-12 04:52:58 -05:00
|
|
|
let label = if let Some(label) = self.labels.iter().position(|l| l.name == name) {
|
2024-05-10 14:33:42 -05:00
|
|
|
self.labels[label].offset = offset;
|
|
|
|
label as u32
|
|
|
|
} else {
|
2024-05-11 09:04:13 -05:00
|
|
|
self.labels.push(FnLabel {
|
2024-05-10 14:33:42 -05:00
|
|
|
offset,
|
|
|
|
name: name.into(),
|
|
|
|
});
|
|
|
|
self.labels.len() as u32 - 1
|
|
|
|
};
|
|
|
|
|
|
|
|
Frame {
|
|
|
|
label,
|
|
|
|
prev_relocs: self.code.relocs.len(),
|
|
|
|
offset,
|
2024-05-10 08:29:11 -05:00
|
|
|
}
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
fn get_label(&self, name: Ident) -> LabelId {
|
|
|
|
self.labels.iter().position(|l| l.name == name).unwrap() as _
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-10 14:33:42 -05:00
|
|
|
fn write_fn_prelude(&mut self, frame: Frame) {
|
2024-05-11 05:51:32 -05:00
|
|
|
self.temp.push(RET_ADDR, 8);
|
2024-05-10 14:33:42 -05:00
|
|
|
for ® in self.gpa.used.clone().iter() {
|
|
|
|
self.temp.push(reg, 8);
|
|
|
|
}
|
2024-05-12 04:52:58 -05:00
|
|
|
self.temp.subi64(STACK_PTR, STACK_PTR, self.stack_size);
|
2024-05-10 08:29:11 -05:00
|
|
|
|
2024-05-10 14:33:42 -05:00
|
|
|
for reloc in &mut self.code.relocs[frame.prev_relocs..] {
|
|
|
|
reloc.offset += self.temp.code.len() as u32;
|
|
|
|
}
|
2024-05-10 08:29:11 -05:00
|
|
|
|
2024-05-11 09:04:13 -05:00
|
|
|
for reloc in &mut self.ret_relocs {
|
|
|
|
reloc.offset += self.temp.code.len() as u32;
|
|
|
|
}
|
|
|
|
|
2024-05-10 14:33:42 -05:00
|
|
|
self.code.code.splice(
|
|
|
|
frame.offset as usize..frame.offset as usize,
|
|
|
|
self.temp.code.drain(..),
|
|
|
|
);
|
|
|
|
}
|
2024-05-10 08:29:11 -05:00
|
|
|
|
2024-05-10 14:33:42 -05:00
|
|
|
fn ret(&mut self) {
|
2024-05-11 09:04:13 -05:00
|
|
|
self.code
|
2024-05-12 04:52:58 -05:00
|
|
|
.encode(instrs::addi64(STACK_PTR, STACK_PTR, self.stack_size));
|
2024-05-10 14:33:42 -05:00
|
|
|
for reg in self.gpa.used.clone().iter().rev() {
|
|
|
|
self.code.pop(*reg, 8);
|
|
|
|
}
|
|
|
|
self.code.ret();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn dump(mut self, out: &mut impl std::io::Write) -> std::io::Result<()> {
|
2024-05-12 04:52:58 -05:00
|
|
|
self.temp.prelude(self.main.unwrap());
|
2024-05-10 14:33:42 -05:00
|
|
|
self.temp
|
|
|
|
.relocate(&self.labels, self.temp.code.len() as i64);
|
|
|
|
|
|
|
|
self.code.relocate(&self.labels, 0);
|
|
|
|
out.write_all(&self.temp.code)?;
|
|
|
|
out.write_all(&self.code.code)
|
|
|
|
}
|
2024-05-11 05:51:32 -05:00
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
fn alloc_pointer(&mut self, ty: Type) -> Type {
|
|
|
|
let ty = self
|
|
|
|
.pointers
|
|
|
|
.iter()
|
|
|
|
.position(|&p| p == ty)
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
self.pointers.push(ty);
|
|
|
|
self.pointers.len() - 1
|
|
|
|
});
|
|
|
|
|
|
|
|
TypeKind::Pointer(ty as Type).encode()
|
2024-05-11 05:51:32 -05:00
|
|
|
}
|
2024-05-10 08:29:11 -05:00
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
pub struct Value {
|
|
|
|
ty: Type,
|
2024-05-10 14:33:42 -05:00
|
|
|
loc: Loc,
|
2024-05-10 08:29:11 -05:00
|
|
|
}
|
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum Loc {
|
|
|
|
Reg(LinReg),
|
|
|
|
RegRef(Reg),
|
|
|
|
Deref(LinReg),
|
2024-05-10 14:33:42 -05:00
|
|
|
Imm(u64),
|
2024-05-11 05:51:32 -05:00
|
|
|
Stack(u64),
|
2024-05-10 08:29:11 -05:00
|
|
|
}
|
2024-05-12 04:52:58 -05:00
|
|
|
impl Loc {
|
|
|
|
fn take_ref(&self) -> Loc {
|
|
|
|
match self {
|
|
|
|
Self::Reg(reg) => Self::RegRef(reg.0),
|
|
|
|
Self::Stack(off) => Self::Stack(*off),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-05-10 08:29:11 -05:00
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2024-05-11 15:22:08 -05:00
|
|
|
use crate::{instrs, log};
|
2024-05-11 09:04:13 -05:00
|
|
|
|
2024-05-10 08:29:11 -05:00
|
|
|
struct TestMem;
|
|
|
|
|
|
|
|
impl hbvm::mem::Memory for TestMem {
|
|
|
|
#[inline]
|
|
|
|
unsafe fn load(
|
|
|
|
&mut self,
|
|
|
|
addr: hbvm::mem::Address,
|
|
|
|
target: *mut u8,
|
|
|
|
count: usize,
|
|
|
|
) -> Result<(), hbvm::mem::LoadError> {
|
2024-05-11 15:22:08 -05:00
|
|
|
log::dbg!(
|
2024-05-11 09:04:13 -05:00
|
|
|
"read: {:x} {} {:?}",
|
|
|
|
addr.get(),
|
|
|
|
count,
|
|
|
|
core::slice::from_raw_parts(target, count)
|
|
|
|
.iter()
|
|
|
|
.rev()
|
|
|
|
.skip_while(|&&b| b == 0)
|
|
|
|
.map(|&b| format!("{:02x}", b))
|
|
|
|
.collect::<String>()
|
|
|
|
);
|
2024-05-10 08:29:11 -05:00
|
|
|
unsafe { core::ptr::copy(addr.get() as *const u8, target, count) }
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
unsafe fn store(
|
|
|
|
&mut self,
|
|
|
|
addr: hbvm::mem::Address,
|
|
|
|
source: *const u8,
|
|
|
|
count: usize,
|
|
|
|
) -> Result<(), hbvm::mem::StoreError> {
|
2024-05-11 15:22:08 -05:00
|
|
|
log::dbg!("write: {:x} {}", addr.get(), count);
|
2024-05-10 08:29:11 -05:00
|
|
|
unsafe { core::ptr::copy(source, addr.get() as *mut u8, count) }
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
unsafe fn prog_read<T: Copy>(&mut self, addr: hbvm::mem::Address) -> T {
|
2024-05-11 15:22:08 -05:00
|
|
|
log::dbg!(
|
2024-05-11 09:04:13 -05:00
|
|
|
"read-typed: {:x} {} {:?}",
|
|
|
|
addr.get(),
|
|
|
|
std::any::type_name::<T>(),
|
|
|
|
if core::mem::size_of::<T>() == 1 {
|
|
|
|
instrs::NAMES[std::ptr::read(addr.get() as *const u8) as usize].to_string()
|
|
|
|
} else {
|
|
|
|
core::slice::from_raw_parts(addr.get() as *const u8, core::mem::size_of::<T>())
|
|
|
|
.iter()
|
|
|
|
.map(|&b| format!("{:02x}", b))
|
|
|
|
.collect::<String>()
|
|
|
|
}
|
|
|
|
);
|
2024-05-10 08:29:11 -05:00
|
|
|
unsafe { core::ptr::read(addr.get() as *const T) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
fn generate(input: &'static str, output: &mut String) {
|
2024-05-10 08:29:11 -05:00
|
|
|
let path = std::path::Path::new("test");
|
|
|
|
let arena = crate::parser::Arena::default();
|
2024-05-12 04:52:58 -05:00
|
|
|
let mut parser = super::parser::Parser::new(input, path, &arena);
|
2024-05-09 16:41:59 -05:00
|
|
|
let exprs = parser.file();
|
2024-05-10 08:29:11 -05:00
|
|
|
let mut codegen = super::Codegen::new();
|
|
|
|
codegen.file(path, &exprs).unwrap();
|
2024-05-10 14:33:42 -05:00
|
|
|
let mut out = Vec::new();
|
|
|
|
codegen.dump(&mut out).unwrap();
|
2024-05-10 08:29:11 -05:00
|
|
|
|
2024-05-11 10:05:22 -05:00
|
|
|
std::fs::write("test.bin", &out).unwrap();
|
2024-05-10 14:33:42 -05:00
|
|
|
use std::fmt::Write;
|
2024-05-10 08:29:11 -05:00
|
|
|
|
2024-05-12 04:52:58 -05:00
|
|
|
let mut stack = [0_u64; 128];
|
2024-05-10 14:33:42 -05:00
|
|
|
|
|
|
|
let mut vm = unsafe {
|
|
|
|
hbvm::Vm::<TestMem, 0>::new(TestMem, hbvm::mem::Address::new(out.as_ptr() as u64))
|
|
|
|
};
|
2024-05-10 08:29:11 -05:00
|
|
|
|
2024-05-11 05:51:32 -05:00
|
|
|
vm.write_reg(
|
|
|
|
super::STACK_PTR,
|
|
|
|
unsafe { stack.as_mut_ptr().add(stack.len()) } as u64,
|
|
|
|
);
|
2024-05-10 08:29:11 -05:00
|
|
|
|
2024-05-10 14:33:42 -05:00
|
|
|
let stat = loop {
|
|
|
|
match vm.run() {
|
|
|
|
Ok(hbvm::VmRunOk::End) => break Ok(()),
|
|
|
|
Ok(ev) => writeln!(output, "ev: {:?}", ev).unwrap(),
|
|
|
|
Err(e) => break Err(e),
|
|
|
|
}
|
|
|
|
};
|
2024-05-10 08:29:11 -05:00
|
|
|
|
2024-05-11 09:04:13 -05:00
|
|
|
writeln!(output, "ret: {:?}", vm.read_reg(1).0).unwrap();
|
2024-05-10 14:33:42 -05:00
|
|
|
writeln!(output, "status: {:?}", stat).unwrap();
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
|
2024-05-09 16:41:59 -05:00
|
|
|
crate::run_tests! { generate:
|
|
|
|
example => include_str!("../examples/main_fn.hb");
|
2024-05-10 15:54:12 -05:00
|
|
|
arithmetic => include_str!("../examples/arithmetic.hb");
|
2024-05-11 05:51:32 -05:00
|
|
|
variables => include_str!("../examples/variables.hb");
|
2024-05-11 09:04:13 -05:00
|
|
|
functions => include_str!("../examples/functions.hb");
|
2024-05-11 10:05:22 -05:00
|
|
|
if_statements => include_str!("../examples/if_statement.hb");
|
2024-05-11 11:16:27 -05:00
|
|
|
loops => include_str!("../examples/loops.hb");
|
2024-05-12 04:52:58 -05:00
|
|
|
fb_driver => include_str!("../examples/fb_driver.hb");
|
|
|
|
pointers => include_str!("../examples/pointers.hb");
|
2024-05-12 05:16:40 -05:00
|
|
|
structs => include_str!("../examples/structs.hb");
|
2024-05-09 11:16:01 -05:00
|
|
|
}
|
|
|
|
}
|