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 {
alloc::{string::String, vec::Vec},
hblang::{
parser::FileId,
son::{hbvm::HbvmBackend, Codegen, CodegenCtx},
ty::Module,
Ent,
},
};
@ -60,7 +61,7 @@ unsafe fn compile_and_run(mut fuel: usize) {
let files = {
let paths = files.iter().map(|f| f.path).collect::<Vec<_>>();
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()),
};
files
@ -79,7 +80,7 @@ unsafe fn compile_and_run(mut fuel: usize) {
let mut ct = {
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() {
log::error!("{}", ctx.parser.errors.borrow());

View file

@ -2,6 +2,7 @@ use {
crate::{
parser::{Ast, Ctx, FileKind},
son::{self, hbvm::HbvmBackend},
ty,
},
alloc::{string::String, vec::Vec},
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);
codegen.push_embeds(parsed.embeds);
codegen.generate(0);
codegen.generate(ty::Module::MAIN);
if !codegen.errors.borrow().is_empty() {
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_embeds = 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, usize>::default());
let tasks = TaskQueue::<Task>::new(extra_threads + 1);
let ast = Mutex::new(Vec::<io::Result<Ast>>::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) => {
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) => {
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() {
let res = execute_task(&mut ctx, task, &mut tmp);
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[indx as usize] = res;
ast[indx] = res;
}
ctx.errors.into_inner()
};

View file

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

View file

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

View file

@ -10,20 +10,20 @@ use {
parser::{
self,
idfl::{self},
CtorField, Expr, FileId, Pos,
CtorField, Expr, Pos,
},
ty::{self, Arg, ArrayLen, Loc, Tuple},
utils::{BitSet, Vc},
ty::{self, Arg, ArrayLen, Loc, Module, Tuple},
utils::{BitSet, Ent, Vc},
CompState, FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Sig, StringRef,
SymKey, TypeParser, Types,
},
alloc::{rc::Rc, string::String, vec::Vec},
alloc::{string::String, vec::Vec},
core::{
assert_matches::debug_assert_matches,
cell::{Cell, RefCell},
fmt::{self, Debug, Display, Write},
format_args as fa, mem,
ops::{self, Deref},
ops::{self},
},
hashbrown::hash_map,
hbbytecode::DisasmError,
@ -2016,7 +2016,7 @@ impl Scope {
#[derive(Default, Clone)]
pub struct ItemCtx {
file: FileId,
file: Module,
pos: Vec<Pos>,
ret: Option<ty::Id>,
task_base: usize,
@ -2031,7 +2031,7 @@ pub struct 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.scope.vars.len(), 0);
debug_assert_eq!(self.scope.aclasses.len(), 0);
@ -2106,7 +2106,7 @@ pub struct Pool {
impl Pool {
fn push_ci(
&mut self,
file: FileId,
file: Module,
ret: Option<ty::Id>,
task_base: usize,
target: &mut ItemCtx,
@ -2173,8 +2173,8 @@ impl Value {
}
#[inline(always)]
fn ty(self, ty: impl Into<ty::Id>) -> Self {
Self { ty: ty.into(), ..self }
fn ty(self, ty: ty::Id) -> 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);
if self.tys.ins.funcs.is_empty() {
return;
}
self.make_func_reachable(0);
self.make_func_reachable(ty::Func::MAIN);
self.complete_call_graph();
}
pub fn assemble_comptime(&mut self) -> Comptime {
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();
core::mem::take(self.ct)
}
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> {
@ -2264,17 +2264,17 @@ impl<'a> Codegen<'a> {
}
pub fn push_embeds(&mut self, embeds: Vec<Vec<u8>>) {
self.tys.ins.globals = embeds
.into_iter()
.map(|data| Global {
for data in embeds {
let g = Global {
ty: self.tys.make_array(ty::Id::U8, data.len() as _),
data,
..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 =
self.ci.nodes[NEVER].inputs.iter().filter(|&&i| self.ci.nodes[i].kind == Kind::Return);
if let Some(&ret) = rets.next()
@ -2291,8 +2291,7 @@ impl<'a> Codegen<'a> {
return 1;
}
let fuc = self.tys.ins.funcs.len() as ty::Func;
self.tys.ins.funcs.push(Func {
let fuc = self.tys.ins.funcs.push(Func {
file,
sig: Some(Sig { args: Tuple::empty(), ret }),
..Default::default()
@ -2413,7 +2412,7 @@ impl<'a> Codegen<'a> {
fn make_func_reachable(&mut self, func: ty::Func) {
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 {
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() }));
@ -2500,9 +2499,9 @@ impl<'a> Codegen<'a> {
Expr::Ident { id, pos, .. } => {
let decl = self.find_type(pos, self.ci.file, self.ci.file, Ok(id), self.files);
match decl.expand() {
ty::Kind::Builtin(ty::NEVER) => Value::NEVER,
ty::Kind::NEVER => Value::NEVER,
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]);
self.ci.nodes[value].aclass = GLOBAL_ACLASS as _;
Some(Value::ptr(value).ty(gl.ty))
@ -2527,8 +2526,8 @@ impl<'a> Codegen<'a> {
occupied_entry.get_key_value().0.value.0
}
(hash_map::RawEntryMut::Vacant(vacant_entry), hash) => {
let global = self.tys.ins.globals.len() as ty::Global;
self.tys.ins.globals.push(Global { data, ty, ..Default::default() });
let global =
self.tys.ins.globals.push(Global { data, ty, ..Default::default() });
vacant_entry
.insert(crate::ctx_map::Key { value: StringRef(global), hash }, ())
.0
@ -2626,9 +2625,9 @@ impl<'a> Codegen<'a> {
.find_type(pos, self.ci.file, m, Err(name), self.files)
.expand()
{
ty::Kind::Builtin(ty::NEVER) => Value::NEVER,
ty::Kind::NEVER => Value::NEVER,
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]);
self.ci.nodes[value].aclass = GLOBAL_ACLASS as _;
@ -2781,7 +2780,7 @@ impl<'a> Codegen<'a> {
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 }
if !matches!(op, TokenKind::Assign | TokenKind::Decl) =>
@ -2850,7 +2849,7 @@ impl<'a> Codegen<'a> {
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))?;
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));
@ -2866,7 +2865,7 @@ impl<'a> Codegen<'a> {
Some(Value::ptr(ptr).ty(elem))
}
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]);
Some(Value::ptr(g).ty(glob.ty))
}
@ -3092,7 +3091,7 @@ impl<'a> Codegen<'a> {
inps[0] = self.ci.ctrl.get();
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,
);
@ -3115,8 +3114,8 @@ impl<'a> Codegen<'a> {
};
self.make_func_reachable(fu);
let fuc = &self.tys.ins.funcs[fu as usize];
let ast = &self.files[fuc.file as usize];
let fuc = &self.tys.ins.funcs[fu];
let ast = &self.files[fuc.file.index()];
let &Expr::Closure { args: cargs, .. } = fuc.expr.get(ast) else { unreachable!() };
if args.len() != cargs.len() {
@ -3195,9 +3194,9 @@ impl<'a> Codegen<'a> {
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 {
unreachable!()
};
@ -3342,7 +3341,7 @@ impl<'a> Codegen<'a> {
Some(Value::ptr(mem).ty(sty))
}
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 elem = slice.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> {
let fuc = &self.tys.ins.funcs[*func as usize];
let fast = self.files[fuc.file as usize].clone();
let fuc = &self.tys.ins.funcs[*func];
let fast = self.files[fuc.file.index()].clone();
let &Expr::Closure { args: cargs, ret, .. } = fuc.expr.get(&fast) else {
unreachable!();
};
@ -3895,20 +3894,24 @@ impl<'a> Codegen<'a> {
let sym = SymKey::FuncInst(*func, args);
let ct = |ins: &mut crate::TypeIns| {
let func_id = ins.funcs.len();
let fuc = &ins.funcs[*func as usize];
ins.funcs.push(Func {
file: fuc.file,
name: fuc.name,
base: Some(*func),
sig: Some(Sig { args, ret }),
expr: fuc.expr,
..Default::default()
});
ty::Kind::Func(func_id as _).compress()
let fuc = &ins.funcs[*func];
ins.funcs
.push(Func {
file: fuc.file,
name: fuc.name,
base: Some(*func),
sig: Some(Sig { args, ret }),
expr: fuc.expr,
..Default::default()
})
.into()
};
*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 }
})
@ -4034,13 +4037,13 @@ impl<'a> Codegen<'a> {
}
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);
let cct = self.ct.active();
debug_assert_eq!(cct, ct);
func.comp_state[cct as usize] = CompState::Compiled;
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);
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.basic_blocks();
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
@ -4438,7 +4439,7 @@ impl<'a> Codegen<'a> {
}
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
}
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();
let mut scope = mem::take(&mut self.ci.scope.vars);
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) {
let state_slot = self.ct.active() as usize;
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]
&& 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();
let gid = self.tys.ins.globals.len() as ty::Global;
self.tys.ins.globals.push(Global { file, name, ..Default::default() });
let gid = self.tys.ins.globals.push(Global { file, name, ..Default::default() });
let ty = ty::Kind::Global(gid);
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) {
let mut mem = vec![0u8; self.tys.size_of(ret) as usize];
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.tys.ins.globals[gid as usize].ty = ret;
self.tys.ins.globals[gid].ty = ret;
self.ct.deactivate();
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();
write!(buf, "{}", self.files[file as usize].report(pos, msg)).unwrap();
write!(buf, "{}", self.files[file.index()].report(pos, msg)).unwrap();
ty::Id::NEVER
}
@ -4531,6 +4531,7 @@ impl TypeParser for Codegen<'_> {
mod tests {
use {
super::{hbvm::HbvmBackend, CodegenCtx},
crate::ty,
alloc::{string::String, vec::Vec},
core::fmt::Write,
};
@ -4546,7 +4547,7 @@ mod tests {
let mut codegen = super::Codegen::new(&mut backend, files, &mut ctx);
codegen.push_embeds(embeds);
codegen.generate(0);
codegen.generate(ty::Module::MAIN);
{
let errors = codegen.errors.borrow();

View file

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

View file

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

View file

@ -5,6 +5,7 @@ use {
alloc::Layout,
fmt::Debug,
hint::unreachable_unchecked,
marker::PhantomData,
mem::MaybeUninit,
ops::{Deref, DerefMut, Not},
ptr::Unique,
@ -532,3 +533,97 @@ struct AllocedVc {
len: 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;