forked from AbleOS/holey-bytes
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 {
|
||||
crate::{
|
||||
ident::{self, Ident},
|
||||
|
@ -7,13 +6,13 @@ use {
|
|||
parser::{
|
||||
self, find_symbol, idfl, CommentOr, CtorField, Expr, ExprRef, FileId, Pos, StructField,
|
||||
},
|
||||
reg,
|
||||
ty::{self, TyCheck},
|
||||
Field, Func, Global, LoggedMem, OffsetIter, ParamAlloc, Reloc, Sig, Struct, SymKey,
|
||||
TypedReloc, Types, HEADER_SIZE,
|
||||
Comptime, Field, Func, Global, OffsetIter, ParamAlloc, Reloc, Sig, Struct, SymKey,
|
||||
TypedReloc, Types,
|
||||
},
|
||||
alloc::{boxed::Box, string::String, vec::Vec},
|
||||
core::fmt::Display,
|
||||
std::assert_matches::debug_assert_matches,
|
||||
alloc::{string::String, vec::Vec},
|
||||
core::{assert_matches::debug_assert_matches, fmt::Display},
|
||||
};
|
||||
|
||||
type Offset = u32;
|
||||
|
@ -163,13 +162,8 @@ mod stack {
|
|||
}
|
||||
}
|
||||
|
||||
mod reg {
|
||||
use 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;
|
||||
mod rall {
|
||||
use {crate::reg::*, alloc::vec::Vec};
|
||||
|
||||
type Reg = u8;
|
||||
|
||||
|
@ -323,7 +317,7 @@ struct CtValue(u64);
|
|||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
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 },
|
||||
}
|
||||
|
||||
|
@ -332,7 +326,7 @@ impl Loc {
|
|||
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();
|
||||
assert!(reg.get() != 0);
|
||||
Self::Rt { derefed: false, reg, stack: None, offset: 0 }
|
||||
|
@ -406,7 +400,7 @@ impl Loc {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -414,8 +408,8 @@ impl Loc {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<reg::Id> for Loc {
|
||||
fn from(reg: reg::Id) -> Self {
|
||||
impl From<rall::Id> for Loc {
|
||||
fn from(reg: rall::Id) -> Self {
|
||||
Loc::reg(reg)
|
||||
}
|
||||
}
|
||||
|
@ -451,13 +445,13 @@ struct ItemCtx {
|
|||
file: FileId,
|
||||
id: ty::Kind,
|
||||
ret: Option<ty::Id>,
|
||||
ret_reg: reg::Id,
|
||||
ret_reg: rall::Id,
|
||||
inline_ret_loc: Loc,
|
||||
|
||||
task_base: usize,
|
||||
|
||||
stack: stack::Alloc,
|
||||
regs: reg::Alloc,
|
||||
regs: rall::Alloc,
|
||||
|
||||
loops: Vec<Loop>,
|
||||
vars: Vec<Variable>,
|
||||
|
@ -510,12 +504,12 @@ impl ItemCtx {
|
|||
}
|
||||
|
||||
fn emit_prelude(&mut self) {
|
||||
self.emit(instrs::addi64(STACK_PTR, STACK_PTR, 0));
|
||||
self.emit(instrs::st(RET_ADDR, STACK_PTR, 0, 0));
|
||||
self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, 0));
|
||||
self.emit(instrs::st(reg::RET_ADDR, reg::STACK_PTR, 0, 0));
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -642,32 +636,6 @@ struct Pool {
|
|||
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 {
|
||||
use {
|
||||
super::ty,
|
||||
|
@ -834,7 +802,7 @@ impl Codegen {
|
|||
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(
|
||||
trap::Trap::MakeStruct(trap::MakeStruct {
|
||||
file: self.ci.file,
|
||||
|
@ -1427,7 +1395,7 @@ impl Codegen {
|
|||
|
||||
let reloc = Reloc::new(self.ci.code.len(), 3, 4);
|
||||
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);
|
||||
|
||||
if should_momize {
|
||||
|
@ -2194,7 +2162,7 @@ impl Codegen {
|
|||
self.ci.emit(instrs::cp(reg.get(), 1));
|
||||
self.ci.ret_reg = reg;
|
||||
} else {
|
||||
self.ci.ret_reg = reg::Id::RET;
|
||||
self.ci.ret_reg = rall::Id::RET;
|
||||
}
|
||||
|
||||
if self.expr(body).is_some() {
|
||||
|
@ -2208,7 +2176,7 @@ impl Codegen {
|
|||
self.ci.vars = vars;
|
||||
|
||||
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.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();
|
||||
|
@ -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() {
|
||||
LocCow::Owned(Loc::Rt { derefed: false, mut reg, offset, stack }) => {
|
||||
debug_assert!(stack.is_none(), "TODO");
|
||||
|
@ -2711,10 +2679,7 @@ impl Codegen {
|
|||
}
|
||||
|
||||
self.tys.dump_reachable(last_fn as _, &mut self.ct.code);
|
||||
let entry =
|
||||
&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;
|
||||
let prev_pc = self.ct.push_pc(self.tys.ins.funcs[last_fn].offset);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
|
@ -2731,7 +2696,7 @@ impl Codegen {
|
|||
}
|
||||
|
||||
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();
|
||||
self.ci.code = func.code;
|
||||
|
@ -2815,7 +2780,7 @@ impl Codegen {
|
|||
&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() {
|
||||
let reg = self.ci.regs.allocate();
|
||||
self.ci.emit(cp(reg.get(), rhs.get()));
|
||||
|
|
|
@ -37,7 +37,7 @@ use {
|
|||
parser::{CommentOr, Expr, ExprRef, FileId, Pos},
|
||||
ty::ArrayLen,
|
||||
},
|
||||
alloc::{collections::BTreeMap, string::String, vec::Vec},
|
||||
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
||||
core::{cell::Cell, ops::Range},
|
||||
hashbrown::hash_map,
|
||||
hbbytecode as instrs,
|
||||
|
@ -531,11 +531,11 @@ mod ty {
|
|||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
|
||||
fn rety(&self, ty: Id) -> Self {
|
||||
pub fn rety(&self, ty: Id) -> Self {
|
||||
Self::new(self.tys, self.files, ty)
|
||||
}
|
||||
}
|
||||
|
@ -1039,7 +1039,7 @@ impl Types {
|
|||
AbleOsExecutableHeader {
|
||||
magic_number: [0x15, 0x91, 0xD2],
|
||||
executable_version: 0,
|
||||
code_length: (code_length - HEADER_SIZE) as _,
|
||||
code_length: code_length.saturating_sub(HEADER_SIZE) as _,
|
||||
data_length: data_length as _,
|
||||
debug_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)]
|
||||
pub fn run_test(
|
||||
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 {
|
||||
match vm.run() {
|
||||
|
|
248
lang/src/son.rs
248
lang/src/son.rs
|
@ -10,9 +10,9 @@ use {
|
|||
Expr, ExprRef, FileId, Pos,
|
||||
},
|
||||
reg, task,
|
||||
ty::{self, ArrayLen},
|
||||
ty::{self, ArrayLen, Tuple},
|
||||
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},
|
||||
core::{
|
||||
|
@ -73,6 +73,43 @@ impl Default for 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) {
|
||||
self.visited.clear(self.values.len());
|
||||
push_up(self);
|
||||
|
@ -436,6 +473,7 @@ impl Nodes {
|
|||
Kind::Call { func } => {
|
||||
write!(out, "call: {func} {} ", self[node].depth)
|
||||
}
|
||||
Kind::Global { global } => write!(out, "glob: {global:<5}"),
|
||||
Kind::Entry => write!(out, "ctrl: {:<5}", "entry"),
|
||||
Kind::Then => write!(out, "ctrl: {:<5}", "then"),
|
||||
Kind::Else => write!(out, "ctrl: {:<5}", "else"),
|
||||
|
@ -808,6 +846,10 @@ pub enum Kind {
|
|||
BinOp {
|
||||
op: lexer::TokenKind,
|
||||
},
|
||||
// [ctrl]
|
||||
Global {
|
||||
global: ty::Global,
|
||||
},
|
||||
// [ctrl, ...args]
|
||||
Call {
|
||||
func: ty::Func,
|
||||
|
@ -931,7 +973,6 @@ impl Scope {
|
|||
#[derive(Default)]
|
||||
struct ItemCtx {
|
||||
file: FileId,
|
||||
id: ty::Id,
|
||||
ret: Option<ty::Id>,
|
||||
task_base: usize,
|
||||
nodes: Nodes,
|
||||
|
@ -946,7 +987,7 @@ struct 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.scope.vars.len(), 0);
|
||||
debug_assert_eq!(self.ret_relocs.len(), 0);
|
||||
|
@ -955,7 +996,6 @@ impl ItemCtx {
|
|||
debug_assert_eq!(self.code.len(), 0);
|
||||
|
||||
self.file = file;
|
||||
self.id = id;
|
||||
self.ret = ret;
|
||||
self.task_base = task_base;
|
||||
|
||||
|
@ -1109,6 +1149,14 @@ impl ItemCtx {
|
|||
});
|
||||
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 => {
|
||||
let base = reg::STACK_PTR;
|
||||
let offset = func.nodes[nid].offset;
|
||||
|
@ -1166,7 +1214,13 @@ impl ItemCtx {
|
|||
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: {
|
||||
self.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, 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.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 {
|
||||
pub fn push_ci(
|
||||
&mut self,
|
||||
target: &mut ItemCtx,
|
||||
file: FileId,
|
||||
id: ty::Id,
|
||||
ret: Option<ty::Id>,
|
||||
task_base: usize,
|
||||
target: &mut ItemCtx,
|
||||
) {
|
||||
if let Some(slot) = self.cis.get_mut(self.used_cis) {
|
||||
core::mem::swap(slot, target);
|
||||
|
@ -1285,7 +1334,7 @@ impl Pool {
|
|||
self.cis.push(ItemCtx::default());
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1363,47 +1412,11 @@ pub struct Codegen<'a> {
|
|||
pool: Pool,
|
||||
#[expect(dead_code)]
|
||||
ralloc: Regalloc,
|
||||
ct: Comptime,
|
||||
errors: RefCell<String>,
|
||||
}
|
||||
|
||||
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 {
|
||||
if value == NEVER {
|
||||
return NEVER;
|
||||
|
@ -1475,8 +1488,20 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
Expr::Ident { id, pos, .. } => {
|
||||
let decl = self.find_or_declare(pos, self.ci.file, Ok(id));
|
||||
|
||||
todo!()
|
||||
match decl {
|
||||
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(
|
||||
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 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 {
|
||||
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 });
|
||||
}
|
||||
|
||||
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(
|
||||
body.pos(),
|
||||
"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();
|
||||
|
||||
if self.errors.borrow().is_empty() {
|
||||
self.graphviz();
|
||||
|
||||
self.ci.nodes.gcm();
|
||||
self.ci.nodes.check_final_integrity();
|
||||
self.ci.nodes.basic_blocks();
|
||||
|
||||
self.graphviz();
|
||||
|
||||
self.ci.emit_body(&mut self.tys, sig);
|
||||
self.ci.emit_body(&mut self.tys, self.files, sig);
|
||||
self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code);
|
||||
self.tys.ins.funcs[id as usize].relocs.append(&mut self.ci.relocs);
|
||||
}
|
||||
|
||||
self.pool.pop_ci(&mut self.ci);
|
||||
|
@ -2334,7 +2353,7 @@ impl<'a> Codegen<'a> {
|
|||
),
|
||||
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);
|
||||
|
@ -2398,8 +2417,81 @@ impl<'a> Codegen<'a> {
|
|||
op: TokenKind::Decl,
|
||||
right: right @ (Expr::Struct { .. } | Expr::Mod { .. }),
|
||||
} => self.ty(right).expand(),
|
||||
Expr::BinOp { left: Expr::Ident { .. }, op: TokenKind::Decl, right } => {
|
||||
todo!("{right:#?}");
|
||||
Expr::BinOp { left: &Expr::Ident { id: name, .. }, op: TokenKind::Decl, 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:#?}"),
|
||||
};
|
||||
|
@ -2755,14 +2847,6 @@ impl<'a> Function<'a> {
|
|||
let mut parama = self.tys.parama(fuc.ret);
|
||||
for (&(mut i), ti) in node.inputs[1..].iter().zip(fuc.args.range()) {
|
||||
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) {
|
||||
0 => continue,
|
||||
1..=8 => {
|
||||
|
@ -2773,6 +2857,14 @@ impl<'a> Function<'a> {
|
|||
}
|
||||
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);
|
||||
ops.push(regalloc2::Operand::reg_fixed_use(
|
||||
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
|
||||
// if node.outputs.iter().all(|&n| {
|
||||
// matches!(self.nodes[n].kind, Kind::Stre | Kind::Load)
|
||||
|
@ -3206,7 +3302,7 @@ mod tests {
|
|||
}
|
||||
|
||||
let mut out = Vec::new();
|
||||
codegen.tys.assemble(&mut out);
|
||||
codegen.tys.reassemble(&mut out);
|
||||
|
||||
let err = codegen.tys.disasm(&out, codegen.files, output, |_| {});
|
||||
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