From 68c0248189c3797db834911210280507f3138c74 Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Fri, 8 Nov 2024 10:25:34 +0100 Subject: [PATCH] making type manipulation nicer --- depell/wasm-hbc/src/lib.rs | 7 +- lang/src/fs.rs | 17 +- lang/src/fuzz.rs | 3 +- lang/src/lib.rs | 365 ++++++++++++++-------------- lang/src/parser.rs | 21 +- lang/src/son.rs | 137 +++++------ lang/src/son/hbvm.rs | 51 ++-- lang/src/son/hbvm/my_regalloc.rs | 4 +- lang/src/son/hbvm/their_regalloc.rs | 4 +- lang/src/utils.rs | 95 ++++++++ 10 files changed, 403 insertions(+), 301 deletions(-) diff --git a/depell/wasm-hbc/src/lib.rs b/depell/wasm-hbc/src/lib.rs index a0505d82..8800b8f6 100644 --- a/depell/wasm-hbc/src/lib.rs +++ b/depell/wasm-hbc/src/lib.rs @@ -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::>(); 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()); diff --git a/lang/src/fs.rs b/lang/src/fs.rs index a0498d09..0768ba8b 100644 --- a/lang/src/fs.rs +++ b/lang/src/fs.rs @@ -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) -> 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 { } } - type Task = (u32, PathBuf); + type Task = (usize, PathBuf); - let seen_modules = Mutex::new(crate::HashMap::::default()); - let seen_embeds = Mutex::new(crate::HashMap::::default()); + let seen_modules = Mutex::new(crate::HashMap::::default()); + let seen_embeds = Mutex::new(crate::HashMap::::default()); let tasks = TaskQueue::::new(extra_threads + 1); let ast = Mutex::new(Vec::>::new()); let embeds = Mutex::new(Vec::>::new()); @@ -264,7 +265,7 @@ pub fn parse_from_fs(extra_threads: usize, root: &str) -> io::Result { } 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 { } 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 { 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() }; diff --git a/lang/src/fuzz.rs b/lang/src/fuzz.rs index dc881e8e..f509e94a 100644 --- a/lang/src/fuzz.rs +++ b/lang/src/fuzz.rs @@ -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) { 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); } } diff --git a/lang/src/lib.rs b/lang/src/lib.rs index fc69e918..e6893732 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -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 { 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 for Id { - fn from(id: u32) -> Self { - Kind::Builtin(id).compress() - } - } - const fn array_to_lower_case(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 { 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 for Builtin { + type Error = (); + + fn try_from(value: Ident) -> Result { + 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, 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, } -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, align: Cell, captures: ty::Tuple, @@ -934,18 +961,19 @@ struct TypesTmp { #[derive(Default)] pub struct TypeIns { - funcs: Vec, args: Vec, - globals: Vec, - structs: Vec, fields: Vec, - ptrs: Vec, - opts: Vec, - slices: Vec, + funcs: EntVec, + globals: EntVec, + consts: EntVec, + structs: EntVec, + ptrs: EntVec, + opts: EntVec, + slices: EntVec, } 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; 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; - 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, 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, 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 { - 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( + fn make_generic_ty, T: Copy>( &mut self, ty: T, - get_col: fn(&mut TypeIns) -> &mut Vec, + get_col: fn(&mut TypeIns) -> &mut EntVec, 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 { 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 { 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()), }; diff --git a/lang/src/parser.rs b/lang/src/parser.rs index 4074166e..161bec70 100644 --- a/lang/src/parser.rs +++ b/lang/src/parser.rs @@ -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 + 'a); +pub type Loader<'a> = &'a mut (dyn FnMut(&str, &str, FileKind) -> Result + 'a); #[derive(PartialEq, Eq, Debug)] pub enum FileKind { @@ -63,7 +64,7 @@ pub mod idfl { } } -pub fn no_loader(_: &str, _: &str, _: FileKind) -> Result { +pub fn no_loader(_: &str, _: &str, _: FileKind) -> Result { 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>( + pub fn find_pattern_path T>( &self, ident: Ident, target: &Expr, mut with_final: F, ) -> Result { 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>); diff --git a/lang/src/son.rs b/lang/src/son.rs index 5e78c55f..393bdcef 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -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, ret: Option, task_base: usize, @@ -2031,7 +2031,7 @@ pub struct ItemCtx { } impl ItemCtx { - fn init(&mut self, file: FileId, ret: Option, task_base: usize) { + fn init(&mut self, file: Module, ret: Option, 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, task_base: usize, target: &mut ItemCtx, @@ -2173,8 +2173,8 @@ impl Value { } #[inline(always)] - fn ty(self, ty: impl Into) -> 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) { - 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>) { - 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 { - 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(); diff --git a/lang/src/son/hbvm.rs b/lang/src/son/hbvm.rs index 194664b2..12e910a4 100644 --- a/lang/src/son/hbvm.rs +++ b/lang/src/son/hbvm.rs @@ -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, - globals: Vec, + funcs: EntVec, + globals: EntVec, 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); diff --git a/lang/src/son/hbvm/my_regalloc.rs b/lang/src/son/hbvm/my_regalloc.rs index 6b70ae39..d0e31328 100644 --- a/lang/src/son/hbvm/my_regalloc.rs +++ b/lang/src/son/hbvm/my_regalloc.rs @@ -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); diff --git a/lang/src/son/hbvm/their_regalloc.rs b/lang/src/son/hbvm/their_regalloc.rs index 1fee4e68..b46be2e9 100644 --- a/lang/src/son/hbvm/their_regalloc.rs +++ b/lang/src/son/hbvm/their_regalloc.rs @@ -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![]; diff --git a/lang/src/utils.rs b/lang/src/utils.rs index b0d3477d..4450b5a9 100644 --- a/lang/src/utils.rs +++ b/lang/src/utils.rs @@ -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, } + +pub trait Ent: Copy { + fn new(index: usize) -> Self; + fn index(self) -> usize; +} + +pub struct EntVec { + data: ::alloc::vec::Vec, + k: PhantomData, +} + +impl Default for EntVec { + fn default() -> Self { + Self { data: Default::default(), k: PhantomData } + } +} + +impl EntVec { + 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 { + self.data.iter() + } +} + +impl core::ops::Index for EntVec { + type Output = T; + + fn index(&self, index: K) -> &Self::Output { + &self.data[index.index()] + } +} + +impl core::ops::IndexMut for EntVec { + 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;