Fix a bunch of errors in reid-llvm-lib

This commit is contained in:
Sofia 2025-08-12 21:21:10 +03:00
parent c23160bc32
commit 0203213b28
3 changed files with 118 additions and 65 deletions

View File

@ -20,13 +20,13 @@ pub struct ModuleValue(pub(crate) usize);
#[derive(Clone, Hash, Copy, PartialEq, Eq, PartialOrd)]
pub struct TypeValue(pub(crate) ModuleValue, pub(crate) usize);
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
#[derive(Clone, Hash, Copy, PartialEq, Eq, PartialOrd)]
pub struct FunctionValue(pub(crate) ModuleValue, pub(crate) usize);
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
#[derive(Clone, Hash, Copy, PartialEq, Eq, PartialOrd)]
pub struct BlockValue(pub(crate) FunctionValue, pub(crate) usize);
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
#[derive(Clone, Hash, Copy, PartialEq, Eq, PartialOrd)]
pub struct InstructionValue(pub(crate) BlockValue, pub(crate) usize);
#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)]
@ -278,7 +278,7 @@ impl Builder {
let function = module.functions.get_unchecked_mut(block.0.1);
let block = function.blocks.get_unchecked_mut(block.1);
if let Some(_) = &block.data.terminator {
Err(ErrorKind::Null)
Err(ErrorKind::BlockAlreadyTerminated)
} else {
block.data.terminator = Some(value);
Ok(())
@ -297,7 +297,7 @@ impl Builder {
let function = module.functions.get_unchecked_mut(block.0.1);
let block = function.blocks.get_unchecked_mut(block.1);
if let Some(_) = &block.data.terminator_location {
Err(ErrorKind::Null)
Err(ErrorKind::BlockTerminatorLocated)
} else {
block.data.terminator_location = Some(location);
Ok(())
@ -411,84 +411,120 @@ impl Builder {
if match_types(&lhs, &rhs, &self)?.category().integer() {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypeNotInteger(lhs, lhs.get_type(&self)?))
}
}
Instr::FAdd(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypeWrongCategory(
lhs,
lhs.get_type(&self)?,
TypeCategory::Real,
))
}
}
Instr::Sub(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category().integer() {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypeNotInteger(lhs, lhs.get_type(&self)?))
}
}
Instr::FSub(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypeWrongCategory(
lhs,
lhs.get_type(&self)?,
TypeCategory::Real,
))
}
}
Instr::Mul(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category().integer() {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypeNotInteger(lhs, lhs.get_type(&self)?))
}
}
Instr::FMul(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypeWrongCategory(
lhs,
lhs.get_type(&self)?,
TypeCategory::Real,
))
}
}
Instr::UDiv(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::UnsignedInteger {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypeWrongCategory(
lhs,
lhs.get_type(&self)?,
TypeCategory::UnsignedInteger,
))
}
}
Instr::SDiv(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::SignedInteger {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypeWrongCategory(
lhs,
lhs.get_type(&self)?,
TypeCategory::SignedInteger,
))
}
}
Instr::FDiv(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypeWrongCategory(
lhs,
lhs.get_type(&self)?,
TypeCategory::Real,
))
}
}
Instr::URem(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::UnsignedInteger {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypeWrongCategory(
lhs,
lhs.get_type(&self)?,
TypeCategory::UnsignedInteger,
))
}
}
Instr::SRem(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::SignedInteger {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypeWrongCategory(
lhs,
lhs.get_type(&self)?,
TypeCategory::SignedInteger,
))
}
}
Instr::FRem(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypeWrongCategory(
lhs,
lhs.get_type(&self)?,
TypeCategory::Real,
))
}
}
Instr::And(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()),
@ -499,7 +535,7 @@ impl Builder {
if t.category().comparable() || !t.category().integer() {
Ok(())
} else {
Err(ErrorKind::Null) // TODO error: Types not comparable
Err(ErrorKind::TypeNotComparable(lhs, t))
}
}
Instr::FCmp(_, lhs, rhs) => {
@ -507,17 +543,17 @@ impl Builder {
if t.category().comparable() || t.category() != TypeCategory::Real {
Ok(())
} else {
Err(ErrorKind::Null) // TODO error: Types not comparable
Err(ErrorKind::TypeNotComparable(lhs, t))
}
}
Instr::FunctionCall(fun, params) => {
let param_types = self.function_data(&fun).params;
if param_types.len() != params.len() {
return Err(ErrorKind::Null); // TODO error: invalid amount of params
return Err(ErrorKind::InvalidLenParams(params.len(), param_types.len()));
}
for (a, b) in param_types.iter().zip(params) {
if *a != b.get_type(&self)? {
return Err(ErrorKind::TypesIncompatible(a.clone(), b.get_type(&self)?)); // TODO error: params do not match
return Err(ErrorKind::TypesIncompatible(a.clone(), b.get_type(&self)?));
}
}
Ok(())
@ -530,7 +566,7 @@ impl Builder {
// incoming values come from blocks that are added later
// than the one where this one exists.
let first = iter.next().ok_or(ErrorKind::Null)?;
let first = iter.next().ok_or(ErrorKind::EmptyPhiList)?;
for item in iter {
match_types(first, item, &self)?;
}
@ -543,10 +579,10 @@ impl Builder {
if *ptr_ty_inner == load_ty {
Ok(())
} else {
Err(ErrorKind::Null) // TODO error: inner type mismatch
Err(ErrorKind::TypesIncompatible(*ptr_ty_inner, load_ty))
}
} else {
Err(ErrorKind::Null) // TODO error: not a pointer
Err(ErrorKind::NotPointer(ptr, ptr_ty))
}
}
Instr::Store(ptr, _) => {
@ -554,21 +590,25 @@ impl Builder {
if let Type::Ptr(_) = ty {
Ok(())
} else {
Err(ErrorKind::Null) // TODO error: not a pointer
Err(ErrorKind::NotPointer(ptr, ty))
}
}
Instr::ArrayAlloca(_, val) => {
if val.get_type(self)?.category() == TypeCategory::UnsignedInteger {
Ok(())
} else {
Err(ErrorKind::Null) // TODO error: not a pointer
Err(ErrorKind::TypeWrongCategory(
val,
val.get_type(self)?,
TypeCategory::UnsignedInteger,
))
}
}
Instr::GetElemPtr(ptr_val, _) => {
let ptr_ty = ptr_val.get_type(&self)?;
match ptr_ty {
Type::Ptr(_) => Ok(()),
_ => Err(ErrorKind::Null),
_ => Err(ErrorKind::NotPointer(ptr_val, ptr_ty)),
}
}
Instr::GetStructElemPtr(ptr_val, idx) => {
@ -578,16 +618,16 @@ impl Builder {
match self.type_data(&val).kind {
CustomTypeKind::NamedStruct(NamedStruct(_, fields)) => {
if fields.len() <= idx as usize {
return Err(ErrorKind::Null); // TODO error: no such field
return Err(ErrorKind::NoSuchField(*ty, idx));
}
}
}
Ok(())
} else {
Err(ErrorKind::Null) // TODO error: not a struct
Err(ErrorKind::NotStruct(ptr_val, *ty))
}
} else {
Err(ErrorKind::Null) // TODO error: not a pointer
Err(ErrorKind::NotPointer(ptr_val, ptr_ty))
}
}
Instr::ExtractValue(val, _) => {
@ -597,7 +637,7 @@ impl Builder {
CustomTypeKind::NamedStruct(_) => Ok(()),
},
Type::Array(_, _) => Ok(()),
_ => Err(ErrorKind::Null),
_ => Err(ErrorKind::NotExtractable(val, val_ty)),
}
}
Instr::Trunc(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
@ -621,7 +661,7 @@ impl Builder {
if let Type::Ptr(_) = val_ty {
Ok(())
} else {
Err(ErrorKind::Null)
Err(ErrorKind::NotPointer(val, val_ty))
}
}
}
@ -695,7 +735,7 @@ impl InstructionValue {
.params
.get(*nth)
.cloned()
.ok_or(ErrorKind::Null),
.ok_or(ErrorKind::NoSuchParam(self.0.0, *nth)),
Constant(c) => Ok(c.get_type()),
Add(lhs, rhs) => match_types(lhs, rhs, &builder),
FAdd(lhs, rhs) => match_types(lhs, rhs, &builder),
@ -715,7 +755,10 @@ impl InstructionValue {
ICmp(_, _, _) => Ok(Type::Bool),
FCmp(_, _, _) => Ok(Type::Bool),
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
Phi(values) => values.first().ok_or(ErrorKind::Null).and_then(|v| v.get_type(&builder)),
Phi(values) => values
.first()
.ok_or(ErrorKind::EmptyPhiList)
.and_then(|v| v.get_type(&builder)),
Alloca(ty) => Ok(Type::Ptr(Box::new(ty.clone()))),
Load(_, ty) => Ok(ty.clone()),
Store(_, value) => value.get_type(builder),
@ -757,7 +800,7 @@ impl InstructionValue {
}
}
Type::Array(elem_ty, _) => *elem_ty.clone(),
_ => return Err(ErrorKind::Null),
_ => return Err(ErrorKind::NotExtractable(*instr, instr_ty)),
})
}
Trunc(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
@ -786,8 +829,9 @@ impl InstructionValue {
}
fn cast_to(&self, builder: &Builder, ty: &Type) -> CompileResult<Instr> {
self.get_type(builder)?
let own_type = self.get_type(builder)?;
own_type
.cast_instruction(*self, &ty)
.ok_or(ErrorKind::Null)
.ok_or(ErrorKind::ImpossibleCast(own_type, ty.clone()))
}
}

View File

@ -28,6 +28,32 @@ pub enum ErrorKind {
Null,
#[error("Types {0:?} and {1:?} incompatible")]
TypesIncompatible(Type, Type),
#[error("Phi list of values is empty")]
EmptyPhiList,
#[error("Type {1:?} of value {0:?} is not extractable")]
NotExtractable(InstructionValue, Type),
#[error("Type {0:?} is not castable to {1:?}")]
ImpossibleCast(Type, Type),
#[error("Block is already terminated")]
BlockAlreadyTerminated,
#[error("Block terminator already has a location")]
BlockTerminatorLocated,
#[error("Value {0:?} must be an integer type. Is {1:?}")]
TypeNotInteger(InstructionValue, Type),
#[error("Value {0:?} must be a {2:?} type. Is {1:?}")]
TypeWrongCategory(InstructionValue, Type, TypeCategory),
#[error("Value {0:?} must be comparable, was {1:?}")]
TypeNotComparable(InstructionValue, Type),
#[error("Got {0:?} parameters, expected {1:?}")]
InvalidLenParams(usize, usize),
#[error("Value {0:?} is not a pointer, is {1:?}")]
NotPointer(InstructionValue, Type),
#[error("Value {0:?} is not a struct, is {1:?}")]
NotStruct(InstructionValue, Type),
#[error("Struct {0:?} has no such field as {1:?}")]
NoSuchField(Type, u32),
#[error("Function {0:?} has no such parameter as {1:?}")]
NoSuchParam(FunctionValue, usize),
}
pub type CompileResult<T> = Result<T, ErrorKind>;
@ -600,7 +626,7 @@ impl ConstValueKind {
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone)]
pub enum TypeCategory {
SignedInteger,
UnsignedInteger,

View File

@ -5,10 +5,7 @@ use std::{
};
use llvm_sys::{
core::{
LLVMCreateMemoryBufferWithMemoryRange, LLVMDisposeMemoryBuffer, LLVMGetBufferSize,
LLVMGetBufferStart,
},
core::{LLVMCreateMemoryBufferWithMemoryRange, LLVMDisposeMemoryBuffer, LLVMGetBufferSize, LLVMGetBufferStart},
error::LLVMDisposeErrorMessage,
prelude::LLVMMemoryBufferRef,
};
@ -32,9 +29,7 @@ pub fn from_cstring(pointer: *mut c_char) -> Option<String> {
}
fn cstring_to_err(value: *mut c_char) -> Result<(), String> {
from_cstring(value)
.filter(|s| !s.is_empty())
.map_or(Ok(()), |s| Err(s))
from_cstring(value).filter(|s| !s.is_empty()).map_or(Ok(()), |s| Err(s))
}
/// Utility struct for LLVM's Error Messages, which need to be disposed
@ -75,12 +70,8 @@ impl MemoryBufferHolder {
pub fn empty(name: &str) -> MemoryBufferHolder {
let array = [0i8; 0];
unsafe {
let buffer = LLVMCreateMemoryBufferWithMemoryRange(
array.as_ptr(),
array.len(),
into_cstring(name).as_ptr(),
0,
);
let buffer =
LLVMCreateMemoryBufferWithMemoryRange(array.as_ptr(), array.len(), into_cstring(name).as_ptr(), 0);
MemoryBufferHolder { buffer }
}
}
@ -113,20 +104,12 @@ impl Drop for MemoryBufferHolder {
/// Make sure types for given instructions match. Return Ok(type) if they do,
/// and error otherwise.
pub fn match_types(
lhs: &InstructionValue,
rhs: &InstructionValue,
builder: &Builder,
) -> CompileResult<Type> {
let lhs_type = lhs.get_type(&builder);
let rhs_type = rhs.get_type(&builder);
if let (Ok(lhs_t), Ok(rhs_t)) = (lhs_type, rhs_type) {
if lhs_t == rhs_t {
Ok(lhs_t)
} else {
Err(ErrorKind::Null)
}
pub fn match_types(lhs: &InstructionValue, rhs: &InstructionValue, builder: &Builder) -> CompileResult<Type> {
let lhs_t = lhs.get_type(&builder)?;
let rhs_t = rhs.get_type(&builder)?;
if lhs_t == rhs_t {
Ok(lhs_t)
} else {
Err(ErrorKind::Null)
Err(ErrorKind::TypesIncompatible(lhs_t, rhs_t))
}
}