Structs and comptime reflection stuff

This commit is contained in:
Mia
2026-03-07 01:42:06 +01:00
parent 81d1dfe3d3
commit fb84e09391
18 changed files with 1399 additions and 321 deletions
+88 -12
View File
@@ -5,7 +5,7 @@ use inkwell::{
module::Module,
targets::TargetMachine,
types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicTypeEnum, IntType},
values::{AnyValue, BasicValue, BasicValueEnum},
values::{AggregateValueEnum, AnyValue as LlvmAnyValue, BasicValue, BasicValueEnum, IntValue},
};
use leaf_assembly::{
assembly::Assembly,
@@ -15,9 +15,10 @@ use leaf_assembly::{
},
types::{
Type,
compound::{Field, StructT},
derivations::{ArrayT, FuncT, PtrT, RefT},
},
values::{AnyConst, Int, Value},
values::{AnyConst, AnyValue, Int, Value},
};
use scc::HashMap;
@@ -32,6 +33,7 @@ pub struct CompilationContext<'l> {
types: HashMap<Type<'l>, AnyTypeEnum<'l>, FxBuildHasher>,
modules: HashMap<&'l Assembly<'l>, Module<'l>, FxBuildHasher>,
functions: HashMap<(&'l Assembly<'l>, &'l Function<'l>), LlvmFunction<'l>, FxBuildHasher>,
fields: HashMap<(&'l StructT<'l>, &'l str), u32, FxBuildHasher>,
}
impl<'l> CompilationContext<'l> {
@@ -41,6 +43,7 @@ impl<'l> CompilationContext<'l> {
types: HashMap::default(),
modules: HashMap::default(),
functions: HashMap::default(),
fields: HashMap::default(),
native_int_ty: match target.get_target_data().get_pointer_byte_size(None) {
8 => ctx.i8_type(),
16 => ctx.i16_type(),
@@ -70,9 +73,9 @@ impl<'l> CompilationContext<'l> {
for (i, func) in assembly.functions() {
let ty = self.get_type(Type::Func(func.ty)).into_function_type();
let name = match func.name.get() {
Some(n) => *n,
None => &format!("<fn_{i}>"),
let name = match func.name {
"" => &format!("<fn_{i}>"),
_ => func.name,
};
self.functions
@@ -87,12 +90,12 @@ impl<'l> CompilationContext<'l> {
continue;
};
let mut values = FxHashMap::<Value, Option<BasicValueEnum>>::default();
let mut values = FxHashMap::<AnyValue, Option<BasicValueEnum>>::default();
for (i, ty) in func.ty.par_t.iter().enumerate() {
let ty = self.get_type(*ty);
if BasicMetadataTypeEnum::try_from(ty).is_ok() {
values.insert(
Value::Parameter(i, func),
AnyValue::Parameter(i, func),
Some(llvm_func.get_nth_param(values.len() as u32).unwrap()),
);
}
@@ -143,7 +146,7 @@ impl<'l> CompilationContext<'l> {
None
}
InstructionVariant::GetElementPtr(ptr, idx) => 'val: {
let pointee_ty = self.get_type(match inst.value_ty() {
let pointee_ty = self.get_type(match inst.ty() {
Type::Ptr(PtrT { base, .. }) => *base,
Type::Ref(RefT { base, .. }) => *base,
_ => unreachable!(),
@@ -159,6 +162,23 @@ impl<'l> CompilationContext<'l> {
Some(ptr.into())
}
}
InstructionVariant::GetElementVal(
val,
AnyValue::Constant(AnyConst::Str(fld)),
) => 'val: {
let Type::Struct(ty) = val.ty() else {
unreachable!()
};
let idx = match self.fields.get_sync(&(ty, *fld)) {
None => break 'val None,
Some(idx) => *idx,
};
let Some(val) = self.get_value(&values, val) else {
break 'val None;
};
let val = val.into_struct_value();
Some(builder.build_extract_value(val, idx, "").unwrap().into())
}
InstructionVariant::IAdd(lhs, rhs) => {
let lhs = self.get_value(&values, lhs).unwrap().into_int_value();
@@ -200,6 +220,11 @@ impl<'l> CompilationContext<'l> {
let target = self.get_type(Type::Int(*target)).into_int_type();
Some(builder.build_int_truncate(val, target, "").unwrap().into())
}
InstructionVariant::IntToPtr(v, ty) => {
let val = self.get_value(&values, v).unwrap().into_int_value();
let ptr = self.get_type(Type::Ptr(ty)).into_pointer_type();
Some(builder.build_int_to_ptr(val, ptr, "").unwrap().into())
}
InstructionVariant::ICmp(lhs, rhs, cmp) => {
let u = !is_signed(lhs.ty());
let cmp = match (cmp, u) {
@@ -219,6 +244,23 @@ impl<'l> CompilationContext<'l> {
Some(builder.build_int_compare(cmp, lhs, rhs, "").unwrap().into())
}
InstructionVariant::MakeStruct(ty, fields) => {
let ty = self.get_type(Type::Struct(ty)).into_struct_type();
let mut i = 0;
let mut val = ty.get_undef();
for field in *fields {
let Some(field) = self.get_value(&values, field) else {
continue;
};
val = builder
.build_insert_value(val, field, i, "")
.unwrap()
.into_struct_value();
i += 1;
}
Some(val.into())
}
InstructionVariant::Call(func, args) => {
// TODO This will fail with external assemblies. Fix this.
let func = *self.functions.get_sync(&(assembly, *func)).unwrap();
@@ -290,6 +332,7 @@ impl<'l> CompilationContext<'l> {
return *ty;
}
let mut post_insertion_action = None::<Box<dyn FnOnce()>>;
let llvm_ty = match ty {
Type::Void => self.ctx.void_type().into(),
Type::I8 | Type::U8 => self.ctx.i8_type().into(),
@@ -312,6 +355,7 @@ impl<'l> CompilationContext<'l> {
match ret_t {
AnyTypeEnum::VoidType(ty) => ty.fn_type(&par_t, false).into(),
AnyTypeEnum::IntType(ty) => ty.fn_type(&par_t, false).into(),
AnyTypeEnum::StructType(ty) => ty.fn_type(&par_t, false).into(),
_ => todo!("{ret_t:?}"),
}
}
@@ -329,23 +373,45 @@ impl<'l> CompilationContext<'l> {
_ => todo!("{ty:#?}"),
}
}
Type::Struct(s @ StructT { fields, name, .. }) => {
let ty = self.ctx.opaque_struct_type(name);
post_insertion_action = Some(Box::new(move || {
let mut types = vec![];
let fields = fields.get().unwrap();
for Field { ty, name, .. } in fields.values() {
if let Ok(ty) = self.get_type(*ty).try_into() {
self.fields
.insert_sync((s, name), types.len() as _)
.unwrap();
types.push(ty);
}
}
ty.set_body(&types, false);
}));
ty.into()
}
_ => todo!("{ty:#?}"),
};
self.types.entry_sync(ty).or_insert(llvm_ty);
if let Some(post_insertion_action) = post_insertion_action {
post_insertion_action();
}
llvm_ty
}
#[allow(clippy::mutable_key_type)]
fn get_value(
&self,
map: &FxHashMap<Value<'l>, Option<BasicValueEnum<'l>>>,
val: &Value<'l>,
map: &FxHashMap<AnyValue<'l>, Option<BasicValueEnum<'l>>>,
val: &AnyValue<'l>,
) -> Option<BasicValueEnum<'l>> {
if let Some(value) = map.get(val) {
return *value;
}
match val {
Value::Constant(val) => match val {
AnyValue::Constant(val) => match val {
AnyConst::Int(Int::U8(v)) => {
Some(self.ctx.i8_type().const_int(*v as u64, false).into())
}
@@ -359,6 +425,7 @@ impl<'l> CompilationContext<'l> {
AnyConst::Int(Int::USize(v)) => {
Some(self.native_int_ty.const_int(*v as u64, false).into())
}
AnyConst::Array([]) => todo!("{val:?}"),
AnyConst::Array(array) => {
let ty = self.get_type(array[0].ty());
@@ -367,7 +434,7 @@ impl<'l> CompilationContext<'l> {
let mut values = vec![];
for v in *array {
let Some(BasicValueEnum::IntValue(v)) =
self.get_value(map, &Value::Constant(*v))
self.get_value(map, &AnyValue::Constant(*v))
else {
unreachable!();
};
@@ -378,6 +445,15 @@ impl<'l> CompilationContext<'l> {
_ => todo!("{ty:?}"),
}
}
AnyConst::Struct(s_ty, vals) => {
let ty = self.get_type(Type::Struct(s_ty)).into_struct_type();
let vals: Vec<_> = vals
.iter()
.filter_map(|v| self.get_value(map, &v.as_any_value()))
.collect();
Some(ty.const_named_struct(&vals).into())
}
_ => todo!("{val:?}"),
},
_ => unreachable!("{val:#?}"),