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

View File

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