Structs and comptime reflection stuff
This commit is contained in:
+88
-12
@@ -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:#?}"),
|
||||
|
||||
Reference in New Issue
Block a user