Casting, GEPs, partial LLVM backend
This commit is contained in:
@@ -1,16 +1,18 @@
|
||||
use crate::{
|
||||
functions::Function,
|
||||
types::derivations::{FuncT, TypeDerivations},
|
||||
values::Const,
|
||||
};
|
||||
use derive_more::Debug;
|
||||
use derive_more::{Debug, Display};
|
||||
use fxhash::FxBuildHasher;
|
||||
use leaf_allocators::SyncAllocator;
|
||||
use scc::HashMap;
|
||||
use std::{borrow::Cow, hash::Hash, sync::OnceLock};
|
||||
use std::{borrow::Cow, fmt::Display, hash::Hash, sync::OnceLock};
|
||||
|
||||
#[derive(derive_more::Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[derive(
|
||||
derive_more::Debug, Display, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
|
||||
)]
|
||||
#[debug("{major}.{minor}.{patch}.{build}")]
|
||||
#[display("{major}.{minor}.{patch}.{build}")]
|
||||
pub struct Version {
|
||||
pub major: u16,
|
||||
pub minor: u16,
|
||||
@@ -18,7 +20,8 @@ pub struct Version {
|
||||
pub build: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[derive(Debug, Display, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[display("{name} v{version}")]
|
||||
pub struct AssemblyIdentifier {
|
||||
pub version: Version,
|
||||
pub name: Cow<'static, str>,
|
||||
@@ -57,6 +60,10 @@ impl<'l> Context<'l> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn alloc(&self) -> &'l dyn SyncAllocator {
|
||||
self.alloc
|
||||
}
|
||||
|
||||
pub fn get_assembly(&'l self, ident: &AssemblyIdentifier) -> Option<&'l Assembly<'l>> {
|
||||
self.assemblies.get_sync(ident).map(|v| *v)
|
||||
}
|
||||
@@ -114,6 +121,10 @@ impl<'l> Assembly<'l> {
|
||||
self.ctx
|
||||
}
|
||||
|
||||
pub fn ident(&self) -> &AssemblyIdentifier {
|
||||
&self.ident
|
||||
}
|
||||
|
||||
pub fn create_function(&'l self, ty: &'l FuncT<'l>) -> &'l Function<'l> {
|
||||
let func = self.ctx.alloc.alloc(Function {
|
||||
ty,
|
||||
@@ -125,6 +136,10 @@ impl<'l> Assembly<'l> {
|
||||
func
|
||||
}
|
||||
|
||||
pub fn functions(&'l self) -> boxcar::vec::Iter<'l, &'l Function<'l>> {
|
||||
self.functions.iter()
|
||||
}
|
||||
|
||||
pub fn find_function(
|
||||
&'l self,
|
||||
filter: impl Fn(&'l Function<'l>) -> bool,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
assembly::Ctx,
|
||||
functions::{Function, FunctionBody},
|
||||
types::{Type, derivations::*},
|
||||
types::{IntT, Type, derivations::*},
|
||||
values::{Value, ValueFlags},
|
||||
};
|
||||
use derive_more::{Debug, Display};
|
||||
@@ -25,15 +25,15 @@ impl Eq for Instruction<'_> {}
|
||||
|
||||
impl PartialEq for Instruction<'_> {
|
||||
#[inline]
|
||||
fn eq(&self, _: &Self) -> bool {
|
||||
false
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
std::ptr::eq(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Instruction<'_> {
|
||||
#[inline]
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
(self as *const Self).hash(state);
|
||||
std::ptr::hash(self, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,10 @@ impl<'l> Instruction<'l> {
|
||||
pub fn value_flags(&self) -> ValueFlags {
|
||||
match self.variant {
|
||||
InstructionVariant::StackAlloc(_) => ValueFlags::LValue,
|
||||
InstructionVariant::GetElementPtr(v, _) if v.flags().contains(ValueFlags::LValue) => {
|
||||
ValueFlags::LValue
|
||||
}
|
||||
InstructionVariant::Reinterpret(_, _, f) => f,
|
||||
_ => ValueFlags::empty(),
|
||||
}
|
||||
}
|
||||
@@ -73,12 +77,35 @@ impl<'l> Instruction<'l> {
|
||||
Type::Ptr(PtrT { base, .. }) => *base,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
InstructionVariant::GetElementPtr(v, _) => match v.ty() {
|
||||
Type::Ptr(PtrT {
|
||||
base: Type::Array(ArrayT { base, .. }),
|
||||
mutable,
|
||||
}) => base.make_ptr(*mutable).into(),
|
||||
Type::Ref(RefT {
|
||||
base: Type::Array(ArrayT { base, .. }),
|
||||
mutable,
|
||||
}) => base.make_ref(*mutable).into(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
InstructionVariant::IAdd(a, _) => a.ty(),
|
||||
InstructionVariant::ISub(a, _) => a.ty(),
|
||||
InstructionVariant::IMul(a, _) => a.ty(),
|
||||
InstructionVariant::IDiv(a, _) => a.ty(),
|
||||
InstructionVariant::IMod(a, _) => a.ty(),
|
||||
InstructionVariant::SExt(_, t) => Type::Int(t),
|
||||
InstructionVariant::ZExt(_, t) => Type::Int(t),
|
||||
InstructionVariant::Trunc(_, t) => Type::Int(t),
|
||||
InstructionVariant::FAdd(a, _) => a.ty(),
|
||||
InstructionVariant::FSub(a, _) => a.ty(),
|
||||
InstructionVariant::FMul(a, _) => a.ty(),
|
||||
InstructionVariant::FDiv(a, _) => a.ty(),
|
||||
InstructionVariant::FMod(a, _) => a.ty(),
|
||||
InstructionVariant::ICmp(_, _, _) => Type::Bool,
|
||||
InstructionVariant::Call(f, _) => f.ty.ret_t,
|
||||
InstructionVariant::Jump(_) => Type::Void,
|
||||
InstructionVariant::Branch { .. } => Type::Void,
|
||||
InstructionVariant::Reinterpret(_, t, _) => t,
|
||||
_ => todo!("{self:?}"),
|
||||
}
|
||||
}
|
||||
@@ -87,6 +114,7 @@ impl<'l> Instruction<'l> {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Cmp {
|
||||
Eq,
|
||||
Ne,
|
||||
Lt,
|
||||
Gt,
|
||||
Le,
|
||||
@@ -100,11 +128,21 @@ pub enum InstructionVariant<'l> {
|
||||
|
||||
Load(Value<'l>),
|
||||
Store(Value<'l>, Value<'l>),
|
||||
GetElementPtr(Value<'l>, Value<'l>),
|
||||
|
||||
IAdd(Value<'l>, Value<'l>),
|
||||
ISub(Value<'l>, Value<'l>),
|
||||
IMul(Value<'l>, Value<'l>),
|
||||
IDiv(Value<'l>, Value<'l>),
|
||||
IMod(Value<'l>, Value<'l>),
|
||||
SExt(Value<'l>, IntT),
|
||||
ZExt(Value<'l>, IntT),
|
||||
Trunc(Value<'l>, IntT),
|
||||
FAdd(Value<'l>, Value<'l>),
|
||||
FSub(Value<'l>, Value<'l>),
|
||||
FMul(Value<'l>, Value<'l>),
|
||||
FDiv(Value<'l>, Value<'l>),
|
||||
FMod(Value<'l>, Value<'l>),
|
||||
|
||||
ICmp(Value<'l>, Value<'l>, Cmp),
|
||||
FCmp(Value<'l>, Value<'l>, Cmp),
|
||||
@@ -117,6 +155,8 @@ pub enum InstructionVariant<'l> {
|
||||
false_case: &'l Block<'l>,
|
||||
},
|
||||
Return(Option<Value<'l>>),
|
||||
|
||||
Reinterpret(Value<'l>, Type<'l>, ValueFlags),
|
||||
}
|
||||
|
||||
impl InstructionVariant<'_> {
|
||||
@@ -137,10 +177,20 @@ impl std::fmt::Debug for InstructionVariant<'_> {
|
||||
Self::GCAlloc(ty) => write!(f, "gcalloc {ty}"),
|
||||
Self::Load(v) => write!(f, "load {v}"),
|
||||
Self::Store(t, v) => write!(f, "store {t}, {v}"),
|
||||
Self::GetElementPtr(t, v) => write!(f, "gep {t}, {v}"),
|
||||
Self::IAdd(a, b) => write!(f, "iadd {a}, {b}"),
|
||||
Self::ISub(a, b) => write!(f, "isub {a}, {b}"),
|
||||
Self::IMul(a, b) => write!(f, "imul {a}, {b}"),
|
||||
Self::IDiv(a, b) => write!(f, "idiv {a}, {b}"),
|
||||
Self::IMod(a, b) => write!(f, "imod {a}, {b}"),
|
||||
Self::SExt(a, b) => write!(f, "sext {a}, {b}"),
|
||||
Self::ZExt(a, b) => write!(f, "zext {a}, {b}"),
|
||||
Self::Trunc(a, b) => write!(f, "trunc {a}, {b}"),
|
||||
Self::FAdd(a, b) => write!(f, "fadd {a}, {b}"),
|
||||
Self::FSub(a, b) => write!(f, "fsub {a}, {b}"),
|
||||
Self::FMul(a, b) => write!(f, "fmul {a}, {b}"),
|
||||
Self::FDiv(a, b) => write!(f, "fdiv {a}, {b}"),
|
||||
Self::FMod(a, b) => write!(f, "fmod {a}, {b}"),
|
||||
Self::ICmp(a, b, c) => write!(f, "icmp {c:?} {a}, {b}"),
|
||||
Self::FCmp(a, b, c) => write!(f, "fcmp {c:?} {a}, {b}"),
|
||||
Self::Call(func, args) => {
|
||||
@@ -164,6 +214,7 @@ impl std::fmt::Debug for InstructionVariant<'_> {
|
||||
Self::Jump(b) => write!(f, "jump #{}", b.id),
|
||||
Self::Return(None) => write!(f, "return"),
|
||||
Self::Return(Some(v)) => write!(f, "return {v}"),
|
||||
Self::Reinterpret(v, t, fl) => write!(f, "reinterpret {v} as {t} {fl:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -260,7 +311,23 @@ impl<'l> BlockBuilder<'l> {
|
||||
let inst = self.push_instruction(InstructionVariant::FAdd(a, b))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
_ => Err(format!("Cannot add values of type `{a_ty}` and `b_ty`.").into()),
|
||||
_ => Err(format!("Cannot add values of type `{a_ty}` and `{b_ty}`.").into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sub(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
let [a_ty, b_ty] = [a.ty(), b.ty()];
|
||||
|
||||
match (a_ty, b_ty) {
|
||||
(Type::Int(a_ty), Type::Int(b_ty)) if a_ty == b_ty => {
|
||||
let inst = self.push_instruction(InstructionVariant::ISub(a, b))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
(Type::Float(a_ty), Type::Float(b_ty)) if a_ty == b_ty => {
|
||||
let inst = self.push_instruction(InstructionVariant::FSub(a, b))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
_ => Err(format!("Cannot subtract values of type `{a_ty}` and `{b_ty}`.").into()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +343,52 @@ impl<'l> BlockBuilder<'l> {
|
||||
let inst = self.push_instruction(InstructionVariant::FMul(a, b))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
_ => Err(format!("Cannot add values of type `{a_ty}` and `b_ty`.").into()),
|
||||
_ => Err(format!("Cannot multiply values of type `{a_ty}` and `{b_ty}`.").into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn div(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
let [a_ty, b_ty] = [a.ty(), b.ty()];
|
||||
|
||||
match (a_ty, b_ty) {
|
||||
(Type::Int(a_ty), Type::Int(b_ty)) if a_ty == b_ty => {
|
||||
let inst = self.push_instruction(InstructionVariant::IDiv(a, b))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
(Type::Float(a_ty), Type::Float(b_ty)) if a_ty == b_ty => {
|
||||
let inst = self.push_instruction(InstructionVariant::FDiv(a, b))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
_ => Err(format!("Cannot divide values of type `{a_ty}` and `{b_ty}`.").into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modulo(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
let [a_ty, b_ty] = [a.ty(), b.ty()];
|
||||
|
||||
match (a_ty, b_ty) {
|
||||
(Type::Int(a_ty), Type::Int(b_ty)) if a_ty == b_ty => {
|
||||
let inst = self.push_instruction(InstructionVariant::IMod(a, b))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
(Type::Float(a_ty), Type::Float(b_ty)) if a_ty == b_ty => {
|
||||
let inst = self.push_instruction(InstructionVariant::FMod(a, b))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
_ => Err(format!("Cannot divide values of type `{a_ty}` and `{b_ty}`.").into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trunc(&mut self, val: Value<'l>, target: IntT) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
let ty = val.ty();
|
||||
match ty {
|
||||
Type::Int(a_ty) if a_ty.precision > target.precision => {
|
||||
let inst = self.push_instruction(InstructionVariant::Trunc(val, target))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
_ => Err(
|
||||
format!("Cannot truncate value of type `{ty}` to one of type `{target}`.").into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,10 +409,34 @@ impl<'l> BlockBuilder<'l> {
|
||||
let inst = self.push_instruction(InstructionVariant::FCmp(a, b, cmp))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
_ => Err(format!("Cannot compare values of type `{a_ty}` and `b_ty`.").into()),
|
||||
_ => Err(format!("Cannot compare values of type `{a_ty}` and `{b_ty}`.").into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gep(&mut self, value: Value<'l>, index: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
let v_ty = value.ty();
|
||||
let i_ty = index.ty();
|
||||
|
||||
let _ = match v_ty {
|
||||
Type::Ptr(PtrT {
|
||||
base: Type::Array(ArrayT { base, .. }),
|
||||
..
|
||||
}) => *base,
|
||||
Type::Ref(RefT {
|
||||
base: Type::Array(ArrayT { base, .. }),
|
||||
..
|
||||
}) => *base,
|
||||
_ => return Err(format!("Cannot index a value of type `{}`.", v_ty).into()),
|
||||
};
|
||||
|
||||
if i_ty != Type::USIZE {
|
||||
return Err(format!("Expeted index type `usize`, found {}.", i_ty).into());
|
||||
}
|
||||
|
||||
let inst = self.push_instruction(InstructionVariant::GetElementPtr(value, index))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
|
||||
pub fn jump(&mut self, block: &'l Block<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
if !std::ptr::eq(block.func, self.block.func) {
|
||||
return Err("Block does not belong to this function.".into());
|
||||
@@ -376,6 +512,21 @@ impl<'l> BlockBuilder<'l> {
|
||||
Ok(inst.into())
|
||||
}
|
||||
|
||||
/// WARNING: Incorrect usage of this function is very likely to cause catastrophic problems. Be sure to know what you're doing.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The target reinterpretation must maintain the IR's invariants.
|
||||
pub unsafe fn reinterpret(
|
||||
&mut self,
|
||||
value: Value<'l>,
|
||||
ty: Type<'l>,
|
||||
flags: ValueFlags,
|
||||
) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
let inst = self.push_instruction(InstructionVariant::Reinterpret(value, ty, flags))?;
|
||||
Ok(inst.into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_termination(&self) -> bool {
|
||||
match self.instructions.as_slice() {
|
||||
@@ -494,10 +645,26 @@ impl<'l> FunctionBodyBuilder<'l> {
|
||||
self.current_builder().add(a, b)
|
||||
}
|
||||
|
||||
pub fn sub(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
self.current_builder().sub(a, b)
|
||||
}
|
||||
|
||||
pub fn mul(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
self.current_builder().mul(a, b)
|
||||
}
|
||||
|
||||
pub fn div(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
self.current_builder().div(a, b)
|
||||
}
|
||||
|
||||
pub fn modulo(&mut self, a: Value<'l>, b: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
self.current_builder().modulo(a, b)
|
||||
}
|
||||
|
||||
pub fn trunc(&mut self, val: Value<'l>, target: IntT) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
self.current_builder().trunc(val, target)
|
||||
}
|
||||
|
||||
pub fn cmp(
|
||||
&mut self,
|
||||
a: Value<'l>,
|
||||
@@ -507,6 +674,10 @@ impl<'l> FunctionBodyBuilder<'l> {
|
||||
self.current_builder().cmp(a, b, cmp)
|
||||
}
|
||||
|
||||
pub fn gep(&mut self, value: Value<'l>, index: Value<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
self.current_builder().gep(value, index)
|
||||
}
|
||||
|
||||
pub fn jump(&mut self, block: &'l Block<'l>) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
self.current_builder().jump(block)
|
||||
}
|
||||
@@ -532,6 +703,20 @@ impl<'l> FunctionBodyBuilder<'l> {
|
||||
self.current_builder().ret(value)
|
||||
}
|
||||
|
||||
/// WARNING: Incorrect usage of this function is very likely to cause catastrophic problems. Be sure to know what you're doing.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The target reinterpretation must maintain the IR's invariants.
|
||||
pub unsafe fn reinterpret(
|
||||
&mut self,
|
||||
value: Value<'l>,
|
||||
ty: Type<'l>,
|
||||
flags: ValueFlags,
|
||||
) -> BlockBuilderResult<'l, Value<'l>> {
|
||||
unsafe { self.current_builder().reinterpret(value, ty, flags) }
|
||||
}
|
||||
|
||||
fn current_builder(&mut self) -> &mut BlockBuilder<'l> {
|
||||
&mut self.blocks[self.current_block]
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ impl<'l> Function<'l> {
|
||||
self.declaring_assembly.ctx()
|
||||
}
|
||||
|
||||
pub fn declaring_assembly(&self) -> &'l Assembly<'l> {
|
||||
self.declaring_assembly
|
||||
}
|
||||
|
||||
pub fn body(&self) -> Option<&FunctionBody<'l>> {
|
||||
self.body.get()
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ pub struct TypeDerivations<'l> {
|
||||
alloc: &'l dyn SyncAllocator,
|
||||
ptr_t: HashMap<(Type<'l>, bool), Type<'l>>,
|
||||
ref_t: HashMap<(Type<'l>, bool), Type<'l>>,
|
||||
arr_t: HashMap<(Type<'l>, Option<u32>), Type<'l>>,
|
||||
fun_t: HashMap<(Type<'l>, Arc<[Type<'l>]>), Type<'l>>,
|
||||
}
|
||||
|
||||
@@ -17,6 +18,7 @@ impl<'l> TypeDerivations<'l> {
|
||||
alloc,
|
||||
ptr_t: HashMap::new(),
|
||||
ref_t: HashMap::new(),
|
||||
arr_t: HashMap::new(),
|
||||
fun_t: HashMap::new(),
|
||||
}
|
||||
}
|
||||
@@ -43,6 +45,17 @@ impl<'l> TypeDerivations<'l> {
|
||||
ty
|
||||
}
|
||||
|
||||
pub fn make_array(&self, base: Type<'l>, length: Option<u32>) -> &'l ArrayT<'l> {
|
||||
let Type::Array(ty) = *self
|
||||
.arr_t
|
||||
.entry_sync((base, length))
|
||||
.or_insert_with(|| (&*self.alloc.alloc(ArrayT { base, length })).into())
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
ty
|
||||
}
|
||||
|
||||
pub fn make_fn(&'l self, ret_t: Type<'l>, par_t: Arc<[Type<'l>]>) -> &'l FuncT<'l> {
|
||||
let Type::Func(ty) = *self
|
||||
.fun_t
|
||||
@@ -95,6 +108,23 @@ pub struct RefT<'l> {
|
||||
pub mutable: bool,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct ArrayT<'l> {
|
||||
#[debug("{base}")]
|
||||
pub base: Type<'l>,
|
||||
pub length: Option<u32>,
|
||||
}
|
||||
|
||||
impl Display for ArrayT<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.length {
|
||||
None => write!(f, "[{}]", self.base),
|
||||
Some(len) => write!(f, "[{}; {len}]", self.base),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct FuncT<'l> {
|
||||
@@ -124,6 +154,10 @@ impl<'l> Type<'l> {
|
||||
self.ctx().derivations.make_ref(*self, mutable)
|
||||
}
|
||||
|
||||
pub fn make_array(&self, length: Option<u32>) -> &'l ArrayT<'l> {
|
||||
self.ctx().derivations.make_array(*self, length)
|
||||
}
|
||||
|
||||
pub fn make_fn(&self, par_t: impl IntoIterator<Item = Type<'l>>) -> &'l FuncT<'l> {
|
||||
self.ctx()
|
||||
.derivations
|
||||
|
||||
@@ -51,6 +51,10 @@ pub enum Type<'l> {
|
||||
#[display("{_0}")]
|
||||
Ref(&'l RefT<'l>),
|
||||
|
||||
#[debug("{_0:?}")]
|
||||
#[display("{_0}")]
|
||||
Array(&'l ArrayT<'l>),
|
||||
|
||||
#[debug("{_0:?}")]
|
||||
#[display("{_0}")]
|
||||
Func(&'l FuncT<'l>),
|
||||
@@ -82,8 +86,9 @@ impl<'l> Type<'l> {
|
||||
Type::ConstStr => None,
|
||||
Type::Int(_) => None,
|
||||
Type::Float(_) => None,
|
||||
Type::Ptr(_) => None,
|
||||
Type::Ref(_) => None,
|
||||
Type::Ptr(PtrT { base, .. }) => base.non_default_ctx(),
|
||||
Type::Ref(RefT { base, .. }) => base.non_default_ctx(),
|
||||
Type::Array(ArrayT { base, .. }) => base.non_default_ctx(),
|
||||
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()),
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
use crate::{functions::Function, types::Type, values::ValueFlags};
|
||||
use crate::{
|
||||
functions::Function,
|
||||
types::{Type, derivations::ArrayT},
|
||||
values::ValueFlags,
|
||||
};
|
||||
use derive_more::{Debug, *};
|
||||
use half::f16;
|
||||
use std::hash::Hash;
|
||||
@@ -55,6 +59,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
struct ListDisplay<'l>(&'l [AnyConst<'l>]);
|
||||
|
||||
impl std::fmt::Display for ListDisplay<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut list = f.debug_list();
|
||||
for ele in self.0 {
|
||||
list.entry(&format_args!("{ele}"));
|
||||
}
|
||||
list.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Display, Clone, Copy, From, TryInto, PartialEq, Eq, Hash)]
|
||||
#[from(forward)]
|
||||
pub enum AnyConst<'l> {
|
||||
@@ -79,6 +95,9 @@ pub enum AnyConst<'l> {
|
||||
#[debug("{:?}", _0)]
|
||||
#[display("{}", _0)]
|
||||
Function(&'l Function<'l>),
|
||||
#[debug("{:?}", _0)]
|
||||
#[display("{}", ListDisplay(_0))]
|
||||
Array(&'l [AnyConst<'l>]),
|
||||
Type(Type<'l>),
|
||||
}
|
||||
|
||||
@@ -104,6 +123,11 @@ impl<'l> AnyConst<'l> {
|
||||
Self::Float(Float::F16(_)) => Type::F16,
|
||||
Self::Float(Float::F32(_)) => Type::F32,
|
||||
Self::Float(Float::F64(_)) => Type::F64,
|
||||
Self::Array([]) => Type::Array(&ArrayT {
|
||||
base: Type::Void,
|
||||
length: Some(0),
|
||||
}),
|
||||
Self::Array(a @ [v, ..]) => Type::Array(v.ty().make_array(Some(a.len() as u32))),
|
||||
_ => todo!("{self:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ impl<'l> Value<'l> {
|
||||
|
||||
pub fn flags(&self) -> ValueFlags {
|
||||
match self {
|
||||
Value::Instruction(instruction) => instruction.value_flags(),
|
||||
Value::Instruction(v) => v.value_flags(),
|
||||
Value::Parameter(_, _) => ValueFlags::empty(),
|
||||
Value::Constant(c) => c.flags(),
|
||||
_ => todo!("{self:?}"),
|
||||
|
||||
Reference in New Issue
Block a user