Ifs and Phis
This commit is contained in:
+105
-22
@@ -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!(),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user