Big restructure pt.2

This commit is contained in:
Mia
2026-02-27 02:20:45 +01:00
parent f4334e79f6
commit 4b07d93ae3
14 changed files with 305 additions and 548 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ edition = "2024"
[dependencies]
bitflags = "2.10.0"
boxcar = "0.2.14"
derive_more = { version = "2.0.1", features = ["deref", "debug", "display"] }
derive_more = { version = "2.0.1", features = ["deref", "deref_mut", "debug", "display", "try_from", "from", "try_into", "into"] }
half = "2.7.1"
scc = "3.3.7"
+11 -142
View File
@@ -1,16 +1,11 @@
use crate::{
assembly::intrinsic_types::make_intrinsic_types,
functions::Function,
types::{
Type,
derivations::{FuncT, TypeDerivations},
intrinsics::*,
},
values::{Const, ConstData, Int},
types::derivations::{FuncT, TypeDerivations},
values::AnyConst,
};
use derive_more::Debug;
use leaf_allocators::SyncAllocator;
use scc::HashMap;
use scc::{HashMap, HashSet};
use std::{borrow::Cow, hash::Hash, sync::OnceLock};
#[derive(derive_more::Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -33,8 +28,6 @@ pub type Ctx<'l> = &'l Context<'l>;
pub struct Context<'l> {
pub(crate) alloc: &'l dyn SyncAllocator,
pub(crate) derivations: TypeDerivations<'l>,
constants: HashMap<&'l ConstData<'l>, &'l Const<'l>>,
intrinsics: OnceLock<Box<intrinsic_types::IntrinsicTypesArray<'l>>>,
assemblies: HashMap<AssemblyIdentifier, &'l Assembly<'l>>,
}
@@ -54,17 +47,11 @@ impl Hash for Context<'_> {
impl<'l> Context<'l> {
pub fn new(alloc: &'l dyn SyncAllocator) -> &'l Self {
let ctx = alloc.alloc(Self {
alloc.alloc(Self {
alloc,
constants: HashMap::new(),
derivations: TypeDerivations::new(alloc),
intrinsics: OnceLock::new(),
assemblies: Default::default(),
});
ctx.intrinsics
.set(Box::new(make_intrinsic_types(ctx)))
.unwrap();
ctx
})
}
pub fn get_assembly(&'l self, ident: &AssemblyIdentifier) -> Option<&'l Assembly<'l>> {
@@ -86,10 +73,10 @@ pub struct Assembly<'l> {
ident: AssemblyIdentifier,
#[debug("{:#?}", {
let mut c = vec![];
constants.iter_sync(|k, _| {c.push(*k); true});
constants.iter_sync(|k| {c.push(*k); true});
c
})]
constants: HashMap<&'l Const<'l>, &'l Const<'l>>,
constants: HashSet<AnyConst<'l>>,
}
impl Eq for Assembly<'_> {}
@@ -111,7 +98,7 @@ impl<'l> Assembly<'l> {
let assembly = ctx.alloc.alloc(Self {
ctx,
ident,
constants: HashMap::new(),
constants: HashSet::new(),
});
assembly
}
@@ -127,127 +114,9 @@ impl<'l> Assembly<'l> {
body: OnceLock::new(),
declaring_assembly: self,
});
let constant = self.ctx.alloc.alloc(Const {
ctx: self.ctx,
data: ConstData::Function(func),
});
self.constants.insert_sync(constant, constant).unwrap();
self.constants
.insert_sync(AnyConst::Function(func))
.unwrap();
func
}
}
pub trait CreateConst<'l, T> {
fn create_const(&'l self, value: T) -> &'l Const<'l>;
}
macro_rules! create_const {
($(impl $ty:ty : $expr:expr,)*) => {
$(
impl<'l> CreateConst<'l, $ty> for Context<'l> {
fn create_const(&'l self, value: $ty) -> &'l Const<'l> {
let constant = ($expr)(self, value);
if let Some(existing) = self.constants.get_sync(&constant.data) {
return *existing;
}
let constant = self.alloc.alloc(constant);
*self.constants.entry_sync(&constant.data).or_insert(constant)
}
}
)*
};
}
create_const! {
impl i8: |ctx, val| Const { ctx, data: ConstData::Int(Int::I8(val)) },
impl i16: |ctx, val| Const { ctx, data: ConstData::Int(Int::I16(val)) },
impl i32: |ctx, val| Const { ctx, data: ConstData::Int(Int::I32(val)) },
impl i64: |ctx, val| Const { ctx, data: ConstData::Int(Int::I64(val)) },
impl i128: |ctx, val| Const { ctx, data: ConstData::Int(Int::I128(val)) },
impl u8: |ctx, val| Const { ctx, data: ConstData::Int(Int::U8(val)) },
impl u16: |ctx, val| Const { ctx, data: ConstData::Int(Int::U16(val)) },
impl u32: |ctx, val| Const { ctx, data: ConstData::Int(Int::U32(val)) },
impl u64: |ctx, val| Const { ctx, data: ConstData::Int(Int::U64(val)) },
impl u128: |ctx, val| Const { ctx, data: ConstData::Int(Int::U128(val)) },
impl (): |ctx, _| Const { ctx, data: ConstData::Void },
impl char: |ctx, val| Const { ctx, data: ConstData::Char(val) },
impl bool: |ctx, val| Const { ctx, data: ConstData::Bool(val) },
impl &'l str: |ctx, val| Const { ctx, data: ConstData::Str(val) },
}
mod intrinsic_types {
use super::*;
use std::mem::MaybeUninit;
macro_rules! create_intrinsics {
($(($id:ident, $fn_id:ident, $init:expr),)*) => {
pub enum IntrinsicTypeKind {
$($id,)*
COUNT,
}
pub type IntrinsicTypesArray<'l> = [Type<'l>; IntrinsicTypeKind::COUNT as usize];
pub fn make_intrinsic_types<'l>(ctx: &'l Context<'l>) -> IntrinsicTypesArray<'l> {
unsafe {
const C: usize = IntrinsicTypeKind::COUNT as usize;
let mut intrinsics = [MaybeUninit::<Type>::uninit(); C];
$(
intrinsics[IntrinsicTypeKind::$id as usize]
.write((&*ctx.alloc.alloc($init(ctx))).into());
)*
std::mem::transmute(intrinsics)
}
}
impl<'l> Context<'l> {
$(
#[inline]
pub fn $fn_id(&'l self) -> Type<'l> {
self.get_intrinsic(IntrinsicTypeKind::$id)
}
)*
#[inline]
fn get_intrinsic(&'l self, intrinsic: IntrinsicTypeKind) -> Type<'l> {
unsafe {
self.intrinsics
.get()
.unwrap_unchecked()
.get_unchecked(intrinsic as usize)
.clone()
}
}
}
};
}
create_intrinsics! {
(Void, void_t, |ctx| VoidT { ctx }),
(Char, char_t, |ctx| CharT { ctx }),
(Bool, bool_t, |ctx| BoolT { ctx }),
(Type, type_t, |ctx| TypeT { ctx, }),
(ConstStr, const_str_t, |ctx| ConstStrT { ctx, }),
(I8, i8_t, |ctx| IntT { ctx, signed: true, precision: 8 }),
(I16, i16_t, |ctx| IntT { ctx, signed: true, precision: 16 }),
(I32, i32_t, |ctx| IntT { ctx, signed: true, precision: 32 }),
(I64, i64_t, |ctx| IntT { ctx, signed: true, precision: 64 }),
(I128, i128_t, |ctx| IntT { ctx, signed: true, precision: 128 }),
(ISize, isize_t, |ctx| IntT { ctx, signed: true, precision: u32::MAX }),
(U8, u8_t, |ctx| IntT { ctx, signed: false, precision: 8 }),
(U16, u16_t, |ctx| IntT { ctx, signed: false, precision: 16 }),
(U32, u32_t, |ctx| IntT { ctx, signed: false, precision: 32 }),
(U64, u64_t, |ctx| IntT { ctx, signed: false, precision: 64 }),
(U128, u128_t, |ctx| IntT { ctx, signed: false, precision: 128 }),
(USize, usize_t, |ctx| IntT { ctx, signed: false, precision: u32::MAX }),
(F16, f16_t, |ctx| FloatT { ctx, precision: 16 }),
(F32, f32_t, |ctx| FloatT { ctx, precision: 32 }),
(F64, f64_t, |ctx| FloatT { ctx, precision: 64 }),
}
}
+9 -15
View File
@@ -4,7 +4,7 @@ use crate::{
types::{Type, derivations::*},
values::{Value, ValueFlags},
};
use derive_more::Debug;
use derive_more::{Debug, Display};
use std::{borrow::Cow, cell::UnsafeCell, hash::Hash, ops::Deref, sync::OnceLock};
// Maybe unsafe but honestly it's extremely unlikely that this will go wrong and it won't cause any issues.
@@ -12,8 +12,9 @@ struct Id(UnsafeCell<u32>);
unsafe impl Send for Id {}
unsafe impl Sync for Id {}
#[derive(Debug)]
#[derive(Debug, Display)]
#[debug("{variant:?}")]
#[display("%{}", unsafe { *id.0.get() })]
pub struct Instruction<'l> {
id: Id,
pub parent_block: &'l Block<'l>,
@@ -45,13 +46,6 @@ impl<'l> Deref for Instruction<'l> {
}
}
impl<'l> Into<Value<'l>> for &'l Instruction<'l> {
#[inline]
fn into(self) -> Value<'l> {
Value::Instruction(self)
}
}
impl<'l> Instruction<'l> {
#[inline]
pub fn ctx(&self) -> Ctx<'l> {
@@ -69,10 +63,10 @@ impl<'l> Instruction<'l> {
}
}
pub fn value_ty(&self) -> Type<'l> {
pub fn value_ty(&'l self) -> Type<'l> {
match self.variant {
InstructionVariant::Return(_) => self.ctx().void_t(),
InstructionVariant::Store(_, _) => self.ctx().void_t(),
InstructionVariant::Return(_) => Type::Void,
InstructionVariant::Store(_, _) => Type::Void,
InstructionVariant::StackAlloc(ty) => ty.make_ptr(true).into(),
InstructionVariant::Load(value) => match value.ty() {
Type::Ptr(PtrT { base, .. }) => *base,
@@ -80,7 +74,7 @@ impl<'l> Instruction<'l> {
},
InstructionVariant::IAdd(a, _) => a.ty(),
InstructionVariant::FAdd(a, _) => a.ty(),
InstructionVariant::ICmp(_, _, _) => self.ctx().bool_t(),
InstructionVariant::ICmp(_, _, _) => Type::Bool,
_ => todo!("{self:?}"),
}
}
@@ -299,7 +293,7 @@ impl<'l> BlockBuilder<'l> {
if !std::ptr::eq(false_case.func, self.block.func) {
return Err("Block does not belong to this function.".into());
}
if !matches!(cond.ty(), Type::Bool(_)) {
if !matches!(cond.ty(), Type::Bool) {
return Err(format!("Expected value of type `bool`, found `{}`.", cond.ty()).into());
}
let inst = self.push_instruction(InstructionVariant::Branch {
@@ -342,7 +336,7 @@ impl<'l> BlockBuilder<'l> {
let ret_t = self.block.func.ty.ret_t;
let value_ty = match value {
Some(v) => v.ty(),
None => self.block.func.ctx().void_t(),
None => Type::Void,
};
if value_ty != ret_t {
return Err(format!(
+10 -37
View File
@@ -78,7 +78,7 @@ impl Hash for TypeDerivations<'_> {
}
#[non_exhaustive]
#[derive(Debug, Display, PartialEq, Eq, Hash)]
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
#[display("*{}{}", if *mutable { "mut " } else { "" }, *base)]
pub struct PtrT<'l> {
#[debug("{base}")]
@@ -86,14 +86,8 @@ pub struct PtrT<'l> {
pub mutable: bool,
}
impl<'l> Into<Type<'l>> for &'l PtrT<'l> {
fn into(self) -> Type<'l> {
Type::Ptr(self)
}
}
#[non_exhaustive]
#[derive(Debug, Display, PartialEq, Eq, Hash)]
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
#[display("&{}{}", if *mutable { "mut " } else { "" }, *base)]
pub struct RefT<'l> {
#[debug("{base}")]
@@ -101,12 +95,6 @@ pub struct RefT<'l> {
pub mutable: bool,
}
impl<'l> Into<Type<'l>> for &'l RefT<'l> {
fn into(self) -> Type<'l> {
Type::Ref(self)
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FuncT<'l> {
@@ -127,33 +115,18 @@ impl Display for FuncT<'_> {
}
}
impl<'l> Into<Type<'l>> for &'l FuncT<'l> {
fn into(self) -> Type<'l> {
Type::Func(self)
}
impl<'l> Type<'l> {
pub fn make_ptr(&self, mutable: bool) -> &'l PtrT<'l> {
self.ctx().derivations.make_ptr(*self, mutable)
}
pub trait MakeTypeDerivations<'l> {
fn make_ptr(self, mutable: bool) -> &'l PtrT<'l>;
fn make_ref(self, mutable: bool) -> &'l RefT<'l>;
fn make_fn(self, par_t: impl IntoIterator<Item = Type<'l>>) -> &'l FuncT<'l>;
pub fn make_ref(&self, mutable: bool) -> &'l RefT<'l> {
self.ctx().derivations.make_ref(*self, mutable)
}
impl<'l, T: 'l + Into<Type<'l>>> MakeTypeDerivations<'l> for T {
fn make_ptr(self, mutable: bool) -> &'l PtrT<'l> {
let ty = self.into();
ty.ctx().derivations.make_ptr(ty, mutable)
}
fn make_ref(self, mutable: bool) -> &'l RefT<'l> {
let ty = self.into();
ty.ctx().derivations.make_ref(ty, mutable)
}
fn make_fn(self, par_t: impl IntoIterator<Item = Type<'l>>) -> &'l FuncT<'l> {
let ty = self.into();
ty.ctx()
pub fn make_fn(&self, par_t: impl IntoIterator<Item = Type<'l>>) -> &'l FuncT<'l> {
self.ctx()
.derivations
.make_fn(ty, par_t.into_iter().collect())
.make_fn(*self, par_t.into_iter().collect())
}
}
-103
View File
@@ -1,103 +0,0 @@
use crate::{assembly::Ctx, types::Type};
use derive_more::{Debug, Display};
use std::fmt::Display;
#[derive(Debug, Display, PartialEq, Eq, Hash)]
#[display("type")]
#[debug("type")]
pub struct TypeT<'l> {
pub(crate) ctx: Ctx<'l>,
}
impl<'l> Into<Type<'l>> for &'l TypeT<'l> {
fn into(self) -> Type<'l> {
Type::Type(self)
}
}
#[derive(Debug, Display, PartialEq, Eq, Hash)]
#[display("void")]
#[debug("void")]
pub struct VoidT<'l> {
pub(crate) ctx: Ctx<'l>,
}
impl<'l> Into<Type<'l>> for &'l VoidT<'l> {
fn into(self) -> Type<'l> {
Type::Void(self)
}
}
#[derive(Debug, Display, PartialEq, Eq, Hash)]
#[display("char")]
#[debug("char")]
pub struct CharT<'l> {
pub(crate) ctx: Ctx<'l>,
}
impl<'l> Into<Type<'l>> for &'l CharT<'l> {
fn into(self) -> Type<'l> {
Type::Char(self)
}
}
#[derive(Debug, Display, PartialEq, Eq, Hash)]
#[display("bool")]
#[debug("bool")]
pub struct BoolT<'l> {
pub(crate) ctx: Ctx<'l>,
}
impl<'l> Into<Type<'l>> for &'l BoolT<'l> {
fn into(self) -> Type<'l> {
Type::Bool(self)
}
}
#[derive(Debug, Display, PartialEq, Eq, Hash)]
#[display("const_str")]
#[debug("const_str")]
pub struct ConstStrT<'l> {
pub(crate) ctx: Ctx<'l>,
}
impl<'l> Into<Type<'l>> for &'l ConstStrT<'l> {
fn into(self) -> Type<'l> {
Type::ConstStr(self)
}
}
#[non_exhaustive]
#[derive(Debug, Display, PartialEq, Eq, Hash)]
#[display(
"{}{}",
if *signed { "i" } else { "u" },
if *precision == u32::MAX { &"size" as &dyn Display } else { precision })
]
#[debug("{self}")]
pub struct IntT<'l> {
pub signed: bool,
pub precision: u32,
pub(crate) ctx: Ctx<'l>,
}
impl<'l> Into<Type<'l>> for &'l IntT<'l> {
fn into(self) -> Type<'l> {
Type::Int(self)
}
}
#[non_exhaustive]
#[derive(Debug, Display, PartialEq, Eq, Hash)]
#[display("f{}", precision)]
#[debug("{self}")]
pub struct FloatT<'l> {
pub precision: u32,
pub(crate) ctx: Ctx<'l>,
}
impl<'l> Into<Type<'l>> for &'l FloatT<'l> {
fn into(self) -> Type<'l> {
Type::Float(self)
}
}
+84 -31
View File
@@ -1,26 +1,47 @@
pub mod derivations;
pub mod intrinsics;
use crate::{assembly::Context, types::derivations::*};
use derive_more::{Debug, Display, From, TryInto};
use leaf_allocators::SyncArenaAllocator;
use std::{fmt::Display, sync::OnceLock};
use crate::{
assembly::Ctx,
types::{derivations::*, intrinsics::*},
};
use derive_more::{Debug, Display};
pub mod derivations;
#[non_exhaustive]
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
#[display(
"{}{}",
if *signed { "i" } else { "u" },
if *precision == u32::MAX { &"size" as &dyn Display } else { precision })
]
#[debug("{self}")]
pub struct IntT {
pub signed: bool,
pub precision: u32,
}
#[non_exhaustive]
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
#[display("f{}", precision)]
#[debug("{self}")]
pub struct FloatT {
pub precision: u32,
}
#[non_exhaustive]
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)]
pub enum Type<'l> {
Void(&'l VoidT<'l>),
Char(&'l CharT<'l>),
Bool(&'l BoolT<'l>),
Void,
Char,
Bool,
Type,
ConstStr,
#[debug("{_0:?}")]
#[display("{_0}")]
Int(&'l IntT<'l>),
Int(IntT),
#[debug("{_0:?}")]
#[display("{_0}")]
Float(&'l FloatT<'l>),
Float(FloatT),
#[debug("{_0:?}")]
#[display("{_0}")]
@@ -33,29 +54,61 @@ pub enum Type<'l> {
#[debug("{_0:?}")]
#[display("{_0}")]
Func(&'l FuncT<'l>),
#[debug("{_0:?}")]
#[display("{_0}")]
Type(&'l TypeT<'l>),
#[debug("{_0:?}")]
#[display("{_0}")]
ConstStr(&'l ConstStrT<'l>),
}
impl<'l> Type<'l> {
pub fn ctx(&self) -> Ctx<'l> {
pub fn ctx(&self) -> &'l Context<'l> {
match self.non_default_ctx() {
Some(ctx) => ctx,
None => unsafe {
static DEFAULT: OnceLock<&'static Context> = OnceLock::new();
static ALLOCATOR: OnceLock<SyncArenaAllocator> = OnceLock::new();
let ctx: &'static Context = DEFAULT.get_or_init(|| {
let allocator: &'static SyncArenaAllocator =
ALLOCATOR.get_or_init(|| SyncArenaAllocator::default());
Context::new(allocator)
});
std::mem::transmute(ctx)
},
}
}
fn non_default_ctx(&self) -> Option<&'l Context<'l>> {
match self {
Type::Void(t) => t.ctx,
Type::Char(t) => t.ctx,
Type::Bool(t) => t.ctx,
Type::Int(t) => t.ctx,
Type::Float(t) => t.ctx,
Type::Ptr(t) => t.base.ctx(),
Type::Ref(t) => t.base.ctx(),
Type::Func(t) => t.ret_t.ctx(),
Type::Type(t) => t.ctx,
Type::ConstStr(t) => t.ctx,
Type::Void => None,
Type::Char => None,
Type::Bool => None,
Type::Type => None,
Type::ConstStr => None,
Type::Int(_) => None,
Type::Float(_) => None,
Type::Ptr(_) => None,
Type::Ref(_) => None,
Type::Func(f) => match f.ret_t.non_default_ctx() {
Some(ctx) => Some(ctx),
None => f.par_t.iter().find_map(|t| t.non_default_ctx()),
},
}
}
}
#[rustfmt::skip]
impl Type<'_> {
pub const I8: Self = Type::Int(IntT { signed: true, precision: 8 });
pub const I16: Self = Type::Int(IntT { signed: true, precision: 16 });
pub const I32: Self = Type::Int(IntT { signed: true, precision: 32 });
pub const I64: Self = Type::Int(IntT { signed: true, precision: 64 });
pub const I128: Self = Type::Int(IntT { signed: true, precision: 128 });
pub const ISIZE: Self = Type::Int(IntT { signed: true, precision: u32::MAX });
pub const U8: Self = Type::Int(IntT { signed: false, precision: 8 });
pub const U16: Self = Type::Int(IntT { signed: false, precision: 16 });
pub const U32: Self = Type::Int(IntT { signed: false, precision: 32 });
pub const U64: Self = Type::Int(IntT { signed: false, precision: 64 });
pub const U128: Self = Type::Int(IntT { signed: false, precision: 128 });
pub const USIZE: Self = Type::Int(IntT { signed: false, precision: u32::MAX });
pub const F16: Self = Type::Float(FloatT { precision: 16 });
pub const F32: Self = Type::Float(FloatT { precision: 32 });
pub const F64: Self = Type::Float(FloatT { precision: 64 });
}
+104
View File
@@ -0,0 +1,104 @@
use crate::{functions::Function, types::Type};
use derive_more::{Debug, *};
use half::f16;
use std::hash::Hash;
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)]
pub enum Int {
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
}
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq)]
pub enum Float {
F16(f16),
F32(f32),
F64(f64),
}
impl Eq for Float {}
impl Hash for Float {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Float::F16(v) => v.to_ne_bytes().hash(state),
Float::F32(v) => v.to_ne_bytes().hash(state),
Float::F64(v) => v.to_ne_bytes().hash(state),
}
}
}
#[derive(Debug, Display, Deref, DerefMut, Clone, Copy, From, PartialEq, Eq, Hash)]
#[debug("{:?}", _0)]
#[display("{}", _0)]
pub struct Const<T>(T);
impl<'l, T: 'l> Into<AnyConst<'l>> for &'l Const<T>
where
for<'a> &'a T: Into<AnyConst<'a>>,
{
fn into(self) -> AnyConst<'l> {
(&self.0).into()
}
}
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)]
#[from(forward)]
pub enum AnyConst<'l> {
#[display("void")]
#[debug("void")]
Void,
#[debug("{:?}", _0)]
#[display("{}", _0)]
Bool(bool),
#[debug("{:?}", _0)]
#[display("{}", _0)]
Char(char),
#[debug("{:?}", _0)]
#[display("{}", _0)]
Int(Int),
#[debug("{:?}", _0)]
#[display("{}", _0)]
Float(Float),
#[debug("{:?}", _0)]
#[display("\"{}\"", _0)]
Str(&'l str),
#[debug("{:?}", _0)]
#[display("{}", _0)]
Function(&'l Function<'l>),
Type(Type<'l>),
}
impl<'l> AnyConst<'l> {
pub fn ty(&self) -> Type<'l> {
match self {
Self::Void => Type::Void,
Self::Bool(_) => Type::Bool,
Self::Char(_) => Type::Char,
Self::Type(_) => Type::Type,
Self::Int(Int::I8(_)) => Type::I8,
Self::Int(Int::I16(_)) => Type::I16,
Self::Int(Int::I32(_)) => Type::I32,
Self::Int(Int::I64(_)) => Type::I64,
Self::Int(Int::I128(_)) => Type::I128,
Self::Int(Int::U8(_)) => Type::U8,
Self::Int(Int::U16(_)) => Type::U16,
Self::Int(Int::U32(_)) => Type::U32,
Self::Int(Int::U64(_)) => Type::U64,
Self::Int(Int::U128(_)) => Type::U128,
Self::Float(Float::F16(_)) => Type::F16,
Self::Float(Float::F32(_)) => Type::F32,
Self::Float(Float::F64(_)) => Type::F64,
_ => todo!("{self:?}"),
}
}
}
+14 -132
View File
@@ -1,13 +1,11 @@
use crate::{
assembly::Context,
functions::{Function, ir::Instruction},
types::Type,
};
use crate::{functions::ir::Instruction, types::Type};
use bitflags::bitflags;
use derive_more::{Debug, Display};
use half::f16;
use derive_more::{Debug, Display, *};
use std::hash::Hash;
mod constants;
pub use constants::*;
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ValueFlags: u16 {
@@ -20,140 +18,24 @@ bitflags! {
}
}
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Int {
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
}
#[derive(Debug, Display, Clone, Copy, PartialEq)]
pub enum Float {
F16(f16),
F32(f32),
F64(f64),
}
impl Eq for Float {}
impl Hash for Float {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Float::F16(v) => v.to_ne_bytes().hash(state),
Float::F32(v) => v.to_ne_bytes().hash(state),
Float::F64(v) => v.to_ne_bytes().hash(state),
}
}
}
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ConstData<'l> {
#[display("()")]
#[debug("()")]
Void,
#[debug("{:?}", _0)]
#[display("{}", _0)]
Bool(bool),
#[debug("{:?}", _0)]
#[display("{}", _0)]
Char(char),
#[debug("{:?}", _0)]
#[display("\"{}\"", _0)]
Str(&'l str),
#[debug("{:?}", _0)]
#[display("{}", _0)]
Int(Int),
#[debug("{:?}", _0)]
#[display("{}", _0)]
Float(Float),
#[debug("{:?}", _0)]
#[display("{}", _0)]
Function(&'l Function<'l>),
}
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash)]
#[debug("{:?}", data)]
#[display("{}", data)]
pub struct Const<'l> {
pub ctx: &'l Context<'l>,
pub data: ConstData<'l>,
}
impl<'l> Const<'l> {
pub fn flags(&self) -> ValueFlags {
ValueFlags::Const
}
pub fn ty(&self) -> Type<'l> {
let ctx = self.ctx;
match self.data {
ConstData::Void => ctx.void_t(),
ConstData::Char(_) => ctx.char_t(),
ConstData::Bool(_) => ctx.bool_t(),
ConstData::Str(_) => ctx.const_str_t(),
ConstData::Int(v) => match v {
Int::I8(_) => ctx.i8_t(),
Int::I16(_) => ctx.i16_t(),
Int::I32(_) => ctx.i32_t(),
Int::I64(_) => ctx.i64_t(),
Int::I128(_) => ctx.i128_t(),
Int::U8(_) => ctx.u8_t(),
Int::U16(_) => ctx.u16_t(),
Int::U32(_) => ctx.u32_t(),
Int::U64(_) => ctx.u64_t(),
Int::U128(_) => ctx.u128_t(),
},
ConstData::Float(v) => match v {
Float::F16(_) => ctx.f16_t(),
Float::F32(_) => ctx.f32_t(),
Float::F64(_) => ctx.f64_t(),
},
ConstData::Function(v) => Type::Func(v.ty),
}
}
}
impl<'l> Into<Value<'l>> for &'l Const<'l> {
fn into(self) -> Value<'l> {
Value::Const(self)
}
}
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)]
pub enum Value<'l> {
#[display("{}", _0)]
Const(&'l Const<'l>),
#[display("{}", _0)]
Type(Type<'l>),
#[display("<function>")]
Func(&'l Function<'l>),
#[display("%{}", _0.id())]
#[display("{_0}")]
Constant(AnyConst<'l>),
#[display("{_0}")]
Instruction(&'l Instruction<'l>),
}
impl<'l> Value<'l> {
pub fn flags(&self) -> ValueFlags {
match self {
Value::Const(c) => c.flags(),
Value::Type(_) => ValueFlags::Type,
Value::Func(_) => ValueFlags::Function,
Value::Instruction(i) => i.value_flags(),
impl From<Int> for Value<'_> {
fn from(value: Int) -> Self {
Value::Constant(AnyConst::Int(value))
}
}
impl<'l> Value<'l> {
pub fn ty(&self) -> Type<'l> {
match self {
Value::Const(v) => v.ty(),
Value::Type(v) => v.ctx().type_t(),
Value::Func(v) => Type::Func(v.ty),
Value::Constant(v) => v.ty(),
Value::Instruction(v) => v.value_ty(),
}
}
+32 -19
View File
@@ -3,10 +3,11 @@ use arcstr::literal_substr;
use leaf_allocators::SyncAllocator;
use leaf_assembly::{
assembly::{Assembly, AssemblyIdentifier, Context},
values::Value,
types::{FloatT, IntT, Type},
values::{AnyConst, Value},
};
use leaf_parser::SourceCode;
use std::{collections::HashMap, sync::Arc};
use std::{collections::HashMap, sync::Arc, u32};
mod error;
mod scope;
@@ -49,23 +50,35 @@ impl<'l> CompilationContext<'l> {
.iter()
.map(|src| {
let mut scope = Scope::new(assembly, src.clone());
scope.insert(literal_substr!("void"), Value::Type(self.ctx.void_t()));
scope.insert(literal_substr!("i8"), Value::Type(self.ctx.i8_t()));
scope.insert(literal_substr!("i16"), Value::Type(self.ctx.i16_t()));
scope.insert(literal_substr!("i32"), Value::Type(self.ctx.i32_t()));
scope.insert(literal_substr!("i64"), Value::Type(self.ctx.i64_t()));
scope.insert(literal_substr!("i128"), Value::Type(self.ctx.i128_t()));
scope.insert(literal_substr!("isize"), Value::Type(self.ctx.isize_t()));
scope.insert(literal_substr!("u8"), Value::Type(self.ctx.u8_t()));
scope.insert(literal_substr!("u16"), Value::Type(self.ctx.u16_t()));
scope.insert(literal_substr!("u32"), Value::Type(self.ctx.u32_t()));
scope.insert(literal_substr!("u64"), Value::Type(self.ctx.u64_t()));
scope.insert(literal_substr!("u128"), Value::Type(self.ctx.u128_t()));
scope.insert(literal_substr!("usize"), Value::Type(self.ctx.usize_t()));
scope.insert(literal_substr!("f16"), Value::Type(self.ctx.f16_t()));
scope.insert(literal_substr!("f32"), Value::Type(self.ctx.f32_t()));
scope.insert(literal_substr!("f64"), Value::Type(self.ctx.f64_t()));
scope.insert(literal_substr!("type"), Value::Type(self.ctx.type_t()));
macro_rules! insert_types {
($($id:literal : $ty:expr,)*) => {
$(
scope.insert(
literal_substr!($id),
Value::Constant(AnyConst::Type($ty.into())),
);
)*
};
}
insert_types! {
"void": Type::Void,
"i8": Type::I8,
"i16": Type::I16,
"i32": Type::I32,
"i64": Type::I64,
"i128": Type::I128,
"isize": Type::ISIZE,
"u8": Type::U8,
"u16": Type::U16,
"u32": Type::U32,
"u64": Type::U64,
"u128": Type::U128,
"usize": Type::USIZE,
"f16": Type::F16,
"f32": Type::F32,
"f64": Type::F64,
"type": Type::Type,
}
scope
})
.collect();
+6 -4
View File
@@ -1,8 +1,8 @@
use arcstr::Substr;
use leaf_assembly::{
assembly::Assembly,
types::{Type, derivations::MakeTypeDerivations},
values::Value,
types::Type,
values::{AnyConst, Value},
};
use leaf_parser::{
SourceCode,
@@ -91,12 +91,14 @@ impl<'l> Scope<'l> {
par_ty.push(ty);
}
let fn_ty = ret_ty.make_fn(par_ty);
Ok(Value::Func(self.assembly.create_function(fn_ty)))
Ok(Value::Constant(AnyConst::Function(
self.assembly.create_function(fn_ty),
)))
}
fn assert_type(&self, val: Value<'l>) -> Result<Type<'l>, CompilationError> {
match val {
Value::Type(ty) => Ok(ty),
Value::Constant(AnyConst::Type(ty)) => Ok(ty),
_ => Err(CompilationError {
kind: Kind::NotAType,
message: format!("Value is not a type."),
+15 -33
View File
@@ -5,8 +5,8 @@ use leaf_assembly::{
Function,
ir::{Cmp, Instruction, InstructionVariant},
},
types::{Type, intrinsics::IntT},
values::{Const, ConstData, Int, Value},
types::{IntT, Type},
values::{AnyConst, Const, Int, Value},
};
use scc::HashMap;
use std::{alloc::Layout, fmt::Debug, ops::Range, sync::Arc};
@@ -112,12 +112,9 @@ impl<'l> InstructionCacheEntry<'l> {
..
},
),
Value::Const(Const {
data: ConstData::Int(Int::U8(v)),
ctx,
}),
Value::Constant(AnyConst::Int(Int::U8(v))),
) => {
assert_eq!(ctx.u8_t(), *ty);
assert_eq!(Type::U8, *ty);
opcodes.push(OpCode::Store_CL_U8(*v, memory_ranges[&t.id()].start));
}
@@ -128,12 +125,9 @@ impl<'l> InstructionCacheEntry<'l> {
..
},
),
Value::Const(Const {
data: ConstData::Int(Int::U16(v)),
ctx,
}),
Value::Constant(AnyConst::Int(Int::U16(v))),
) => {
assert_eq!(ctx.u16_t(), *ty);
assert_eq!(Type::U16, *ty);
opcodes.push(OpCode::Store_CL_U16(*v, memory_ranges[&t.id()].start));
}
@@ -144,12 +138,9 @@ impl<'l> InstructionCacheEntry<'l> {
..
},
),
Value::Const(Const {
data: ConstData::Int(Int::U32(v)),
ctx,
}),
Value::Constant(AnyConst::Int(Int::U32(v))),
) => {
assert_eq!(ctx.u32_t(), *ty);
assert_eq!(Type::U32, *ty);
opcodes.push(OpCode::Store_CL_U32(*v, memory_ranges[&t.id()].start));
}
@@ -160,12 +151,9 @@ impl<'l> InstructionCacheEntry<'l> {
..
},
),
Value::Const(Const {
data: ConstData::Int(Int::U64(v)),
ctx,
}),
Value::Constant(AnyConst::Int(Int::U64(v))),
) => {
assert_eq!(ctx.u64_t(), *ty);
assert_eq!(Type::U64, *ty);
opcodes.push(OpCode::Store_CL_U64(*v, memory_ranges[&t.id()].start));
}
@@ -212,10 +200,7 @@ impl<'l> InstructionCacheEntry<'l> {
InstructionVariant::IAdd(
Value::Instruction(a),
Value::Const(Const {
data: ConstData::Int(Int::U32(b)),
ctx,
}),
Value::Constant(AnyConst::Int(Int::U32(b))),
) => {
assert!(matches!(
a.value_ty(),
@@ -226,16 +211,13 @@ impl<'l> InstructionCacheEntry<'l> {
})
));
let a = memory_ranges[&a.id()].start;
let c = alloc_range!(ctx.u32_t(), inst.id()).start;
let c = alloc_range!(Type::U32, inst.id()).start;
opcodes.push(OpCode::Add_LC_U32(a, *b, c));
}
InstructionVariant::ICmp(
Value::Instruction(a),
Value::Const(Const {
data: ConstData::Int(Int::U32(b)),
ctx,
}),
Value::Constant(AnyConst::Int(Int::U32(b))),
cmp,
) => {
assert!(matches!(
@@ -247,7 +229,7 @@ impl<'l> InstructionCacheEntry<'l> {
})
));
let a = memory_ranges[&a.id()].start;
let target = alloc_range!(ctx.bool_t(), inst.id()).start;
let target = alloc_range!(Type::Bool, inst.id()).start;
match *cmp {
Cmp::Eq => opcodes.push(OpCode::CmpEq_LC_U32(a, *b, target)),
Cmp::Lt => opcodes.push(OpCode::CmpLt_LC_U32(a, *b, target)),
@@ -284,7 +266,7 @@ impl<'l> InstructionCacheEntry<'l> {
true_case,
false_case,
} => {
assert!(matches!(i.value_ty(), Type::Bool(_)));
assert!(matches!(i.value_ty(), Type::Bool));
backpatch.push(opcodes.len());
opcodes.push(OpCode::Branch {
cond: memory_ranges[&i.id()].start,
+3 -6
View File
@@ -6,8 +6,8 @@ use fxhash::FxHashMap;
use leaf_assembly::{
assembly::Ctx,
functions::Function,
types::{Type, intrinsics::IntT},
values::{Const, ConstData, Int, Value},
types::{IntT, Type},
values::{AnyConst, Int, Value},
};
use smallvec::SmallVec;
use std::{ops::Range, sync::Arc};
@@ -211,10 +211,7 @@ impl<'l> Interpreter<'l> {
fn push_ctx_val(&mut self, sp: &mut usize, value: &Value) -> Range<usize> {
let ptr = &self.stack[*sp] as *const u8;
match value {
Value::Const(Const {
data: ConstData::Int(Int::U32(v)),
..
}) => {
Value::Constant(AnyConst::Int(Int::U32(v))) => {
*sp += ptr.align_offset(align_of::<u32>());
let range = *sp..*sp + size_of::<u32>();
self.stack[range.clone()].copy_from_slice(&v.to_ne_bytes());
+3 -3
View File
@@ -1,5 +1,5 @@
use fxhash::FxBuildHasher;
use leaf_assembly::types::{Type, derivations::PtrT, intrinsics::IntT};
use leaf_assembly::types::{IntT, Type, derivations::PtrT};
use scc::HashMap;
use std::{
alloc::Layout,
@@ -43,7 +43,7 @@ impl<'l> GetLayout<Type<'_>> for LayoutCache<'l> {
fn get_layout(&self, ty: Type<'_>) -> Arc<Self::LayoutT> {
match ty {
Type::Void(_) => {
Type::Void => {
static LAYOUT: OnceLock<Arc<TypeLayout>> = OnceLock::new();
LAYOUT
.get_or_init(|| {
@@ -55,7 +55,7 @@ impl<'l> GetLayout<Type<'_>> for LayoutCache<'l> {
.clone()
}
Type::Bool(_) => {
Type::Bool => {
static LAYOUT: OnceLock<Arc<TypeLayout>> = OnceLock::new();
LAYOUT
.get_or_init(|| {
+12 -21
View File
@@ -1,7 +1,8 @@
use leaf_allocators::SyncArenaAllocator;
use leaf_assembly::assembly::{Assembly, AssemblyIdentifier, Context, CreateConst, Version};
use leaf_assembly::assembly::{AssemblyIdentifier, Context, Version};
use leaf_assembly::functions::ir::Cmp;
use leaf_assembly::types::derivations::MakeTypeDerivations;
use leaf_assembly::types::Type;
use leaf_assembly::values::Int;
use leaf_interpreter::interpreter::{AnyValue, Error, Interpreter, NativeFunction};
use std::ffi::CStr;
use std::time::{Duration, Instant};
@@ -14,32 +15,24 @@ fn main() {
name: "test".into(),
});
let puts = assembly.create_function(
context
.void_t()
.make_fn([context.u8_t().make_ptr(false).into()]),
);
let puts = assembly.create_function(Type::Void.make_fn([Type::U8.make_ptr(false).into()]));
let print_u32 = assembly.create_function(context.void_t().make_fn([context.u32_t().into()]));
let print_u32 = assembly.create_function(Type::Void.make_fn([Type::U32.into()]));
let random_func = {
let func = assembly.create_function(context.u32_t().make_fn([]));
let func = assembly.create_function(Type::U32.make_fn([]));
let mut builder = func.create_body().unwrap();
let loop_check = builder.create_block();
let loop_body = builder.create_block();
let loop_end = builder.create_block();
let var0 = builder.stack_alloc(context.u32_t()).unwrap();
let var1 = builder.stack_alloc(context.u32_t()).unwrap();
let var0 = builder.stack_alloc(Type::U32).unwrap();
let var1 = builder.stack_alloc(Type::U32).unwrap();
builder
.store(var0, context.create_const(42u32).into())
.unwrap();
builder.store(var0, Int::U32(42).into()).unwrap();
builder
.store(var1, context.create_const(0u32).into())
.unwrap();
builder.store(var1, Int::U32(0u32).into()).unwrap();
builder.jump(loop_check).unwrap();
builder.set_current_block(loop_check);
@@ -49,14 +42,12 @@ fn main() {
let c = builder.add(a, b).unwrap();
builder.call(print_u32, vec![c]).unwrap();
let cond = builder
.cmp(c, context.create_const(69u32).into(), Cmp::Lt)
.unwrap();
let cond = builder.cmp(c, Int::U32(69u32).into(), Cmp::Lt).unwrap();
builder.branch(cond, loop_body, loop_end).unwrap();
builder.set_current_block(loop_body);
let v = builder.load(var1).unwrap();
let v = builder.add(v, context.create_const(1u32).into()).unwrap();
let v = builder.add(v, Int::U32(1u32).into()).unwrap();
builder.store(var1, v).unwrap();
builder.jump(loop_check).unwrap();