forked from AbleOS/holey-bytes
making better use of parameter and return registers (use register 2 for arguments when possible)
This commit is contained in:
parent
4502a64514
commit
aae217dd00
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -194,6 +194,10 @@ dependencies = [
|
||||||
name = "hbbytecode"
|
name = "hbbytecode"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hbjit"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hblang"
|
name = "hblang"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = ["hbasm", "hbbytecode", "hbvm", "hbxrt", "xtask", "hblang"]
|
members = ["hbasm", "hbbytecode", "hbvm", "hbxrt", "xtask", "hblang", "hbjit"]
|
||||||
|
|
6
hbjit/Cargo.toml
Normal file
6
hbjit/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[package]
|
||||||
|
name = "hbjit"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
3
hbjit/src/main.rs
Normal file
3
hbjit/src/main.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
14
hblang/examples/global_variables.hb
Normal file
14
hblang/examples/global_variables.hb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
global_var := 10;
|
||||||
|
|
||||||
|
complex_global_var := fib(global_var) - 5;
|
||||||
|
|
||||||
|
fib := fn(n: int): int {
|
||||||
|
if n <= 2 {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
return fib(n - 1) + fib(n - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
main := fn(): int {
|
||||||
|
return complex_global_var;
|
||||||
|
}
|
|
@ -3,6 +3,8 @@ use std::{
|
||||||
ops::Range,
|
ops::Range,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use hbvm::Vm;
|
||||||
|
|
||||||
use crate::ident::{self, Ident};
|
use crate::ident::{self, Ident};
|
||||||
|
|
||||||
use {
|
use {
|
||||||
|
@ -483,10 +485,63 @@ struct Global {
|
||||||
ty: Type,
|
ty: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CompileMem {
|
||||||
|
code: *mut u8,
|
||||||
|
mem: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CompileMem {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
code: std::ptr::null_mut(),
|
||||||
|
mem: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl hbvm::mem::Memory for CompileMem {
|
||||||
|
unsafe fn load(
|
||||||
|
&mut self,
|
||||||
|
addr: hbvm::mem::Address,
|
||||||
|
target: *mut u8,
|
||||||
|
count: usize,
|
||||||
|
) -> Result<(), hbvm::mem::LoadError> {
|
||||||
|
let sub = self
|
||||||
|
.mem
|
||||||
|
.get(addr.get() as usize..addr.get() as usize + count)
|
||||||
|
.ok_or(hbvm::mem::LoadError(addr))?;
|
||||||
|
|
||||||
|
target.copy_from(sub.as_ptr(), count);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn store(
|
||||||
|
&mut self,
|
||||||
|
addr: hbvm::mem::Address,
|
||||||
|
source: *const u8,
|
||||||
|
count: usize,
|
||||||
|
) -> Result<(), hbvm::mem::StoreError> {
|
||||||
|
self.mem
|
||||||
|
.get_mut(addr.get() as usize..addr.get() as usize + count)
|
||||||
|
.ok_or(hbvm::mem::StoreError(addr))?
|
||||||
|
.as_mut_ptr()
|
||||||
|
.copy_from(source, count);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn prog_read<T: Copy>(&mut self, addr: hbvm::mem::Address) -> T {
|
||||||
|
debug_assert!(std::mem::align_of::<T>() == 1);
|
||||||
|
*(self.code.add(addr.get() as usize) as *const T)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Codegen<'a> {
|
pub struct Codegen<'a> {
|
||||||
path: &'a str,
|
path: &'a str,
|
||||||
input: &'a [u8],
|
input: &'a [u8],
|
||||||
|
|
||||||
ret: Type,
|
ret: Type,
|
||||||
gpa: Rc<RefCell<RegAlloc>>,
|
gpa: Rc<RefCell<RegAlloc>>,
|
||||||
sa: Rc<RefCell<StackAlloc>>,
|
sa: Rc<RefCell<StackAlloc>>,
|
||||||
|
@ -500,6 +555,8 @@ pub struct Codegen<'a> {
|
||||||
pointers: Vec<Type>,
|
pointers: Vec<Type>,
|
||||||
globals: Vec<Global>,
|
globals: Vec<Global>,
|
||||||
main: Option<LabelId>,
|
main: Option<LabelId>,
|
||||||
|
|
||||||
|
vm: Vm<CompileMem, 0>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Codegen<'a> {
|
impl<'a> Codegen<'a> {
|
||||||
|
@ -573,9 +630,9 @@ impl<'a> Codegen<'a> {
|
||||||
self.gpa.borrow_mut().init_callee();
|
self.gpa.borrow_mut().init_callee();
|
||||||
|
|
||||||
log::dbg!("fn-args");
|
log::dbg!("fn-args");
|
||||||
let mut parama = 3..12;
|
let mut parama = self.param_alloc(fn_label.ret);
|
||||||
for (arg, &ty) in args.iter().zip(fn_label.args.iter()) {
|
for (arg, &ty) in args.iter().zip(fn_label.args.iter()) {
|
||||||
let refed = arg.last.is_some_and(|l| l.get() & parser::REFERENCED != 0);
|
let refed = arg.last.map_or(0, Cell::get);
|
||||||
let loc = self.load_arg(refed, ty, &mut parama);
|
let loc = self.load_arg(refed, ty, &mut parama);
|
||||||
self.vars.push(Variable {
|
self.vars.push(Variable {
|
||||||
id: arg.id,
|
id: arg.id,
|
||||||
|
@ -772,7 +829,9 @@ impl<'a> Codegen<'a> {
|
||||||
args: [ret_ty, args @ ..],
|
args: [ret_ty, args @ ..],
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let mut parama = 3..12;
|
let ty = self.ty(ret_ty);
|
||||||
|
|
||||||
|
let mut parama = self.param_alloc(ty);
|
||||||
let mut values = Vec::with_capacity(args.len());
|
let mut values = Vec::with_capacity(args.len());
|
||||||
for arg in args {
|
for arg in args {
|
||||||
let arg = self.expr(arg)?;
|
let arg = self.expr(arg)?;
|
||||||
|
@ -781,7 +840,6 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
drop(values);
|
drop(values);
|
||||||
|
|
||||||
let ty = self.ty(ret_ty);
|
|
||||||
let loc = self.alloc_ret_loc(ty, ctx);
|
let loc = self.alloc_ret_loc(ty, ctx);
|
||||||
|
|
||||||
self.code.encode(i::eca());
|
self.code.encode(i::eca());
|
||||||
|
@ -1019,7 +1077,7 @@ impl<'a> Codegen<'a> {
|
||||||
let func = self.get_label(*id);
|
let func = self.get_label(*id);
|
||||||
let fn_label = self.labels[func as usize].clone();
|
let fn_label = self.labels[func as usize].clone();
|
||||||
|
|
||||||
let mut parama = 3..12;
|
let mut parama = self.param_alloc(fn_label.ret);
|
||||||
let mut values = Vec::with_capacity(args.len());
|
let mut values = Vec::with_capacity(args.len());
|
||||||
for (earg, &ty) in args.iter().zip(fn_label.args.iter()) {
|
for (earg, &ty) in args.iter().zip(fn_label.args.iter()) {
|
||||||
let arg = self.expr_ctx(earg, Ctx::Inferred(ty))?;
|
let arg = self.expr_ctx(earg, Ctx::Inferred(ty))?;
|
||||||
|
@ -1137,6 +1195,7 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
E::Loop { body, .. } => 'a: {
|
E::Loop { body, .. } => 'a: {
|
||||||
log::dbg!("loop");
|
log::dbg!("loop");
|
||||||
|
|
||||||
let loop_start = self.code.code.len() as u32;
|
let loop_start = self.code.code.len() as u32;
|
||||||
self.loops.push(Loop {
|
self.loops.push(Loop {
|
||||||
var_count: self.vars.len() as _,
|
var_count: self.vars.len() as _,
|
||||||
|
@ -1715,11 +1774,11 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_arg(&mut self, referenced: bool, ty: Type, parama: &mut Range<u8>) -> Loc {
|
fn load_arg(&mut self, flags: parser::IdentFlags, ty: Type, parama: &mut Range<u8>) -> Loc {
|
||||||
let size = self.size_of(ty);
|
let size = self.size_of(ty);
|
||||||
match size {
|
match size {
|
||||||
0 => Loc::Imm(0),
|
0 => Loc::Imm(0),
|
||||||
..=8 if !referenced => {
|
..=8 if flags & parser::REFERENCED == 0 => {
|
||||||
let reg = self.alloc_reg();
|
let reg = self.alloc_reg();
|
||||||
self.code.encode(instrs::cp(reg.0, parama.next().unwrap()));
|
self.code.encode(instrs::cp(reg.0, parama.next().unwrap()));
|
||||||
Loc::Reg(reg)
|
Loc::Reg(reg)
|
||||||
|
@ -1735,7 +1794,13 @@ impl<'a> Codegen<'a> {
|
||||||
parama.next().unwrap();
|
parama.next().unwrap();
|
||||||
Loc::Stack(stack, 0)
|
Loc::Stack(stack, 0)
|
||||||
}
|
}
|
||||||
..=u64::MAX => {
|
_ if flags & (parser::MUTABLE | parser::REFERENCED) == 0 => {
|
||||||
|
let ptr = parama.next().unwrap();
|
||||||
|
let reg = self.alloc_reg();
|
||||||
|
self.code.encode(instrs::cp(reg.0, ptr));
|
||||||
|
Loc::Deref(reg, None, 0)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
let ptr = parama.next().unwrap();
|
let ptr = parama.next().unwrap();
|
||||||
let stack = self.alloc_stack(size);
|
let stack = self.alloc_stack(size);
|
||||||
self.assign(
|
self.assign(
|
||||||
|
@ -1802,6 +1867,10 @@ impl<'a> Codegen<'a> {
|
||||||
..=u64::MAX => {}
|
..=u64::MAX => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn param_alloc(&self, ret: Type) -> Range<u8> {
|
||||||
|
2 + (9..=16).contains(&self.size_of(ret)) as u8..12
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1986,5 +2055,6 @@ mod tests {
|
||||||
different_types => include_str!("../examples/different_types.hb");
|
different_types => include_str!("../examples/different_types.hb");
|
||||||
struct_operators => include_str!("../examples/struct_operators.hb");
|
struct_operators => include_str!("../examples/struct_operators.hb");
|
||||||
directives => include_str!("../examples/directives.hb");
|
directives => include_str!("../examples/directives.hb");
|
||||||
|
global_variables => include_str!("../examples/global_variables.hb");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
self.lexer = Lexer::new(input);
|
self.lexer = Lexer::new(input);
|
||||||
self.token = self.lexer.next();
|
self.token = self.lexer.next();
|
||||||
|
|
||||||
let f = self.collect(|s| (s.token.kind != TokenKind::Eof).then(|| s.expr()));
|
let f = self.collect_list(TokenKind::Semi, TokenKind::Eof, Self::expr);
|
||||||
self.pop_scope(0);
|
self.pop_scope(0);
|
||||||
let has_undeclared = !self.idents.is_empty();
|
let has_undeclared = !self.idents.is_empty();
|
||||||
for id in self.idents.drain(..) {
|
for id in self.idents.drain(..) {
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
code size: 483
|
code size: 461
|
||||||
ret: 3
|
ret: 3
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
|
@ -54,6 +54,18 @@ pub struct Vm<Mem, const TIMER_QUOTIENT: usize> {
|
||||||
copier: Option<BlockCopier>,
|
copier: Option<BlockCopier>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Mem: Default, const TIMER_QUOTIENT: usize> Default for Vm<Mem, TIMER_QUOTIENT> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
registers: [Value::from(0_u64); 256],
|
||||||
|
memory: Mem::default(),
|
||||||
|
pc: Address::default(),
|
||||||
|
timer: 0,
|
||||||
|
copier: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<Mem, const TIMER_QUOTIENT: usize> Vm<Mem, TIMER_QUOTIENT>
|
impl<Mem, const TIMER_QUOTIENT: usize> Vm<Mem, TIMER_QUOTIENT>
|
||||||
where
|
where
|
||||||
Mem: Memory,
|
Mem: Memory,
|
||||||
|
|
|
@ -6,7 +6,7 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Memory address
|
/// Memory address
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Address(u64);
|
pub struct Address(u64);
|
||||||
impl Address {
|
impl Address {
|
||||||
/// A null address
|
/// A null address
|
||||||
|
|
Loading…
Reference in a new issue