implementing global variables
This commit is contained in:
parent
15e4762d4a
commit
00949c4ea8
|
@ -1,4 +1,3 @@
|
||||||
pub use self::reg::{RET_ADDR, STACK_PTR, ZERO};
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
ident::{self, Ident},
|
ident::{self, Ident},
|
||||||
|
@ -7,13 +6,13 @@ use {
|
||||||
parser::{
|
parser::{
|
||||||
self, find_symbol, idfl, CommentOr, CtorField, Expr, ExprRef, FileId, Pos, StructField,
|
self, find_symbol, idfl, CommentOr, CtorField, Expr, ExprRef, FileId, Pos, StructField,
|
||||||
},
|
},
|
||||||
|
reg,
|
||||||
ty::{self, TyCheck},
|
ty::{self, TyCheck},
|
||||||
Field, Func, Global, LoggedMem, OffsetIter, ParamAlloc, Reloc, Sig, Struct, SymKey,
|
Comptime, Field, Func, Global, OffsetIter, ParamAlloc, Reloc, Sig, Struct, SymKey,
|
||||||
TypedReloc, Types, HEADER_SIZE,
|
TypedReloc, Types,
|
||||||
},
|
},
|
||||||
alloc::{boxed::Box, string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
core::fmt::Display,
|
core::{assert_matches::debug_assert_matches, fmt::Display},
|
||||||
std::assert_matches::debug_assert_matches,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type Offset = u32;
|
type Offset = u32;
|
||||||
|
@ -163,13 +162,8 @@ mod stack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod reg {
|
mod rall {
|
||||||
use alloc::vec::Vec;
|
use {crate::reg::*, alloc::vec::Vec};
|
||||||
|
|
||||||
pub const STACK_PTR: Reg = 254;
|
|
||||||
pub const ZERO: Reg = 0;
|
|
||||||
pub const RET: Reg = 1;
|
|
||||||
pub const RET_ADDR: Reg = 31;
|
|
||||||
|
|
||||||
type Reg = u8;
|
type Reg = u8;
|
||||||
|
|
||||||
|
@ -323,7 +317,7 @@ struct CtValue(u64);
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
enum Loc {
|
enum Loc {
|
||||||
Rt { derefed: bool, reg: reg::Id, stack: Option<stack::Id>, offset: Offset },
|
Rt { derefed: bool, reg: rall::Id, stack: Option<stack::Id>, offset: Offset },
|
||||||
Ct { derefed: bool, value: CtValue },
|
Ct { derefed: bool, value: CtValue },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,7 +326,7 @@ impl Loc {
|
||||||
Self::Rt { stack: Some(stack), reg: reg::STACK_PTR.into(), derefed: true, offset: 0 }
|
Self::Rt { stack: Some(stack), reg: reg::STACK_PTR.into(), derefed: true, offset: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reg(reg: impl Into<reg::Id>) -> Self {
|
fn reg(reg: impl Into<rall::Id>) -> Self {
|
||||||
let reg = reg.into();
|
let reg = reg.into();
|
||||||
assert!(reg.get() != 0);
|
assert!(reg.get() != 0);
|
||||||
Self::Rt { derefed: false, reg, stack: None, offset: 0 }
|
Self::Rt { derefed: false, reg, stack: None, offset: 0 }
|
||||||
|
@ -406,7 +400,7 @@ impl Loc {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_stack(&self) -> bool {
|
fn is_stack(&self) -> bool {
|
||||||
matches!(self, Self::Rt { derefed: true, reg, stack: Some(_), offset: 0 } if reg.get() == STACK_PTR)
|
matches!(self, Self::Rt { derefed: true, reg, stack: Some(_), offset: 0 } if reg.get() == reg::STACK_PTR)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_reg(&self) -> bool {
|
fn is_reg(&self) -> bool {
|
||||||
|
@ -414,8 +408,8 @@ impl Loc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<reg::Id> for Loc {
|
impl From<rall::Id> for Loc {
|
||||||
fn from(reg: reg::Id) -> Self {
|
fn from(reg: rall::Id) -> Self {
|
||||||
Loc::reg(reg)
|
Loc::reg(reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -451,13 +445,13 @@ struct ItemCtx {
|
||||||
file: FileId,
|
file: FileId,
|
||||||
id: ty::Kind,
|
id: ty::Kind,
|
||||||
ret: Option<ty::Id>,
|
ret: Option<ty::Id>,
|
||||||
ret_reg: reg::Id,
|
ret_reg: rall::Id,
|
||||||
inline_ret_loc: Loc,
|
inline_ret_loc: Loc,
|
||||||
|
|
||||||
task_base: usize,
|
task_base: usize,
|
||||||
|
|
||||||
stack: stack::Alloc,
|
stack: stack::Alloc,
|
||||||
regs: reg::Alloc,
|
regs: rall::Alloc,
|
||||||
|
|
||||||
loops: Vec<Loop>,
|
loops: Vec<Loop>,
|
||||||
vars: Vec<Variable>,
|
vars: Vec<Variable>,
|
||||||
|
@ -510,12 +504,12 @@ impl ItemCtx {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_prelude(&mut self) {
|
fn emit_prelude(&mut self) {
|
||||||
self.emit(instrs::addi64(STACK_PTR, STACK_PTR, 0));
|
self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, 0));
|
||||||
self.emit(instrs::st(RET_ADDR, STACK_PTR, 0, 0));
|
self.emit(instrs::st(reg::RET_ADDR, reg::STACK_PTR, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_entry_prelude(&mut self) {
|
fn emit_entry_prelude(&mut self) {
|
||||||
self.emit(jal(RET_ADDR, reg::ZERO, 0));
|
self.emit(jal(reg::RET_ADDR, reg::ZERO, 0));
|
||||||
self.emit(tx());
|
self.emit(tx());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,32 +636,6 @@ struct Pool {
|
||||||
arg_locs: Vec<Loc>,
|
arg_locs: Vec<Loc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const VM_STACK_SIZE: usize = 1024 * 64;
|
|
||||||
|
|
||||||
pub struct Comptime {
|
|
||||||
pub vm: hbvm::Vm<LoggedMem, { 1024 * 10 }>,
|
|
||||||
stack: Box<[u8; VM_STACK_SIZE]>,
|
|
||||||
code: Vec<u8>,
|
|
||||||
}
|
|
||||||
impl Comptime {
|
|
||||||
fn reset(&mut self) {
|
|
||||||
let ptr = unsafe { self.stack.as_mut_ptr().cast::<u8>().add(VM_STACK_SIZE) as u64 };
|
|
||||||
self.vm.registers.fill(hbvm::value::Value(0));
|
|
||||||
self.vm.write_reg(STACK_PTR, ptr);
|
|
||||||
self.vm.pc = hbvm::mem::Address::new(self.code.as_ptr() as u64 + HEADER_SIZE as u64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Comptime {
|
|
||||||
fn default() -> Self {
|
|
||||||
let mut stack = Box::<[u8; VM_STACK_SIZE]>::new_uninit();
|
|
||||||
let mut vm = hbvm::Vm::default();
|
|
||||||
let ptr = unsafe { stack.as_mut_ptr().cast::<u8>().add(VM_STACK_SIZE) as u64 };
|
|
||||||
vm.write_reg(STACK_PTR, ptr);
|
|
||||||
Self { vm, stack: unsafe { stack.assume_init() }, code: Default::default() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod trap {
|
mod trap {
|
||||||
use {
|
use {
|
||||||
super::ty,
|
super::ty,
|
||||||
|
@ -834,7 +802,7 @@ impl Codegen {
|
||||||
ptr = ptr.offset(size);
|
ptr = ptr.offset(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stack_offset(2, STACK_PTR, Some(&stack), 0);
|
self.stack_offset(2, reg::STACK_PTR, Some(&stack), 0);
|
||||||
let val = self.eca(
|
let val = self.eca(
|
||||||
trap::Trap::MakeStruct(trap::MakeStruct {
|
trap::Trap::MakeStruct(trap::MakeStruct {
|
||||||
file: self.ci.file,
|
file: self.ci.file,
|
||||||
|
@ -1427,7 +1395,7 @@ impl Codegen {
|
||||||
|
|
||||||
let reloc = Reloc::new(self.ci.code.len(), 3, 4);
|
let reloc = Reloc::new(self.ci.code.len(), 3, 4);
|
||||||
self.ci.relocs.push(TypedReloc { target: ty::Kind::Func(func).compress(), reloc });
|
self.ci.relocs.push(TypedReloc { target: ty::Kind::Func(func).compress(), reloc });
|
||||||
self.ci.emit(jal(RET_ADDR, ZERO, 0));
|
self.ci.emit(jal(reg::RET_ADDR, reg::ZERO, 0));
|
||||||
self.make_func_reachable(func);
|
self.make_func_reachable(func);
|
||||||
|
|
||||||
if should_momize {
|
if should_momize {
|
||||||
|
@ -2194,7 +2162,7 @@ impl Codegen {
|
||||||
self.ci.emit(instrs::cp(reg.get(), 1));
|
self.ci.emit(instrs::cp(reg.get(), 1));
|
||||||
self.ci.ret_reg = reg;
|
self.ci.ret_reg = reg;
|
||||||
} else {
|
} else {
|
||||||
self.ci.ret_reg = reg::Id::RET;
|
self.ci.ret_reg = rall::Id::RET;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.expr(body).is_some() {
|
if self.expr(body).is_some() {
|
||||||
|
@ -2208,7 +2176,7 @@ impl Codegen {
|
||||||
self.ci.vars = vars;
|
self.ci.vars = vars;
|
||||||
|
|
||||||
self.ci.finalize();
|
self.ci.finalize();
|
||||||
self.ci.emit(jala(ZERO, RET_ADDR, 0));
|
self.ci.emit(jala(reg::ZERO, reg::RET_ADDR, 0));
|
||||||
self.ci.regs.free(core::mem::take(&mut self.ci.ret_reg));
|
self.ci.regs.free(core::mem::take(&mut self.ci.ret_reg));
|
||||||
self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code);
|
self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code);
|
||||||
self.tys.ins.funcs[id as usize].relocs = self.ci.relocs.drain(..).collect();
|
self.tys.ins.funcs[id as usize].relocs = self.ci.relocs.drain(..).collect();
|
||||||
|
@ -2273,7 +2241,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loc_to_reg(&mut self, loc: impl Into<LocCow>, size: Size) -> reg::Id {
|
fn loc_to_reg(&mut self, loc: impl Into<LocCow>, size: Size) -> rall::Id {
|
||||||
match loc.into() {
|
match loc.into() {
|
||||||
LocCow::Owned(Loc::Rt { derefed: false, mut reg, offset, stack }) => {
|
LocCow::Owned(Loc::Rt { derefed: false, mut reg, offset, stack }) => {
|
||||||
debug_assert!(stack.is_none(), "TODO");
|
debug_assert!(stack.is_none(), "TODO");
|
||||||
|
@ -2711,10 +2679,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tys.dump_reachable(last_fn as _, &mut self.ct.code);
|
self.tys.dump_reachable(last_fn as _, &mut self.ct.code);
|
||||||
let entry =
|
let prev_pc = self.ct.push_pc(self.tys.ins.funcs[last_fn].offset);
|
||||||
&mut self.ct.code[self.tys.ins.funcs[last_fn].offset as usize] as *mut _ as _;
|
|
||||||
let prev_pc = core::mem::replace(&mut self.ct.vm.pc, hbvm::mem::Address::new(entry))
|
|
||||||
- self.ct.code.as_ptr() as usize;
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
|
@ -2731,7 +2696,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.run_vm();
|
self.run_vm();
|
||||||
self.ct.vm.pc = prev_pc + self.ct.code.as_ptr() as usize;
|
self.ct.pop_pc(prev_pc);
|
||||||
|
|
||||||
let func = self.tys.ins.funcs.pop().unwrap();
|
let func = self.tys.ins.funcs.pop().unwrap();
|
||||||
self.ci.code = func.code;
|
self.ci.code = func.code;
|
||||||
|
@ -2815,7 +2780,7 @@ impl Codegen {
|
||||||
&self.files[self.ci.file as usize]
|
&self.files[self.ci.file as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cow_reg(&mut self, rhs: reg::Id) -> reg::Id {
|
fn cow_reg(&mut self, rhs: rall::Id) -> rall::Id {
|
||||||
if rhs.is_ref() {
|
if rhs.is_ref() {
|
||||||
let reg = self.ci.regs.allocate();
|
let reg = self.ci.regs.allocate();
|
||||||
self.ci.emit(cp(reg.get(), rhs.get()));
|
self.ci.emit(cp(reg.get(), rhs.get()));
|
||||||
|
|
|
@ -37,7 +37,7 @@ use {
|
||||||
parser::{CommentOr, Expr, ExprRef, FileId, Pos},
|
parser::{CommentOr, Expr, ExprRef, FileId, Pos},
|
||||||
ty::ArrayLen,
|
ty::ArrayLen,
|
||||||
},
|
},
|
||||||
alloc::{collections::BTreeMap, string::String, vec::Vec},
|
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
||||||
core::{cell::Cell, ops::Range},
|
core::{cell::Cell, ops::Range},
|
||||||
hashbrown::hash_map,
|
hashbrown::hash_map,
|
||||||
hbbytecode as instrs,
|
hbbytecode as instrs,
|
||||||
|
@ -531,11 +531,11 @@ mod ty {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Display<'a> {
|
impl<'a> Display<'a> {
|
||||||
pub(super) fn new(tys: &'a super::Types, files: &'a [parser::Ast], ty: Id) -> Self {
|
pub fn new(tys: &'a super::Types, files: &'a [parser::Ast], ty: Id) -> Self {
|
||||||
Self { tys, files, ty }
|
Self { tys, files, ty }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rety(&self, ty: Id) -> Self {
|
pub fn rety(&self, ty: Id) -> Self {
|
||||||
Self::new(self.tys, self.files, ty)
|
Self::new(self.tys, self.files, ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1039,7 +1039,7 @@ impl Types {
|
||||||
AbleOsExecutableHeader {
|
AbleOsExecutableHeader {
|
||||||
magic_number: [0x15, 0x91, 0xD2],
|
magic_number: [0x15, 0x91, 0xD2],
|
||||||
executable_version: 0,
|
executable_version: 0,
|
||||||
code_length: (code_length - HEADER_SIZE) as _,
|
code_length: code_length.saturating_sub(HEADER_SIZE) as _,
|
||||||
data_length: data_length as _,
|
data_length: data_length as _,
|
||||||
debug_length: 0,
|
debug_length: 0,
|
||||||
config_length: 0,
|
config_length: 0,
|
||||||
|
@ -1294,6 +1294,43 @@ impl Default for FnvHasher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VM_STACK_SIZE: usize = 1024 * 64;
|
||||||
|
|
||||||
|
pub struct Comptime {
|
||||||
|
pub vm: hbvm::Vm<LoggedMem, { 1024 * 10 }>,
|
||||||
|
stack: Box<[u8; VM_STACK_SIZE]>,
|
||||||
|
code: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Comptime {
|
||||||
|
fn reset(&mut self) {
|
||||||
|
let ptr = unsafe { self.stack.as_mut_ptr().cast::<u8>().add(VM_STACK_SIZE) as u64 };
|
||||||
|
self.vm.registers.fill(hbvm::value::Value(0));
|
||||||
|
self.vm.write_reg(reg::STACK_PTR, ptr);
|
||||||
|
self.vm.pc = hbvm::mem::Address::new(self.code.as_ptr() as u64 + HEADER_SIZE as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_pc(&mut self, offset: Offset) -> hbvm::mem::Address {
|
||||||
|
let entry = &mut self.code[offset as usize] as *mut _ as _;
|
||||||
|
core::mem::replace(&mut self.vm.pc, hbvm::mem::Address::new(entry))
|
||||||
|
- self.code.as_ptr() as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_pc(&mut self, prev_pc: hbvm::mem::Address) {
|
||||||
|
self.vm.pc = prev_pc + self.code.as_ptr() as usize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Comptime {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut stack = Box::<[u8; VM_STACK_SIZE]>::new_uninit();
|
||||||
|
let mut vm = hbvm::Vm::default();
|
||||||
|
let ptr = unsafe { stack.as_mut_ptr().cast::<u8>().add(VM_STACK_SIZE) as u64 };
|
||||||
|
vm.write_reg(reg::STACK_PTR, ptr);
|
||||||
|
Self { vm, stack: unsafe { stack.assume_init() }, code: Default::default() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn run_test(
|
pub fn run_test(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
|
@ -1455,7 +1492,7 @@ fn test_run_vm(out: &[u8], output: &mut String) {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
vm.write_reg(codegen::STACK_PTR, unsafe { stack.as_mut_ptr().add(stack.len()) } as u64);
|
vm.write_reg(reg::STACK_PTR, unsafe { stack.as_mut_ptr().add(stack.len()) } as u64);
|
||||||
|
|
||||||
let stat = loop {
|
let stat = loop {
|
||||||
match vm.run() {
|
match vm.run() {
|
||||||
|
|
248
lang/src/son.rs
248
lang/src/son.rs
|
@ -10,9 +10,9 @@ use {
|
||||||
Expr, ExprRef, FileId, Pos,
|
Expr, ExprRef, FileId, Pos,
|
||||||
},
|
},
|
||||||
reg, task,
|
reg, task,
|
||||||
ty::{self, ArrayLen},
|
ty::{self, ArrayLen, Tuple},
|
||||||
vc::{BitSet, Vc},
|
vc::{BitSet, Vc},
|
||||||
Func, HashMap, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types,
|
Comptime, Func, Global, HashMap, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types,
|
||||||
},
|
},
|
||||||
alloc::{string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
core::{
|
core::{
|
||||||
|
@ -73,6 +73,43 @@ impl Default for Nodes {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Nodes {
|
impl Nodes {
|
||||||
|
fn graphviz_low(
|
||||||
|
&self,
|
||||||
|
tys: &Types,
|
||||||
|
files: &[parser::Ast],
|
||||||
|
out: &mut String,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
for (i, node) in self.iter() {
|
||||||
|
let color = if self.is_cfg(i) { "yellow" } else { "white" };
|
||||||
|
writeln!(
|
||||||
|
out,
|
||||||
|
"node{i}[label=\"{} {}\" color={color}]",
|
||||||
|
node.kind,
|
||||||
|
ty::Display::new(tys, files, node.ty)
|
||||||
|
)?;
|
||||||
|
for (j, &o) in node.outputs.iter().enumerate() {
|
||||||
|
let color = if self.is_cfg(i) && self.is_cfg(o) { "red" } else { "lightgray" };
|
||||||
|
let index = self[o].inputs.iter().position(|&inp| i == inp).unwrap();
|
||||||
|
let style = if index == 0 && !self.is_cfg(o) { "style=dotted" } else { "" };
|
||||||
|
writeln!(
|
||||||
|
out,
|
||||||
|
"node{o} -> node{i}[color={color} taillabel={index} headlabel={j} {style}]",
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn graphviz(&self, tys: &Types, files: &[parser::Ast]) {
|
||||||
|
let out = &mut String::new();
|
||||||
|
_ = self.graphviz_low(tys, files, out);
|
||||||
|
log::info!("{out}");
|
||||||
|
}
|
||||||
|
|
||||||
fn gcm(&mut self) {
|
fn gcm(&mut self) {
|
||||||
self.visited.clear(self.values.len());
|
self.visited.clear(self.values.len());
|
||||||
push_up(self);
|
push_up(self);
|
||||||
|
@ -436,6 +473,7 @@ impl Nodes {
|
||||||
Kind::Call { func } => {
|
Kind::Call { func } => {
|
||||||
write!(out, "call: {func} {} ", self[node].depth)
|
write!(out, "call: {func} {} ", self[node].depth)
|
||||||
}
|
}
|
||||||
|
Kind::Global { global } => write!(out, "glob: {global:<5}"),
|
||||||
Kind::Entry => write!(out, "ctrl: {:<5}", "entry"),
|
Kind::Entry => write!(out, "ctrl: {:<5}", "entry"),
|
||||||
Kind::Then => write!(out, "ctrl: {:<5}", "then"),
|
Kind::Then => write!(out, "ctrl: {:<5}", "then"),
|
||||||
Kind::Else => write!(out, "ctrl: {:<5}", "else"),
|
Kind::Else => write!(out, "ctrl: {:<5}", "else"),
|
||||||
|
@ -808,6 +846,10 @@ pub enum Kind {
|
||||||
BinOp {
|
BinOp {
|
||||||
op: lexer::TokenKind,
|
op: lexer::TokenKind,
|
||||||
},
|
},
|
||||||
|
// [ctrl]
|
||||||
|
Global {
|
||||||
|
global: ty::Global,
|
||||||
|
},
|
||||||
// [ctrl, ...args]
|
// [ctrl, ...args]
|
||||||
Call {
|
Call {
|
||||||
func: ty::Func,
|
func: ty::Func,
|
||||||
|
@ -931,7 +973,6 @@ impl Scope {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ItemCtx {
|
struct ItemCtx {
|
||||||
file: FileId,
|
file: FileId,
|
||||||
id: ty::Id,
|
|
||||||
ret: Option<ty::Id>,
|
ret: Option<ty::Id>,
|
||||||
task_base: usize,
|
task_base: usize,
|
||||||
nodes: Nodes,
|
nodes: Nodes,
|
||||||
|
@ -946,7 +987,7 @@ struct ItemCtx {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemCtx {
|
impl ItemCtx {
|
||||||
fn init(&mut self, file: FileId, id: ty::Id, ret: Option<ty::Id>, task_base: usize) {
|
fn init(&mut self, file: FileId, ret: Option<ty::Id>, task_base: usize) {
|
||||||
debug_assert_eq!(self.loops.len(), 0);
|
debug_assert_eq!(self.loops.len(), 0);
|
||||||
debug_assert_eq!(self.scope.vars.len(), 0);
|
debug_assert_eq!(self.scope.vars.len(), 0);
|
||||||
debug_assert_eq!(self.ret_relocs.len(), 0);
|
debug_assert_eq!(self.ret_relocs.len(), 0);
|
||||||
|
@ -955,7 +996,6 @@ impl ItemCtx {
|
||||||
debug_assert_eq!(self.code.len(), 0);
|
debug_assert_eq!(self.code.len(), 0);
|
||||||
|
|
||||||
self.file = file;
|
self.file = file;
|
||||||
self.id = id;
|
|
||||||
self.ret = ret;
|
self.ret = ret;
|
||||||
self.task_base = task_base;
|
self.task_base = task_base;
|
||||||
|
|
||||||
|
@ -1109,6 +1149,14 @@ impl ItemCtx {
|
||||||
});
|
});
|
||||||
self.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
self.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
||||||
}
|
}
|
||||||
|
Kind::Global { global } => {
|
||||||
|
let reloc = Reloc::new(self.code.len(), 3, 4);
|
||||||
|
self.relocs.push(TypedReloc {
|
||||||
|
target: ty::Kind::Global(global).compress(),
|
||||||
|
reloc,
|
||||||
|
});
|
||||||
|
self.emit(instrs::lra(atr(allocs[0]), 0, 0));
|
||||||
|
}
|
||||||
Kind::Stck => {
|
Kind::Stck => {
|
||||||
let base = reg::STACK_PTR;
|
let base = reg::STACK_PTR;
|
||||||
let offset = func.nodes[nid].offset;
|
let offset = func.nodes[nid].offset;
|
||||||
|
@ -1166,7 +1214,13 @@ impl ItemCtx {
|
||||||
saved_regs.len()
|
saved_regs.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_body(&mut self, tys: &mut Types, sig: Sig) {
|
fn emit_body(&mut self, tys: &mut Types, files: &[parser::Ast], sig: Sig) {
|
||||||
|
self.nodes.graphviz(tys, files);
|
||||||
|
self.nodes.gcm();
|
||||||
|
self.nodes.check_final_integrity();
|
||||||
|
self.nodes.basic_blocks();
|
||||||
|
self.nodes.graphviz(tys, files);
|
||||||
|
|
||||||
'_open_function: {
|
'_open_function: {
|
||||||
self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, 0));
|
self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, 0));
|
||||||
self.emit(instrs::st(reg::RET_ADDR, reg::STACK_PTR, 0, 0));
|
self.emit(instrs::st(reg::RET_ADDR, reg::STACK_PTR, 0, 0));
|
||||||
|
@ -1236,10 +1290,6 @@ impl ItemCtx {
|
||||||
}
|
}
|
||||||
self.relocs.iter_mut().for_each(|r| r.reloc.offset -= stripped_prelude_size as u32);
|
self.relocs.iter_mut().for_each(|r| r.reloc.offset -= stripped_prelude_size as u32);
|
||||||
self.emit(instrs::jala(reg::ZERO, reg::RET_ADDR, 0));
|
self.emit(instrs::jala(reg::ZERO, reg::RET_ADDR, 0));
|
||||||
|
|
||||||
let ty::Kind::Func(id) = self.id.expand() else { unreachable!() };
|
|
||||||
tys.ins.funcs[id as usize].code.append(&mut self.code);
|
|
||||||
tys.ins.funcs[id as usize].relocs.append(&mut self.relocs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1273,11 +1323,10 @@ struct Pool {
|
||||||
impl Pool {
|
impl Pool {
|
||||||
pub fn push_ci(
|
pub fn push_ci(
|
||||||
&mut self,
|
&mut self,
|
||||||
target: &mut ItemCtx,
|
|
||||||
file: FileId,
|
file: FileId,
|
||||||
id: ty::Id,
|
|
||||||
ret: Option<ty::Id>,
|
ret: Option<ty::Id>,
|
||||||
task_base: usize,
|
task_base: usize,
|
||||||
|
target: &mut ItemCtx,
|
||||||
) {
|
) {
|
||||||
if let Some(slot) = self.cis.get_mut(self.used_cis) {
|
if let Some(slot) = self.cis.get_mut(self.used_cis) {
|
||||||
core::mem::swap(slot, target);
|
core::mem::swap(slot, target);
|
||||||
|
@ -1285,7 +1334,7 @@ impl Pool {
|
||||||
self.cis.push(ItemCtx::default());
|
self.cis.push(ItemCtx::default());
|
||||||
core::mem::swap(self.cis.last_mut().unwrap(), target);
|
core::mem::swap(self.cis.last_mut().unwrap(), target);
|
||||||
}
|
}
|
||||||
target.init(file, id, ret, task_base);
|
target.init(file, ret, task_base);
|
||||||
self.used_cis += 1;
|
self.used_cis += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1363,47 +1412,11 @@ pub struct Codegen<'a> {
|
||||||
pool: Pool,
|
pool: Pool,
|
||||||
#[expect(dead_code)]
|
#[expect(dead_code)]
|
||||||
ralloc: Regalloc,
|
ralloc: Regalloc,
|
||||||
|
ct: Comptime,
|
||||||
errors: RefCell<String>,
|
errors: RefCell<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Codegen<'a> {
|
impl<'a> Codegen<'a> {
|
||||||
fn graphviz_low(&self, out: &mut String) -> core::fmt::Result {
|
|
||||||
use core::fmt::Write;
|
|
||||||
|
|
||||||
for (i, node) in self.ci.nodes.iter() {
|
|
||||||
let color = if self.ci.nodes.is_cfg(i) { "yellow" } else { "white" };
|
|
||||||
writeln!(
|
|
||||||
out,
|
|
||||||
"node{i}[label=\"{} {}\" color={color}]",
|
|
||||||
node.kind,
|
|
||||||
self.ty_display(node.ty)
|
|
||||||
)?;
|
|
||||||
for (j, &o) in node.outputs.iter().enumerate() {
|
|
||||||
let color = if self.ci.nodes.is_cfg(i) && self.ci.nodes.is_cfg(o) {
|
|
||||||
"red"
|
|
||||||
} else {
|
|
||||||
"lightgray"
|
|
||||||
};
|
|
||||||
let index = self.ci.nodes[o].inputs.iter().position(|&inp| i == inp).unwrap();
|
|
||||||
let style =
|
|
||||||
if index == 0 && !self.ci.nodes.is_cfg(o) { "style=dotted" } else { "" };
|
|
||||||
writeln!(
|
|
||||||
out,
|
|
||||||
"node{o} -> node{i}[color={color} taillabel={index} headlabel={j} {style}]",
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn graphviz(&self) {
|
|
||||||
let out = &mut String::new();
|
|
||||||
_ = self.graphviz_low(out);
|
|
||||||
log::info!("{out}");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn store_mem(&mut self, region: Nid, value: Nid) -> Nid {
|
fn store_mem(&mut self, region: Nid, value: Nid) -> Nid {
|
||||||
if value == NEVER {
|
if value == NEVER {
|
||||||
return NEVER;
|
return NEVER;
|
||||||
|
@ -1475,8 +1488,20 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
Expr::Ident { id, pos, .. } => {
|
Expr::Ident { id, pos, .. } => {
|
||||||
let decl = self.find_or_declare(pos, self.ci.file, Ok(id));
|
let decl = self.find_or_declare(pos, self.ci.file, Ok(id));
|
||||||
|
match decl {
|
||||||
todo!()
|
ty::Kind::Global(g) => {
|
||||||
|
let gl = &self.tys.ins.globals[g as usize];
|
||||||
|
Some(
|
||||||
|
Value::ptr(self.ci.nodes.new_node(
|
||||||
|
gl.ty,
|
||||||
|
Kind::Global { global: g },
|
||||||
|
[VOID],
|
||||||
|
))
|
||||||
|
.ty(gl.ty),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => todo!("{decl:?}"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Expr::Number { value, .. } => Some(self.ci.nodes.new_node_lit(
|
Expr::Number { value, .. } => Some(self.ci.nodes.new_node_lit(
|
||||||
ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::Id::INT),
|
ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::Id::INT),
|
||||||
|
@ -2260,7 +2285,7 @@ impl<'a> Codegen<'a> {
|
||||||
let ast = &self.files[file as usize];
|
let ast = &self.files[file as usize];
|
||||||
let expr = func.expr.get(ast).unwrap();
|
let expr = func.expr.get(ast).unwrap();
|
||||||
|
|
||||||
self.pool.push_ci(&mut self.ci, file, ty::Kind::Func(id).compress(), Some(sig.ret), 0);
|
self.pool.push_ci(file, Some(sig.ret), 0, &mut self.ci);
|
||||||
|
|
||||||
let Expr::BinOp { right: &Expr::Closure { body, args, .. }, .. } = expr else {
|
let Expr::BinOp { right: &Expr::Closure { body, args, .. }, .. } = expr else {
|
||||||
unreachable!("{}", self.ast_display(expr))
|
unreachable!("{}", self.ast_display(expr))
|
||||||
|
@ -2276,26 +2301,20 @@ impl<'a> Codegen<'a> {
|
||||||
self.ci.scope.vars.push(Variable { id: arg.id, value, ty, ptr: false });
|
self.ci.scope.vars.push(Variable { id: arg.id, value, ty, ptr: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.expr(body).is_some() && self.tys.size_of(sig.ret) != 0 {
|
if self.expr(body).is_some() && sig.ret == ty::Id::VOID {
|
||||||
self.report(
|
self.report(
|
||||||
body.pos(),
|
body.pos(),
|
||||||
"expected all paths in the fucntion to return \
|
"expected all paths in the fucntion to return \
|
||||||
or the return type to be zero sized",
|
or the return type to be 'void'",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ci.finalize();
|
self.ci.finalize();
|
||||||
|
|
||||||
if self.errors.borrow().is_empty() {
|
if self.errors.borrow().is_empty() {
|
||||||
self.graphviz();
|
self.ci.emit_body(&mut self.tys, self.files, sig);
|
||||||
|
self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code);
|
||||||
self.ci.nodes.gcm();
|
self.tys.ins.funcs[id as usize].relocs.append(&mut self.ci.relocs);
|
||||||
self.ci.nodes.check_final_integrity();
|
|
||||||
self.ci.nodes.basic_blocks();
|
|
||||||
|
|
||||||
self.graphviz();
|
|
||||||
|
|
||||||
self.ci.emit_body(&mut self.tys, sig);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pool.pop_ci(&mut self.ci);
|
self.pool.pop_ci(&mut self.ci);
|
||||||
|
@ -2334,7 +2353,7 @@ impl<'a> Codegen<'a> {
|
||||||
),
|
),
|
||||||
Err(name) => self.report(pos, fa!("idk indentifier: {name}")),
|
Err(name) => self.report(pos, fa!("idk indentifier: {name}")),
|
||||||
}
|
}
|
||||||
return ty::Kind::Builtin(ty::NEVER);
|
return ty::Id::NEVER.expand();
|
||||||
};
|
};
|
||||||
|
|
||||||
let key = SymKey::Decl(file, ident);
|
let key = SymKey::Decl(file, ident);
|
||||||
|
@ -2398,8 +2417,81 @@ impl<'a> Codegen<'a> {
|
||||||
op: TokenKind::Decl,
|
op: TokenKind::Decl,
|
||||||
right: right @ (Expr::Struct { .. } | Expr::Mod { .. }),
|
right: right @ (Expr::Struct { .. } | Expr::Mod { .. }),
|
||||||
} => self.ty(right).expand(),
|
} => self.ty(right).expand(),
|
||||||
Expr::BinOp { left: Expr::Ident { .. }, op: TokenKind::Decl, right } => {
|
Expr::BinOp { left: &Expr::Ident { id: name, .. }, op: TokenKind::Decl, right } => {
|
||||||
todo!("{right:#?}");
|
let gid = self.tys.ins.globals.len() as ty::Global;
|
||||||
|
self.tys.ins.globals.push(Global { file, name, ..Default::default() });
|
||||||
|
|
||||||
|
let ty = ty::Kind::Global(gid);
|
||||||
|
self.pool.push_ci(file, None, self.tasks.len(), &mut self.ci);
|
||||||
|
|
||||||
|
let ret = Expr::Return { pos: right.pos(), val: Some(right) };
|
||||||
|
self.expr(&ret);
|
||||||
|
|
||||||
|
self.ci.finalize();
|
||||||
|
|
||||||
|
let ret = self.ci.ret.expect("for return type to be infered");
|
||||||
|
if self.errors.borrow().is_empty() {
|
||||||
|
self.ci.emit_body(&mut self.tys, self.files, Sig { args: Tuple::empty(), ret });
|
||||||
|
self.ci.code.truncate(self.ci.code.len() - instrs::jala(0, 0, 0).0);
|
||||||
|
self.ci.emit(instrs::tx());
|
||||||
|
|
||||||
|
let func = Func {
|
||||||
|
file,
|
||||||
|
name,
|
||||||
|
expr: ExprRef::new(expr),
|
||||||
|
relocs: core::mem::take(&mut self.ci.relocs),
|
||||||
|
code: core::mem::take(&mut self.ci.code),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
self.pool.pop_ci(&mut self.ci);
|
||||||
|
self.complete_call_graph();
|
||||||
|
|
||||||
|
let mut mem = vec![0u8; self.tys.size_of(ret) as usize];
|
||||||
|
|
||||||
|
// TODO: return them back
|
||||||
|
let fuc = self.tys.ins.funcs.len() as ty::Func;
|
||||||
|
self.tys.ins.funcs.push(func);
|
||||||
|
|
||||||
|
self.tys.dump_reachable(fuc, &mut self.ct.code);
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
let mut vc = String::new();
|
||||||
|
if let Err(e) = self.tys.disasm(&self.ct.code, self.files, &mut vc, |_| {})
|
||||||
|
{
|
||||||
|
panic!("{e} {}", vc);
|
||||||
|
} else {
|
||||||
|
log::trace!("{}", vc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ct.vm.write_reg(reg::RET, mem.as_mut_ptr() as u64);
|
||||||
|
let prev_pc = self.ct.push_pc(self.tys.ins.funcs[fuc as usize].offset);
|
||||||
|
loop {
|
||||||
|
match self.ct.vm.run().expect("TODO") {
|
||||||
|
hbvm::VmRunOk::End => break,
|
||||||
|
hbvm::VmRunOk::Timer => todo!(),
|
||||||
|
hbvm::VmRunOk::Ecall => todo!(),
|
||||||
|
hbvm::VmRunOk::Breakpoint => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.ct.pop_pc(prev_pc);
|
||||||
|
|
||||||
|
match mem.len() {
|
||||||
|
0 => unreachable!(),
|
||||||
|
len @ 1..=8 => mem
|
||||||
|
.copy_from_slice(&self.ct.vm.read_reg(reg::RET).0.to_ne_bytes()[..len]),
|
||||||
|
9..=16 => todo!(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tys.ins.globals[gid as usize].data = mem;
|
||||||
|
} else {
|
||||||
|
self.pool.pop_ci(&mut self.ci);
|
||||||
|
}
|
||||||
|
self.tys.ins.globals[gid as usize].ty = ret;
|
||||||
|
|
||||||
|
ty
|
||||||
}
|
}
|
||||||
e => unimplemented!("{e:#?}"),
|
e => unimplemented!("{e:#?}"),
|
||||||
};
|
};
|
||||||
|
@ -2755,14 +2847,6 @@ impl<'a> Function<'a> {
|
||||||
let mut parama = self.tys.parama(fuc.ret);
|
let mut parama = self.tys.parama(fuc.ret);
|
||||||
for (&(mut i), ti) in node.inputs[1..].iter().zip(fuc.args.range()) {
|
for (&(mut i), ti) in node.inputs[1..].iter().zip(fuc.args.range()) {
|
||||||
let ty = self.tys.ins.args[ti];
|
let ty = self.tys.ins.args[ti];
|
||||||
loop {
|
|
||||||
match self.nodes[i].kind {
|
|
||||||
Kind::Stre { .. } => i = self.nodes[i].inputs[2],
|
|
||||||
Kind::Load { .. } => i = self.nodes[i].inputs[1],
|
|
||||||
_ => break,
|
|
||||||
}
|
|
||||||
debug_assert_ne!(i, 0);
|
|
||||||
}
|
|
||||||
match self.tys.size_of(ty) {
|
match self.tys.size_of(ty) {
|
||||||
0 => continue,
|
0 => continue,
|
||||||
1..=8 => {
|
1..=8 => {
|
||||||
|
@ -2773,6 +2857,14 @@ impl<'a> Function<'a> {
|
||||||
}
|
}
|
||||||
9..=16 => todo!("pass in two register"),
|
9..=16 => todo!("pass in two register"),
|
||||||
_ => {
|
_ => {
|
||||||
|
loop {
|
||||||
|
match self.nodes[i].kind {
|
||||||
|
Kind::Stre { .. } => i = self.nodes[i].inputs[2],
|
||||||
|
Kind::Load { .. } => i = self.nodes[i].inputs[1],
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
debug_assert_ne!(i, 0);
|
||||||
|
}
|
||||||
debug_assert!(i != 0);
|
debug_assert!(i != 0);
|
||||||
ops.push(regalloc2::Operand::reg_fixed_use(
|
ops.push(regalloc2::Operand::reg_fixed_use(
|
||||||
self.rg(i),
|
self.rg(i),
|
||||||
|
@ -2790,6 +2882,10 @@ impl<'a> Function<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Kind::Global { .. } => {
|
||||||
|
let ops = vec![self.drg(nid)];
|
||||||
|
self.add_instr(nid, ops);
|
||||||
|
}
|
||||||
//Kind::Stck
|
//Kind::Stck
|
||||||
// if node.outputs.iter().all(|&n| {
|
// if node.outputs.iter().all(|&n| {
|
||||||
// matches!(self.nodes[n].kind, Kind::Stre | Kind::Load)
|
// matches!(self.nodes[n].kind, Kind::Stre | Kind::Load)
|
||||||
|
@ -3206,7 +3302,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
codegen.tys.assemble(&mut out);
|
codegen.tys.reassemble(&mut out);
|
||||||
|
|
||||||
let err = codegen.tys.disasm(&out, codegen.files, output, |_| {});
|
let err = codegen.tys.disasm(&out, codegen.files, output, |_| {});
|
||||||
if let Err(e) = err {
|
if let Err(e) = err {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
main:
|
||||||
|
LRA r2, r0, :complex_global_var
|
||||||
|
LD r3, r2, 0a, 8h
|
||||||
|
ADDI64 r1, r3, 5d
|
||||||
|
ST r1, r2, 0a, 8h
|
||||||
|
JALA r0, r31, 0a
|
||||||
|
code size: 71
|
||||||
|
ret: 55
|
||||||
|
status: Ok(())
|
Loading…
Reference in a new issue