making type manipulation nicer

This commit is contained in:
Jakub Doka 2024-11-08 10:25:34 +01:00
parent 0ef74d89cb
commit 68c0248189
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
10 changed files with 403 additions and 301 deletions

View file

@ -5,8 +5,9 @@
use { use {
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
hblang::{ hblang::{
parser::FileId,
son::{hbvm::HbvmBackend, Codegen, CodegenCtx}, son::{hbvm::HbvmBackend, Codegen, CodegenCtx},
ty::Module,
Ent,
}, },
}; };
@ -60,7 +61,7 @@ unsafe fn compile_and_run(mut fuel: usize) {
let files = { let files = {
let paths = files.iter().map(|f| f.path).collect::<Vec<_>>(); let paths = files.iter().map(|f| f.path).collect::<Vec<_>>();
let mut loader = |path: &str, _: &str, kind| match kind { let mut loader = |path: &str, _: &str, kind| match kind {
hblang::parser::FileKind::Module => Ok(paths.binary_search(&path).unwrap() as FileId), hblang::parser::FileKind::Module => Ok(paths.binary_search(&path).unwrap()),
hblang::parser::FileKind::Embed => Err("embeds are not supported".into()), hblang::parser::FileKind::Embed => Err("embeds are not supported".into()),
}; };
files files
@ -79,7 +80,7 @@ unsafe fn compile_and_run(mut fuel: usize) {
let mut ct = { let mut ct = {
let mut backend = HbvmBackend::default(); let mut backend = HbvmBackend::default();
Codegen::new(&mut backend, &files, &mut ctx).generate(root as FileId); Codegen::new(&mut backend, &files, &mut ctx).generate(Module::new(root));
if !ctx.parser.errors.borrow().is_empty() { if !ctx.parser.errors.borrow().is_empty() {
log::error!("{}", ctx.parser.errors.borrow()); log::error!("{}", ctx.parser.errors.borrow());

View file

@ -2,6 +2,7 @@ use {
crate::{ crate::{
parser::{Ast, Ctx, FileKind}, parser::{Ast, Ctx, FileKind},
son::{self, hbvm::HbvmBackend}, son::{self, hbvm::HbvmBackend},
ty,
}, },
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
core::{fmt::Write, num::NonZeroUsize, ops::Deref}, core::{fmt::Write, num::NonZeroUsize, ops::Deref},
@ -96,7 +97,7 @@ pub fn run_compiler(root_file: &str, options: Options, out: &mut Vec<u8>) -> std
let mut codegen = son::Codegen::new(&mut backend, &parsed.ast, &mut ctx); let mut codegen = son::Codegen::new(&mut backend, &parsed.ast, &mut ctx);
codegen.push_embeds(parsed.embeds); codegen.push_embeds(parsed.embeds);
codegen.generate(0); codegen.generate(ty::Module::MAIN);
if !codegen.errors.borrow().is_empty() { if !codegen.errors.borrow().is_empty() {
drop(codegen); drop(codegen);
@ -242,10 +243,10 @@ pub fn parse_from_fs(extra_threads: usize, root: &str) -> io::Result<Loaded> {
} }
} }
type Task = (u32, PathBuf); type Task = (usize, PathBuf);
let seen_modules = Mutex::new(crate::HashMap::<PathBuf, u32>::default()); let seen_modules = Mutex::new(crate::HashMap::<PathBuf, usize>::default());
let seen_embeds = Mutex::new(crate::HashMap::<PathBuf, u32>::default()); let seen_embeds = Mutex::new(crate::HashMap::<PathBuf, usize>::default());
let tasks = TaskQueue::<Task>::new(extra_threads + 1); let tasks = TaskQueue::<Task>::new(extra_threads + 1);
let ast = Mutex::new(Vec::<io::Result<Ast>>::new()); let ast = Mutex::new(Vec::<io::Result<Ast>>::new());
let embeds = Mutex::new(Vec::<Vec<u8>>::new()); let embeds = Mutex::new(Vec::<Vec<u8>>::new());
@ -264,7 +265,7 @@ pub fn parse_from_fs(extra_threads: usize, root: &str) -> io::Result<Loaded> {
} }
hash_map::Entry::Vacant(entry) => { hash_map::Entry::Vacant(entry) => {
physiscal_path = entry.insert_entry(len as _).key().clone(); physiscal_path = entry.insert_entry(len as _).key().clone();
len as u32 len
} }
} }
}; };
@ -289,7 +290,7 @@ pub fn parse_from_fs(extra_threads: usize, root: &str) -> io::Result<Loaded> {
} }
hash_map::Entry::Vacant(entry) => { hash_map::Entry::Vacant(entry) => {
physiscal_path = entry.insert_entry(len as _).key().clone(); physiscal_path = entry.insert_entry(len as _).key().clone();
len as u32 len
} }
} }
}; };
@ -331,9 +332,9 @@ pub fn parse_from_fs(extra_threads: usize, root: &str) -> io::Result<Loaded> {
while let Some(task @ (indx, ..)) = tasks.pop() { while let Some(task @ (indx, ..)) = tasks.pop() {
let res = execute_task(&mut ctx, task, &mut tmp); let res = execute_task(&mut ctx, task, &mut tmp);
let mut ast = ast.lock().unwrap(); let mut ast = ast.lock().unwrap();
let len = ast.len().max(indx as usize + 1); let len = ast.len().max(indx + 1);
ast.resize_with(len, || Err(io::ErrorKind::InvalidData.into())); ast.resize_with(len, || Err(io::ErrorKind::InvalidData.into()));
ast[indx as usize] = res; ast[indx] = res;
} }
ctx.errors.into_inner() ctx.errors.into_inner()
}; };

View file

@ -3,6 +3,7 @@ use {
lexer::TokenKind, lexer::TokenKind,
parser, parser,
son::{hbvm::HbvmBackend, Codegen, CodegenCtx}, son::{hbvm::HbvmBackend, Codegen, CodegenCtx},
ty::Module,
}, },
alloc::string::String, alloc::string::String,
core::{fmt::Write, hash::BuildHasher, ops::Range}, core::{fmt::Write, hash::BuildHasher, ops::Range},
@ -135,6 +136,6 @@ pub fn fuzz(seed_range: Range<u64>) {
let mut backend = HbvmBackend::default(); let mut backend = HbvmBackend::default();
let mut cdg = Codegen::new(&mut backend, core::slice::from_ref(&parsed), &mut ctx); let mut cdg = Codegen::new(&mut backend, core::slice::from_ref(&parsed), &mut ctx);
cdg.generate(0); cdg.generate(Module::MAIN);
} }
} }

View file

@ -32,11 +32,13 @@
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use fs::*; pub use fs::*;
pub use utils::Ent;
use { use {
self::{ self::{
lexer::TokenKind, lexer::TokenKind,
parser::{idfl, CommentOr, Expr, ExprRef, FileId, Pos}, parser::{idfl, CommentOr, Expr, ExprRef, Pos},
ty::ArrayLen, ty::{ArrayLen, Builtin, Module},
utils::EntVec,
}, },
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
core::{cell::Cell, fmt::Display, ops::Range}, core::{cell::Cell, fmt::Display, ops::Range},
@ -251,17 +253,17 @@ impl Ident {
pos..pos + len pos..pos + len
} }
fn builtin(builtin: u32) -> Ident { fn builtin(builtin: Builtin) -> Ident {
debug_assert!(Self(builtin).is_null()); Self(builtin.index() as _)
Self(builtin)
} }
} }
mod ty { pub mod ty {
use { use {
crate::{ crate::{
lexer::TokenKind, lexer::TokenKind,
parser::{self, FileId, Pos}, parser::{self, Pos},
utils::Ent,
Ident, Size, Types, Ident, Size, Types,
}, },
core::{num::NonZeroU32, ops::Range}, core::{num::NonZeroU32, ops::Range},
@ -269,16 +271,10 @@ mod ty {
pub type ArrayLen = u32; pub type ArrayLen = u32;
pub type Builtin = u32; impl Func {
pub type Struct = u32; pub const ECA: Func = Func(u32::MAX);
pub type Opt = u32; pub const MAIN: Func = Func(u32::MIN);
pub type Ptr = u32; }
pub type Func = u32;
pub type Global = u32;
pub type Module = u32;
pub type Slice = u32;
pub const ECA: Func = Func::MAX;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, PartialOrd, Ord)] #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, PartialOrd, Ord)]
pub struct Tuple(pub u32); pub struct Tuple(pub u32);
@ -305,6 +301,10 @@ mod ty {
self.0 as usize & Self::LEN_MASK self.0 as usize & Self::LEN_MASK
} }
pub fn is_empty(self) -> bool {
self.len() == 0
}
pub fn empty() -> Self { pub fn empty() -> Self {
Self(0) Self(0)
} }
@ -350,28 +350,30 @@ mod ty {
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> { fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> {
match self.expand() { match self.expand() {
Kind::Struct(s) => { Kind::Struct(s) => {
let st = &ctx.structs[s as usize]; let st = &ctx.structs[s];
debug_assert_ne!(st.pos, Pos::MAX); debug_assert_ne!(st.pos, Pos::MAX);
crate::SymKey::Struct(st.file, st.pos, st.captures) crate::SymKey::Struct(st.file, st.pos, st.captures)
} }
Kind::Ptr(p) => crate::SymKey::Pointer(&ctx.ptrs[p as usize]), Kind::Ptr(p) => crate::SymKey::Pointer(&ctx.ptrs[p]),
Kind::Opt(p) => crate::SymKey::Optional(&ctx.opts[p as usize]), Kind::Opt(p) => crate::SymKey::Optional(&ctx.opts[p]),
Kind::Func(f) => { Kind::Func(f) => {
let fc = &ctx.funcs[f as usize]; let fc = &ctx.funcs[f];
if let Some(base) = fc.base { if let Some(base) = fc.base {
// TODO: merge base and sig
crate::SymKey::FuncInst(base, fc.sig.unwrap().args) crate::SymKey::FuncInst(base, fc.sig.unwrap().args)
} else { } else {
crate::SymKey::Decl(fc.file, fc.name) crate::SymKey::Decl(fc.file, fc.name)
} }
} }
Kind::Global(g) => { Kind::Global(g) => {
let gb = &ctx.globals[g as usize]; let gb = &ctx.globals[g];
crate::SymKey::Decl(gb.file, gb.name) crate::SymKey::Decl(gb.file, gb.name)
} }
Kind::Slice(s) => crate::SymKey::Array(&ctx.slices[s as usize]), Kind::Slice(s) => crate::SymKey::Array(&ctx.slices[s]),
Kind::Module(_) | Kind::Builtin(_) => { Kind::Module(_) | Kind::Builtin(_) => {
crate::SymKey::Decl(FileId::MAX, Ident::INVALID) crate::SymKey::Decl(Module::default(), Ident::INVALID)
} }
Kind::Const(c) => crate::SymKey::Constant(&ctx.consts[c]),
} }
} }
} }
@ -388,7 +390,7 @@ mod ty {
pub fn bin_ret(self, op: TokenKind) -> Id { pub fn bin_ret(self, op: TokenKind) -> Id {
use TokenKind as T; use TokenKind as T;
match op { match op {
T::Lt | T::Gt | T::Le | T::Ge | T::Ne | T::Eq => BOOL.into(), T::Lt | T::Gt | T::Le | T::Ge | T::Ne | T::Eq => Id::BOOL,
_ => self, _ => self,
} }
} }
@ -415,7 +417,7 @@ mod ty {
pub fn strip_pointer(self) -> Self { pub fn strip_pointer(self) -> Self {
match self.expand() { match self.expand() {
Kind::Ptr(_) => Kind::Builtin(UINT).compress(), Kind::Ptr(_) => Id::UINT,
_ => self, _ => self,
} }
} }
@ -432,8 +434,8 @@ mod ty {
let (oa, ob) = (Self(self.0.min(ob.0)), Self(self.0.max(ob.0))); let (oa, ob) = (Self(self.0.min(ob.0)), Self(self.0.max(ob.0)));
let (a, b) = (oa.strip_pointer(), ob.strip_pointer()); let (a, b) = (oa.strip_pointer(), ob.strip_pointer());
Some(match () { Some(match () {
_ if oa == Self::from(NEVER) => ob, _ if oa == Id::NEVER => ob,
_ if ob == Self::from(NEVER) => oa, _ if ob == Id::NEVER => oa,
_ if oa == ob => oa, _ if oa == ob => oa,
_ if ob.is_optional() => ob, _ if ob.is_optional() => ob,
_ if oa.is_pointer() && ob.is_pointer() => return None, _ if oa.is_pointer() && ob.is_pointer() => return None,
@ -456,12 +458,12 @@ mod ty {
pub(crate) fn simple_size(&self) -> Option<Size> { pub(crate) fn simple_size(&self) -> Option<Size> {
Some(match self.expand() { Some(match self.expand() {
Kind::Ptr(_) => 8, Kind::Ptr(_) => 8,
Kind::Builtin(VOID) => 0, Kind::Builtin(Builtin(VOID)) => 0,
Kind::Builtin(NEVER) => 0, Kind::Builtin(Builtin(NEVER)) => 0,
Kind::Builtin(INT | UINT | F64) => 8, Kind::Builtin(Builtin(INT | UINT | F64)) => 8,
Kind::Builtin(I32 | U32 | TYPE | F32) => 4, Kind::Builtin(Builtin(I32 | U32 | TYPE | F32)) => 4,
Kind::Builtin(I16 | U16) => 2, Kind::Builtin(Builtin(I16 | U16)) => 2,
Kind::Builtin(I8 | U8 | BOOL) => 1, Kind::Builtin(Builtin(I8 | U8 | BOOL)) => 1,
_ => return None, _ => return None,
}) })
} }
@ -479,7 +481,7 @@ mod ty {
pub(crate) fn loc(&self, tys: &Types) -> Loc { pub(crate) fn loc(&self, tys: &Types) -> Loc {
match self.expand() { match self.expand() {
Kind::Opt(o) Kind::Opt(o)
if let ty = tys.ins.opts[o as usize].base if let ty = tys.ins.opts[o].base
&& ty.loc(tys) == Loc::Reg && ty.loc(tys) == Loc::Reg
&& (ty.is_pointer() || tys.size_of(ty) < 8) => && (ty.is_pointer() || tys.size_of(ty) < 8) =>
{ {
@ -488,7 +490,9 @@ mod ty {
Kind::Ptr(_) | Kind::Builtin(_) => Loc::Reg, Kind::Ptr(_) | Kind::Builtin(_) => Loc::Reg,
Kind::Struct(_) if tys.size_of(*self) == 0 => Loc::Reg, Kind::Struct(_) if tys.size_of(*self) == 0 => Loc::Reg,
Kind::Struct(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack, Kind::Struct(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack,
Kind::Func(_) | Kind::Global(_) | Kind::Module(_) => unreachable!(), Kind::Func(_) | Kind::Global(_) | Kind::Module(_) | Kind::Const(_) => {
unreachable!()
}
} }
} }
@ -496,7 +500,7 @@ mod ty {
match self.expand() { match self.expand() {
Kind::Struct(s) => tys.struct_fields(s).iter().any(|f| f.ty.has_pointers(tys)), Kind::Struct(s) => tys.struct_fields(s).iter().any(|f| f.ty.has_pointers(tys)),
Kind::Ptr(_) => true, Kind::Ptr(_) => true,
Kind::Slice(s) => tys.ins.slices[s as usize].len == ArrayLen::MAX, Kind::Slice(s) => tys.ins.slices[s].len == ArrayLen::MAX,
_ => false, _ => false,
} }
} }
@ -514,12 +518,6 @@ mod ty {
} }
} }
impl From<u32> for Id {
fn from(id: u32) -> Self {
Kind::Builtin(id).compress()
}
}
const fn array_to_lower_case<const N: usize>(array: [u8; N]) -> [u8; N] { const fn array_to_lower_case<const N: usize>(array: [u8; N]) -> [u8; N] {
let mut result = [0; N]; let mut result = [0; N];
let mut i = 0; let mut i = 0;
@ -533,7 +531,7 @@ mod ty {
macro_rules! builtin_type { macro_rules! builtin_type {
($($name:ident;)*) => { ($($name:ident;)*) => {
$(pub const $name: Builtin = ${index(0)} + 1;)* $(const $name: u32 = ${index(0)} + 1;)*
mod __lc_names { mod __lc_names {
use super::*; use super::*;
@ -547,20 +545,23 @@ mod ty {
};)* };)*
} }
#[expect(dead_code)]
impl Id { impl Id {
$(pub const $name: Self = Kind::Builtin($name).compress();)* $(pub const $name: Self = Kind::Builtin(Builtin($name)).compress();)*
}
impl Kind {
$(pub const $name: Self = Kind::Builtin(Builtin($name));)*
} }
pub fn from_str(name: &str) -> Option<Builtin> { pub fn from_str(name: &str) -> Option<Builtin> {
match name { match name {
$(__lc_names::$name => Some($name),)* $(__lc_names::$name => Some(Builtin($name)),)*
_ => None, _ => None,
} }
} }
pub fn to_str(ty: Builtin) -> &'static str { pub fn to_str(ty: Builtin) -> &'static str {
match ty { match ty.0 {
$($name => __lc_names::$name,)* $($name => __lc_names::$name,)*
v => unreachable!("invalid type: {}", v), v => unreachable!("invalid type: {}", v),
} }
@ -590,6 +591,10 @@ mod ty {
macro_rules! type_kind { macro_rules! type_kind {
($(#[$meta:meta])* $vis:vis enum $name:ident {$( $variant:ident, )*}) => { ($(#[$meta:meta])* $vis:vis enum $name:ident {$( $variant:ident, )*}) => {
crate::utils::decl_ent! {
$(pub struct $variant(u32);)*
}
$(#[$meta])* $(#[$meta])*
$vis enum $name { $vis enum $name {
$($variant($variant),)* $($variant($variant),)*
@ -603,24 +608,32 @@ mod ty {
$vis fn from_ty(ty: Id) -> Self { $vis fn from_ty(ty: Id) -> Self {
let (flag, index) = (ty.repr() >> Self::FLAG_OFFSET, ty.repr() & Self::INDEX_MASK); let (flag, index) = (ty.repr() >> Self::FLAG_OFFSET, ty.repr() & Self::INDEX_MASK);
match flag { match flag {
$(${index(0)} => Self::$variant(index),)* $(${index(0)} => Self::$variant($variant(index)),)*
i => unreachable!("{i}"), i => unreachable!("{i}"),
} }
} }
$vis const fn compress(self) -> Id { $vis const fn compress(self) -> Id {
let (index, flag) = match self { let (index, flag) = match self {
$(Self::$variant(index) => (index, ${index(0)}),)* $(Self::$variant(index) => (index.0, ${index(0)}),)*
}; };
Id(unsafe { NonZeroU32::new_unchecked((flag << Self::FLAG_OFFSET) | index) }) Id(unsafe { NonZeroU32::new_unchecked((flag << Self::FLAG_OFFSET) | index) })
} }
}
$vis const fn inner(self) -> u32 { $(
match self { impl From<$variant> for $name {
$(Self::$variant(index) => index,)* fn from(value: $variant) -> Self {
Self::$variant(value)
} }
} }
}
impl From<$variant> for Id {
fn from(value: $variant) -> Self {
$name::$variant(value).compress()
}
}
)*
}; };
} }
@ -635,12 +648,35 @@ mod ty {
Func, Func,
Global, Global,
Module, Module,
Const,
}
}
impl Module {
pub const MAIN: Self = Self(0);
}
impl Default for Module {
fn default() -> Self {
Self(u32::MAX)
}
}
impl TryFrom<Ident> for Builtin {
type Error = ();
fn try_from(value: Ident) -> Result<Self, Self::Error> {
if value.is_null() {
Ok(Self(value.len()))
} else {
Err(())
}
} }
} }
impl Default for Kind { impl Default for Kind {
fn default() -> Self { fn default() -> Self {
Self::Builtin(UNDECLARED) Id::UNDECLARED.expand()
} }
} }
@ -666,7 +702,7 @@ mod ty {
match TK::from_ty(self.ty) { match TK::from_ty(self.ty) {
TK::Module(idx) => { TK::Module(idx) => {
f.write_str("@use(\"")?; f.write_str("@use(\"")?;
self.files[idx as usize].path.fmt(f)?; self.files[idx.index()].path.fmt(f)?;
f.write_str(")[")?; f.write_str(")[")?;
idx.fmt(f)?; idx.fmt(f)?;
f.write_str("]") f.write_str("]")
@ -674,14 +710,14 @@ mod ty {
TK::Builtin(ty) => f.write_str(to_str(ty)), TK::Builtin(ty) => f.write_str(to_str(ty)),
TK::Opt(ty) => { TK::Opt(ty) => {
f.write_str("?")?; f.write_str("?")?;
self.rety(self.tys.ins.opts[ty as usize].base).fmt(f) self.rety(self.tys.ins.opts[ty].base).fmt(f)
} }
TK::Ptr(ty) => { TK::Ptr(ty) => {
f.write_str("^")?; f.write_str("^")?;
self.rety(self.tys.ins.ptrs[ty as usize].base).fmt(f) self.rety(self.tys.ins.ptrs[ty].base).fmt(f)
} }
TK::Struct(idx) => { TK::Struct(idx) => {
let record = &self.tys.ins.structs[idx as usize]; let record = &self.tys.ins.structs[idx];
if record.name.is_null() { if record.name.is_null() {
f.write_str("[")?; f.write_str("[")?;
idx.fmt(f)?; idx.fmt(f)?;
@ -698,7 +734,7 @@ mod ty {
} }
f.write_str("}") f.write_str("}")
} else { } else {
let file = &self.files[record.file as usize]; let file = &self.files[record.file.index()];
f.write_str(file.ident_str(record.name)) f.write_str(file.ident_str(record.name))
} }
} }
@ -707,11 +743,12 @@ mod ty {
idx.fmt(f) idx.fmt(f)
} }
TK::Global(idx) => { TK::Global(idx) => {
f.write_str("global")?; let global = &self.tys.ins.globals[idx];
idx.fmt(f) let file = &self.files[global.file.index()];
f.write_str(file.ident_str(global.name))
} }
TK::Slice(idx) => { TK::Slice(idx) => {
let array = self.tys.ins.slices[idx as usize]; let array = self.tys.ins.slices[idx];
f.write_str("[")?; f.write_str("[")?;
self.rety(array.elem).fmt(f)?; self.rety(array.elem).fmt(f)?;
if array.len != ArrayLen::MAX { if array.len != ArrayLen::MAX {
@ -720,6 +757,11 @@ mod ty {
} }
f.write_str("]") f.write_str("]")
} }
TK::Const(idx) => {
let cnst = &self.tys.ins.consts[idx];
let file = &self.files[cnst.file.index()];
f.write_str(file.ident_str(cnst.name))
}
} }
} }
} }
@ -732,10 +774,11 @@ type Size = u32;
pub enum SymKey<'a> { pub enum SymKey<'a> {
Pointer(&'a Ptr), Pointer(&'a Ptr),
Optional(&'a Opt), Optional(&'a Opt),
Struct(FileId, Pos, ty::Tuple), Struct(Module, Pos, ty::Tuple),
FuncInst(ty::Func, ty::Tuple), FuncInst(ty::Func, ty::Tuple),
Decl(FileId, Ident), Decl(Module, Ident),
Array(&'a Array), Array(&'a Array),
Constant(&'a Const),
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -744,8 +787,9 @@ pub struct Sig {
ret: ty::Id, ret: ty::Id,
} }
#[derive(Default)]
struct Func { struct Func {
file: FileId, file: Module,
name: Ident, name: Ident,
base: Option<ty::Func>, base: Option<ty::Func>,
expr: ExprRef, expr: ExprRef,
@ -753,19 +797,6 @@ struct Func {
comp_state: [CompState; 2], comp_state: [CompState; 2],
} }
impl Default for Func {
fn default() -> Self {
Self {
file: u32::MAX,
name: Default::default(),
base: None,
expr: Default::default(),
sig: None,
comp_state: Default::default(),
}
}
}
#[derive(Default, PartialEq, Eq)] #[derive(Default, PartialEq, Eq)]
enum CompState { enum CompState {
#[default] #[default]
@ -780,23 +811,19 @@ struct TypedReloc {
reloc: Reloc, reloc: Reloc,
} }
#[derive(Clone)] #[derive(Clone, Default)]
struct Global { struct Global {
file: FileId, file: Module,
name: Ident, name: Ident,
ty: ty::Id, ty: ty::Id,
data: Vec<u8>, data: Vec<u8>,
} }
impl Default for Global { #[derive(PartialEq, Eq, Hash)]
fn default() -> Self { pub struct Const {
Self { ast: ExprRef,
ty: Default::default(), name: Ident,
data: Default::default(), file: Module,
file: u32::MAX,
name: Default::default(),
}
}
} }
// TODO: make into bit struct (width: u2, sub_offset: u3, offset: u27) // TODO: make into bit struct (width: u2, sub_offset: u3, offset: u27)
@ -835,7 +862,7 @@ struct Field {
struct Struct { struct Struct {
name: Ident, name: Ident,
pos: Pos, pos: Pos,
file: FileId, file: Module,
size: Cell<Size>, size: Cell<Size>,
align: Cell<u8>, align: Cell<u8>,
captures: ty::Tuple, captures: ty::Tuple,
@ -934,18 +961,19 @@ struct TypesTmp {
#[derive(Default)] #[derive(Default)]
pub struct TypeIns { pub struct TypeIns {
funcs: Vec<Func>,
args: Vec<ty::Id>, args: Vec<ty::Id>,
globals: Vec<Global>,
structs: Vec<Struct>,
fields: Vec<Field>, fields: Vec<Field>,
ptrs: Vec<Ptr>, funcs: EntVec<ty::Func, Func>,
opts: Vec<Opt>, globals: EntVec<ty::Global, Global>,
slices: Vec<Array>, consts: EntVec<ty::Const, Const>,
structs: EntVec<ty::Struct, Struct>,
ptrs: EntVec<ty::Ptr, Ptr>,
opts: EntVec<ty::Opt, Opt>,
slices: EntVec<ty::Slice, Array>,
} }
struct FTask { struct FTask {
file: FileId, file: Module,
id: ty::Func, id: ty::Func,
ct: bool, ct: bool,
} }
@ -953,11 +981,11 @@ struct FTask {
struct StringRef(ty::Global); struct StringRef(ty::Global);
impl ctx_map::CtxEntry for StringRef { impl ctx_map::CtxEntry for StringRef {
type Ctx = [Global]; type Ctx = EntVec<ty::Global, Global>;
type Key<'a> = &'a [u8]; type Key<'a> = &'a [u8];
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> { fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> {
&ctx[self.0 as usize].data &ctx[self.0].data
} }
} }
@ -975,16 +1003,16 @@ trait TypeParser {
fn tys(&mut self) -> &mut Types; fn tys(&mut self) -> &mut Types;
fn on_reuse(&mut self, existing: ty::Id); fn on_reuse(&mut self, existing: ty::Id);
fn find_local_ty(&mut self, name: Ident) -> Option<ty::Id>; fn find_local_ty(&mut self, name: Ident) -> Option<ty::Id>;
fn eval_const(&mut self, file: FileId, expr: &Expr, ty: ty::Id) -> u64; fn eval_const(&mut self, file: Module, expr: &Expr, ty: ty::Id) -> u64;
fn eval_global(&mut self, file: FileId, name: Ident, expr: &Expr) -> ty::Id; fn eval_global(&mut self, file: Module, name: Ident, expr: &Expr) -> ty::Id;
fn infer_type(&mut self, expr: &Expr) -> ty::Id; fn infer_type(&mut self, expr: &Expr) -> ty::Id;
fn report(&self, file: FileId, pos: Pos, msg: impl Display) -> ty::Id; fn report(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id;
fn find_type( fn find_type(
&mut self, &mut self,
pos: Pos, pos: Pos,
from_file: FileId, from_file: Module,
file: FileId, file: Module,
id: Result<Ident, &str>, id: Result<Ident, &str>,
files: &[parser::Ast], files: &[parser::Ast],
) -> ty::Id { ) -> ty::Id {
@ -999,9 +1027,9 @@ trait TypeParser {
self.on_reuse(ty); self.on_reuse(ty);
ty ty
} else { } else {
let f = &files[file as usize]; let f = &files[file.index()];
let Some((Expr::BinOp { left, right, .. }, name)) = f.find_decl(id) else { let Some((expr @ Expr::BinOp { left, right, .. }, name)) = f.find_decl(id) else {
return match id { return match id {
Ok(_) => ty::Id::NEVER, Ok(_) => ty::Id::NEVER,
Err("main") => self.report( Err("main") => self.report(
@ -1025,20 +1053,19 @@ trait TypeParser {
ty ty
} else { } else {
let ty = left let ty = left
.find_pattern_path(name, right, |right| { .find_pattern_path(name, right, |right, is_ct| {
self.parse_ty(file, right, Some(name), files) if is_ct {
self.tys()
.ins
.consts
.push(Const { ast: ExprRef::new(expr), name, file })
.into()
} else {
self.parse_ty(file, right, Some(name), files)
}
}) })
.unwrap_or_else(|_| unreachable!()); .unwrap_or_else(|_| unreachable!());
let tys = self.tys(); let tys = self.tys();
let nm = match ty.expand() {
ty::Kind::Struct(s) => &mut tys.ins.structs[s as usize].name,
ty::Kind::Func(s) => &mut tys.ins.funcs[s as usize].name,
ty::Kind::Global(s) => &mut tys.ins.globals[s as usize].name,
_ => &mut Ident::default(),
};
if nm.is_null() {
*nm = name;
}
tys.syms.insert(SymKey::Decl(file, name), ty, &tys.ins); tys.syms.insert(SymKey::Decl(file, name), ty, &tys.ins);
ty ty
} }
@ -1046,7 +1073,7 @@ trait TypeParser {
let tys = self.tys(); let tys = self.tys();
if let ty::Kind::Global(g) = ty.expand() { if let ty::Kind::Global(g) = ty.expand() {
let g = &tys.ins.globals[g as usize]; let g = &tys.ins.globals[g];
if g.ty == ty::Id::TYPE { if g.ty == ty::Id::TYPE {
return ty::Id::from( return ty::Id::from(
u32::from_ne_bytes(g.data.as_slice().try_into().unwrap()) as u64 u32::from_ne_bytes(g.data.as_slice().try_into().unwrap()) as u64
@ -1059,7 +1086,7 @@ trait TypeParser {
/// returns none if comptime eval is required /// returns none if comptime eval is required
fn parse_ty( fn parse_ty(
&mut self, &mut self,
file: FileId, file: Module,
expr: &Expr, expr: &Expr,
name: Option<Ident>, name: Option<Ident>,
files: &[parser::Ast], files: &[parser::Ast],
@ -1074,7 +1101,7 @@ trait TypeParser {
let base = self.parse_ty(file, val, None, files); let base = self.parse_ty(file, val, None, files);
self.tys().make_opt(base) self.tys().make_opt(base)
} }
Expr::Ident { id, .. } if id.is_null() => id.len().into(), Expr::Ident { id, .. } if let Ok(bt) = ty::Builtin::try_from(id) => bt.into(),
Expr::Ident { id, pos, .. } => self.find_type(pos, file, file, Ok(id), files), Expr::Ident { id, pos, .. } => self.find_type(pos, file, file, Ok(id), files),
Expr::Field { target, pos, name } Expr::Field { target, pos, name }
if let ty::Kind::Module(inside) = if let ty::Kind::Module(inside) =
@ -1119,18 +1146,21 @@ trait TypeParser {
} }
let tys = self.tys(); let tys = self.tys();
tys.ins.structs.push(Struct { let ty = tys
file, .ins
pos, .structs
name: name.unwrap_or_default(), .push(Struct {
field_start: tys.ins.fields.len() as _, file,
explicit_alignment: packed.then_some(1), pos,
..Default::default() name: name.unwrap_or_default(),
}); field_start: tys.ins.fields.len() as _,
explicit_alignment: packed.then_some(1),
..Default::default()
})
.into();
tys.ins.fields.extend(tys.tmp.fields.drain(prev_tmp..)); tys.ins.fields.extend(tys.tmp.fields.drain(prev_tmp..));
let ty = ty::Kind::Struct(tys.ins.structs.len() as u32 - 1).compress();
tys.syms.insert(sym, ty, &tys.ins); tys.syms.insert(sym, ty, &tys.ins);
ty ty
} }
@ -1141,7 +1171,7 @@ trait TypeParser {
sig: 'b: { sig: 'b: {
let arg_base = self.tys().tmp.args.len(); let arg_base = self.tys().tmp.args.len();
for arg in args { for arg in args {
let sym = parser::find_symbol(&files[file as usize].symbols, arg.id); let sym = parser::find_symbol(&files[file.index()].symbols, arg.id);
if sym.flags & idfl::COMPTIME != 0 { if sym.flags & idfl::COMPTIME != 0 {
self.tys().tmp.args.truncate(arg_base); self.tys().tmp.args.truncate(arg_base);
break 'b None; break 'b None;
@ -1161,10 +1191,7 @@ trait TypeParser {
..Default::default() ..Default::default()
}; };
let id = self.tys().ins.funcs.len() as _; self.tys().ins.funcs.push(func).into()
self.tys().ins.funcs.push(func);
ty::Kind::Func(id).compress()
} }
_ if let Some(name) = name => self.eval_global(file, name, expr), _ if let Some(name) = name => self.eval_global(file, name, expr),
_ => ty::Id::from(self.eval_const(file, expr, ty::Id::TYPE)), _ => ty::Id::from(self.eval_const(file, expr, ty::Id::TYPE)),
@ -1174,12 +1201,9 @@ trait TypeParser {
impl Types { impl Types {
fn struct_field_range(&self, strct: ty::Struct) -> Range<usize> { fn struct_field_range(&self, strct: ty::Struct) -> Range<usize> {
let start = self.ins.structs[strct as usize].field_start as usize; let start = self.ins.structs[strct].field_start as usize;
let end = self let end =
.ins self.ins.structs.next(strct).map_or(self.ins.fields.len(), |s| s.field_start as usize);
.structs
.get(strct as usize + 1)
.map_or(self.ins.fields.len(), |s| s.field_start as usize);
start..end start..end
} }
@ -1210,49 +1234,30 @@ impl Types {
} }
fn make_opt(&mut self, base: ty::Id) -> ty::Id { fn make_opt(&mut self, base: ty::Id) -> ty::Id {
self.make_generic_ty( self.make_generic_ty(Opt { base }, |ins| &mut ins.opts, |e| SymKey::Optional(e))
Opt { base },
|ins| &mut ins.opts,
|e| SymKey::Optional(e),
ty::Kind::Opt,
)
} }
fn make_ptr(&mut self, base: ty::Id) -> ty::Id { fn make_ptr(&mut self, base: ty::Id) -> ty::Id {
self.make_generic_ty( self.make_generic_ty(Ptr { base }, |ins| &mut ins.ptrs, |e| SymKey::Pointer(e))
Ptr { base },
|ins| &mut ins.ptrs,
|e| SymKey::Pointer(e),
ty::Kind::Ptr,
)
} }
fn make_array(&mut self, elem: ty::Id, len: ArrayLen) -> ty::Id { fn make_array(&mut self, elem: ty::Id, len: ArrayLen) -> ty::Id {
self.make_generic_ty( self.make_generic_ty(Array { elem, len }, |ins| &mut ins.slices, |e| SymKey::Array(e))
Array { elem, len },
|ins| &mut ins.slices,
|e| SymKey::Array(e),
ty::Kind::Slice,
)
} }
fn make_generic_ty<T: Copy>( fn make_generic_ty<K: Ent + Into<ty::Id>, T: Copy>(
&mut self, &mut self,
ty: T, ty: T,
get_col: fn(&mut TypeIns) -> &mut Vec<T>, get_col: fn(&mut TypeIns) -> &mut EntVec<K, T>,
key: fn(&T) -> SymKey, key: fn(&T) -> SymKey,
kind: fn(u32) -> ty::Kind,
) -> ty::Id { ) -> ty::Id {
*self.syms.get_or_insert(key(&{ ty }), &mut self.ins, |ins| { *self.syms.get_or_insert(key(&{ ty }), &mut self.ins, |ins| get_col(ins).push(ty).into())
get_col(ins).push(ty);
kind(get_col(ins).len() as u32 - 1).compress()
})
} }
fn size_of(&self, ty: ty::Id) -> Size { fn size_of(&self, ty: ty::Id) -> Size {
match ty.expand() { match ty.expand() {
ty::Kind::Slice(arr) => { ty::Kind::Slice(arr) => {
let arr = &self.ins.slices[arr as usize]; let arr = &self.ins.slices[arr];
match arr.len { match arr.len {
0 => 0, 0 => 0,
ArrayLen::MAX => 16, ArrayLen::MAX => 16,
@ -1260,17 +1265,17 @@ impl Types {
} }
} }
ty::Kind::Struct(stru) => { ty::Kind::Struct(stru) => {
if self.ins.structs[stru as usize].size.get() != 0 { if self.ins.structs[stru].size.get() != 0 {
return self.ins.structs[stru as usize].size.get(); return self.ins.structs[stru].size.get();
} }
let mut oiter = OffsetIter::new(stru, self); let mut oiter = OffsetIter::new(stru, self);
while oiter.next(self).is_some() {} while oiter.next(self).is_some() {}
self.ins.structs[stru as usize].size.set(oiter.offset); self.ins.structs[stru].size.set(oiter.offset);
oiter.offset oiter.offset
} }
ty::Kind::Opt(opt) => { ty::Kind::Opt(opt) => {
let base = self.ins.opts[opt as usize].base; let base = self.ins.opts[opt].base;
if self.nieche_of(base).is_some() { if self.nieche_of(base).is_some() {
self.size_of(base) self.size_of(base)
} else { } else {
@ -1285,10 +1290,10 @@ impl Types {
fn align_of(&self, ty: ty::Id) -> Size { fn align_of(&self, ty: ty::Id) -> Size {
match ty.expand() { match ty.expand() {
ty::Kind::Struct(stru) => { ty::Kind::Struct(stru) => {
if self.ins.structs[stru as usize].align.get() != 0 { if self.ins.structs[stru].align.get() != 0 {
return self.ins.structs[stru as usize].align.get() as _; return self.ins.structs[stru].align.get() as _;
} }
let align = self.ins.structs[stru as usize].explicit_alignment.map_or_else( let align = self.ins.structs[stru].explicit_alignment.map_or_else(
|| { || {
self.struct_fields(stru) self.struct_fields(stru)
.iter() .iter()
@ -1298,11 +1303,11 @@ impl Types {
}, },
|a| a as _, |a| a as _,
); );
self.ins.structs[stru as usize].align.set(align.try_into().unwrap()); self.ins.structs[stru].align.set(align.try_into().unwrap());
align align
} }
ty::Kind::Slice(arr) => { ty::Kind::Slice(arr) => {
let arr = &self.ins.slices[arr as usize]; let arr = &self.ins.slices[arr];
match arr.len { match arr.len {
ArrayLen::MAX => 8, ArrayLen::MAX => 8,
_ => self.align_of(arr.elem), _ => self.align_of(arr.elem),
@ -1314,14 +1319,14 @@ impl Types {
fn base_of(&self, ty: ty::Id) -> Option<ty::Id> { fn base_of(&self, ty: ty::Id) -> Option<ty::Id> {
match ty.expand() { match ty.expand() {
ty::Kind::Ptr(p) => Some(self.ins.ptrs[p as usize].base), ty::Kind::Ptr(p) => Some(self.ins.ptrs[p].base),
_ => None, _ => None,
} }
} }
fn inner_of(&self, ty: ty::Id) -> Option<ty::Id> { fn inner_of(&self, ty: ty::Id) -> Option<ty::Id> {
match ty.expand() { match ty.expand() {
ty::Kind::Opt(o) => Some(self.ins.opts[o as usize].base), ty::Kind::Opt(o) => Some(self.ins.opts[o].base),
_ => None, _ => None,
} }
} }
@ -1401,7 +1406,7 @@ impl OffsetIter {
} }
fn next<'a>(&mut self, tys: &'a Types) -> Option<(&'a Field, Offset)> { fn next<'a>(&mut self, tys: &'a Types) -> Option<(&'a Field, Offset)> {
let stru = &tys.ins.structs[self.strct as usize]; let stru = &tys.ins.structs[self.strct];
let field = &tys.ins.fields[self.fields.next()?]; let field = &tys.ins.fields[self.fields.next()?];
let align = stru.explicit_alignment.map_or_else(|| tys.align_of(field.ty), |a| a as u32); let align = stru.explicit_alignment.map_or_else(|| tys.align_of(field.ty), |a| a as u32);
@ -1579,12 +1584,10 @@ fn test_parse_files(
FileKind::Module => module_map FileKind::Module => module_map
.iter() .iter()
.position(|&(name, _)| name == path) .position(|&(name, _)| name == path)
.map(|i| i as parser::FileId)
.ok_or("Module Not Found".to_string()), .ok_or("Module Not Found".to_string()),
FileKind::Embed => embed_map FileKind::Embed => embed_map
.iter() .iter()
.position(|&(name, _)| name == path) .position(|&(name, _)| name == path)
.map(|i| i as parser::FileId)
.ok_or("Embed Not Found".to_string()), .ok_or("Embed Not Found".to_string()),
}; };

View file

@ -2,6 +2,8 @@ use {
crate::{ crate::{
fmt::Formatter, fmt::Formatter,
lexer::{self, Lexer, Token, TokenKind}, lexer::{self, Lexer, Token, TokenKind},
ty::{Global, Module},
utils::Ent as _,
Ident, Ident,
}, },
alloc::{boxed::Box, string::String, vec::Vec}, alloc::{boxed::Box, string::String, vec::Vec},
@ -19,10 +21,9 @@ use {
pub type Pos = u32; pub type Pos = u32;
pub type IdentFlags = u32; pub type IdentFlags = u32;
pub type FileId = u32;
pub type IdentIndex = u16; pub type IdentIndex = u16;
pub type LoaderError = String; pub type LoaderError = String;
pub type Loader<'a> = &'a mut (dyn FnMut(&str, &str, FileKind) -> Result<FileId, LoaderError> + 'a); pub type Loader<'a> = &'a mut (dyn FnMut(&str, &str, FileKind) -> Result<usize, LoaderError> + 'a);
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Eq, Debug)]
pub enum FileKind { pub enum FileKind {
@ -63,7 +64,7 @@ pub mod idfl {
} }
} }
pub fn no_loader(_: &str, _: &str, _: FileKind) -> Result<FileId, LoaderError> { pub fn no_loader(_: &str, _: &str, _: FileKind) -> Result<usize, LoaderError> {
Ok(0) Ok(0)
} }
@ -307,7 +308,7 @@ impl<'a, 'b> Parser<'a, 'b> {
pos, pos,
path, path,
id: match (self.loader)(path, self.path, FileKind::Module) { id: match (self.loader)(path, self.path, FileKind::Module) {
Ok(id) => id, Ok(id) => Module::new(id),
Err(e) => { Err(e) => {
self.report(str.start, format_args!("error loading dependency: {e:#}"))? self.report(str.start, format_args!("error loading dependency: {e:#}"))?
} }
@ -325,7 +326,7 @@ impl<'a, 'b> Parser<'a, 'b> {
pos, pos,
path, path,
id: match (self.loader)(path, self.path, FileKind::Embed) { id: match (self.loader)(path, self.path, FileKind::Embed) {
Ok(id) => id, Ok(id) => Global::new(id),
Err(e) => self.report( Err(e) => self.report(
str.start, str.start,
format_args!("error loading embedded file: {e:#}"), format_args!("error loading embedded file: {e:#}"),
@ -929,13 +930,13 @@ generate_expr! {
/// `'@use' '(' String ')'` /// `'@use' '(' String ')'`
Mod { Mod {
pos: Pos, pos: Pos,
id: FileId, id: Module,
path: &'a str, path: &'a str,
}, },
/// `'@use' '(' String ')'` /// `'@use' '(' String ')'`
Embed { Embed {
pos: Pos, pos: Pos,
id: FileId, id: Global,
path: &'a str, path: &'a str,
}, },
} }
@ -960,14 +961,14 @@ impl Expr<'_> {
} }
} }
pub fn find_pattern_path<T, F: FnOnce(&Expr) -> T>( pub fn find_pattern_path<T, F: FnOnce(&Expr, bool) -> T>(
&self, &self,
ident: Ident, ident: Ident,
target: &Expr, target: &Expr,
mut with_final: F, mut with_final: F,
) -> Result<T, F> { ) -> Result<T, F> {
match *self { match *self {
Self::Ident { id, .. } if id == ident => Ok(with_final(target)), Self::Ident { id, is_ct, .. } if id == ident => Ok(with_final(target, is_ct)),
Self::Ctor { fields, .. } => { Self::Ctor { fields, .. } => {
for &CtorField { name, value, pos } in fields { for &CtorField { name, value, pos } in fields {
match value.find_pattern_path( match value.find_pattern_path(
@ -1234,7 +1235,7 @@ impl Default for Ast {
} }
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(packed)] #[repr(packed)]
pub struct ExprRef(NonNull<Expr<'static>>); pub struct ExprRef(NonNull<Expr<'static>>);

View file

@ -10,20 +10,20 @@ use {
parser::{ parser::{
self, self,
idfl::{self}, idfl::{self},
CtorField, Expr, FileId, Pos, CtorField, Expr, Pos,
}, },
ty::{self, Arg, ArrayLen, Loc, Tuple}, ty::{self, Arg, ArrayLen, Loc, Module, Tuple},
utils::{BitSet, Vc}, utils::{BitSet, Ent, Vc},
CompState, FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Sig, StringRef, CompState, FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Sig, StringRef,
SymKey, TypeParser, Types, SymKey, TypeParser, Types,
}, },
alloc::{rc::Rc, string::String, vec::Vec}, alloc::{string::String, vec::Vec},
core::{ core::{
assert_matches::debug_assert_matches, assert_matches::debug_assert_matches,
cell::{Cell, RefCell}, cell::{Cell, RefCell},
fmt::{self, Debug, Display, Write}, fmt::{self, Debug, Display, Write},
format_args as fa, mem, format_args as fa, mem,
ops::{self, Deref}, ops::{self},
}, },
hashbrown::hash_map, hashbrown::hash_map,
hbbytecode::DisasmError, hbbytecode::DisasmError,
@ -2016,7 +2016,7 @@ impl Scope {
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct ItemCtx { pub struct ItemCtx {
file: FileId, file: Module,
pos: Vec<Pos>, pos: Vec<Pos>,
ret: Option<ty::Id>, ret: Option<ty::Id>,
task_base: usize, task_base: usize,
@ -2031,7 +2031,7 @@ pub struct ItemCtx {
} }
impl ItemCtx { impl ItemCtx {
fn init(&mut self, file: FileId, ret: Option<ty::Id>, task_base: usize) { fn init(&mut self, file: Module, 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.scope.aclasses.len(), 0); debug_assert_eq!(self.scope.aclasses.len(), 0);
@ -2106,7 +2106,7 @@ pub struct Pool {
impl Pool { impl Pool {
fn push_ci( fn push_ci(
&mut self, &mut self,
file: FileId, file: Module,
ret: Option<ty::Id>, ret: Option<ty::Id>,
task_base: usize, task_base: usize,
target: &mut ItemCtx, target: &mut ItemCtx,
@ -2173,8 +2173,8 @@ impl Value {
} }
#[inline(always)] #[inline(always)]
fn ty(self, ty: impl Into<ty::Id>) -> Self { fn ty(self, ty: ty::Id) -> Self {
Self { ty: ty.into(), ..self } Self { ty, ..self }
} }
} }
@ -2239,24 +2239,24 @@ impl<'a> Codegen<'a> {
} }
} }
pub fn generate(&mut self, entry: FileId) { pub fn generate(&mut self, entry: Module) {
self.find_type(0, entry, entry, Err("main"), self.files); self.find_type(0, entry, entry, Err("main"), self.files);
if self.tys.ins.funcs.is_empty() { if self.tys.ins.funcs.is_empty() {
return; return;
} }
self.make_func_reachable(0); self.make_func_reachable(ty::Func::MAIN);
self.complete_call_graph(); self.complete_call_graph();
} }
pub fn assemble_comptime(&mut self) -> Comptime { pub fn assemble_comptime(&mut self) -> Comptime {
self.ct.code.clear(); self.ct.code.clear();
self.ct_backend.assemble_bin(0, self.tys, &mut self.ct.code); self.ct_backend.assemble_bin(ty::Func::MAIN, self.tys, &mut self.ct.code);
self.ct.reset(); self.ct.reset();
core::mem::take(self.ct) core::mem::take(self.ct)
} }
pub fn assemble(&mut self, buf: &mut Vec<u8>) { pub fn assemble(&mut self, buf: &mut Vec<u8>) {
self.backend.assemble_bin(0, self.tys, buf); self.backend.assemble_bin(ty::Func::MAIN, self.tys, buf);
} }
pub fn disasm(&mut self, output: &mut String, bin: &[u8]) -> Result<(), DisasmError> { pub fn disasm(&mut self, output: &mut String, bin: &[u8]) -> Result<(), DisasmError> {
@ -2264,17 +2264,17 @@ impl<'a> Codegen<'a> {
} }
pub fn push_embeds(&mut self, embeds: Vec<Vec<u8>>) { pub fn push_embeds(&mut self, embeds: Vec<Vec<u8>>) {
self.tys.ins.globals = embeds for data in embeds {
.into_iter() let g = Global {
.map(|data| Global {
ty: self.tys.make_array(ty::Id::U8, data.len() as _), ty: self.tys.make_array(ty::Id::U8, data.len() as _),
data, data,
..Default::default() ..Default::default()
}) };
.collect(); self.tys.ins.globals.push(g);
}
} }
fn emit_and_eval(&mut self, file: FileId, ret: ty::Id, ret_loc: &mut [u8]) -> u64 { fn emit_and_eval(&mut self, file: Module, ret: ty::Id, ret_loc: &mut [u8]) -> u64 {
let mut rets = let mut rets =
self.ci.nodes[NEVER].inputs.iter().filter(|&&i| self.ci.nodes[i].kind == Kind::Return); self.ci.nodes[NEVER].inputs.iter().filter(|&&i| self.ci.nodes[i].kind == Kind::Return);
if let Some(&ret) = rets.next() if let Some(&ret) = rets.next()
@ -2291,8 +2291,7 @@ impl<'a> Codegen<'a> {
return 1; return 1;
} }
let fuc = self.tys.ins.funcs.len() as ty::Func; let fuc = self.tys.ins.funcs.push(Func {
self.tys.ins.funcs.push(Func {
file, file,
sig: Some(Sig { args: Tuple::empty(), ret }), sig: Some(Sig { args: Tuple::empty(), ret }),
..Default::default() ..Default::default()
@ -2413,7 +2412,7 @@ impl<'a> Codegen<'a> {
fn make_func_reachable(&mut self, func: ty::Func) { fn make_func_reachable(&mut self, func: ty::Func) {
let state_slot = self.ct.active() as usize; let state_slot = self.ct.active() as usize;
let fuc = &mut self.tys.ins.funcs[func as usize]; let fuc = &mut self.tys.ins.funcs[func];
if fuc.comp_state[state_slot] == CompState::Dead { if fuc.comp_state[state_slot] == CompState::Dead {
fuc.comp_state[state_slot] = CompState::Queued(self.tys.tasks.len() as _); fuc.comp_state[state_slot] = CompState::Queued(self.tys.tasks.len() as _);
self.tys.tasks.push(Some(FTask { file: fuc.file, id: func, ct: self.ct.active() })); self.tys.tasks.push(Some(FTask { file: fuc.file, id: func, ct: self.ct.active() }));
@ -2500,9 +2499,9 @@ impl<'a> Codegen<'a> {
Expr::Ident { id, pos, .. } => { Expr::Ident { id, pos, .. } => {
let decl = self.find_type(pos, self.ci.file, self.ci.file, Ok(id), self.files); let decl = self.find_type(pos, self.ci.file, self.ci.file, Ok(id), self.files);
match decl.expand() { match decl.expand() {
ty::Kind::Builtin(ty::NEVER) => Value::NEVER, ty::Kind::NEVER => Value::NEVER,
ty::Kind::Global(global) => { ty::Kind::Global(global) => {
let gl = &self.tys.ins.globals[global as usize]; let gl = &self.tys.ins.globals[global];
let value = self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]); let value = self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]);
self.ci.nodes[value].aclass = GLOBAL_ACLASS as _; self.ci.nodes[value].aclass = GLOBAL_ACLASS as _;
Some(Value::ptr(value).ty(gl.ty)) Some(Value::ptr(value).ty(gl.ty))
@ -2527,8 +2526,8 @@ impl<'a> Codegen<'a> {
occupied_entry.get_key_value().0.value.0 occupied_entry.get_key_value().0.value.0
} }
(hash_map::RawEntryMut::Vacant(vacant_entry), hash) => { (hash_map::RawEntryMut::Vacant(vacant_entry), hash) => {
let global = self.tys.ins.globals.len() as ty::Global; let global =
self.tys.ins.globals.push(Global { data, ty, ..Default::default() }); self.tys.ins.globals.push(Global { data, ty, ..Default::default() });
vacant_entry vacant_entry
.insert(crate::ctx_map::Key { value: StringRef(global), hash }, ()) .insert(crate::ctx_map::Key { value: StringRef(global), hash }, ())
.0 .0
@ -2626,9 +2625,9 @@ impl<'a> Codegen<'a> {
.find_type(pos, self.ci.file, m, Err(name), self.files) .find_type(pos, self.ci.file, m, Err(name), self.files)
.expand() .expand()
{ {
ty::Kind::Builtin(ty::NEVER) => Value::NEVER, ty::Kind::NEVER => Value::NEVER,
ty::Kind::Global(global) => { ty::Kind::Global(global) => {
let gl = &self.tys.ins.globals[global as usize]; let gl = &self.tys.ins.globals[global];
let value = let value =
self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]); self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]);
self.ci.nodes[value].aclass = GLOBAL_ACLASS as _; self.ci.nodes[value].aclass = GLOBAL_ACLASS as _;
@ -2781,7 +2780,7 @@ impl<'a> Codegen<'a> {
return Value::NEVER; return Value::NEVER;
}; };
Some(Value::new(self.gen_null_check(cmped, ty, op)).ty(ty::BOOL)) Some(Value::new(self.gen_null_check(cmped, ty, op)).ty(ty::Id::BOOL))
} }
Expr::BinOp { left, pos, op, right } Expr::BinOp { left, pos, op, right }
if !matches!(op, TokenKind::Assign | TokenKind::Decl) => if !matches!(op, TokenKind::Assign | TokenKind::Decl) =>
@ -2850,7 +2849,7 @@ impl<'a> Codegen<'a> {
return Value::NEVER; return Value::NEVER;
}; };
let elem = self.tys.ins.slices[s as usize].elem; let elem = self.tys.ins.slices[s].elem;
let mut idx = self.expr_ctx(index, Ctx::default().with_ty(ty::Id::DEFAULT_INT))?; let mut idx = self.expr_ctx(index, Ctx::default().with_ty(ty::Id::DEFAULT_INT))?;
self.assert_ty(index.pos(), &mut idx, ty::Id::DEFAULT_INT, "subscript"); self.assert_ty(index.pos(), &mut idx, ty::Id::DEFAULT_INT, "subscript");
let size = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem)); let size = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem));
@ -2866,7 +2865,7 @@ impl<'a> Codegen<'a> {
Some(Value::ptr(ptr).ty(elem)) Some(Value::ptr(ptr).ty(elem))
} }
Expr::Embed { id, .. } => { Expr::Embed { id, .. } => {
let glob = &self.tys.ins.globals[id as usize]; let glob = &self.tys.ins.globals[id];
let g = self.ci.nodes.new_node(glob.ty, Kind::Global { global: id }, [VOID]); let g = self.ci.nodes.new_node(glob.ty, Kind::Global { global: id }, [VOID]);
Some(Value::ptr(g).ty(glob.ty)) Some(Value::ptr(g).ty(glob.ty))
} }
@ -3092,7 +3091,7 @@ impl<'a> Codegen<'a> {
inps[0] = self.ci.ctrl.get(); inps[0] = self.ci.ctrl.get();
self.ci.ctrl.set( self.ci.ctrl.set(
self.ci.nodes.new_node(ty, Kind::Call { func: ty::ECA, args }, inps), self.ci.nodes.new_node(ty, Kind::Call { func: ty::Func::ECA, args }, inps),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
@ -3115,8 +3114,8 @@ impl<'a> Codegen<'a> {
}; };
self.make_func_reachable(fu); self.make_func_reachable(fu);
let fuc = &self.tys.ins.funcs[fu as usize]; let fuc = &self.tys.ins.funcs[fu];
let ast = &self.files[fuc.file as usize]; let ast = &self.files[fuc.file.index()];
let &Expr::Closure { args: cargs, .. } = fuc.expr.get(ast) else { unreachable!() }; let &Expr::Closure { args: cargs, .. } = fuc.expr.get(ast) else { unreachable!() };
if args.len() != cargs.len() { if args.len() != cargs.len() {
@ -3195,9 +3194,9 @@ impl<'a> Codegen<'a> {
return Value::NEVER; return Value::NEVER;
}; };
let Func { expr, file, .. } = self.tys.ins.funcs[fu as usize]; let Func { expr, file, .. } = self.tys.ins.funcs[fu];
let ast = &self.files[file as usize]; let ast = &self.files[file.index()];
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else {
unreachable!() unreachable!()
}; };
@ -3342,7 +3341,7 @@ impl<'a> Codegen<'a> {
Some(Value::ptr(mem).ty(sty)) Some(Value::ptr(mem).ty(sty))
} }
ty::Kind::Slice(s) => { ty::Kind::Slice(s) => {
let slice = &self.tys.ins.slices[s as usize]; let slice = &self.tys.ins.slices[s];
let len = slice.len().unwrap_or(fields.len()); let len = slice.len().unwrap_or(fields.len());
let elem = slice.elem; let elem = slice.elem;
let elem_size = self.tys.size_of(elem); let elem_size = self.tys.size_of(elem);
@ -3839,8 +3838,8 @@ impl<'a> Codegen<'a> {
} }
fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> { fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> {
let fuc = &self.tys.ins.funcs[*func as usize]; let fuc = &self.tys.ins.funcs[*func];
let fast = self.files[fuc.file as usize].clone(); let fast = self.files[fuc.file.index()].clone();
let &Expr::Closure { args: cargs, ret, .. } = fuc.expr.get(&fast) else { let &Expr::Closure { args: cargs, ret, .. } = fuc.expr.get(&fast) else {
unreachable!(); unreachable!();
}; };
@ -3895,20 +3894,24 @@ impl<'a> Codegen<'a> {
let sym = SymKey::FuncInst(*func, args); let sym = SymKey::FuncInst(*func, args);
let ct = |ins: &mut crate::TypeIns| { let ct = |ins: &mut crate::TypeIns| {
let func_id = ins.funcs.len(); let fuc = &ins.funcs[*func];
let fuc = &ins.funcs[*func as usize]; ins.funcs
ins.funcs.push(Func { .push(Func {
file: fuc.file, file: fuc.file,
name: fuc.name, name: fuc.name,
base: Some(*func), base: Some(*func),
sig: Some(Sig { args, ret }), sig: Some(Sig { args, ret }),
expr: fuc.expr, expr: fuc.expr,
..Default::default() ..Default::default()
}); })
.into()
ty::Kind::Func(func_id as _).compress()
}; };
*func = self.tys.syms.get_or_insert(sym, &mut self.tys.ins, ct).expand().inner(); let ty::Kind::Func(f) =
self.tys.syms.get_or_insert(sym, &mut self.tys.ins, ct).expand()
else {
unreachable!()
};
*func = f;
Sig { args, ret } Sig { args, ret }
}) })
@ -4034,13 +4037,13 @@ impl<'a> Codegen<'a> {
} }
fn emit_func(&mut self, FTask { file, id, ct }: FTask) { fn emit_func(&mut self, FTask { file, id, ct }: FTask) {
let func = &mut self.tys.ins.funcs[id as usize]; let func = &mut self.tys.ins.funcs[id];
debug_assert_eq!(func.file, file); debug_assert_eq!(func.file, file);
let cct = self.ct.active(); let cct = self.ct.active();
debug_assert_eq!(cct, ct); debug_assert_eq!(cct, ct);
func.comp_state[cct as usize] = CompState::Compiled; func.comp_state[cct as usize] = CompState::Compiled;
let sig = func.sig.expect("to emmit only concrete functions"); let sig = func.sig.expect("to emmit only concrete functions");
let ast = &self.files[file as usize]; let ast = &self.files[file.index()];
let expr = func.expr.get(ast); let expr = func.expr.get(ast);
self.pool.push_ci(file, Some(sig.ret), 0, &mut self.ci); self.pool.push_ci(file, Some(sig.ret), 0, &mut self.ci);
@ -4192,8 +4195,6 @@ impl<'a> Codegen<'a> {
self.ci.nodes.gcm(&mut self.pool.nid_stack, &mut self.pool.nid_set); self.ci.nodes.gcm(&mut self.pool.nid_stack, &mut self.pool.nid_set);
self.ci.nodes.basic_blocks(); self.ci.nodes.basic_blocks();
self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID)); self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID));
} else {
self.ci.nodes.graphviz_in_browser(self.ty_display(ty::Id::VOID));
} }
self.errors.borrow().len() == prev_err_len self.errors.borrow().len() == prev_err_len
@ -4438,7 +4439,7 @@ impl<'a> Codegen<'a> {
} }
fn file(&self) -> &'a parser::Ast { fn file(&self) -> &'a parser::Ast {
&self.files[self.ci.file as usize] &self.files[self.ci.file.index()]
} }
} }
@ -4447,7 +4448,7 @@ impl TypeParser for Codegen<'_> {
self.tys self.tys
} }
fn eval_const(&mut self, file: FileId, expr: &Expr, ret: ty::Id) -> u64 { fn eval_const(&mut self, file: Module, expr: &Expr, ret: ty::Id) -> u64 {
self.ct.activate(); self.ct.activate();
let mut scope = mem::take(&mut self.ci.scope.vars); let mut scope = mem::take(&mut self.ci.scope.vars);
self.pool.push_ci(file, Some(ret), self.tys.tasks.len(), &mut self.ci); self.pool.push_ci(file, Some(ret), self.tys.tasks.len(), &mut self.ci);
@ -4480,7 +4481,7 @@ impl TypeParser for Codegen<'_> {
fn on_reuse(&mut self, existing: ty::Id) { fn on_reuse(&mut self, existing: ty::Id) {
let state_slot = self.ct.active() as usize; let state_slot = self.ct.active() as usize;
if let ty::Kind::Func(id) = existing.expand() if let ty::Kind::Func(id) = existing.expand()
&& let func = &mut self.tys.ins.funcs[id as usize] && let func = &mut self.tys.ins.funcs[id]
&& let CompState::Queued(idx) = func.comp_state[state_slot] && let CompState::Queued(idx) = func.comp_state[state_slot]
&& idx < self.tys.tasks.len() && idx < self.tys.tasks.len()
{ {
@ -4490,11 +4491,10 @@ impl TypeParser for Codegen<'_> {
} }
} }
fn eval_global(&mut self, file: FileId, name: Ident, expr: &Expr) -> ty::Id { fn eval_global(&mut self, file: Module, name: Ident, expr: &Expr) -> ty::Id {
self.ct.activate(); self.ct.activate();
let gid = self.tys.ins.globals.len() as ty::Global; let gid = self.tys.ins.globals.push(Global { file, name, ..Default::default() });
self.tys.ins.globals.push(Global { file, name, ..Default::default() });
let ty = ty::Kind::Global(gid); let ty = ty::Kind::Global(gid);
self.pool.push_ci(file, None, self.tys.tasks.len(), &mut self.ci); self.pool.push_ci(file, None, self.tys.tasks.len(), &mut self.ci);
@ -4506,19 +4506,19 @@ impl TypeParser for Codegen<'_> {
if self.finalize(prev_err_len) { if self.finalize(prev_err_len) {
let mut mem = vec![0u8; self.tys.size_of(ret) as usize]; let mut mem = vec![0u8; self.tys.size_of(ret) as usize];
self.emit_and_eval(file, ret, &mut mem); self.emit_and_eval(file, ret, &mut mem);
self.tys.ins.globals[gid as usize].data = mem; self.tys.ins.globals[gid].data = mem;
} }
self.pool.pop_ci(&mut self.ci); self.pool.pop_ci(&mut self.ci);
self.tys.ins.globals[gid as usize].ty = ret; self.tys.ins.globals[gid].ty = ret;
self.ct.deactivate(); self.ct.deactivate();
ty.compress() ty.compress()
} }
fn report(&self, file: FileId, pos: Pos, msg: impl Display) -> ty::Id { fn report(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id {
let mut buf = self.errors.borrow_mut(); let mut buf = self.errors.borrow_mut();
write!(buf, "{}", self.files[file as usize].report(pos, msg)).unwrap(); write!(buf, "{}", self.files[file.index()].report(pos, msg)).unwrap();
ty::Id::NEVER ty::Id::NEVER
} }
@ -4531,6 +4531,7 @@ impl TypeParser for Codegen<'_> {
mod tests { mod tests {
use { use {
super::{hbvm::HbvmBackend, CodegenCtx}, super::{hbvm::HbvmBackend, CodegenCtx},
crate::ty,
alloc::{string::String, vec::Vec}, alloc::{string::String, vec::Vec},
core::fmt::Write, core::fmt::Write,
}; };
@ -4546,7 +4547,7 @@ mod tests {
let mut codegen = super::Codegen::new(&mut backend, files, &mut ctx); let mut codegen = super::Codegen::new(&mut backend, files, &mut ctx);
codegen.push_embeds(embeds); codegen.push_embeds(embeds);
codegen.generate(0); codegen.generate(ty::Module::MAIN);
{ {
let errors = codegen.errors.borrow(); let errors = codegen.errors.borrow();

View file

@ -4,7 +4,8 @@ use {
lexer::TokenKind, lexer::TokenKind,
parser, reg, parser, reg,
son::{debug_assert_matches, write_reloc, Kind, MEM}, son::{debug_assert_matches, write_reloc, Kind, MEM},
ty::{self, Loc}, ty::{self, Loc, Module},
utils::{Ent, EntVec},
Offset, Reloc, Size, TypedReloc, Types, Offset, Reloc, Size, TypedReloc, Types,
}, },
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec}, alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
@ -47,8 +48,8 @@ struct Assembler {
#[derive(Default)] #[derive(Default)]
pub struct HbvmBackend { pub struct HbvmBackend {
funcs: Vec<FuncDt>, funcs: EntVec<ty::Func, FuncDt>,
globals: Vec<GlobalDt>, globals: EntVec<ty::Global, GlobalDt>,
asm: Assembler, asm: Assembler,
ralloc: their_regalloc::Regalloc, ralloc: their_regalloc::Regalloc,
ralloc_my: my_regalloc::Res, ralloc_my: my_regalloc::Res,
@ -98,13 +99,13 @@ impl Backend for HbvmBackend {
debug_assert!(self.asm.funcs.is_empty()); debug_assert!(self.asm.funcs.is_empty());
debug_assert!(self.asm.globals.is_empty()); debug_assert!(self.asm.globals.is_empty());
self.globals.resize_with(types.ins.globals.len(), Default::default); self.globals.shadow(types.ins.globals.len());
self.asm.frontier.push(ty::Kind::Func(from).compress()); self.asm.frontier.push(ty::Kind::Func(from).compress());
while let Some(itm) = self.asm.frontier.pop() { while let Some(itm) = self.asm.frontier.pop() {
match itm.expand() { match itm.expand() {
ty::Kind::Func(func) => { ty::Kind::Func(func) => {
let fuc = &mut self.funcs[func as usize]; let fuc = &mut self.funcs[func];
debug_assert!(!fuc.code.is_empty()); debug_assert!(!fuc.code.is_empty());
if fuc.offset != u32::MAX { if fuc.offset != u32::MAX {
continue; continue;
@ -114,7 +115,7 @@ impl Backend for HbvmBackend {
self.asm.frontier.extend(fuc.relocs.iter().map(|r| r.target)); self.asm.frontier.extend(fuc.relocs.iter().map(|r| r.target));
} }
ty::Kind::Global(glob) => { ty::Kind::Global(glob) => {
let glb = &mut self.globals[glob as usize]; let glb = &mut self.globals[glob];
if glb.offset != u32::MAX { if glb.offset != u32::MAX {
continue; continue;
} }
@ -128,7 +129,7 @@ impl Backend for HbvmBackend {
let init_len = to.len(); let init_len = to.len();
for &func in &self.asm.funcs { for &func in &self.asm.funcs {
let fuc = &mut self.funcs[func as usize]; let fuc = &mut self.funcs[func];
fuc.offset = to.len() as _; fuc.offset = to.len() as _;
debug_assert!(!fuc.code.is_empty()); debug_assert!(!fuc.code.is_empty());
to.extend(&fuc.code); to.extend(&fuc.code);
@ -137,18 +138,18 @@ impl Backend for HbvmBackend {
let code_length = to.len() - init_len; let code_length = to.len() - init_len;
for global in self.asm.globals.drain(..) { for global in self.asm.globals.drain(..) {
self.globals[global as usize].offset = to.len() as _; self.globals[global].offset = to.len() as _;
to.extend(&types.ins.globals[global as usize].data); to.extend(&types.ins.globals[global].data);
} }
let data_length = to.len() - code_length - init_len; let data_length = to.len() - code_length - init_len;
for func in self.asm.funcs.drain(..) { for func in self.asm.funcs.drain(..) {
let fuc = &self.funcs[func as usize]; let fuc = &self.funcs[func];
for rel in &fuc.relocs { for rel in &fuc.relocs {
let offset = match rel.target.expand() { let offset = match rel.target.expand() {
ty::Kind::Func(fun) => self.funcs[fun as usize].offset, ty::Kind::Func(fun) => self.funcs[fun].offset,
ty::Kind::Global(glo) => self.globals[glo as usize].offset, ty::Kind::Global(glo) => self.globals[glo].offset,
_ => unreachable!(), _ => unreachable!(),
}; };
rel.reloc.apply_jump(to, offset, fuc.offset); rel.reloc.apply_jump(to, offset, fuc.offset);
@ -158,7 +159,7 @@ impl Backend for HbvmBackend {
AssemblySpec { AssemblySpec {
code_length: code_length as _, code_length: code_length as _,
data_length: data_length as _, data_length: data_length as _,
entry: self.funcs[from as usize].offset, entry: self.funcs[from].offset,
} }
} }
@ -175,11 +176,11 @@ impl Backend for HbvmBackend {
.ins .ins
.funcs .funcs
.iter() .iter()
.zip(&self.funcs) .zip(self.funcs.iter())
.filter(|(_, f)| f.offset != u32::MAX) .filter(|(_, f)| f.offset != u32::MAX)
.map(|(f, fd)| { .map(|(f, fd)| {
let name = if f.file != u32::MAX { let name = if f.file != Module::default() {
let file = &files[f.file as usize]; let file = &files[f.file.index()];
file.ident_str(f.name) file.ident_str(f.name)
} else { } else {
"target_fn" "target_fn"
@ -191,13 +192,13 @@ impl Backend for HbvmBackend {
.ins .ins
.globals .globals
.iter() .iter()
.zip(&self.globals) .zip(self.globals.iter())
.filter(|(_, g)| g.offset != u32::MAX) .filter(|(_, g)| g.offset != u32::MAX)
.map(|(g, gd)| { .map(|(g, gd)| {
let name = if g.file == u32::MAX { let name = if g.file == Module::default() {
core::str::from_utf8(&g.data).unwrap_or("invalid utf-8") core::str::from_utf8(&g.data).unwrap_or("invalid utf-8")
} else { } else {
let file = &files[g.file as usize]; let file = &files[g.file.index()];
file.ident_str(g.name) file.ident_str(g.name)
}; };
(gd.offset, (name, g.data.len() as Size, DisasmItem::Global)) (gd.offset, (name, g.data.len() as Size, DisasmItem::Global))
@ -215,13 +216,13 @@ impl Backend for HbvmBackend {
files: &[parser::Ast], files: &[parser::Ast],
) { ) {
self.emit_body(id, nodes, tys, files); self.emit_body(id, nodes, tys, files);
let fd = &mut self.funcs[id as usize]; let fd = &mut self.funcs[id];
fd.code.truncate(fd.code.len() - instrs::jala(0, 0, 0).0); fd.code.truncate(fd.code.len() - instrs::jala(0, 0, 0).0);
emit(&mut fd.code, instrs::tx()); emit(&mut fd.code, instrs::tx());
} }
fn emit_body(&mut self, id: ty::Func, nodes: &mut Nodes, tys: &Types, files: &[parser::Ast]) { fn emit_body(&mut self, id: ty::Func, nodes: &mut Nodes, tys: &Types, files: &[parser::Ast]) {
let sig = tys.ins.funcs[id as usize].sig.unwrap(); let sig = tys.ins.funcs[id].sig.unwrap();
debug_assert!(self.code.is_empty()); debug_assert!(self.code.is_empty());
@ -319,11 +320,9 @@ impl Backend for HbvmBackend {
self.emit(instrs::jala(reg::ZERO, reg::RET_ADDR, 0)); self.emit(instrs::jala(reg::ZERO, reg::RET_ADDR, 0));
} }
if self.funcs.get(id as usize).is_none() { self.funcs.shadow(tys.ins.funcs.len());
self.funcs.resize_with(id as usize + 1, Default::default); self.funcs[id].code = mem::take(&mut self.code);
} self.funcs[id].relocs = mem::take(&mut self.relocs);
self.funcs[id as usize].code = mem::take(&mut self.code);
self.funcs[id as usize].relocs = mem::take(&mut self.relocs);
debug_assert_eq!(self.ret_relocs.len(), 0); debug_assert_eq!(self.ret_relocs.len(), 0);
debug_assert_eq!(self.relocs.len(), 0); debug_assert_eq!(self.relocs.len(), 0);

View file

@ -305,7 +305,7 @@ impl HbvmBackend {
!matches!(ret, Some(PLoc::Ref(..))) || allocs.next().is_some() !matches!(ret, Some(PLoc::Ref(..))) || allocs.next().is_some()
); );
if func == ty::ECA { if func == ty::Func::ECA {
self.emit(instrs::eca()); self.emit(instrs::eca());
} else { } else {
self.relocs.push(TypedReloc { self.relocs.push(TypedReloc {
@ -647,7 +647,7 @@ impl<'a> Function<'a> {
} }
} }
Kind::Call { func, .. } => { Kind::Call { func, .. } => {
self.tail &= func == ty::ECA; self.tail &= func == ty::Func::ECA;
self.add_instr(nid); self.add_instr(nid);

View file

@ -315,7 +315,7 @@ impl HbvmBackend {
!matches!(ret, Some(PLoc::Ref(..))) || allocs.next().is_some() !matches!(ret, Some(PLoc::Ref(..))) || allocs.next().is_some()
); );
if func == ty::ECA { if func == ty::Func::ECA {
self.emit(instrs::eca()); self.emit(instrs::eca());
} else { } else {
self.relocs.push(TypedReloc { self.relocs.push(TypedReloc {
@ -710,7 +710,7 @@ impl<'a> Function<'a> {
self.add_instr(nid, ops); self.add_instr(nid, ops);
} }
Kind::Call { args, func } => { Kind::Call { args, func } => {
self.tail &= func == ty::ECA; self.tail &= func == ty::Func::ECA;
self.backrefs[nid as usize] = self.backrefs[prev as usize]; self.backrefs[nid as usize] = self.backrefs[prev as usize];
let mut ops = vec![]; let mut ops = vec![];

View file

@ -5,6 +5,7 @@ use {
alloc::Layout, alloc::Layout,
fmt::Debug, fmt::Debug,
hint::unreachable_unchecked, hint::unreachable_unchecked,
marker::PhantomData,
mem::MaybeUninit, mem::MaybeUninit,
ops::{Deref, DerefMut, Not}, ops::{Deref, DerefMut, Not},
ptr::Unique, ptr::Unique,
@ -532,3 +533,97 @@ struct AllocedVc {
len: Nid, len: Nid,
base: Unique<Nid>, base: Unique<Nid>,
} }
pub trait Ent: Copy {
fn new(index: usize) -> Self;
fn index(self) -> usize;
}
pub struct EntVec<K: Ent, T> {
data: ::alloc::vec::Vec<T>,
k: PhantomData<fn(K)>,
}
impl<K: Ent, T> Default for EntVec<K, T> {
fn default() -> Self {
Self { data: Default::default(), k: PhantomData }
}
}
impl<K: Ent, T> EntVec<K, T> {
pub fn clear(&mut self) {
self.data.clear();
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn push(&mut self, value: T) -> K {
let k = K::new(self.data.len());
self.data.push(value);
k
}
pub fn next(&self, index: K) -> Option<&T> {
self.data.get(index.index() + 1)
}
pub fn shadow(&mut self, len: usize)
where
T: Default,
{
if self.data.len() < len {
self.data.resize_with(len, Default::default);
}
}
pub fn iter(&self) -> core::slice::Iter<T> {
self.data.iter()
}
}
impl<K: Ent, T> core::ops::Index<K> for EntVec<K, T> {
type Output = T;
fn index(&self, index: K) -> &Self::Output {
&self.data[index.index()]
}
}
impl<K: Ent, T> core::ops::IndexMut<K> for EntVec<K, T> {
fn index_mut(&mut self, index: K) -> &mut Self::Output {
&mut self.data[index.index()]
}
}
macro_rules! decl_ent {
($(
$vis:vis struct $name:ident($index:ty);
)*) => {$(
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
$vis struct $name($index);
impl crate::utils::Ent for $name {
fn new(index: usize) -> Self {
Self(index as $index)
}
fn index(self) -> usize {
self.0 as _
}
}
impl core::fmt::Display for $name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, concat!(stringify!($name), "{}"), self.0)
}
}
)*};
}
pub(crate) use decl_ent;