diff --git a/assembly/Cargo.toml b/assembly/Cargo.toml index 5445556..6423dd3 100644 --- a/assembly/Cargo.toml +++ b/assembly/Cargo.toml @@ -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" diff --git a/assembly/src/assembly.rs b/assembly/src/assembly.rs index c864d61..73a41f3 100644 --- a/assembly/src/assembly.rs +++ b/assembly/src/assembly.rs @@ -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>>, assemblies: HashMap>, } @@ -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>, } 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::::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 }), - } -} diff --git a/assembly/src/functions/ir.rs b/assembly/src/functions/ir.rs index 0602fcb..2dc4632 100644 --- a/assembly/src/functions/ir.rs +++ b/assembly/src/functions/ir.rs @@ -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); 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> 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!( diff --git a/assembly/src/types/derivations.rs b/assembly/src/types/derivations.rs index b676c13..87a0aca 100644 --- a/assembly/src/types/derivations.rs +++ b/assembly/src/types/derivations.rs @@ -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> 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> 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> for &'l FuncT<'l> { - fn into(self) -> Type<'l> { - Type::Func(self) - } -} - -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>) -> &'l FuncT<'l>; -} - -impl<'l, T: 'l + Into>> MakeTypeDerivations<'l> for T { - fn make_ptr(self, mutable: bool) -> &'l PtrT<'l> { - let ty = self.into(); - ty.ctx().derivations.make_ptr(ty, mutable) +impl<'l> Type<'l> { + pub fn make_ptr(&self, mutable: bool) -> &'l PtrT<'l> { + self.ctx().derivations.make_ptr(*self, mutable) } - fn make_ref(self, mutable: bool) -> &'l RefT<'l> { - let ty = self.into(); - ty.ctx().derivations.make_ref(ty, mutable) + pub fn make_ref(&self, mutable: bool) -> &'l RefT<'l> { + self.ctx().derivations.make_ref(*self, mutable) } - fn make_fn(self, par_t: impl IntoIterator>) -> &'l FuncT<'l> { - let ty = self.into(); - ty.ctx() + pub fn make_fn(&self, par_t: impl IntoIterator>) -> &'l FuncT<'l> { + self.ctx() .derivations - .make_fn(ty, par_t.into_iter().collect()) + .make_fn(*self, par_t.into_iter().collect()) } } diff --git a/assembly/src/types/intrinsics.rs b/assembly/src/types/intrinsics.rs deleted file mode 100644 index b475a82..0000000 --- a/assembly/src/types/intrinsics.rs +++ /dev/null @@ -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> 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> 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> 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> 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> 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> 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> for &'l FloatT<'l> { - fn into(self) -> Type<'l> { - Type::Float(self) - } -} diff --git a/assembly/src/types/mod.rs b/assembly/src/types/mod.rs index 6d2e7d8..335796a 100644 --- a/assembly/src/types/mod.rs +++ b/assembly/src/types/mod.rs @@ -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 = 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 }); +} diff --git a/assembly/src/values/constants.rs b/assembly/src/values/constants.rs new file mode 100644 index 0000000..2910848 --- /dev/null +++ b/assembly/src/values/constants.rs @@ -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(&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); + +impl<'l, T: 'l> Into> for &'l Const +where + for<'a> &'a T: Into>, +{ + 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:?}"), + } + } +} diff --git a/assembly/src/values/mod.rs b/assembly/src/values/mod.rs index 0e89a0e..6cb8211 100644 --- a/assembly/src/values/mod.rs +++ b/assembly/src/values/mod.rs @@ -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(&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> 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("")] - 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 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(), } } diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index d76dd33..232aeeb 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -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(); diff --git a/compiler/src/scope.rs b/compiler/src/scope.rs index 662061a..a9ba2f5 100644 --- a/compiler/src/scope.rs +++ b/compiler/src/scope.rs @@ -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, 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."), diff --git a/interpreter/src/instruction_cache.rs b/interpreter/src/instruction_cache.rs index 4f8dad9..031e5d9 100644 --- a/interpreter/src/instruction_cache.rs +++ b/interpreter/src/instruction_cache.rs @@ -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, diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 633c33a..f6859a6 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -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 { 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::()); let range = *sp..*sp + size_of::(); self.stack[range.clone()].copy_from_slice(&v.to_ne_bytes()); diff --git a/interpreter/src/layout_cache.rs b/interpreter/src/layout_cache.rs index 17762b0..4080b32 100644 --- a/interpreter/src/layout_cache.rs +++ b/interpreter/src/layout_cache.rs @@ -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> for LayoutCache<'l> { fn get_layout(&self, ty: Type<'_>) -> Arc { match ty { - Type::Void(_) => { + Type::Void => { static LAYOUT: OnceLock> = OnceLock::new(); LAYOUT .get_or_init(|| { @@ -55,7 +55,7 @@ impl<'l> GetLayout> for LayoutCache<'l> { .clone() } - Type::Bool(_) => { + Type::Bool => { static LAYOUT: OnceLock> = OnceLock::new(); LAYOUT .get_or_init(|| { diff --git a/interpreter/src/main.rs b/interpreter/src/main.rs index 98be31f..fa58839 100644 --- a/interpreter/src/main.rs +++ b/interpreter/src/main.rs @@ -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();