forked from AbleOS/holey-bytes
making type manipulation nicer
This commit is contained in:
parent
0ef74d89cb
commit
68c0248189
|
@ -5,8 +5,9 @@
|
||||||
use {
|
use {
|
||||||
alloc::{string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
hblang::{
|
hblang::{
|
||||||
parser::FileId,
|
|
||||||
son::{hbvm::HbvmBackend, Codegen, CodegenCtx},
|
son::{hbvm::HbvmBackend, Codegen, CodegenCtx},
|
||||||
|
ty::Module,
|
||||||
|
Ent,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ unsafe fn compile_and_run(mut fuel: usize) {
|
||||||
let files = {
|
let files = {
|
||||||
let paths = files.iter().map(|f| f.path).collect::<Vec<_>>();
|
let paths = files.iter().map(|f| f.path).collect::<Vec<_>>();
|
||||||
let mut loader = |path: &str, _: &str, kind| match kind {
|
let mut loader = |path: &str, _: &str, kind| match kind {
|
||||||
hblang::parser::FileKind::Module => Ok(paths.binary_search(&path).unwrap() as FileId),
|
hblang::parser::FileKind::Module => Ok(paths.binary_search(&path).unwrap()),
|
||||||
hblang::parser::FileKind::Embed => Err("embeds are not supported".into()),
|
hblang::parser::FileKind::Embed => Err("embeds are not supported".into()),
|
||||||
};
|
};
|
||||||
files
|
files
|
||||||
|
@ -79,7 +80,7 @@ unsafe fn compile_and_run(mut fuel: usize) {
|
||||||
|
|
||||||
let mut ct = {
|
let mut ct = {
|
||||||
let mut backend = HbvmBackend::default();
|
let mut backend = HbvmBackend::default();
|
||||||
Codegen::new(&mut backend, &files, &mut ctx).generate(root as FileId);
|
Codegen::new(&mut backend, &files, &mut ctx).generate(Module::new(root));
|
||||||
|
|
||||||
if !ctx.parser.errors.borrow().is_empty() {
|
if !ctx.parser.errors.borrow().is_empty() {
|
||||||
log::error!("{}", ctx.parser.errors.borrow());
|
log::error!("{}", ctx.parser.errors.borrow());
|
||||||
|
|
|
@ -2,6 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
parser::{Ast, Ctx, FileKind},
|
parser::{Ast, Ctx, FileKind},
|
||||||
son::{self, hbvm::HbvmBackend},
|
son::{self, hbvm::HbvmBackend},
|
||||||
|
ty,
|
||||||
},
|
},
|
||||||
alloc::{string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
core::{fmt::Write, num::NonZeroUsize, ops::Deref},
|
core::{fmt::Write, num::NonZeroUsize, ops::Deref},
|
||||||
|
@ -96,7 +97,7 @@ pub fn run_compiler(root_file: &str, options: Options, out: &mut Vec<u8>) -> std
|
||||||
let mut codegen = son::Codegen::new(&mut backend, &parsed.ast, &mut ctx);
|
let mut codegen = son::Codegen::new(&mut backend, &parsed.ast, &mut ctx);
|
||||||
|
|
||||||
codegen.push_embeds(parsed.embeds);
|
codegen.push_embeds(parsed.embeds);
|
||||||
codegen.generate(0);
|
codegen.generate(ty::Module::MAIN);
|
||||||
|
|
||||||
if !codegen.errors.borrow().is_empty() {
|
if !codegen.errors.borrow().is_empty() {
|
||||||
drop(codegen);
|
drop(codegen);
|
||||||
|
@ -242,10 +243,10 @@ pub fn parse_from_fs(extra_threads: usize, root: &str) -> io::Result<Loaded> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Task = (u32, PathBuf);
|
type Task = (usize, PathBuf);
|
||||||
|
|
||||||
let seen_modules = Mutex::new(crate::HashMap::<PathBuf, u32>::default());
|
let seen_modules = Mutex::new(crate::HashMap::<PathBuf, usize>::default());
|
||||||
let seen_embeds = Mutex::new(crate::HashMap::<PathBuf, u32>::default());
|
let seen_embeds = Mutex::new(crate::HashMap::<PathBuf, usize>::default());
|
||||||
let tasks = TaskQueue::<Task>::new(extra_threads + 1);
|
let tasks = TaskQueue::<Task>::new(extra_threads + 1);
|
||||||
let ast = Mutex::new(Vec::<io::Result<Ast>>::new());
|
let ast = Mutex::new(Vec::<io::Result<Ast>>::new());
|
||||||
let embeds = Mutex::new(Vec::<Vec<u8>>::new());
|
let embeds = Mutex::new(Vec::<Vec<u8>>::new());
|
||||||
|
@ -264,7 +265,7 @@ pub fn parse_from_fs(extra_threads: usize, root: &str) -> io::Result<Loaded> {
|
||||||
}
|
}
|
||||||
hash_map::Entry::Vacant(entry) => {
|
hash_map::Entry::Vacant(entry) => {
|
||||||
physiscal_path = entry.insert_entry(len as _).key().clone();
|
physiscal_path = entry.insert_entry(len as _).key().clone();
|
||||||
len as u32
|
len
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -289,7 +290,7 @@ pub fn parse_from_fs(extra_threads: usize, root: &str) -> io::Result<Loaded> {
|
||||||
}
|
}
|
||||||
hash_map::Entry::Vacant(entry) => {
|
hash_map::Entry::Vacant(entry) => {
|
||||||
physiscal_path = entry.insert_entry(len as _).key().clone();
|
physiscal_path = entry.insert_entry(len as _).key().clone();
|
||||||
len as u32
|
len
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -331,9 +332,9 @@ pub fn parse_from_fs(extra_threads: usize, root: &str) -> io::Result<Loaded> {
|
||||||
while let Some(task @ (indx, ..)) = tasks.pop() {
|
while let Some(task @ (indx, ..)) = tasks.pop() {
|
||||||
let res = execute_task(&mut ctx, task, &mut tmp);
|
let res = execute_task(&mut ctx, task, &mut tmp);
|
||||||
let mut ast = ast.lock().unwrap();
|
let mut ast = ast.lock().unwrap();
|
||||||
let len = ast.len().max(indx as usize + 1);
|
let len = ast.len().max(indx + 1);
|
||||||
ast.resize_with(len, || Err(io::ErrorKind::InvalidData.into()));
|
ast.resize_with(len, || Err(io::ErrorKind::InvalidData.into()));
|
||||||
ast[indx as usize] = res;
|
ast[indx] = res;
|
||||||
}
|
}
|
||||||
ctx.errors.into_inner()
|
ctx.errors.into_inner()
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@ use {
|
||||||
lexer::TokenKind,
|
lexer::TokenKind,
|
||||||
parser,
|
parser,
|
||||||
son::{hbvm::HbvmBackend, Codegen, CodegenCtx},
|
son::{hbvm::HbvmBackend, Codegen, CodegenCtx},
|
||||||
|
ty::Module,
|
||||||
},
|
},
|
||||||
alloc::string::String,
|
alloc::string::String,
|
||||||
core::{fmt::Write, hash::BuildHasher, ops::Range},
|
core::{fmt::Write, hash::BuildHasher, ops::Range},
|
||||||
|
@ -135,6 +136,6 @@ pub fn fuzz(seed_range: Range<u64>) {
|
||||||
|
|
||||||
let mut backend = HbvmBackend::default();
|
let mut backend = HbvmBackend::default();
|
||||||
let mut cdg = Codegen::new(&mut backend, core::slice::from_ref(&parsed), &mut ctx);
|
let mut cdg = Codegen::new(&mut backend, core::slice::from_ref(&parsed), &mut ctx);
|
||||||
cdg.generate(0);
|
cdg.generate(Module::MAIN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
365
lang/src/lib.rs
365
lang/src/lib.rs
|
@ -32,11 +32,13 @@
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use fs::*;
|
pub use fs::*;
|
||||||
|
pub use utils::Ent;
|
||||||
use {
|
use {
|
||||||
self::{
|
self::{
|
||||||
lexer::TokenKind,
|
lexer::TokenKind,
|
||||||
parser::{idfl, CommentOr, Expr, ExprRef, FileId, Pos},
|
parser::{idfl, CommentOr, Expr, ExprRef, Pos},
|
||||||
ty::ArrayLen,
|
ty::{ArrayLen, Builtin, Module},
|
||||||
|
utils::EntVec,
|
||||||
},
|
},
|
||||||
alloc::{string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
core::{cell::Cell, fmt::Display, ops::Range},
|
core::{cell::Cell, fmt::Display, ops::Range},
|
||||||
|
@ -251,17 +253,17 @@ impl Ident {
|
||||||
pos..pos + len
|
pos..pos + len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn builtin(builtin: u32) -> Ident {
|
fn builtin(builtin: Builtin) -> Ident {
|
||||||
debug_assert!(Self(builtin).is_null());
|
Self(builtin.index() as _)
|
||||||
Self(builtin)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod ty {
|
pub mod ty {
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
lexer::TokenKind,
|
lexer::TokenKind,
|
||||||
parser::{self, FileId, Pos},
|
parser::{self, Pos},
|
||||||
|
utils::Ent,
|
||||||
Ident, Size, Types,
|
Ident, Size, Types,
|
||||||
},
|
},
|
||||||
core::{num::NonZeroU32, ops::Range},
|
core::{num::NonZeroU32, ops::Range},
|
||||||
|
@ -269,16 +271,10 @@ mod ty {
|
||||||
|
|
||||||
pub type ArrayLen = u32;
|
pub type ArrayLen = u32;
|
||||||
|
|
||||||
pub type Builtin = u32;
|
impl Func {
|
||||||
pub type Struct = u32;
|
pub const ECA: Func = Func(u32::MAX);
|
||||||
pub type Opt = u32;
|
pub const MAIN: Func = Func(u32::MIN);
|
||||||
pub type Ptr = u32;
|
}
|
||||||
pub type Func = u32;
|
|
||||||
pub type Global = u32;
|
|
||||||
pub type Module = u32;
|
|
||||||
pub type Slice = u32;
|
|
||||||
|
|
||||||
pub const ECA: Func = Func::MAX;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, PartialOrd, Ord)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, PartialOrd, Ord)]
|
||||||
pub struct Tuple(pub u32);
|
pub struct Tuple(pub u32);
|
||||||
|
@ -305,6 +301,10 @@ mod ty {
|
||||||
self.0 as usize & Self::LEN_MASK
|
self.0 as usize & Self::LEN_MASK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self(0)
|
Self(0)
|
||||||
}
|
}
|
||||||
|
@ -350,28 +350,30 @@ mod ty {
|
||||||
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> {
|
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> {
|
||||||
match self.expand() {
|
match self.expand() {
|
||||||
Kind::Struct(s) => {
|
Kind::Struct(s) => {
|
||||||
let st = &ctx.structs[s as usize];
|
let st = &ctx.structs[s];
|
||||||
debug_assert_ne!(st.pos, Pos::MAX);
|
debug_assert_ne!(st.pos, Pos::MAX);
|
||||||
crate::SymKey::Struct(st.file, st.pos, st.captures)
|
crate::SymKey::Struct(st.file, st.pos, st.captures)
|
||||||
}
|
}
|
||||||
Kind::Ptr(p) => crate::SymKey::Pointer(&ctx.ptrs[p as usize]),
|
Kind::Ptr(p) => crate::SymKey::Pointer(&ctx.ptrs[p]),
|
||||||
Kind::Opt(p) => crate::SymKey::Optional(&ctx.opts[p as usize]),
|
Kind::Opt(p) => crate::SymKey::Optional(&ctx.opts[p]),
|
||||||
Kind::Func(f) => {
|
Kind::Func(f) => {
|
||||||
let fc = &ctx.funcs[f as usize];
|
let fc = &ctx.funcs[f];
|
||||||
if let Some(base) = fc.base {
|
if let Some(base) = fc.base {
|
||||||
|
// TODO: merge base and sig
|
||||||
crate::SymKey::FuncInst(base, fc.sig.unwrap().args)
|
crate::SymKey::FuncInst(base, fc.sig.unwrap().args)
|
||||||
} else {
|
} else {
|
||||||
crate::SymKey::Decl(fc.file, fc.name)
|
crate::SymKey::Decl(fc.file, fc.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Global(g) => {
|
Kind::Global(g) => {
|
||||||
let gb = &ctx.globals[g as usize];
|
let gb = &ctx.globals[g];
|
||||||
crate::SymKey::Decl(gb.file, gb.name)
|
crate::SymKey::Decl(gb.file, gb.name)
|
||||||
}
|
}
|
||||||
Kind::Slice(s) => crate::SymKey::Array(&ctx.slices[s as usize]),
|
Kind::Slice(s) => crate::SymKey::Array(&ctx.slices[s]),
|
||||||
Kind::Module(_) | Kind::Builtin(_) => {
|
Kind::Module(_) | Kind::Builtin(_) => {
|
||||||
crate::SymKey::Decl(FileId::MAX, Ident::INVALID)
|
crate::SymKey::Decl(Module::default(), Ident::INVALID)
|
||||||
}
|
}
|
||||||
|
Kind::Const(c) => crate::SymKey::Constant(&ctx.consts[c]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,7 +390,7 @@ mod ty {
|
||||||
pub fn bin_ret(self, op: TokenKind) -> Id {
|
pub fn bin_ret(self, op: TokenKind) -> Id {
|
||||||
use TokenKind as T;
|
use TokenKind as T;
|
||||||
match op {
|
match op {
|
||||||
T::Lt | T::Gt | T::Le | T::Ge | T::Ne | T::Eq => BOOL.into(),
|
T::Lt | T::Gt | T::Le | T::Ge | T::Ne | T::Eq => Id::BOOL,
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,7 +417,7 @@ mod ty {
|
||||||
|
|
||||||
pub fn strip_pointer(self) -> Self {
|
pub fn strip_pointer(self) -> Self {
|
||||||
match self.expand() {
|
match self.expand() {
|
||||||
Kind::Ptr(_) => Kind::Builtin(UINT).compress(),
|
Kind::Ptr(_) => Id::UINT,
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -432,8 +434,8 @@ mod ty {
|
||||||
let (oa, ob) = (Self(self.0.min(ob.0)), Self(self.0.max(ob.0)));
|
let (oa, ob) = (Self(self.0.min(ob.0)), Self(self.0.max(ob.0)));
|
||||||
let (a, b) = (oa.strip_pointer(), ob.strip_pointer());
|
let (a, b) = (oa.strip_pointer(), ob.strip_pointer());
|
||||||
Some(match () {
|
Some(match () {
|
||||||
_ if oa == Self::from(NEVER) => ob,
|
_ if oa == Id::NEVER => ob,
|
||||||
_ if ob == Self::from(NEVER) => oa,
|
_ if ob == Id::NEVER => oa,
|
||||||
_ if oa == ob => oa,
|
_ if oa == ob => oa,
|
||||||
_ if ob.is_optional() => ob,
|
_ if ob.is_optional() => ob,
|
||||||
_ if oa.is_pointer() && ob.is_pointer() => return None,
|
_ if oa.is_pointer() && ob.is_pointer() => return None,
|
||||||
|
@ -456,12 +458,12 @@ mod ty {
|
||||||
pub(crate) fn simple_size(&self) -> Option<Size> {
|
pub(crate) fn simple_size(&self) -> Option<Size> {
|
||||||
Some(match self.expand() {
|
Some(match self.expand() {
|
||||||
Kind::Ptr(_) => 8,
|
Kind::Ptr(_) => 8,
|
||||||
Kind::Builtin(VOID) => 0,
|
Kind::Builtin(Builtin(VOID)) => 0,
|
||||||
Kind::Builtin(NEVER) => 0,
|
Kind::Builtin(Builtin(NEVER)) => 0,
|
||||||
Kind::Builtin(INT | UINT | F64) => 8,
|
Kind::Builtin(Builtin(INT | UINT | F64)) => 8,
|
||||||
Kind::Builtin(I32 | U32 | TYPE | F32) => 4,
|
Kind::Builtin(Builtin(I32 | U32 | TYPE | F32)) => 4,
|
||||||
Kind::Builtin(I16 | U16) => 2,
|
Kind::Builtin(Builtin(I16 | U16)) => 2,
|
||||||
Kind::Builtin(I8 | U8 | BOOL) => 1,
|
Kind::Builtin(Builtin(I8 | U8 | BOOL)) => 1,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -479,7 +481,7 @@ mod ty {
|
||||||
pub(crate) fn loc(&self, tys: &Types) -> Loc {
|
pub(crate) fn loc(&self, tys: &Types) -> Loc {
|
||||||
match self.expand() {
|
match self.expand() {
|
||||||
Kind::Opt(o)
|
Kind::Opt(o)
|
||||||
if let ty = tys.ins.opts[o as usize].base
|
if let ty = tys.ins.opts[o].base
|
||||||
&& ty.loc(tys) == Loc::Reg
|
&& ty.loc(tys) == Loc::Reg
|
||||||
&& (ty.is_pointer() || tys.size_of(ty) < 8) =>
|
&& (ty.is_pointer() || tys.size_of(ty) < 8) =>
|
||||||
{
|
{
|
||||||
|
@ -488,7 +490,9 @@ mod ty {
|
||||||
Kind::Ptr(_) | Kind::Builtin(_) => Loc::Reg,
|
Kind::Ptr(_) | Kind::Builtin(_) => Loc::Reg,
|
||||||
Kind::Struct(_) if tys.size_of(*self) == 0 => Loc::Reg,
|
Kind::Struct(_) if tys.size_of(*self) == 0 => Loc::Reg,
|
||||||
Kind::Struct(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack,
|
Kind::Struct(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack,
|
||||||
Kind::Func(_) | Kind::Global(_) | Kind::Module(_) => unreachable!(),
|
Kind::Func(_) | Kind::Global(_) | Kind::Module(_) | Kind::Const(_) => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,7 +500,7 @@ mod ty {
|
||||||
match self.expand() {
|
match self.expand() {
|
||||||
Kind::Struct(s) => tys.struct_fields(s).iter().any(|f| f.ty.has_pointers(tys)),
|
Kind::Struct(s) => tys.struct_fields(s).iter().any(|f| f.ty.has_pointers(tys)),
|
||||||
Kind::Ptr(_) => true,
|
Kind::Ptr(_) => true,
|
||||||
Kind::Slice(s) => tys.ins.slices[s as usize].len == ArrayLen::MAX,
|
Kind::Slice(s) => tys.ins.slices[s].len == ArrayLen::MAX,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -514,12 +518,6 @@ mod ty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u32> for Id {
|
|
||||||
fn from(id: u32) -> Self {
|
|
||||||
Kind::Builtin(id).compress()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn array_to_lower_case<const N: usize>(array: [u8; N]) -> [u8; N] {
|
const fn array_to_lower_case<const N: usize>(array: [u8; N]) -> [u8; N] {
|
||||||
let mut result = [0; N];
|
let mut result = [0; N];
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
@ -533,7 +531,7 @@ mod ty {
|
||||||
|
|
||||||
macro_rules! builtin_type {
|
macro_rules! builtin_type {
|
||||||
($($name:ident;)*) => {
|
($($name:ident;)*) => {
|
||||||
$(pub const $name: Builtin = ${index(0)} + 1;)*
|
$(const $name: u32 = ${index(0)} + 1;)*
|
||||||
|
|
||||||
mod __lc_names {
|
mod __lc_names {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -547,20 +545,23 @@ mod ty {
|
||||||
};)*
|
};)*
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
impl Id {
|
impl Id {
|
||||||
$(pub const $name: Self = Kind::Builtin($name).compress();)*
|
$(pub const $name: Self = Kind::Builtin(Builtin($name)).compress();)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kind {
|
||||||
|
$(pub const $name: Self = Kind::Builtin(Builtin($name));)*
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_str(name: &str) -> Option<Builtin> {
|
pub fn from_str(name: &str) -> Option<Builtin> {
|
||||||
match name {
|
match name {
|
||||||
$(__lc_names::$name => Some($name),)*
|
$(__lc_names::$name => Some(Builtin($name)),)*
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_str(ty: Builtin) -> &'static str {
|
pub fn to_str(ty: Builtin) -> &'static str {
|
||||||
match ty {
|
match ty.0 {
|
||||||
$($name => __lc_names::$name,)*
|
$($name => __lc_names::$name,)*
|
||||||
v => unreachable!("invalid type: {}", v),
|
v => unreachable!("invalid type: {}", v),
|
||||||
}
|
}
|
||||||
|
@ -590,6 +591,10 @@ mod ty {
|
||||||
|
|
||||||
macro_rules! type_kind {
|
macro_rules! type_kind {
|
||||||
($(#[$meta:meta])* $vis:vis enum $name:ident {$( $variant:ident, )*}) => {
|
($(#[$meta:meta])* $vis:vis enum $name:ident {$( $variant:ident, )*}) => {
|
||||||
|
crate::utils::decl_ent! {
|
||||||
|
$(pub struct $variant(u32);)*
|
||||||
|
}
|
||||||
|
|
||||||
$(#[$meta])*
|
$(#[$meta])*
|
||||||
$vis enum $name {
|
$vis enum $name {
|
||||||
$($variant($variant),)*
|
$($variant($variant),)*
|
||||||
|
@ -603,24 +608,32 @@ mod ty {
|
||||||
$vis fn from_ty(ty: Id) -> Self {
|
$vis fn from_ty(ty: Id) -> Self {
|
||||||
let (flag, index) = (ty.repr() >> Self::FLAG_OFFSET, ty.repr() & Self::INDEX_MASK);
|
let (flag, index) = (ty.repr() >> Self::FLAG_OFFSET, ty.repr() & Self::INDEX_MASK);
|
||||||
match flag {
|
match flag {
|
||||||
$(${index(0)} => Self::$variant(index),)*
|
$(${index(0)} => Self::$variant($variant(index)),)*
|
||||||
i => unreachable!("{i}"),
|
i => unreachable!("{i}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$vis const fn compress(self) -> Id {
|
$vis const fn compress(self) -> Id {
|
||||||
let (index, flag) = match self {
|
let (index, flag) = match self {
|
||||||
$(Self::$variant(index) => (index, ${index(0)}),)*
|
$(Self::$variant(index) => (index.0, ${index(0)}),)*
|
||||||
};
|
};
|
||||||
Id(unsafe { NonZeroU32::new_unchecked((flag << Self::FLAG_OFFSET) | index) })
|
Id(unsafe { NonZeroU32::new_unchecked((flag << Self::FLAG_OFFSET) | index) })
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$vis const fn inner(self) -> u32 {
|
$(
|
||||||
match self {
|
impl From<$variant> for $name {
|
||||||
$(Self::$variant(index) => index,)*
|
fn from(value: $variant) -> Self {
|
||||||
|
Self::$variant(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
impl From<$variant> for Id {
|
||||||
|
fn from(value: $variant) -> Self {
|
||||||
|
$name::$variant(value).compress()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,12 +648,35 @@ mod ty {
|
||||||
Func,
|
Func,
|
||||||
Global,
|
Global,
|
||||||
Module,
|
Module,
|
||||||
|
Const,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
pub const MAIN: Self = Self(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Module {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(u32::MAX)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Ident> for Builtin {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: Ident) -> Result<Self, Self::Error> {
|
||||||
|
if value.is_null() {
|
||||||
|
Ok(Self(value.len()))
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Kind {
|
impl Default for Kind {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Builtin(UNDECLARED)
|
Id::UNDECLARED.expand()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,7 +702,7 @@ mod ty {
|
||||||
match TK::from_ty(self.ty) {
|
match TK::from_ty(self.ty) {
|
||||||
TK::Module(idx) => {
|
TK::Module(idx) => {
|
||||||
f.write_str("@use(\"")?;
|
f.write_str("@use(\"")?;
|
||||||
self.files[idx as usize].path.fmt(f)?;
|
self.files[idx.index()].path.fmt(f)?;
|
||||||
f.write_str(")[")?;
|
f.write_str(")[")?;
|
||||||
idx.fmt(f)?;
|
idx.fmt(f)?;
|
||||||
f.write_str("]")
|
f.write_str("]")
|
||||||
|
@ -674,14 +710,14 @@ mod ty {
|
||||||
TK::Builtin(ty) => f.write_str(to_str(ty)),
|
TK::Builtin(ty) => f.write_str(to_str(ty)),
|
||||||
TK::Opt(ty) => {
|
TK::Opt(ty) => {
|
||||||
f.write_str("?")?;
|
f.write_str("?")?;
|
||||||
self.rety(self.tys.ins.opts[ty as usize].base).fmt(f)
|
self.rety(self.tys.ins.opts[ty].base).fmt(f)
|
||||||
}
|
}
|
||||||
TK::Ptr(ty) => {
|
TK::Ptr(ty) => {
|
||||||
f.write_str("^")?;
|
f.write_str("^")?;
|
||||||
self.rety(self.tys.ins.ptrs[ty as usize].base).fmt(f)
|
self.rety(self.tys.ins.ptrs[ty].base).fmt(f)
|
||||||
}
|
}
|
||||||
TK::Struct(idx) => {
|
TK::Struct(idx) => {
|
||||||
let record = &self.tys.ins.structs[idx as usize];
|
let record = &self.tys.ins.structs[idx];
|
||||||
if record.name.is_null() {
|
if record.name.is_null() {
|
||||||
f.write_str("[")?;
|
f.write_str("[")?;
|
||||||
idx.fmt(f)?;
|
idx.fmt(f)?;
|
||||||
|
@ -698,7 +734,7 @@ mod ty {
|
||||||
}
|
}
|
||||||
f.write_str("}")
|
f.write_str("}")
|
||||||
} else {
|
} else {
|
||||||
let file = &self.files[record.file as usize];
|
let file = &self.files[record.file.index()];
|
||||||
f.write_str(file.ident_str(record.name))
|
f.write_str(file.ident_str(record.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -707,11 +743,12 @@ mod ty {
|
||||||
idx.fmt(f)
|
idx.fmt(f)
|
||||||
}
|
}
|
||||||
TK::Global(idx) => {
|
TK::Global(idx) => {
|
||||||
f.write_str("global")?;
|
let global = &self.tys.ins.globals[idx];
|
||||||
idx.fmt(f)
|
let file = &self.files[global.file.index()];
|
||||||
|
f.write_str(file.ident_str(global.name))
|
||||||
}
|
}
|
||||||
TK::Slice(idx) => {
|
TK::Slice(idx) => {
|
||||||
let array = self.tys.ins.slices[idx as usize];
|
let array = self.tys.ins.slices[idx];
|
||||||
f.write_str("[")?;
|
f.write_str("[")?;
|
||||||
self.rety(array.elem).fmt(f)?;
|
self.rety(array.elem).fmt(f)?;
|
||||||
if array.len != ArrayLen::MAX {
|
if array.len != ArrayLen::MAX {
|
||||||
|
@ -720,6 +757,11 @@ mod ty {
|
||||||
}
|
}
|
||||||
f.write_str("]")
|
f.write_str("]")
|
||||||
}
|
}
|
||||||
|
TK::Const(idx) => {
|
||||||
|
let cnst = &self.tys.ins.consts[idx];
|
||||||
|
let file = &self.files[cnst.file.index()];
|
||||||
|
f.write_str(file.ident_str(cnst.name))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -732,10 +774,11 @@ type Size = u32;
|
||||||
pub enum SymKey<'a> {
|
pub enum SymKey<'a> {
|
||||||
Pointer(&'a Ptr),
|
Pointer(&'a Ptr),
|
||||||
Optional(&'a Opt),
|
Optional(&'a Opt),
|
||||||
Struct(FileId, Pos, ty::Tuple),
|
Struct(Module, Pos, ty::Tuple),
|
||||||
FuncInst(ty::Func, ty::Tuple),
|
FuncInst(ty::Func, ty::Tuple),
|
||||||
Decl(FileId, Ident),
|
Decl(Module, Ident),
|
||||||
Array(&'a Array),
|
Array(&'a Array),
|
||||||
|
Constant(&'a Const),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -744,8 +787,9 @@ pub struct Sig {
|
||||||
ret: ty::Id,
|
ret: ty::Id,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
struct Func {
|
struct Func {
|
||||||
file: FileId,
|
file: Module,
|
||||||
name: Ident,
|
name: Ident,
|
||||||
base: Option<ty::Func>,
|
base: Option<ty::Func>,
|
||||||
expr: ExprRef,
|
expr: ExprRef,
|
||||||
|
@ -753,19 +797,6 @@ struct Func {
|
||||||
comp_state: [CompState; 2],
|
comp_state: [CompState; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Func {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
file: u32::MAX,
|
|
||||||
name: Default::default(),
|
|
||||||
base: None,
|
|
||||||
expr: Default::default(),
|
|
||||||
sig: None,
|
|
||||||
comp_state: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, PartialEq, Eq)]
|
#[derive(Default, PartialEq, Eq)]
|
||||||
enum CompState {
|
enum CompState {
|
||||||
#[default]
|
#[default]
|
||||||
|
@ -780,23 +811,19 @@ struct TypedReloc {
|
||||||
reloc: Reloc,
|
reloc: Reloc,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
struct Global {
|
struct Global {
|
||||||
file: FileId,
|
file: Module,
|
||||||
name: Ident,
|
name: Ident,
|
||||||
ty: ty::Id,
|
ty: ty::Id,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Global {
|
#[derive(PartialEq, Eq, Hash)]
|
||||||
fn default() -> Self {
|
pub struct Const {
|
||||||
Self {
|
ast: ExprRef,
|
||||||
ty: Default::default(),
|
name: Ident,
|
||||||
data: Default::default(),
|
file: Module,
|
||||||
file: u32::MAX,
|
|
||||||
name: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make into bit struct (width: u2, sub_offset: u3, offset: u27)
|
// TODO: make into bit struct (width: u2, sub_offset: u3, offset: u27)
|
||||||
|
@ -835,7 +862,7 @@ struct Field {
|
||||||
struct Struct {
|
struct Struct {
|
||||||
name: Ident,
|
name: Ident,
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
file: FileId,
|
file: Module,
|
||||||
size: Cell<Size>,
|
size: Cell<Size>,
|
||||||
align: Cell<u8>,
|
align: Cell<u8>,
|
||||||
captures: ty::Tuple,
|
captures: ty::Tuple,
|
||||||
|
@ -934,18 +961,19 @@ struct TypesTmp {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct TypeIns {
|
pub struct TypeIns {
|
||||||
funcs: Vec<Func>,
|
|
||||||
args: Vec<ty::Id>,
|
args: Vec<ty::Id>,
|
||||||
globals: Vec<Global>,
|
|
||||||
structs: Vec<Struct>,
|
|
||||||
fields: Vec<Field>,
|
fields: Vec<Field>,
|
||||||
ptrs: Vec<Ptr>,
|
funcs: EntVec<ty::Func, Func>,
|
||||||
opts: Vec<Opt>,
|
globals: EntVec<ty::Global, Global>,
|
||||||
slices: Vec<Array>,
|
consts: EntVec<ty::Const, Const>,
|
||||||
|
structs: EntVec<ty::Struct, Struct>,
|
||||||
|
ptrs: EntVec<ty::Ptr, Ptr>,
|
||||||
|
opts: EntVec<ty::Opt, Opt>,
|
||||||
|
slices: EntVec<ty::Slice, Array>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FTask {
|
struct FTask {
|
||||||
file: FileId,
|
file: Module,
|
||||||
id: ty::Func,
|
id: ty::Func,
|
||||||
ct: bool,
|
ct: bool,
|
||||||
}
|
}
|
||||||
|
@ -953,11 +981,11 @@ struct FTask {
|
||||||
struct StringRef(ty::Global);
|
struct StringRef(ty::Global);
|
||||||
|
|
||||||
impl ctx_map::CtxEntry for StringRef {
|
impl ctx_map::CtxEntry for StringRef {
|
||||||
type Ctx = [Global];
|
type Ctx = EntVec<ty::Global, Global>;
|
||||||
type Key<'a> = &'a [u8];
|
type Key<'a> = &'a [u8];
|
||||||
|
|
||||||
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> {
|
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> {
|
||||||
&ctx[self.0 as usize].data
|
&ctx[self.0].data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,16 +1003,16 @@ trait TypeParser {
|
||||||
fn tys(&mut self) -> &mut Types;
|
fn tys(&mut self) -> &mut Types;
|
||||||
fn on_reuse(&mut self, existing: ty::Id);
|
fn on_reuse(&mut self, existing: ty::Id);
|
||||||
fn find_local_ty(&mut self, name: Ident) -> Option<ty::Id>;
|
fn find_local_ty(&mut self, name: Ident) -> Option<ty::Id>;
|
||||||
fn eval_const(&mut self, file: FileId, expr: &Expr, ty: ty::Id) -> u64;
|
fn eval_const(&mut self, file: Module, expr: &Expr, ty: ty::Id) -> u64;
|
||||||
fn eval_global(&mut self, file: FileId, name: Ident, expr: &Expr) -> ty::Id;
|
fn eval_global(&mut self, file: Module, name: Ident, expr: &Expr) -> ty::Id;
|
||||||
fn infer_type(&mut self, expr: &Expr) -> ty::Id;
|
fn infer_type(&mut self, expr: &Expr) -> ty::Id;
|
||||||
fn report(&self, file: FileId, pos: Pos, msg: impl Display) -> ty::Id;
|
fn report(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id;
|
||||||
|
|
||||||
fn find_type(
|
fn find_type(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
from_file: FileId,
|
from_file: Module,
|
||||||
file: FileId,
|
file: Module,
|
||||||
id: Result<Ident, &str>,
|
id: Result<Ident, &str>,
|
||||||
files: &[parser::Ast],
|
files: &[parser::Ast],
|
||||||
) -> ty::Id {
|
) -> ty::Id {
|
||||||
|
@ -999,9 +1027,9 @@ trait TypeParser {
|
||||||
self.on_reuse(ty);
|
self.on_reuse(ty);
|
||||||
ty
|
ty
|
||||||
} else {
|
} else {
|
||||||
let f = &files[file as usize];
|
let f = &files[file.index()];
|
||||||
|
|
||||||
let Some((Expr::BinOp { left, right, .. }, name)) = f.find_decl(id) else {
|
let Some((expr @ Expr::BinOp { left, right, .. }, name)) = f.find_decl(id) else {
|
||||||
return match id {
|
return match id {
|
||||||
Ok(_) => ty::Id::NEVER,
|
Ok(_) => ty::Id::NEVER,
|
||||||
Err("main") => self.report(
|
Err("main") => self.report(
|
||||||
|
@ -1025,20 +1053,19 @@ trait TypeParser {
|
||||||
ty
|
ty
|
||||||
} else {
|
} else {
|
||||||
let ty = left
|
let ty = left
|
||||||
.find_pattern_path(name, right, |right| {
|
.find_pattern_path(name, right, |right, is_ct| {
|
||||||
self.parse_ty(file, right, Some(name), files)
|
if is_ct {
|
||||||
|
self.tys()
|
||||||
|
.ins
|
||||||
|
.consts
|
||||||
|
.push(Const { ast: ExprRef::new(expr), name, file })
|
||||||
|
.into()
|
||||||
|
} else {
|
||||||
|
self.parse_ty(file, right, Some(name), files)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|_| unreachable!());
|
.unwrap_or_else(|_| unreachable!());
|
||||||
let tys = self.tys();
|
let tys = self.tys();
|
||||||
let nm = match ty.expand() {
|
|
||||||
ty::Kind::Struct(s) => &mut tys.ins.structs[s as usize].name,
|
|
||||||
ty::Kind::Func(s) => &mut tys.ins.funcs[s as usize].name,
|
|
||||||
ty::Kind::Global(s) => &mut tys.ins.globals[s as usize].name,
|
|
||||||
_ => &mut Ident::default(),
|
|
||||||
};
|
|
||||||
if nm.is_null() {
|
|
||||||
*nm = name;
|
|
||||||
}
|
|
||||||
tys.syms.insert(SymKey::Decl(file, name), ty, &tys.ins);
|
tys.syms.insert(SymKey::Decl(file, name), ty, &tys.ins);
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
@ -1046,7 +1073,7 @@ trait TypeParser {
|
||||||
|
|
||||||
let tys = self.tys();
|
let tys = self.tys();
|
||||||
if let ty::Kind::Global(g) = ty.expand() {
|
if let ty::Kind::Global(g) = ty.expand() {
|
||||||
let g = &tys.ins.globals[g as usize];
|
let g = &tys.ins.globals[g];
|
||||||
if g.ty == ty::Id::TYPE {
|
if g.ty == ty::Id::TYPE {
|
||||||
return ty::Id::from(
|
return ty::Id::from(
|
||||||
u32::from_ne_bytes(g.data.as_slice().try_into().unwrap()) as u64
|
u32::from_ne_bytes(g.data.as_slice().try_into().unwrap()) as u64
|
||||||
|
@ -1059,7 +1086,7 @@ trait TypeParser {
|
||||||
/// returns none if comptime eval is required
|
/// returns none if comptime eval is required
|
||||||
fn parse_ty(
|
fn parse_ty(
|
||||||
&mut self,
|
&mut self,
|
||||||
file: FileId,
|
file: Module,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
name: Option<Ident>,
|
name: Option<Ident>,
|
||||||
files: &[parser::Ast],
|
files: &[parser::Ast],
|
||||||
|
@ -1074,7 +1101,7 @@ trait TypeParser {
|
||||||
let base = self.parse_ty(file, val, None, files);
|
let base = self.parse_ty(file, val, None, files);
|
||||||
self.tys().make_opt(base)
|
self.tys().make_opt(base)
|
||||||
}
|
}
|
||||||
Expr::Ident { id, .. } if id.is_null() => id.len().into(),
|
Expr::Ident { id, .. } if let Ok(bt) = ty::Builtin::try_from(id) => bt.into(),
|
||||||
Expr::Ident { id, pos, .. } => self.find_type(pos, file, file, Ok(id), files),
|
Expr::Ident { id, pos, .. } => self.find_type(pos, file, file, Ok(id), files),
|
||||||
Expr::Field { target, pos, name }
|
Expr::Field { target, pos, name }
|
||||||
if let ty::Kind::Module(inside) =
|
if let ty::Kind::Module(inside) =
|
||||||
|
@ -1119,18 +1146,21 @@ trait TypeParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
let tys = self.tys();
|
let tys = self.tys();
|
||||||
tys.ins.structs.push(Struct {
|
let ty = tys
|
||||||
file,
|
.ins
|
||||||
pos,
|
.structs
|
||||||
name: name.unwrap_or_default(),
|
.push(Struct {
|
||||||
field_start: tys.ins.fields.len() as _,
|
file,
|
||||||
explicit_alignment: packed.then_some(1),
|
pos,
|
||||||
..Default::default()
|
name: name.unwrap_or_default(),
|
||||||
});
|
field_start: tys.ins.fields.len() as _,
|
||||||
|
explicit_alignment: packed.then_some(1),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.into();
|
||||||
|
|
||||||
tys.ins.fields.extend(tys.tmp.fields.drain(prev_tmp..));
|
tys.ins.fields.extend(tys.tmp.fields.drain(prev_tmp..));
|
||||||
|
|
||||||
let ty = ty::Kind::Struct(tys.ins.structs.len() as u32 - 1).compress();
|
|
||||||
tys.syms.insert(sym, ty, &tys.ins);
|
tys.syms.insert(sym, ty, &tys.ins);
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
@ -1141,7 +1171,7 @@ trait TypeParser {
|
||||||
sig: 'b: {
|
sig: 'b: {
|
||||||
let arg_base = self.tys().tmp.args.len();
|
let arg_base = self.tys().tmp.args.len();
|
||||||
for arg in args {
|
for arg in args {
|
||||||
let sym = parser::find_symbol(&files[file as usize].symbols, arg.id);
|
let sym = parser::find_symbol(&files[file.index()].symbols, arg.id);
|
||||||
if sym.flags & idfl::COMPTIME != 0 {
|
if sym.flags & idfl::COMPTIME != 0 {
|
||||||
self.tys().tmp.args.truncate(arg_base);
|
self.tys().tmp.args.truncate(arg_base);
|
||||||
break 'b None;
|
break 'b None;
|
||||||
|
@ -1161,10 +1191,7 @@ trait TypeParser {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let id = self.tys().ins.funcs.len() as _;
|
self.tys().ins.funcs.push(func).into()
|
||||||
self.tys().ins.funcs.push(func);
|
|
||||||
|
|
||||||
ty::Kind::Func(id).compress()
|
|
||||||
}
|
}
|
||||||
_ if let Some(name) = name => self.eval_global(file, name, expr),
|
_ if let Some(name) = name => self.eval_global(file, name, expr),
|
||||||
_ => ty::Id::from(self.eval_const(file, expr, ty::Id::TYPE)),
|
_ => ty::Id::from(self.eval_const(file, expr, ty::Id::TYPE)),
|
||||||
|
@ -1174,12 +1201,9 @@ trait TypeParser {
|
||||||
|
|
||||||
impl Types {
|
impl Types {
|
||||||
fn struct_field_range(&self, strct: ty::Struct) -> Range<usize> {
|
fn struct_field_range(&self, strct: ty::Struct) -> Range<usize> {
|
||||||
let start = self.ins.structs[strct as usize].field_start as usize;
|
let start = self.ins.structs[strct].field_start as usize;
|
||||||
let end = self
|
let end =
|
||||||
.ins
|
self.ins.structs.next(strct).map_or(self.ins.fields.len(), |s| s.field_start as usize);
|
||||||
.structs
|
|
||||||
.get(strct as usize + 1)
|
|
||||||
.map_or(self.ins.fields.len(), |s| s.field_start as usize);
|
|
||||||
start..end
|
start..end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1210,49 +1234,30 @@ impl Types {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_opt(&mut self, base: ty::Id) -> ty::Id {
|
fn make_opt(&mut self, base: ty::Id) -> ty::Id {
|
||||||
self.make_generic_ty(
|
self.make_generic_ty(Opt { base }, |ins| &mut ins.opts, |e| SymKey::Optional(e))
|
||||||
Opt { base },
|
|
||||||
|ins| &mut ins.opts,
|
|
||||||
|e| SymKey::Optional(e),
|
|
||||||
ty::Kind::Opt,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_ptr(&mut self, base: ty::Id) -> ty::Id {
|
fn make_ptr(&mut self, base: ty::Id) -> ty::Id {
|
||||||
self.make_generic_ty(
|
self.make_generic_ty(Ptr { base }, |ins| &mut ins.ptrs, |e| SymKey::Pointer(e))
|
||||||
Ptr { base },
|
|
||||||
|ins| &mut ins.ptrs,
|
|
||||||
|e| SymKey::Pointer(e),
|
|
||||||
ty::Kind::Ptr,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_array(&mut self, elem: ty::Id, len: ArrayLen) -> ty::Id {
|
fn make_array(&mut self, elem: ty::Id, len: ArrayLen) -> ty::Id {
|
||||||
self.make_generic_ty(
|
self.make_generic_ty(Array { elem, len }, |ins| &mut ins.slices, |e| SymKey::Array(e))
|
||||||
Array { elem, len },
|
|
||||||
|ins| &mut ins.slices,
|
|
||||||
|e| SymKey::Array(e),
|
|
||||||
ty::Kind::Slice,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_generic_ty<T: Copy>(
|
fn make_generic_ty<K: Ent + Into<ty::Id>, T: Copy>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ty: T,
|
ty: T,
|
||||||
get_col: fn(&mut TypeIns) -> &mut Vec<T>,
|
get_col: fn(&mut TypeIns) -> &mut EntVec<K, T>,
|
||||||
key: fn(&T) -> SymKey,
|
key: fn(&T) -> SymKey,
|
||||||
kind: fn(u32) -> ty::Kind,
|
|
||||||
) -> ty::Id {
|
) -> ty::Id {
|
||||||
*self.syms.get_or_insert(key(&{ ty }), &mut self.ins, |ins| {
|
*self.syms.get_or_insert(key(&{ ty }), &mut self.ins, |ins| get_col(ins).push(ty).into())
|
||||||
get_col(ins).push(ty);
|
|
||||||
kind(get_col(ins).len() as u32 - 1).compress()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_of(&self, ty: ty::Id) -> Size {
|
fn size_of(&self, ty: ty::Id) -> Size {
|
||||||
match ty.expand() {
|
match ty.expand() {
|
||||||
ty::Kind::Slice(arr) => {
|
ty::Kind::Slice(arr) => {
|
||||||
let arr = &self.ins.slices[arr as usize];
|
let arr = &self.ins.slices[arr];
|
||||||
match arr.len {
|
match arr.len {
|
||||||
0 => 0,
|
0 => 0,
|
||||||
ArrayLen::MAX => 16,
|
ArrayLen::MAX => 16,
|
||||||
|
@ -1260,17 +1265,17 @@ impl Types {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Kind::Struct(stru) => {
|
ty::Kind::Struct(stru) => {
|
||||||
if self.ins.structs[stru as usize].size.get() != 0 {
|
if self.ins.structs[stru].size.get() != 0 {
|
||||||
return self.ins.structs[stru as usize].size.get();
|
return self.ins.structs[stru].size.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut oiter = OffsetIter::new(stru, self);
|
let mut oiter = OffsetIter::new(stru, self);
|
||||||
while oiter.next(self).is_some() {}
|
while oiter.next(self).is_some() {}
|
||||||
self.ins.structs[stru as usize].size.set(oiter.offset);
|
self.ins.structs[stru].size.set(oiter.offset);
|
||||||
oiter.offset
|
oiter.offset
|
||||||
}
|
}
|
||||||
ty::Kind::Opt(opt) => {
|
ty::Kind::Opt(opt) => {
|
||||||
let base = self.ins.opts[opt as usize].base;
|
let base = self.ins.opts[opt].base;
|
||||||
if self.nieche_of(base).is_some() {
|
if self.nieche_of(base).is_some() {
|
||||||
self.size_of(base)
|
self.size_of(base)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1285,10 +1290,10 @@ impl Types {
|
||||||
fn align_of(&self, ty: ty::Id) -> Size {
|
fn align_of(&self, ty: ty::Id) -> Size {
|
||||||
match ty.expand() {
|
match ty.expand() {
|
||||||
ty::Kind::Struct(stru) => {
|
ty::Kind::Struct(stru) => {
|
||||||
if self.ins.structs[stru as usize].align.get() != 0 {
|
if self.ins.structs[stru].align.get() != 0 {
|
||||||
return self.ins.structs[stru as usize].align.get() as _;
|
return self.ins.structs[stru].align.get() as _;
|
||||||
}
|
}
|
||||||
let align = self.ins.structs[stru as usize].explicit_alignment.map_or_else(
|
let align = self.ins.structs[stru].explicit_alignment.map_or_else(
|
||||||
|| {
|
|| {
|
||||||
self.struct_fields(stru)
|
self.struct_fields(stru)
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1298,11 +1303,11 @@ impl Types {
|
||||||
},
|
},
|
||||||
|a| a as _,
|
|a| a as _,
|
||||||
);
|
);
|
||||||
self.ins.structs[stru as usize].align.set(align.try_into().unwrap());
|
self.ins.structs[stru].align.set(align.try_into().unwrap());
|
||||||
align
|
align
|
||||||
}
|
}
|
||||||
ty::Kind::Slice(arr) => {
|
ty::Kind::Slice(arr) => {
|
||||||
let arr = &self.ins.slices[arr as usize];
|
let arr = &self.ins.slices[arr];
|
||||||
match arr.len {
|
match arr.len {
|
||||||
ArrayLen::MAX => 8,
|
ArrayLen::MAX => 8,
|
||||||
_ => self.align_of(arr.elem),
|
_ => self.align_of(arr.elem),
|
||||||
|
@ -1314,14 +1319,14 @@ impl Types {
|
||||||
|
|
||||||
fn base_of(&self, ty: ty::Id) -> Option<ty::Id> {
|
fn base_of(&self, ty: ty::Id) -> Option<ty::Id> {
|
||||||
match ty.expand() {
|
match ty.expand() {
|
||||||
ty::Kind::Ptr(p) => Some(self.ins.ptrs[p as usize].base),
|
ty::Kind::Ptr(p) => Some(self.ins.ptrs[p].base),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner_of(&self, ty: ty::Id) -> Option<ty::Id> {
|
fn inner_of(&self, ty: ty::Id) -> Option<ty::Id> {
|
||||||
match ty.expand() {
|
match ty.expand() {
|
||||||
ty::Kind::Opt(o) => Some(self.ins.opts[o as usize].base),
|
ty::Kind::Opt(o) => Some(self.ins.opts[o].base),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1401,7 +1406,7 @@ impl OffsetIter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next<'a>(&mut self, tys: &'a Types) -> Option<(&'a Field, Offset)> {
|
fn next<'a>(&mut self, tys: &'a Types) -> Option<(&'a Field, Offset)> {
|
||||||
let stru = &tys.ins.structs[self.strct as usize];
|
let stru = &tys.ins.structs[self.strct];
|
||||||
let field = &tys.ins.fields[self.fields.next()?];
|
let field = &tys.ins.fields[self.fields.next()?];
|
||||||
|
|
||||||
let align = stru.explicit_alignment.map_or_else(|| tys.align_of(field.ty), |a| a as u32);
|
let align = stru.explicit_alignment.map_or_else(|| tys.align_of(field.ty), |a| a as u32);
|
||||||
|
@ -1579,12 +1584,10 @@ fn test_parse_files(
|
||||||
FileKind::Module => module_map
|
FileKind::Module => module_map
|
||||||
.iter()
|
.iter()
|
||||||
.position(|&(name, _)| name == path)
|
.position(|&(name, _)| name == path)
|
||||||
.map(|i| i as parser::FileId)
|
|
||||||
.ok_or("Module Not Found".to_string()),
|
.ok_or("Module Not Found".to_string()),
|
||||||
FileKind::Embed => embed_map
|
FileKind::Embed => embed_map
|
||||||
.iter()
|
.iter()
|
||||||
.position(|&(name, _)| name == path)
|
.position(|&(name, _)| name == path)
|
||||||
.map(|i| i as parser::FileId)
|
|
||||||
.ok_or("Embed Not Found".to_string()),
|
.ok_or("Embed Not Found".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
fmt::Formatter,
|
fmt::Formatter,
|
||||||
lexer::{self, Lexer, Token, TokenKind},
|
lexer::{self, Lexer, Token, TokenKind},
|
||||||
|
ty::{Global, Module},
|
||||||
|
utils::Ent as _,
|
||||||
Ident,
|
Ident,
|
||||||
},
|
},
|
||||||
alloc::{boxed::Box, string::String, vec::Vec},
|
alloc::{boxed::Box, string::String, vec::Vec},
|
||||||
|
@ -19,10 +21,9 @@ use {
|
||||||
|
|
||||||
pub type Pos = u32;
|
pub type Pos = u32;
|
||||||
pub type IdentFlags = u32;
|
pub type IdentFlags = u32;
|
||||||
pub type FileId = u32;
|
|
||||||
pub type IdentIndex = u16;
|
pub type IdentIndex = u16;
|
||||||
pub type LoaderError = String;
|
pub type LoaderError = String;
|
||||||
pub type Loader<'a> = &'a mut (dyn FnMut(&str, &str, FileKind) -> Result<FileId, LoaderError> + 'a);
|
pub type Loader<'a> = &'a mut (dyn FnMut(&str, &str, FileKind) -> Result<usize, LoaderError> + 'a);
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub enum FileKind {
|
pub enum FileKind {
|
||||||
|
@ -63,7 +64,7 @@ pub mod idfl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn no_loader(_: &str, _: &str, _: FileKind) -> Result<FileId, LoaderError> {
|
pub fn no_loader(_: &str, _: &str, _: FileKind) -> Result<usize, LoaderError> {
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,7 +308,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
pos,
|
pos,
|
||||||
path,
|
path,
|
||||||
id: match (self.loader)(path, self.path, FileKind::Module) {
|
id: match (self.loader)(path, self.path, FileKind::Module) {
|
||||||
Ok(id) => id,
|
Ok(id) => Module::new(id),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.report(str.start, format_args!("error loading dependency: {e:#}"))?
|
self.report(str.start, format_args!("error loading dependency: {e:#}"))?
|
||||||
}
|
}
|
||||||
|
@ -325,7 +326,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
pos,
|
pos,
|
||||||
path,
|
path,
|
||||||
id: match (self.loader)(path, self.path, FileKind::Embed) {
|
id: match (self.loader)(path, self.path, FileKind::Embed) {
|
||||||
Ok(id) => id,
|
Ok(id) => Global::new(id),
|
||||||
Err(e) => self.report(
|
Err(e) => self.report(
|
||||||
str.start,
|
str.start,
|
||||||
format_args!("error loading embedded file: {e:#}"),
|
format_args!("error loading embedded file: {e:#}"),
|
||||||
|
@ -929,13 +930,13 @@ generate_expr! {
|
||||||
/// `'@use' '(' String ')'`
|
/// `'@use' '(' String ')'`
|
||||||
Mod {
|
Mod {
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
id: FileId,
|
id: Module,
|
||||||
path: &'a str,
|
path: &'a str,
|
||||||
},
|
},
|
||||||
/// `'@use' '(' String ')'`
|
/// `'@use' '(' String ')'`
|
||||||
Embed {
|
Embed {
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
id: FileId,
|
id: Global,
|
||||||
path: &'a str,
|
path: &'a str,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -960,14 +961,14 @@ impl Expr<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_pattern_path<T, F: FnOnce(&Expr) -> T>(
|
pub fn find_pattern_path<T, F: FnOnce(&Expr, bool) -> T>(
|
||||||
&self,
|
&self,
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
target: &Expr,
|
target: &Expr,
|
||||||
mut with_final: F,
|
mut with_final: F,
|
||||||
) -> Result<T, F> {
|
) -> Result<T, F> {
|
||||||
match *self {
|
match *self {
|
||||||
Self::Ident { id, .. } if id == ident => Ok(with_final(target)),
|
Self::Ident { id, is_ct, .. } if id == ident => Ok(with_final(target, is_ct)),
|
||||||
Self::Ctor { fields, .. } => {
|
Self::Ctor { fields, .. } => {
|
||||||
for &CtorField { name, value, pos } in fields {
|
for &CtorField { name, value, pos } in fields {
|
||||||
match value.find_pattern_path(
|
match value.find_pattern_path(
|
||||||
|
@ -1234,7 +1235,7 @@ impl Default for Ast {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
pub struct ExprRef(NonNull<Expr<'static>>);
|
pub struct ExprRef(NonNull<Expr<'static>>);
|
||||||
|
|
||||||
|
|
137
lang/src/son.rs
137
lang/src/son.rs
|
@ -10,20 +10,20 @@ use {
|
||||||
parser::{
|
parser::{
|
||||||
self,
|
self,
|
||||||
idfl::{self},
|
idfl::{self},
|
||||||
CtorField, Expr, FileId, Pos,
|
CtorField, Expr, Pos,
|
||||||
},
|
},
|
||||||
ty::{self, Arg, ArrayLen, Loc, Tuple},
|
ty::{self, Arg, ArrayLen, Loc, Module, Tuple},
|
||||||
utils::{BitSet, Vc},
|
utils::{BitSet, Ent, Vc},
|
||||||
CompState, FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Sig, StringRef,
|
CompState, FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Sig, StringRef,
|
||||||
SymKey, TypeParser, Types,
|
SymKey, TypeParser, Types,
|
||||||
},
|
},
|
||||||
alloc::{rc::Rc, string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
core::{
|
core::{
|
||||||
assert_matches::debug_assert_matches,
|
assert_matches::debug_assert_matches,
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
fmt::{self, Debug, Display, Write},
|
fmt::{self, Debug, Display, Write},
|
||||||
format_args as fa, mem,
|
format_args as fa, mem,
|
||||||
ops::{self, Deref},
|
ops::{self},
|
||||||
},
|
},
|
||||||
hashbrown::hash_map,
|
hashbrown::hash_map,
|
||||||
hbbytecode::DisasmError,
|
hbbytecode::DisasmError,
|
||||||
|
@ -2016,7 +2016,7 @@ impl Scope {
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct ItemCtx {
|
pub struct ItemCtx {
|
||||||
file: FileId,
|
file: Module,
|
||||||
pos: Vec<Pos>,
|
pos: Vec<Pos>,
|
||||||
ret: Option<ty::Id>,
|
ret: Option<ty::Id>,
|
||||||
task_base: usize,
|
task_base: usize,
|
||||||
|
@ -2031,7 +2031,7 @@ pub struct ItemCtx {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemCtx {
|
impl ItemCtx {
|
||||||
fn init(&mut self, file: FileId, ret: Option<ty::Id>, task_base: usize) {
|
fn init(&mut self, file: Module, ret: Option<ty::Id>, task_base: usize) {
|
||||||
debug_assert_eq!(self.loops.len(), 0);
|
debug_assert_eq!(self.loops.len(), 0);
|
||||||
debug_assert_eq!(self.scope.vars.len(), 0);
|
debug_assert_eq!(self.scope.vars.len(), 0);
|
||||||
debug_assert_eq!(self.scope.aclasses.len(), 0);
|
debug_assert_eq!(self.scope.aclasses.len(), 0);
|
||||||
|
@ -2106,7 +2106,7 @@ pub struct Pool {
|
||||||
impl Pool {
|
impl Pool {
|
||||||
fn push_ci(
|
fn push_ci(
|
||||||
&mut self,
|
&mut self,
|
||||||
file: FileId,
|
file: Module,
|
||||||
ret: Option<ty::Id>,
|
ret: Option<ty::Id>,
|
||||||
task_base: usize,
|
task_base: usize,
|
||||||
target: &mut ItemCtx,
|
target: &mut ItemCtx,
|
||||||
|
@ -2173,8 +2173,8 @@ impl Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ty(self, ty: impl Into<ty::Id>) -> Self {
|
fn ty(self, ty: ty::Id) -> Self {
|
||||||
Self { ty: ty.into(), ..self }
|
Self { ty, ..self }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2239,24 +2239,24 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(&mut self, entry: FileId) {
|
pub fn generate(&mut self, entry: Module) {
|
||||||
self.find_type(0, entry, entry, Err("main"), self.files);
|
self.find_type(0, entry, entry, Err("main"), self.files);
|
||||||
if self.tys.ins.funcs.is_empty() {
|
if self.tys.ins.funcs.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.make_func_reachable(0);
|
self.make_func_reachable(ty::Func::MAIN);
|
||||||
self.complete_call_graph();
|
self.complete_call_graph();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assemble_comptime(&mut self) -> Comptime {
|
pub fn assemble_comptime(&mut self) -> Comptime {
|
||||||
self.ct.code.clear();
|
self.ct.code.clear();
|
||||||
self.ct_backend.assemble_bin(0, self.tys, &mut self.ct.code);
|
self.ct_backend.assemble_bin(ty::Func::MAIN, self.tys, &mut self.ct.code);
|
||||||
self.ct.reset();
|
self.ct.reset();
|
||||||
core::mem::take(self.ct)
|
core::mem::take(self.ct)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assemble(&mut self, buf: &mut Vec<u8>) {
|
pub fn assemble(&mut self, buf: &mut Vec<u8>) {
|
||||||
self.backend.assemble_bin(0, self.tys, buf);
|
self.backend.assemble_bin(ty::Func::MAIN, self.tys, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disasm(&mut self, output: &mut String, bin: &[u8]) -> Result<(), DisasmError> {
|
pub fn disasm(&mut self, output: &mut String, bin: &[u8]) -> Result<(), DisasmError> {
|
||||||
|
@ -2264,17 +2264,17 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_embeds(&mut self, embeds: Vec<Vec<u8>>) {
|
pub fn push_embeds(&mut self, embeds: Vec<Vec<u8>>) {
|
||||||
self.tys.ins.globals = embeds
|
for data in embeds {
|
||||||
.into_iter()
|
let g = Global {
|
||||||
.map(|data| Global {
|
|
||||||
ty: self.tys.make_array(ty::Id::U8, data.len() as _),
|
ty: self.tys.make_array(ty::Id::U8, data.len() as _),
|
||||||
data,
|
data,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
};
|
||||||
.collect();
|
self.tys.ins.globals.push(g);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_and_eval(&mut self, file: FileId, ret: ty::Id, ret_loc: &mut [u8]) -> u64 {
|
fn emit_and_eval(&mut self, file: Module, ret: ty::Id, ret_loc: &mut [u8]) -> u64 {
|
||||||
let mut rets =
|
let mut rets =
|
||||||
self.ci.nodes[NEVER].inputs.iter().filter(|&&i| self.ci.nodes[i].kind == Kind::Return);
|
self.ci.nodes[NEVER].inputs.iter().filter(|&&i| self.ci.nodes[i].kind == Kind::Return);
|
||||||
if let Some(&ret) = rets.next()
|
if let Some(&ret) = rets.next()
|
||||||
|
@ -2291,8 +2291,7 @@ impl<'a> Codegen<'a> {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let fuc = self.tys.ins.funcs.len() as ty::Func;
|
let fuc = self.tys.ins.funcs.push(Func {
|
||||||
self.tys.ins.funcs.push(Func {
|
|
||||||
file,
|
file,
|
||||||
sig: Some(Sig { args: Tuple::empty(), ret }),
|
sig: Some(Sig { args: Tuple::empty(), ret }),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -2413,7 +2412,7 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
fn make_func_reachable(&mut self, func: ty::Func) {
|
fn make_func_reachable(&mut self, func: ty::Func) {
|
||||||
let state_slot = self.ct.active() as usize;
|
let state_slot = self.ct.active() as usize;
|
||||||
let fuc = &mut self.tys.ins.funcs[func as usize];
|
let fuc = &mut self.tys.ins.funcs[func];
|
||||||
if fuc.comp_state[state_slot] == CompState::Dead {
|
if fuc.comp_state[state_slot] == CompState::Dead {
|
||||||
fuc.comp_state[state_slot] = CompState::Queued(self.tys.tasks.len() as _);
|
fuc.comp_state[state_slot] = CompState::Queued(self.tys.tasks.len() as _);
|
||||||
self.tys.tasks.push(Some(FTask { file: fuc.file, id: func, ct: self.ct.active() }));
|
self.tys.tasks.push(Some(FTask { file: fuc.file, id: func, ct: self.ct.active() }));
|
||||||
|
@ -2500,9 +2499,9 @@ impl<'a> Codegen<'a> {
|
||||||
Expr::Ident { id, pos, .. } => {
|
Expr::Ident { id, pos, .. } => {
|
||||||
let decl = self.find_type(pos, self.ci.file, self.ci.file, Ok(id), self.files);
|
let decl = self.find_type(pos, self.ci.file, self.ci.file, Ok(id), self.files);
|
||||||
match decl.expand() {
|
match decl.expand() {
|
||||||
ty::Kind::Builtin(ty::NEVER) => Value::NEVER,
|
ty::Kind::NEVER => Value::NEVER,
|
||||||
ty::Kind::Global(global) => {
|
ty::Kind::Global(global) => {
|
||||||
let gl = &self.tys.ins.globals[global as usize];
|
let gl = &self.tys.ins.globals[global];
|
||||||
let value = self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]);
|
let value = self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]);
|
||||||
self.ci.nodes[value].aclass = GLOBAL_ACLASS as _;
|
self.ci.nodes[value].aclass = GLOBAL_ACLASS as _;
|
||||||
Some(Value::ptr(value).ty(gl.ty))
|
Some(Value::ptr(value).ty(gl.ty))
|
||||||
|
@ -2527,8 +2526,8 @@ impl<'a> Codegen<'a> {
|
||||||
occupied_entry.get_key_value().0.value.0
|
occupied_entry.get_key_value().0.value.0
|
||||||
}
|
}
|
||||||
(hash_map::RawEntryMut::Vacant(vacant_entry), hash) => {
|
(hash_map::RawEntryMut::Vacant(vacant_entry), hash) => {
|
||||||
let global = self.tys.ins.globals.len() as ty::Global;
|
let global =
|
||||||
self.tys.ins.globals.push(Global { data, ty, ..Default::default() });
|
self.tys.ins.globals.push(Global { data, ty, ..Default::default() });
|
||||||
vacant_entry
|
vacant_entry
|
||||||
.insert(crate::ctx_map::Key { value: StringRef(global), hash }, ())
|
.insert(crate::ctx_map::Key { value: StringRef(global), hash }, ())
|
||||||
.0
|
.0
|
||||||
|
@ -2626,9 +2625,9 @@ impl<'a> Codegen<'a> {
|
||||||
.find_type(pos, self.ci.file, m, Err(name), self.files)
|
.find_type(pos, self.ci.file, m, Err(name), self.files)
|
||||||
.expand()
|
.expand()
|
||||||
{
|
{
|
||||||
ty::Kind::Builtin(ty::NEVER) => Value::NEVER,
|
ty::Kind::NEVER => Value::NEVER,
|
||||||
ty::Kind::Global(global) => {
|
ty::Kind::Global(global) => {
|
||||||
let gl = &self.tys.ins.globals[global as usize];
|
let gl = &self.tys.ins.globals[global];
|
||||||
let value =
|
let value =
|
||||||
self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]);
|
self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]);
|
||||||
self.ci.nodes[value].aclass = GLOBAL_ACLASS as _;
|
self.ci.nodes[value].aclass = GLOBAL_ACLASS as _;
|
||||||
|
@ -2781,7 +2780,7 @@ impl<'a> Codegen<'a> {
|
||||||
return Value::NEVER;
|
return Value::NEVER;
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(Value::new(self.gen_null_check(cmped, ty, op)).ty(ty::BOOL))
|
Some(Value::new(self.gen_null_check(cmped, ty, op)).ty(ty::Id::BOOL))
|
||||||
}
|
}
|
||||||
Expr::BinOp { left, pos, op, right }
|
Expr::BinOp { left, pos, op, right }
|
||||||
if !matches!(op, TokenKind::Assign | TokenKind::Decl) =>
|
if !matches!(op, TokenKind::Assign | TokenKind::Decl) =>
|
||||||
|
@ -2850,7 +2849,7 @@ impl<'a> Codegen<'a> {
|
||||||
return Value::NEVER;
|
return Value::NEVER;
|
||||||
};
|
};
|
||||||
|
|
||||||
let elem = self.tys.ins.slices[s as usize].elem;
|
let elem = self.tys.ins.slices[s].elem;
|
||||||
let mut idx = self.expr_ctx(index, Ctx::default().with_ty(ty::Id::DEFAULT_INT))?;
|
let mut idx = self.expr_ctx(index, Ctx::default().with_ty(ty::Id::DEFAULT_INT))?;
|
||||||
self.assert_ty(index.pos(), &mut idx, ty::Id::DEFAULT_INT, "subscript");
|
self.assert_ty(index.pos(), &mut idx, ty::Id::DEFAULT_INT, "subscript");
|
||||||
let size = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem));
|
let size = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem));
|
||||||
|
@ -2866,7 +2865,7 @@ impl<'a> Codegen<'a> {
|
||||||
Some(Value::ptr(ptr).ty(elem))
|
Some(Value::ptr(ptr).ty(elem))
|
||||||
}
|
}
|
||||||
Expr::Embed { id, .. } => {
|
Expr::Embed { id, .. } => {
|
||||||
let glob = &self.tys.ins.globals[id as usize];
|
let glob = &self.tys.ins.globals[id];
|
||||||
let g = self.ci.nodes.new_node(glob.ty, Kind::Global { global: id }, [VOID]);
|
let g = self.ci.nodes.new_node(glob.ty, Kind::Global { global: id }, [VOID]);
|
||||||
Some(Value::ptr(g).ty(glob.ty))
|
Some(Value::ptr(g).ty(glob.ty))
|
||||||
}
|
}
|
||||||
|
@ -3092,7 +3091,7 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
inps[0] = self.ci.ctrl.get();
|
inps[0] = self.ci.ctrl.get();
|
||||||
self.ci.ctrl.set(
|
self.ci.ctrl.set(
|
||||||
self.ci.nodes.new_node(ty, Kind::Call { func: ty::ECA, args }, inps),
|
self.ci.nodes.new_node(ty, Kind::Call { func: ty::Func::ECA, args }, inps),
|
||||||
&mut self.ci.nodes,
|
&mut self.ci.nodes,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3115,8 +3114,8 @@ impl<'a> Codegen<'a> {
|
||||||
};
|
};
|
||||||
self.make_func_reachable(fu);
|
self.make_func_reachable(fu);
|
||||||
|
|
||||||
let fuc = &self.tys.ins.funcs[fu as usize];
|
let fuc = &self.tys.ins.funcs[fu];
|
||||||
let ast = &self.files[fuc.file as usize];
|
let ast = &self.files[fuc.file.index()];
|
||||||
let &Expr::Closure { args: cargs, .. } = fuc.expr.get(ast) else { unreachable!() };
|
let &Expr::Closure { args: cargs, .. } = fuc.expr.get(ast) else { unreachable!() };
|
||||||
|
|
||||||
if args.len() != cargs.len() {
|
if args.len() != cargs.len() {
|
||||||
|
@ -3195,9 +3194,9 @@ impl<'a> Codegen<'a> {
|
||||||
return Value::NEVER;
|
return Value::NEVER;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Func { expr, file, .. } = self.tys.ins.funcs[fu as usize];
|
let Func { expr, file, .. } = self.tys.ins.funcs[fu];
|
||||||
|
|
||||||
let ast = &self.files[file as usize];
|
let ast = &self.files[file.index()];
|
||||||
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else {
|
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
@ -3342,7 +3341,7 @@ impl<'a> Codegen<'a> {
|
||||||
Some(Value::ptr(mem).ty(sty))
|
Some(Value::ptr(mem).ty(sty))
|
||||||
}
|
}
|
||||||
ty::Kind::Slice(s) => {
|
ty::Kind::Slice(s) => {
|
||||||
let slice = &self.tys.ins.slices[s as usize];
|
let slice = &self.tys.ins.slices[s];
|
||||||
let len = slice.len().unwrap_or(fields.len());
|
let len = slice.len().unwrap_or(fields.len());
|
||||||
let elem = slice.elem;
|
let elem = slice.elem;
|
||||||
let elem_size = self.tys.size_of(elem);
|
let elem_size = self.tys.size_of(elem);
|
||||||
|
@ -3839,8 +3838,8 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> {
|
fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> {
|
||||||
let fuc = &self.tys.ins.funcs[*func as usize];
|
let fuc = &self.tys.ins.funcs[*func];
|
||||||
let fast = self.files[fuc.file as usize].clone();
|
let fast = self.files[fuc.file.index()].clone();
|
||||||
let &Expr::Closure { args: cargs, ret, .. } = fuc.expr.get(&fast) else {
|
let &Expr::Closure { args: cargs, ret, .. } = fuc.expr.get(&fast) else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
@ -3895,20 +3894,24 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
let sym = SymKey::FuncInst(*func, args);
|
let sym = SymKey::FuncInst(*func, args);
|
||||||
let ct = |ins: &mut crate::TypeIns| {
|
let ct = |ins: &mut crate::TypeIns| {
|
||||||
let func_id = ins.funcs.len();
|
let fuc = &ins.funcs[*func];
|
||||||
let fuc = &ins.funcs[*func as usize];
|
ins.funcs
|
||||||
ins.funcs.push(Func {
|
.push(Func {
|
||||||
file: fuc.file,
|
file: fuc.file,
|
||||||
name: fuc.name,
|
name: fuc.name,
|
||||||
base: Some(*func),
|
base: Some(*func),
|
||||||
sig: Some(Sig { args, ret }),
|
sig: Some(Sig { args, ret }),
|
||||||
expr: fuc.expr,
|
expr: fuc.expr,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
})
|
||||||
|
.into()
|
||||||
ty::Kind::Func(func_id as _).compress()
|
|
||||||
};
|
};
|
||||||
*func = self.tys.syms.get_or_insert(sym, &mut self.tys.ins, ct).expand().inner();
|
let ty::Kind::Func(f) =
|
||||||
|
self.tys.syms.get_or_insert(sym, &mut self.tys.ins, ct).expand()
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
*func = f;
|
||||||
|
|
||||||
Sig { args, ret }
|
Sig { args, ret }
|
||||||
})
|
})
|
||||||
|
@ -4034,13 +4037,13 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_func(&mut self, FTask { file, id, ct }: FTask) {
|
fn emit_func(&mut self, FTask { file, id, ct }: FTask) {
|
||||||
let func = &mut self.tys.ins.funcs[id as usize];
|
let func = &mut self.tys.ins.funcs[id];
|
||||||
debug_assert_eq!(func.file, file);
|
debug_assert_eq!(func.file, file);
|
||||||
let cct = self.ct.active();
|
let cct = self.ct.active();
|
||||||
debug_assert_eq!(cct, ct);
|
debug_assert_eq!(cct, ct);
|
||||||
func.comp_state[cct as usize] = CompState::Compiled;
|
func.comp_state[cct as usize] = CompState::Compiled;
|
||||||
let sig = func.sig.expect("to emmit only concrete functions");
|
let sig = func.sig.expect("to emmit only concrete functions");
|
||||||
let ast = &self.files[file as usize];
|
let ast = &self.files[file.index()];
|
||||||
let expr = func.expr.get(ast);
|
let expr = func.expr.get(ast);
|
||||||
|
|
||||||
self.pool.push_ci(file, Some(sig.ret), 0, &mut self.ci);
|
self.pool.push_ci(file, Some(sig.ret), 0, &mut self.ci);
|
||||||
|
@ -4192,8 +4195,6 @@ impl<'a> Codegen<'a> {
|
||||||
self.ci.nodes.gcm(&mut self.pool.nid_stack, &mut self.pool.nid_set);
|
self.ci.nodes.gcm(&mut self.pool.nid_stack, &mut self.pool.nid_set);
|
||||||
self.ci.nodes.basic_blocks();
|
self.ci.nodes.basic_blocks();
|
||||||
self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID));
|
self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID));
|
||||||
} else {
|
|
||||||
self.ci.nodes.graphviz_in_browser(self.ty_display(ty::Id::VOID));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.errors.borrow().len() == prev_err_len
|
self.errors.borrow().len() == prev_err_len
|
||||||
|
@ -4438,7 +4439,7 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self) -> &'a parser::Ast {
|
fn file(&self) -> &'a parser::Ast {
|
||||||
&self.files[self.ci.file as usize]
|
&self.files[self.ci.file.index()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4447,7 +4448,7 @@ impl TypeParser for Codegen<'_> {
|
||||||
self.tys
|
self.tys
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const(&mut self, file: FileId, expr: &Expr, ret: ty::Id) -> u64 {
|
fn eval_const(&mut self, file: Module, expr: &Expr, ret: ty::Id) -> u64 {
|
||||||
self.ct.activate();
|
self.ct.activate();
|
||||||
let mut scope = mem::take(&mut self.ci.scope.vars);
|
let mut scope = mem::take(&mut self.ci.scope.vars);
|
||||||
self.pool.push_ci(file, Some(ret), self.tys.tasks.len(), &mut self.ci);
|
self.pool.push_ci(file, Some(ret), self.tys.tasks.len(), &mut self.ci);
|
||||||
|
@ -4480,7 +4481,7 @@ impl TypeParser for Codegen<'_> {
|
||||||
fn on_reuse(&mut self, existing: ty::Id) {
|
fn on_reuse(&mut self, existing: ty::Id) {
|
||||||
let state_slot = self.ct.active() as usize;
|
let state_slot = self.ct.active() as usize;
|
||||||
if let ty::Kind::Func(id) = existing.expand()
|
if let ty::Kind::Func(id) = existing.expand()
|
||||||
&& let func = &mut self.tys.ins.funcs[id as usize]
|
&& let func = &mut self.tys.ins.funcs[id]
|
||||||
&& let CompState::Queued(idx) = func.comp_state[state_slot]
|
&& let CompState::Queued(idx) = func.comp_state[state_slot]
|
||||||
&& idx < self.tys.tasks.len()
|
&& idx < self.tys.tasks.len()
|
||||||
{
|
{
|
||||||
|
@ -4490,11 +4491,10 @@ impl TypeParser for Codegen<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_global(&mut self, file: FileId, name: Ident, expr: &Expr) -> ty::Id {
|
fn eval_global(&mut self, file: Module, name: Ident, expr: &Expr) -> ty::Id {
|
||||||
self.ct.activate();
|
self.ct.activate();
|
||||||
|
|
||||||
let gid = self.tys.ins.globals.len() as ty::Global;
|
let gid = self.tys.ins.globals.push(Global { file, name, ..Default::default() });
|
||||||
self.tys.ins.globals.push(Global { file, name, ..Default::default() });
|
|
||||||
|
|
||||||
let ty = ty::Kind::Global(gid);
|
let ty = ty::Kind::Global(gid);
|
||||||
self.pool.push_ci(file, None, self.tys.tasks.len(), &mut self.ci);
|
self.pool.push_ci(file, None, self.tys.tasks.len(), &mut self.ci);
|
||||||
|
@ -4506,19 +4506,19 @@ impl TypeParser for Codegen<'_> {
|
||||||
if self.finalize(prev_err_len) {
|
if self.finalize(prev_err_len) {
|
||||||
let mut mem = vec![0u8; self.tys.size_of(ret) as usize];
|
let mut mem = vec![0u8; self.tys.size_of(ret) as usize];
|
||||||
self.emit_and_eval(file, ret, &mut mem);
|
self.emit_and_eval(file, ret, &mut mem);
|
||||||
self.tys.ins.globals[gid as usize].data = mem;
|
self.tys.ins.globals[gid].data = mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pool.pop_ci(&mut self.ci);
|
self.pool.pop_ci(&mut self.ci);
|
||||||
self.tys.ins.globals[gid as usize].ty = ret;
|
self.tys.ins.globals[gid].ty = ret;
|
||||||
|
|
||||||
self.ct.deactivate();
|
self.ct.deactivate();
|
||||||
ty.compress()
|
ty.compress()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report(&self, file: FileId, pos: Pos, msg: impl Display) -> ty::Id {
|
fn report(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id {
|
||||||
let mut buf = self.errors.borrow_mut();
|
let mut buf = self.errors.borrow_mut();
|
||||||
write!(buf, "{}", self.files[file as usize].report(pos, msg)).unwrap();
|
write!(buf, "{}", self.files[file.index()].report(pos, msg)).unwrap();
|
||||||
ty::Id::NEVER
|
ty::Id::NEVER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4531,6 +4531,7 @@ impl TypeParser for Codegen<'_> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use {
|
use {
|
||||||
super::{hbvm::HbvmBackend, CodegenCtx},
|
super::{hbvm::HbvmBackend, CodegenCtx},
|
||||||
|
crate::ty,
|
||||||
alloc::{string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
core::fmt::Write,
|
core::fmt::Write,
|
||||||
};
|
};
|
||||||
|
@ -4546,7 +4547,7 @@ mod tests {
|
||||||
let mut codegen = super::Codegen::new(&mut backend, files, &mut ctx);
|
let mut codegen = super::Codegen::new(&mut backend, files, &mut ctx);
|
||||||
codegen.push_embeds(embeds);
|
codegen.push_embeds(embeds);
|
||||||
|
|
||||||
codegen.generate(0);
|
codegen.generate(ty::Module::MAIN);
|
||||||
|
|
||||||
{
|
{
|
||||||
let errors = codegen.errors.borrow();
|
let errors = codegen.errors.borrow();
|
||||||
|
|
|
@ -4,7 +4,8 @@ use {
|
||||||
lexer::TokenKind,
|
lexer::TokenKind,
|
||||||
parser, reg,
|
parser, reg,
|
||||||
son::{debug_assert_matches, write_reloc, Kind, MEM},
|
son::{debug_assert_matches, write_reloc, Kind, MEM},
|
||||||
ty::{self, Loc},
|
ty::{self, Loc, Module},
|
||||||
|
utils::{Ent, EntVec},
|
||||||
Offset, Reloc, Size, TypedReloc, Types,
|
Offset, Reloc, Size, TypedReloc, Types,
|
||||||
},
|
},
|
||||||
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
||||||
|
@ -47,8 +48,8 @@ struct Assembler {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct HbvmBackend {
|
pub struct HbvmBackend {
|
||||||
funcs: Vec<FuncDt>,
|
funcs: EntVec<ty::Func, FuncDt>,
|
||||||
globals: Vec<GlobalDt>,
|
globals: EntVec<ty::Global, GlobalDt>,
|
||||||
asm: Assembler,
|
asm: Assembler,
|
||||||
ralloc: their_regalloc::Regalloc,
|
ralloc: their_regalloc::Regalloc,
|
||||||
ralloc_my: my_regalloc::Res,
|
ralloc_my: my_regalloc::Res,
|
||||||
|
@ -98,13 +99,13 @@ impl Backend for HbvmBackend {
|
||||||
debug_assert!(self.asm.funcs.is_empty());
|
debug_assert!(self.asm.funcs.is_empty());
|
||||||
debug_assert!(self.asm.globals.is_empty());
|
debug_assert!(self.asm.globals.is_empty());
|
||||||
|
|
||||||
self.globals.resize_with(types.ins.globals.len(), Default::default);
|
self.globals.shadow(types.ins.globals.len());
|
||||||
|
|
||||||
self.asm.frontier.push(ty::Kind::Func(from).compress());
|
self.asm.frontier.push(ty::Kind::Func(from).compress());
|
||||||
while let Some(itm) = self.asm.frontier.pop() {
|
while let Some(itm) = self.asm.frontier.pop() {
|
||||||
match itm.expand() {
|
match itm.expand() {
|
||||||
ty::Kind::Func(func) => {
|
ty::Kind::Func(func) => {
|
||||||
let fuc = &mut self.funcs[func as usize];
|
let fuc = &mut self.funcs[func];
|
||||||
debug_assert!(!fuc.code.is_empty());
|
debug_assert!(!fuc.code.is_empty());
|
||||||
if fuc.offset != u32::MAX {
|
if fuc.offset != u32::MAX {
|
||||||
continue;
|
continue;
|
||||||
|
@ -114,7 +115,7 @@ impl Backend for HbvmBackend {
|
||||||
self.asm.frontier.extend(fuc.relocs.iter().map(|r| r.target));
|
self.asm.frontier.extend(fuc.relocs.iter().map(|r| r.target));
|
||||||
}
|
}
|
||||||
ty::Kind::Global(glob) => {
|
ty::Kind::Global(glob) => {
|
||||||
let glb = &mut self.globals[glob as usize];
|
let glb = &mut self.globals[glob];
|
||||||
if glb.offset != u32::MAX {
|
if glb.offset != u32::MAX {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -128,7 +129,7 @@ impl Backend for HbvmBackend {
|
||||||
let init_len = to.len();
|
let init_len = to.len();
|
||||||
|
|
||||||
for &func in &self.asm.funcs {
|
for &func in &self.asm.funcs {
|
||||||
let fuc = &mut self.funcs[func as usize];
|
let fuc = &mut self.funcs[func];
|
||||||
fuc.offset = to.len() as _;
|
fuc.offset = to.len() as _;
|
||||||
debug_assert!(!fuc.code.is_empty());
|
debug_assert!(!fuc.code.is_empty());
|
||||||
to.extend(&fuc.code);
|
to.extend(&fuc.code);
|
||||||
|
@ -137,18 +138,18 @@ impl Backend for HbvmBackend {
|
||||||
let code_length = to.len() - init_len;
|
let code_length = to.len() - init_len;
|
||||||
|
|
||||||
for global in self.asm.globals.drain(..) {
|
for global in self.asm.globals.drain(..) {
|
||||||
self.globals[global as usize].offset = to.len() as _;
|
self.globals[global].offset = to.len() as _;
|
||||||
to.extend(&types.ins.globals[global as usize].data);
|
to.extend(&types.ins.globals[global].data);
|
||||||
}
|
}
|
||||||
|
|
||||||
let data_length = to.len() - code_length - init_len;
|
let data_length = to.len() - code_length - init_len;
|
||||||
|
|
||||||
for func in self.asm.funcs.drain(..) {
|
for func in self.asm.funcs.drain(..) {
|
||||||
let fuc = &self.funcs[func as usize];
|
let fuc = &self.funcs[func];
|
||||||
for rel in &fuc.relocs {
|
for rel in &fuc.relocs {
|
||||||
let offset = match rel.target.expand() {
|
let offset = match rel.target.expand() {
|
||||||
ty::Kind::Func(fun) => self.funcs[fun as usize].offset,
|
ty::Kind::Func(fun) => self.funcs[fun].offset,
|
||||||
ty::Kind::Global(glo) => self.globals[glo as usize].offset,
|
ty::Kind::Global(glo) => self.globals[glo].offset,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
rel.reloc.apply_jump(to, offset, fuc.offset);
|
rel.reloc.apply_jump(to, offset, fuc.offset);
|
||||||
|
@ -158,7 +159,7 @@ impl Backend for HbvmBackend {
|
||||||
AssemblySpec {
|
AssemblySpec {
|
||||||
code_length: code_length as _,
|
code_length: code_length as _,
|
||||||
data_length: data_length as _,
|
data_length: data_length as _,
|
||||||
entry: self.funcs[from as usize].offset,
|
entry: self.funcs[from].offset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,11 +176,11 @@ impl Backend for HbvmBackend {
|
||||||
.ins
|
.ins
|
||||||
.funcs
|
.funcs
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&self.funcs)
|
.zip(self.funcs.iter())
|
||||||
.filter(|(_, f)| f.offset != u32::MAX)
|
.filter(|(_, f)| f.offset != u32::MAX)
|
||||||
.map(|(f, fd)| {
|
.map(|(f, fd)| {
|
||||||
let name = if f.file != u32::MAX {
|
let name = if f.file != Module::default() {
|
||||||
let file = &files[f.file as usize];
|
let file = &files[f.file.index()];
|
||||||
file.ident_str(f.name)
|
file.ident_str(f.name)
|
||||||
} else {
|
} else {
|
||||||
"target_fn"
|
"target_fn"
|
||||||
|
@ -191,13 +192,13 @@ impl Backend for HbvmBackend {
|
||||||
.ins
|
.ins
|
||||||
.globals
|
.globals
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&self.globals)
|
.zip(self.globals.iter())
|
||||||
.filter(|(_, g)| g.offset != u32::MAX)
|
.filter(|(_, g)| g.offset != u32::MAX)
|
||||||
.map(|(g, gd)| {
|
.map(|(g, gd)| {
|
||||||
let name = if g.file == u32::MAX {
|
let name = if g.file == Module::default() {
|
||||||
core::str::from_utf8(&g.data).unwrap_or("invalid utf-8")
|
core::str::from_utf8(&g.data).unwrap_or("invalid utf-8")
|
||||||
} else {
|
} else {
|
||||||
let file = &files[g.file as usize];
|
let file = &files[g.file.index()];
|
||||||
file.ident_str(g.name)
|
file.ident_str(g.name)
|
||||||
};
|
};
|
||||||
(gd.offset, (name, g.data.len() as Size, DisasmItem::Global))
|
(gd.offset, (name, g.data.len() as Size, DisasmItem::Global))
|
||||||
|
@ -215,13 +216,13 @@ impl Backend for HbvmBackend {
|
||||||
files: &[parser::Ast],
|
files: &[parser::Ast],
|
||||||
) {
|
) {
|
||||||
self.emit_body(id, nodes, tys, files);
|
self.emit_body(id, nodes, tys, files);
|
||||||
let fd = &mut self.funcs[id as usize];
|
let fd = &mut self.funcs[id];
|
||||||
fd.code.truncate(fd.code.len() - instrs::jala(0, 0, 0).0);
|
fd.code.truncate(fd.code.len() - instrs::jala(0, 0, 0).0);
|
||||||
emit(&mut fd.code, instrs::tx());
|
emit(&mut fd.code, instrs::tx());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_body(&mut self, id: ty::Func, nodes: &mut Nodes, tys: &Types, files: &[parser::Ast]) {
|
fn emit_body(&mut self, id: ty::Func, nodes: &mut Nodes, tys: &Types, files: &[parser::Ast]) {
|
||||||
let sig = tys.ins.funcs[id as usize].sig.unwrap();
|
let sig = tys.ins.funcs[id].sig.unwrap();
|
||||||
|
|
||||||
debug_assert!(self.code.is_empty());
|
debug_assert!(self.code.is_empty());
|
||||||
|
|
||||||
|
@ -319,11 +320,9 @@ impl Backend for HbvmBackend {
|
||||||
self.emit(instrs::jala(reg::ZERO, reg::RET_ADDR, 0));
|
self.emit(instrs::jala(reg::ZERO, reg::RET_ADDR, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.funcs.get(id as usize).is_none() {
|
self.funcs.shadow(tys.ins.funcs.len());
|
||||||
self.funcs.resize_with(id as usize + 1, Default::default);
|
self.funcs[id].code = mem::take(&mut self.code);
|
||||||
}
|
self.funcs[id].relocs = mem::take(&mut self.relocs);
|
||||||
self.funcs[id as usize].code = mem::take(&mut self.code);
|
|
||||||
self.funcs[id as usize].relocs = mem::take(&mut self.relocs);
|
|
||||||
|
|
||||||
debug_assert_eq!(self.ret_relocs.len(), 0);
|
debug_assert_eq!(self.ret_relocs.len(), 0);
|
||||||
debug_assert_eq!(self.relocs.len(), 0);
|
debug_assert_eq!(self.relocs.len(), 0);
|
||||||
|
|
|
@ -305,7 +305,7 @@ impl HbvmBackend {
|
||||||
!matches!(ret, Some(PLoc::Ref(..))) || allocs.next().is_some()
|
!matches!(ret, Some(PLoc::Ref(..))) || allocs.next().is_some()
|
||||||
);
|
);
|
||||||
|
|
||||||
if func == ty::ECA {
|
if func == ty::Func::ECA {
|
||||||
self.emit(instrs::eca());
|
self.emit(instrs::eca());
|
||||||
} else {
|
} else {
|
||||||
self.relocs.push(TypedReloc {
|
self.relocs.push(TypedReloc {
|
||||||
|
@ -647,7 +647,7 @@ impl<'a> Function<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Call { func, .. } => {
|
Kind::Call { func, .. } => {
|
||||||
self.tail &= func == ty::ECA;
|
self.tail &= func == ty::Func::ECA;
|
||||||
|
|
||||||
self.add_instr(nid);
|
self.add_instr(nid);
|
||||||
|
|
||||||
|
|
|
@ -315,7 +315,7 @@ impl HbvmBackend {
|
||||||
!matches!(ret, Some(PLoc::Ref(..))) || allocs.next().is_some()
|
!matches!(ret, Some(PLoc::Ref(..))) || allocs.next().is_some()
|
||||||
);
|
);
|
||||||
|
|
||||||
if func == ty::ECA {
|
if func == ty::Func::ECA {
|
||||||
self.emit(instrs::eca());
|
self.emit(instrs::eca());
|
||||||
} else {
|
} else {
|
||||||
self.relocs.push(TypedReloc {
|
self.relocs.push(TypedReloc {
|
||||||
|
@ -710,7 +710,7 @@ impl<'a> Function<'a> {
|
||||||
self.add_instr(nid, ops);
|
self.add_instr(nid, ops);
|
||||||
}
|
}
|
||||||
Kind::Call { args, func } => {
|
Kind::Call { args, func } => {
|
||||||
self.tail &= func == ty::ECA;
|
self.tail &= func == ty::Func::ECA;
|
||||||
self.backrefs[nid as usize] = self.backrefs[prev as usize];
|
self.backrefs[nid as usize] = self.backrefs[prev as usize];
|
||||||
let mut ops = vec![];
|
let mut ops = vec![];
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use {
|
||||||
alloc::Layout,
|
alloc::Layout,
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
hint::unreachable_unchecked,
|
hint::unreachable_unchecked,
|
||||||
|
marker::PhantomData,
|
||||||
mem::MaybeUninit,
|
mem::MaybeUninit,
|
||||||
ops::{Deref, DerefMut, Not},
|
ops::{Deref, DerefMut, Not},
|
||||||
ptr::Unique,
|
ptr::Unique,
|
||||||
|
@ -532,3 +533,97 @@ struct AllocedVc {
|
||||||
len: Nid,
|
len: Nid,
|
||||||
base: Unique<Nid>,
|
base: Unique<Nid>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Ent: Copy {
|
||||||
|
fn new(index: usize) -> Self;
|
||||||
|
fn index(self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EntVec<K: Ent, T> {
|
||||||
|
data: ::alloc::vec::Vec<T>,
|
||||||
|
k: PhantomData<fn(K)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Ent, T> Default for EntVec<K, T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { data: Default::default(), k: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Ent, T> EntVec<K, T> {
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.data.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.data.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, value: T) -> K {
|
||||||
|
let k = K::new(self.data.len());
|
||||||
|
self.data.push(value);
|
||||||
|
k
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(&self, index: K) -> Option<&T> {
|
||||||
|
self.data.get(index.index() + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shadow(&mut self, len: usize)
|
||||||
|
where
|
||||||
|
T: Default,
|
||||||
|
{
|
||||||
|
if self.data.len() < len {
|
||||||
|
self.data.resize_with(len, Default::default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> core::slice::Iter<T> {
|
||||||
|
self.data.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Ent, T> core::ops::Index<K> for EntVec<K, T> {
|
||||||
|
type Output = T;
|
||||||
|
|
||||||
|
fn index(&self, index: K) -> &Self::Output {
|
||||||
|
&self.data[index.index()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Ent, T> core::ops::IndexMut<K> for EntVec<K, T> {
|
||||||
|
fn index_mut(&mut self, index: K) -> &mut Self::Output {
|
||||||
|
&mut self.data[index.index()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! decl_ent {
|
||||||
|
($(
|
||||||
|
$vis:vis struct $name:ident($index:ty);
|
||||||
|
)*) => {$(
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
|
$vis struct $name($index);
|
||||||
|
|
||||||
|
impl crate::utils::Ent for $name {
|
||||||
|
fn new(index: usize) -> Self {
|
||||||
|
Self(index as $index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index(self) -> usize {
|
||||||
|
self.0 as _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl core::fmt::Display for $name {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
write!(f, concat!(stringify!($name), "{}"), self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*};
|
||||||
|
}
|
||||||
|
pub(crate) use decl_ent;
|
||||||
|
|
Loading…
Reference in a new issue