Ifs and Phis

This commit is contained in:
Mia
2026-03-07 16:24:32 +01:00
parent fb84e09391
commit 168a12b4fc
11 changed files with 612 additions and 150 deletions
+105 -22
View File
@@ -5,7 +5,7 @@ use inkwell::{
module::Module,
targets::TargetMachine,
types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicTypeEnum, IntType},
values::{AggregateValueEnum, AnyValue as LlvmAnyValue, BasicValue, BasicValueEnum, IntValue},
values::{AnyValue as LlvmAnyValue, BasicValue, BasicValueEnum},
};
use leaf_assembly::{
assembly::Assembly,
@@ -45,11 +45,11 @@ impl<'l> CompilationContext<'l> {
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(),
32 => ctx.i32_type(),
64 => ctx.i64_type(),
128 => ctx.i128_type(),
1 => ctx.i8_type(),
2 => ctx.i16_type(),
4 => ctx.i32_type(),
8 => ctx.i64_type(),
16 => ctx.i128_type(),
_ => unreachable!(),
},
}
@@ -146,20 +146,61 @@ impl<'l> CompilationContext<'l> {
None
}
InstructionVariant::GetElementPtr(ptr, idx) => 'val: {
let pointee_ty = self.get_type(match inst.ty() {
Type::Ptr(PtrT { base, .. }) => *base,
Type::Ref(RefT { base, .. }) => *base,
_ => unreachable!(),
});
let Ok(pointee_ty): Result<BasicTypeEnum, _> = pointee_ty.try_into()
else {
break 'val None;
};
let ptr = self.get_value(&values, ptr).unwrap().into_pointer_value();
let idx = self.get_value(&values, idx).unwrap().into_int_value();
unsafe {
let ptr = builder.build_gep(pointee_ty, ptr, &[idx], "").unwrap();
Some(ptr.into())
let ptr_val =
self.get_value(&values, ptr).unwrap().into_pointer_value();
match ptr.ty() {
Type::Ptr(PtrT {
base: Type::Array(_),
..
})
| Type::Ref(RefT {
base: Type::Array(_),
..
}) => unsafe {
let pointee_ty = match inst.ty() {
Type::Ptr(PtrT { base, .. }) => *base,
Type::Ref(RefT { base, .. }) => *base,
_ => unreachable!(),
};
let Ok(pointee): Result<BasicTypeEnum, _> =
self.get_type(pointee_ty).try_into()
else {
break 'val None;
};
let idx =
self.get_value(&values, idx).unwrap().into_int_value();
let ptr =
builder.build_gep(pointee, ptr_val, &[idx], "").unwrap();
Some(ptr.into())
},
Type::Ptr(PtrT {
base: Type::Struct(ty),
..
})
| Type::Ref(RefT {
base: Type::Struct(ty),
..
}) => {
let Ok(pointee): Result<BasicTypeEnum, _> =
self.get_type(Type::Struct(ty)).try_into()
else {
break 'val None;
};
let AnyValue::Constant(AnyConst::Str(name)) = idx else {
unreachable!()
};
let idx = match self.fields.get_sync(&(*ty, *name)) {
Some(idx) => *idx,
None => break 'val None,
};
let ptr = builder
.build_struct_gep(pointee, ptr_val, idx, "")
.unwrap();
Some(ptr.into())
}
_ => unreachable!("{}", ptr.ty()),
}
}
InstructionVariant::GetElementVal(
@@ -225,6 +266,11 @@ impl<'l> CompilationContext<'l> {
let ptr = self.get_type(Type::Ptr(ty)).into_pointer_type();
Some(builder.build_int_to_ptr(val, ptr, "").unwrap().into())
}
InstructionVariant::PtrToInt(v, ty) => {
let val = self.get_value(&values, v).unwrap().into_pointer_value();
let int = self.get_type(Type::Int(*ty)).into_int_type();
Some(builder.build_ptr_to_int(val, int, "").unwrap().into())
}
InstructionVariant::ICmp(lhs, rhs, cmp) => {
let u = !is_signed(lhs.ty());
let cmp = match (cmp, u) {
@@ -261,6 +307,26 @@ impl<'l> CompilationContext<'l> {
Some(val.into())
}
InstructionVariant::Phi(phi_values) => 'val: {
let Ok(ty): Result<BasicTypeEnum, _> =
self.get_type(phi_values[0].value.ty()).try_into()
else {
break 'val None;
};
let llvm_vals: Vec<_> = phi_values
.iter()
.map(|v| self.get_value(&values, &v.value).unwrap())
.collect();
let llvm_vals: Vec<_> = phi_values
.iter()
.zip(&llvm_vals)
.map(|(p, v)| (v as &dyn BasicValue, blocks[p.block as usize]))
.collect();
let phi = builder.build_phi(ty, "").unwrap();
phi.add_incoming(&llvm_vals);
Some(phi.as_basic_value())
}
InstructionVariant::Call(func, args) => {
// TODO This will fail with external assemblies. Fix this.
let func = *self.functions.get_sync(&(assembly, *func)).unwrap();
@@ -307,7 +373,7 @@ impl<'l> CompilationContext<'l> {
None
}
InstructionVariant::Reinterpret(v, t, _) => match (v.ty(), t) {
InstructionVariant::Reinterpret(v, t) => match (v.ty(), t) {
(Type::Ptr(_), Type::Ptr(_)) => {
Some(self.get_value(&values, v).unwrap())
}
@@ -356,6 +422,7 @@ impl<'l> CompilationContext<'l> {
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(),
AnyTypeEnum::PointerType(ty) => ty.fn_type(&par_t, false).into(),
_ => todo!("{ret_t:?}"),
}
}
@@ -454,6 +521,15 @@ impl<'l> CompilationContext<'l> {
.collect();
Some(ty.const_named_struct(&vals).into())
}
AnyConst::SizeOf(Type::Int(ty)) => {
let ty = self.get_type(Type::Int(*ty)).into_int_type();
Some(
ty.size_of()
.const_truncate_or_bit_cast(self.native_int_ty)
.into(),
)
}
_ => todo!("{val:?}"),
},
_ => unreachable!("{val:#?}"),
@@ -464,7 +540,14 @@ impl<'l> CompilationContext<'l> {
#[inline]
fn is_signed(ty: Type) -> bool {
match ty {
Type::U8 | Type::U16 | Type::U32 | Type::U64 | Type::U128 | Type::USIZE => false,
Type::U8
| Type::U16
| Type::U32
| Type::U64
| Type::U128
| Type::USIZE
| Type::Ptr(_)
| Type::Ref(_) => false,
Type::I8 | Type::I16 | Type::I32 | Type::I64 | Type::I128 | Type::ISIZE => true,
_ => unreachable!(),
}