From d5a4168b0d84b81dbd38ae784ec4387ee868d828 Mon Sep 17 00:00:00 2001 From: sofia Date: Sun, 7 Sep 2025 15:34:22 +0300 Subject: [PATCH] Remove reid-llvm-lib, move to own git repo --- reid-llvm-lib/Cargo.toml | 12 - reid-llvm-lib/examples/libtest.rs | 56 -- reid-llvm-lib/src/builder.rs | 835 ---------------- reid-llvm-lib/src/compile.rs | 1257 ------------------------ reid-llvm-lib/src/debug_information.rs | 399 -------- reid-llvm-lib/src/fmt.rs | 595 ----------- reid-llvm-lib/src/intrinsics.rs | 263 ----- reid-llvm-lib/src/lib.rs | 741 -------------- reid-llvm-lib/src/pad_adapter.rs | 69 -- reid-llvm-lib/src/util.rs | 115 --- 10 files changed, 4342 deletions(-) delete mode 100644 reid-llvm-lib/Cargo.toml delete mode 100644 reid-llvm-lib/examples/libtest.rs delete mode 100644 reid-llvm-lib/src/builder.rs delete mode 100644 reid-llvm-lib/src/compile.rs delete mode 100644 reid-llvm-lib/src/debug_information.rs delete mode 100644 reid-llvm-lib/src/fmt.rs delete mode 100644 reid-llvm-lib/src/intrinsics.rs delete mode 100644 reid-llvm-lib/src/lib.rs delete mode 100644 reid-llvm-lib/src/pad_adapter.rs delete mode 100644 reid-llvm-lib/src/util.rs diff --git a/reid-llvm-lib/Cargo.toml b/reid-llvm-lib/Cargo.toml deleted file mode 100644 index 76e8e34..0000000 --- a/reid-llvm-lib/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "reid-lib" -version = "1.0.0-beta.4" -edition = "2024" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -## LLVM Bindings -llvm-sys = {version ="201.0.1" } -## Make it easier to generate errors -thiserror = "1.0.44" \ No newline at end of file diff --git a/reid-llvm-lib/examples/libtest.rs b/reid-llvm-lib/examples/libtest.rs deleted file mode 100644 index 4733ad1..0000000 --- a/reid-llvm-lib/examples/libtest.rs +++ /dev/null @@ -1,56 +0,0 @@ -use reid_lib::{CmpPredicate, ConstValueKind, Context, FunctionFlags, Instr, TerminatorKind, Type}; - -fn main() { - use ConstValueKind::*; - use Instr::*; - - let context = Context::new("libtest"); - - let module = context.module("test", true); - - let main = module.function("main", None, Type::I32, Vec::new(), FunctionFlags::default()); - let mut m_entry = main.block("entry"); - - let fibonacci = module.function("fibonacci", None, Type::I32, vec![Type::I32], FunctionFlags::default()); - - let arg = m_entry.build_named("const", Constant(I32(5))).unwrap(); - let fibonacci_call = m_entry - .build_named("const", FunctionCall(fibonacci.value(), vec![arg])) - .unwrap(); - m_entry.terminate(TerminatorKind::Ret(fibonacci_call)).unwrap(); - - let mut f_entry = fibonacci.block("entry"); - - let num_3 = f_entry.build_named("const", Constant(I32(3))).unwrap(); - let param_n = f_entry.build_named("param", Param(0)).unwrap(); - let cond = f_entry - .build_named("cmp", ICmp(CmpPredicate::LT, param_n, num_3)) - .unwrap(); - - let mut then_b = fibonacci.block("then"); - let mut else_b = fibonacci.block("else"); - - f_entry - .terminate(TerminatorKind::CondBr(cond, then_b.value(), else_b.value())) - .unwrap(); - - let ret_const = then_b.build_named("const", Constant(I32(1))).unwrap(); - then_b.terminate(TerminatorKind::Ret(ret_const)).unwrap(); - - let const_1 = else_b.build_named("const", Constant(I32(1))).unwrap(); - let const_2 = else_b.build_named("const", Constant(I32(2))).unwrap(); - let param_1 = else_b.build_named("sub", Sub(param_n, const_1)).unwrap(); - let param_2 = else_b.build_named("sub", Sub(param_n, const_2)).unwrap(); - let call_1 = else_b - .build_named("fibonacci", FunctionCall(fibonacci.value(), vec![param_1])) - .unwrap(); - let call_2 = else_b - .build_named("fibonacci", FunctionCall(fibonacci.value(), vec![param_2])) - .unwrap(); - - let add = else_b.build_named("add", Add(call_1, call_2)).unwrap(); - - else_b.terminate(TerminatorKind::Ret(add)).unwrap(); - - context.compile(None, Vec::new()); -} diff --git a/reid-llvm-lib/src/builder.rs b/reid-llvm-lib/src/builder.rs deleted file mode 100644 index fd89f89..0000000 --- a/reid-llvm-lib/src/builder.rs +++ /dev/null @@ -1,835 +0,0 @@ -//! This module contains simply [`Builder`] and it's related utility Values. -//! Builder is the actual struct being modified when building the LLIR. - -use std::{cell::RefCell, rc::Rc}; - -use crate::{ - Block, BlockData, CompileResult, ConstValueKind, CustomTypeKind, ErrorKind, FunctionData, Instr, InstructionData, - ModuleData, NamedStruct, TerminatorKind, Type, TypeCategory, TypeData, - debug_information::{ - DebugInformation, DebugLocationValue, DebugMetadataValue, DebugScopeValue, InstructionDebugRecordData, - }, - util::match_types, -}; - -#[derive(Clone, Hash, Copy, PartialEq, Eq, PartialOrd)] -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, PartialOrd)] -pub struct FunctionValue(pub(crate) ModuleValue, pub(crate) usize); - -#[derive(Clone, Hash, Copy, PartialEq, Eq, PartialOrd)] -pub struct BlockValue(pub(crate) FunctionValue, pub(crate) usize); - -#[derive(Clone, Hash, Copy, PartialEq, Eq, PartialOrd)] -pub struct InstructionValue(pub(crate) BlockValue, pub(crate) usize); - -#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)] -pub struct ConstantValue(pub(crate) ModuleValue, pub(crate) usize); - -#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)] -pub struct GlobalValue(pub(crate) ModuleValue, pub(crate) usize); - -#[derive(Clone)] -pub struct ModuleHolder { - pub(crate) value: ModuleValue, - pub(crate) data: ModuleData, - pub(crate) functions: Vec, - pub(crate) types: Vec, - pub(crate) debug_information: Option, - pub(crate) constants: Vec, - pub(crate) globals: Vec, -} - -#[derive(Clone)] -pub struct ConstantValueHolder { - pub(crate) value: ConstantValue, - pub(crate) kind: ConstValueKind, -} -#[derive(Clone)] -pub struct GlobalValueHolder { - pub(crate) value: GlobalValue, - pub(crate) name: String, - pub(crate) initializer: ConstantValue, -} - -#[derive(Clone)] -pub struct TypeHolder { - pub(crate) value: TypeValue, - pub(crate) data: TypeData, -} - -#[derive(Clone)] -pub struct FunctionHolder { - pub(crate) value: FunctionValue, - pub(crate) data: FunctionData, - pub(crate) blocks: Vec, - /// Debug scope value of this current function - pub(crate) debug_info: Option, -} - -#[derive(Clone)] -pub struct BlockHolder { - pub(crate) value: BlockValue, - pub(crate) data: BlockData, - pub(crate) instructions: Vec, -} - -#[derive(Clone)] -pub struct InstructionHolder { - pub(crate) value: InstructionValue, - pub(crate) data: InstructionData, - pub(crate) name: String, - pub(crate) record: Option, -} - -#[derive(Clone)] -pub(crate) struct Builder { - pub(crate) modules: Rc>>, - pub(crate) producer: String, -} - -impl Builder { - pub fn new(producer: String) -> Builder { - Builder { - modules: Rc::new(RefCell::new(Vec::new())), - producer, - } - } - - pub(crate) fn add_module(&self, data: ModuleData) -> ModuleValue { - let value = ModuleValue(self.modules.borrow().len()); - self.modules.borrow_mut().push(ModuleHolder { - value, - data, - functions: Vec::new(), - types: Vec::new(), - debug_information: None, - constants: Vec::new(), - globals: Vec::new(), - }); - value - } - - pub(crate) fn set_debug_information(&self, mod_val: &ModuleValue, debug_info: DebugInformation) { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(mod_val.0); - module.debug_information = Some(debug_info); - } - } - - pub(crate) unsafe fn add_type(&self, mod_val: &ModuleValue, data: TypeData) -> TypeValue { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(mod_val.0); - let value = TypeValue(module.value, module.types.len()); - module.types.push(TypeHolder { value, data }); - value - } - } - - pub(crate) unsafe fn add_function(&self, mod_val: &ModuleValue, data: FunctionData) -> FunctionValue { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(mod_val.0); - let value = FunctionValue(module.value, module.functions.len()); - module.functions.push(FunctionHolder { - value, - data, - blocks: Vec::new(), - debug_info: None, - }); - value - } - } - - pub(crate) unsafe fn add_block(&self, fun_val: &FunctionValue, data: BlockData) -> BlockValue { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(fun_val.0.0); - let function = module.functions.get_unchecked_mut(fun_val.1); - let value = BlockValue(function.value, function.blocks.len()); - function.blocks.push(BlockHolder { - value, - data, - instructions: Vec::new(), - }); - value - } - } - - pub(crate) unsafe fn add_instruction( - &self, - block_val: &BlockValue, - data: InstructionData, - name: String, - ) -> CompileResult { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(block_val.0.0.0); - let function = module.functions.get_unchecked_mut(block_val.0.1); - let block = function.blocks.get_unchecked_mut(block_val.1); - let value = InstructionValue(block.value, block.instructions.len()); - block.instructions.push(InstructionHolder { - value, - data, - name, - record: None, - }); - - // Drop modules so that it is no longer mutable borrowed - // (check_instruction requires an immutable borrow). - drop(modules); - - self.check_instruction(&value)?; - Ok(value) - } - } - - pub(crate) unsafe fn build_constant(&self, module: ModuleValue, kind: ConstValueKind) -> ConstantValue { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(module.0); - let value = ConstantValue(module.value, module.constants.len()); - module.constants.push(ConstantValueHolder { value, kind }); - value - } - } - - pub(crate) unsafe fn add_global( - &self, - module: ModuleValue, - name: String, - initializer: ConstantValue, - ) -> GlobalValue { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(module.0); - let value = GlobalValue(module.value, module.globals.len()); - module.globals.push(GlobalValueHolder { - value, - name, - initializer, - }); - value - } - } - - pub(crate) unsafe fn find_function(&self, module: ModuleValue, name: &String) -> Option { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(module.0); - module.functions.iter().find(|f| f.data.name == *name).map(|f| f.value) - } - } - - pub(crate) unsafe fn add_instruction_location(&self, value: &InstructionValue, location: DebugLocationValue) { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(value.0.0.0.0); - let function = module.functions.get_unchecked_mut(value.0.0.1); - let block = function.blocks.get_unchecked_mut(value.0.1); - let instr = block.instructions.get_unchecked_mut(value.1); - instr.data.location = Some(location) - } - } - - pub(crate) unsafe fn add_instruction_metadata(&self, value: &InstructionValue, metadata: DebugMetadataValue) { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(value.0.0.0.0); - let function = module.functions.get_unchecked_mut(value.0.0.1); - let block = function.blocks.get_unchecked_mut(value.0.1); - let instr = block.instructions.get_unchecked_mut(value.1); - instr.data.meta = Some(metadata) - } - } - - pub(crate) unsafe fn add_instruction_record(&self, value: &InstructionValue, record: InstructionDebugRecordData) { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(value.0.0.0.0); - let function = module.functions.get_unchecked_mut(value.0.0.1); - let block = function.blocks.get_unchecked_mut(value.0.1); - let instr = block.instructions.get_unchecked_mut(value.1); - instr.record = Some(record) - } - } - - pub(crate) unsafe fn set_debug_subprogram(&self, value: &FunctionValue, subprogram: DebugScopeValue) { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(value.0.0); - let function = module.functions.get_unchecked_mut(value.1); - function.debug_info = Some(subprogram) - } - } - - pub(crate) unsafe fn terminate(&self, block: &BlockValue, value: TerminatorKind) -> CompileResult<()> { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(block.0.0.0); - 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::BlockAlreadyTerminated) - } else { - block.data.terminator = Some(value); - Ok(()) - } - } - } - - pub(crate) unsafe fn set_terminator_location( - &self, - block: &BlockValue, - location: DebugLocationValue, - ) -> CompileResult<()> { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(block.0.0.0); - 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::BlockTerminatorLocated) - } else { - block.data.terminator_location = Some(location); - Ok(()) - } - } - } - - pub(crate) unsafe fn delete_block(&self, block: &BlockValue) -> CompileResult<()> { - unsafe { - let mut modules = self.modules.borrow_mut(); - let module = modules.get_unchecked_mut(block.0.0.0); - let function = module.functions.get_unchecked_mut(block.0.1); - let block = function.blocks.get_unchecked_mut(block.1); - block.data.deleted = true; - Ok(()) - } - } - - #[allow(dead_code)] - pub(crate) unsafe fn module_data(&self, value: &ModuleValue) -> ModuleData { - unsafe { self.modules.borrow().get_unchecked(value.0).data.clone() } - } - - pub(crate) unsafe fn function_data(&self, value: &FunctionValue) -> FunctionData { - unsafe { - self.modules - .borrow() - .get_unchecked(value.0.0) - .functions - .get_unchecked(value.1) - .data - .clone() - } - } - - #[allow(dead_code)] - pub(crate) unsafe fn block_data(&self, value: &BlockValue) -> BlockData { - unsafe { - self.modules - .borrow() - .get_unchecked(value.0.0.0) - .functions - .get_unchecked(value.0.1) - .blocks - .get_unchecked(value.1) - .data - .clone() - } - } - - pub(crate) unsafe fn instr_data(&self, value: &InstructionValue) -> InstructionData { - unsafe { - self.modules - .borrow() - .get_unchecked(value.0.0.0.0) - .functions - .get_unchecked(value.0.0.1) - .blocks - .get_unchecked(value.0.1) - .instructions - .get_unchecked(value.1) - .data - .clone() - } - } - - pub(crate) unsafe fn type_data(&self, value: &TypeValue) -> TypeData { - unsafe { - self.modules - .borrow() - .get_unchecked(value.0.0) - .types - .get_unchecked(value.1) - .data - .clone() - } - } - - pub(crate) fn find_module<'ctx>(&'ctx self, value: ModuleValue) -> ModuleHolder { - unsafe { self.modules.borrow().get_unchecked(value.0).clone() } - } - - pub(crate) fn get_modules(&self) -> Rc>> { - self.modules.clone() - } - - pub(crate) fn get_global_initializer(&self, value: GlobalValue) -> ConstantValue { - unsafe { - let modules = self.modules.borrow(); - let module = modules.get_unchecked(value.0.0); - let global = module.globals.get_unchecked(value.1); - global.initializer - } - } - - pub(crate) fn get_const_kind(&self, value: ConstantValue) -> ConstValueKind { - unsafe { - let modules = self.modules.borrow(); - let module = modules.get_unchecked(value.0.0); - let constant = module.constants.get_unchecked(value.1); - constant.kind.clone() - } - } - - pub fn check_instruction(&self, instruction: &InstructionValue) -> CompileResult<()> { - unsafe { - match self.instr_data(&instruction).kind { - Instr::Param(_) => Ok(()), - Instr::Constant(_) => Ok(()), - Instr::Add(lhs, rhs) => { - if match_types(&lhs, &rhs, &self)?.category().integer() { - Ok(()) - } else { - 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::TypeWrongCategory( - lhs, - lhs.get_type(&self)?, - TypeCategory::Real, - )) - } - } - Instr::Sub(lhs, rhs) => { - if match_types(&lhs, &rhs, &self)?.category().integer() { - Ok(()) - } else { - 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::TypeWrongCategory( - lhs, - lhs.get_type(&self)?, - TypeCategory::Real, - )) - } - } - Instr::Mul(lhs, rhs) => { - if match_types(&lhs, &rhs, &self)?.category().integer() { - Ok(()) - } else { - 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::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::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::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::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::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::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::TypeWrongCategory( - lhs, - lhs.get_type(&self)?, - TypeCategory::Real, - )) - } - } - Instr::And(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), - Instr::Or(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), - Instr::XOr(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), - Instr::ICmp(_, lhs, rhs) => { - let t = match_types(&lhs, &rhs, self)?; - if t.category().comparable() || !t.category().integer() { - Ok(()) - } else { - Err(ErrorKind::TypeNotComparable(lhs, t)) - } - } - Instr::FCmp(_, lhs, rhs) => { - let t = match_types(&lhs, &rhs, self)?; - if t.category().comparable() || t.category() != TypeCategory::Real { - Ok(()) - } else { - 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::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)?)); - } - } - Ok(()) - } - Instr::Phi(vals) => { - let mut iter = vals.iter(); - // TODO error: Phi must contain at least one item - - // TODO error: compile can actually crash here if any of the - // incoming values come from blocks that are added later - // than the one where this one exists. - - let first = iter.next().ok_or(ErrorKind::EmptyPhiList)?; - for item in iter { - match_types(first, item, &self)?; - } - Ok(()) - } - Instr::Alloca(_) => Ok(()), - Instr::Load(ptr, load_ty) => { - let ptr_ty = ptr.get_type(&self)?; - if let Type::Ptr(ptr_ty_inner) = ptr_ty { - if *ptr_ty_inner == load_ty { - Ok(()) - } else { - Err(ErrorKind::TypesIncompatible(*ptr_ty_inner, load_ty)) - } - } else { - Err(ErrorKind::NotPointer(ptr, ptr_ty)) - } - } - Instr::Store(ptr, _) => { - let ty = ptr.get_type(&self)?; - if let Type::Ptr(_) = ty { - Ok(()) - } else { - Err(ErrorKind::NotPointer(ptr, ty)) - } - } - Instr::ArrayAlloca(_, val) => { - if val.get_type(self)?.category() == TypeCategory::UnsignedInteger { - Ok(()) - } else { - 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::NotPointer(ptr_val, ptr_ty)), - } - } - Instr::GetStructElemPtr(ptr_val, idx) => { - let ptr_ty = ptr_val.get_type(&self)?; - if let Type::Ptr(ty) = ptr_ty { - if let Type::CustomType(val) = *ty { - match self.type_data(&val).kind { - CustomTypeKind::NamedStruct(NamedStruct(_, fields)) => { - if fields.len() <= idx as usize { - return Err(ErrorKind::NoSuchField(*ty, idx)); - } - } - } - Ok(()) - } else { - Err(ErrorKind::NotStruct(ptr_val, *ty)) - } - } else { - Err(ErrorKind::NotPointer(ptr_val, ptr_ty)) - } - } - Instr::ExtractValue(val, _) => { - let val_ty = val.get_type(&self)?; - match val_ty { - Type::CustomType(custom) => match self.type_data(&custom).kind { - CustomTypeKind::NamedStruct(_) => Ok(()), - }, - Type::Array(_, _) => Ok(()), - _ => Err(ErrorKind::NotExtractable(val, val_ty)), - } - } - Instr::Trunc(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), - Instr::ZExt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), - Instr::SExt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), - Instr::FPTrunc(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), - Instr::FPExt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), - Instr::FPToUI(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), - Instr::FPToSI(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), - Instr::UIToFP(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), - Instr::SIToFP(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), - Instr::PtrToInt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), - Instr::IntToPtr(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), - Instr::BitCast(..) => Ok(()), - Instr::ShiftRightLogical(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), - Instr::ShiftRightArithmetic(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), - Instr::ShiftLeft(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), - Instr::GetGlobal(_) => Ok(()), - Instr::IsNull(val) => { - let val_ty = val.get_type(&self)?; - if let Type::Ptr(_) = val_ty { - Ok(()) - } else { - Err(ErrorKind::NotPointer(val, val_ty)) - } - } - } - } - } - - pub fn is_block_used(&self, block_v: BlockValue) -> bool { - unsafe { - let modules = self.modules.borrow(); - let module = modules.get_unchecked(block_v.0.0.0); - let function = module.functions.get_unchecked(block_v.0.1); - let block = function.blocks.get_unchecked(block_v.1); - - if block.instructions.len() > 0 || block.data.terminator.is_some() { - return true; - } - - for other in &function.blocks { - if let Some(term) = &other.data.terminator { - match term { - TerminatorKind::Ret(_) => {} - TerminatorKind::RetVoid => {} - TerminatorKind::Br(other_val) => { - if other_val == &block_v { - return true; - } - } - TerminatorKind::CondBr(_, then_other_v, else_other_v) => { - if then_other_v == &block_v || else_other_v == &block_v { - return true; - } - } - } - } - } - - false - } - } -} - -impl InstructionValue { - pub fn with_location(self, block: &Block, location: DebugLocationValue) -> InstructionValue { - unsafe { - block.builder.add_instruction_location(&self, location); - } - self - } - - pub fn maybe_location(self, block: &mut Block, location: Option) -> InstructionValue { - unsafe { - if let Some(location) = location { - block.builder.add_instruction_location(&self, location); - } - } - self - } - - pub fn add_record(&self, block: &mut Block, record: InstructionDebugRecordData) { - unsafe { - block.builder.add_instruction_record(self, record); - } - } - - pub(crate) fn get_type(&self, builder: &Builder) -> CompileResult { - use Instr::*; - unsafe { - match &builder.instr_data(self).kind { - Param(nth) => builder - .function_data(&self.0.0) - .params - .get(*nth) - .cloned() - .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), - Sub(lhs, rhs) => match_types(lhs, rhs, &builder), - FSub(lhs, rhs) => match_types(lhs, rhs, &builder), - Mul(lhs, rhs) => match_types(lhs, rhs, &builder), - FMul(lhs, rhs) => match_types(lhs, rhs, &builder), - UDiv(lhs, rhs) => match_types(lhs, rhs, &builder), - SDiv(lhs, rhs) => match_types(lhs, rhs, &builder), - FDiv(lhs, rhs) => match_types(lhs, rhs, &builder), - URem(lhs, rhs) => match_types(lhs, rhs, &builder), - SRem(lhs, rhs) => match_types(lhs, rhs, &builder), - FRem(lhs, rhs) => match_types(lhs, rhs, &builder), - And(lhs, rhs) => match_types(lhs, rhs, &builder), - Or(lhs, rhs) => match_types(lhs, rhs, &builder), - XOr(lhs, rhs) => match_types(lhs, rhs, &builder), - 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::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), - ArrayAlloca(ty, _) => Ok(Type::Ptr(Box::new(ty.clone()))), - GetElemPtr(instr, _) => { - let instr_ty = instr.get_type(builder)?; - let Type::Ptr(inner_ty) = &instr_ty else { - panic!("GetStructElemPtr on non-pointer! ({:?})", &instr_ty) - }; - match *inner_ty.clone() { - Type::Array(elem_ty, _) => Ok(Type::Ptr(Box::new(*elem_ty.clone()))), - _ => Ok(instr_ty), - } - } - GetStructElemPtr(instr, idx) => { - let instr_ty = instr.get_type(builder)?; - let Type::Ptr(inner_ty) = instr_ty else { - panic!("GetStructElemPtr on non-pointer! ({:?})", &instr_ty) - }; - let Type::CustomType(ty_value) = *inner_ty else { - panic!("GetStructElemPtr on non-struct! ({:?})", &inner_ty) - }; - let field_ty = match builder.type_data(&ty_value).kind { - CustomTypeKind::NamedStruct(NamedStruct(_, fields)) => { - fields.get_unchecked(*idx as usize).clone() - } - }; - Ok(Type::Ptr(Box::new(field_ty))) - } - ExtractValue(instr, idx) => { - let instr_ty = instr.get_type(builder)?; - Ok(match instr_ty { - Type::CustomType(struct_ty) => { - let data = builder.type_data(&struct_ty); - match data.kind { - CustomTypeKind::NamedStruct(named_struct) => { - named_struct.1.get(*idx as usize).unwrap().clone() - } - } - } - Type::Array(elem_ty, _) => *elem_ty.clone(), - _ => return Err(ErrorKind::NotExtractable(*instr, instr_ty)), - }) - } - Trunc(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), - ZExt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), - SExt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), - FPTrunc(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), - FPExt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), - FPToUI(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), - FPToSI(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), - UIToFP(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), - SIToFP(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), - PtrToInt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), - IntToPtr(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), - BitCast(_, ty) => Ok(ty.clone()), - ShiftRightLogical(lhs, _) => lhs.get_type(builder), - ShiftRightArithmetic(lhs, _) => lhs.get_type(builder), - ShiftLeft(lhs, _) => lhs.get_type(builder), - GetGlobal(global_value) => { - let constant = builder.get_global_initializer(*global_value); - let kind = builder.get_const_kind(constant); - Ok(kind.get_type()) - } - IsNull(_) => Ok(Type::Bool), - } - } - } - - fn cast_to(&self, builder: &Builder, ty: &Type) -> CompileResult { - let own_type = self.get_type(builder)?; - own_type - .cast_instruction(*self, &ty) - .ok_or(ErrorKind::ImpossibleCast(own_type, ty.clone())) - } -} diff --git a/reid-llvm-lib/src/compile.rs b/reid-llvm-lib/src/compile.rs deleted file mode 100644 index ff60150..0000000 --- a/reid-llvm-lib/src/compile.rs +++ /dev/null @@ -1,1257 +0,0 @@ -//! This module contains all of the relevant code that is needed to compile the -//! LLIR ([`Context`]) into LLVM IR. This module is the only one that interfaces -//! with the LLVM API. - -use std::{ - cell::Ref, - collections::HashMap, - ptr::{null, null_mut}, -}; - -use llvm_sys::{ - LLVMIntPredicate, LLVMLinkage, LLVMRealPredicate, LLVMValueKind, - analysis::LLVMVerifyModule, - core::*, - debuginfo::*, - linker::LLVMLinkModules2, - prelude::*, - target::{ - LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos, - LLVM_InitializeAllTargetMCs, LLVM_InitializeAllTargets, LLVMSetModuleDataLayout, - }, - target_machine::{ - LLVMCodeGenFileType, LLVMCreateTargetDataLayout, LLVMCreateTargetMachine, LLVMGetDefaultTargetTriple, - LLVMGetTargetFromTriple, LLVMTargetMachineEmitToMemoryBuffer, - }, -}; - -use crate::{ - CustomTypeKind, - builder::{ConstantValue, GlobalValue, TypeHolder, TypeValue}, - debug_information::*, - util::{ErrorMessageHolder, MemoryBufferHolder, from_cstring, into_cstring}, -}; - -use super::{ - CmpPredicate, ConstValueKind, Context, TerminatorKind, Type, - builder::{ - BlockHolder, BlockValue, Builder, FunctionHolder, FunctionValue, InstructionHolder, InstructionValue, - ModuleHolder, - }, -}; - -pub struct LLVMContext { - context_ref: LLVMContextRef, - builder_ref: LLVMBuilderRef, -} - -impl Drop for LLVMContext { - fn drop(&mut self) { - unsafe { - LLVMDisposeBuilder(self.builder_ref); - LLVMContextDispose(self.context_ref); - } - } -} - -pub struct CompiledModule { - module_ref: LLVMModuleRef, - _context: LLVMContext, - cpu: String, - features: String, -} - -pub struct CompileOutput { - pub triple: String, - pub assembly: String, - pub obj_buffer: Vec, - pub llvm_ir: String, -} - -impl CompiledModule { - pub fn output(&self) -> CompileOutput { - unsafe { - LLVM_InitializeAllTargets(); - LLVM_InitializeAllTargetInfos(); - LLVM_InitializeAllTargetMCs(); - LLVM_InitializeAllAsmParsers(); - LLVM_InitializeAllAsmPrinters(); - - let triple = LLVMGetDefaultTargetTriple(); - - let mut target: _ = null_mut(); - let mut err = ErrorMessageHolder::null(); - LLVMGetTargetFromTriple(triple, &mut target, err.borrow_mut()); - err.into_result().unwrap(); - - let target_machine = LLVMCreateTargetMachine( - target, - triple, - into_cstring(self.cpu.clone()).as_ptr(), - into_cstring(self.features.clone()).as_ptr(), - llvm_sys::target_machine::LLVMCodeGenOptLevel::LLVMCodeGenLevelNone, - llvm_sys::target_machine::LLVMRelocMode::LLVMRelocDefault, - llvm_sys::target_machine::LLVMCodeModel::LLVMCodeModelDefault, - ); - - let data_layout = LLVMCreateTargetDataLayout(target_machine); - LLVMSetTarget(self.module_ref, triple); - LLVMSetModuleDataLayout(self.module_ref, data_layout); - - let mut asm_buffer = MemoryBufferHolder::empty("asm"); - let mut err = ErrorMessageHolder::null(); - LLVMTargetMachineEmitToMemoryBuffer( - target_machine, - self.module_ref, - LLVMCodeGenFileType::LLVMAssemblyFile, - err.borrow_mut(), - &mut asm_buffer.buffer, - ); - err.into_result().unwrap(); - - let mut obj_buffer = MemoryBufferHolder::empty("obj"); - let mut err = ErrorMessageHolder::null(); - LLVMTargetMachineEmitToMemoryBuffer( - target_machine, - self.module_ref, - LLVMCodeGenFileType::LLVMObjectFile, - err.borrow_mut(), - &mut obj_buffer.buffer, - ); - err.into_result().unwrap(); - - let llvm_ir = - from_cstring(LLVMPrintModuleToString(self.module_ref)).expect("Unable to print LLVM IR to string"); - - let mut err = ErrorMessageHolder::null(); - LLVMVerifyModule( - self.module_ref, - llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction, - err.borrow_mut(), - ); - - CompileOutput { - triple: from_cstring(triple).expect("Unable to convert triple from cstring"), - assembly: asm_buffer - .as_string() - .expect("Error while converting assembly-buffer to string"), - obj_buffer: obj_buffer.as_buffer(), - llvm_ir, - } - } - } -} - -impl Context { - pub fn compile(&self, cpu: Option, features: Vec) -> CompiledModule { - unsafe { - let context_ref = LLVMContextCreate(); - - let context = LLVMContext { - context_ref, - builder_ref: LLVMCreateBuilderInContext(context_ref), - }; - - let module_holders = self.builder.get_modules(); - - let main_module = module_holders - .borrow() - .iter() - .find(|m| m.data.name == "main") - .unwrap_or(module_holders.borrow().first().unwrap()) - .clone(); - - let main_module_ref = main_module.compile(&context, &self.builder); - - for holder in module_holders.borrow().iter() { - if holder.value == main_module.value { - continue; - } - let module_ref = holder.compile(&context, &self.builder); - LLVMLinkModules2(main_module_ref, module_ref); - } - - CompiledModule { - module_ref: main_module_ref, - _context: context, - cpu: cpu.unwrap_or("generic".to_owned()), - features: features.join(","), - } - } - } -} - -pub struct LLVMModule<'a> { - builder: &'a Builder, - context_ref: LLVMContextRef, - builder_ref: LLVMBuilderRef, - #[allow(dead_code)] - module_ref: LLVMModuleRef, - functions: HashMap, - blocks: HashMap, - values: HashMap, - types: HashMap, - constants: HashMap, - globals: HashMap, - debug: Option>, -} - -impl<'a> Drop for LLVMModule<'a> { - fn drop(&mut self) { - if let Some(LLVMDebugInformation { builder, .. }) = self.debug { - unsafe { - LLVMDisposeDIBuilder(builder); - } - } - } -} - -pub struct LLVMDebugInformation<'a> { - info: &'a DebugInformation, - builder: LLVMDIBuilderRef, - file_ref: LLVMMetadataRef, - scopes: &'a mut HashMap, - types: &'a mut HashMap, - metadata: &'a mut HashMap, - locations: &'a mut HashMap, -} - -#[derive(Clone, Copy)] -pub struct LLVMFunction { - type_ref: LLVMTypeRef, - value_ref: LLVMValueRef, - metadata: Option, -} - -pub struct LLVMValue { - ty: Type, - value_ref: LLVMValueRef, -} - -impl ModuleHolder { - fn compile(&self, context: &LLVMContext, builder: &Builder) -> LLVMModuleRef { - unsafe { - let module_ref = - LLVMModuleCreateWithNameInContext(into_cstring(&self.data.name).as_ptr(), context.context_ref); - - // Compile the contents - - let mut types = HashMap::new(); - let mut constants = HashMap::new(); - let mut globals = HashMap::new(); - let mut metadata = HashMap::new(); - let mut scopes = HashMap::new(); - let mut locations = HashMap::new(); - - let mut debug = if let Some(debug) = &self.debug_information { - let di_builder = LLVMCreateDIBuilder(module_ref); - - let file_ref = LLVMDIBuilderCreateFile( - di_builder, - into_cstring(debug.file.name.clone()).as_ptr(), - debug.file.name.len(), - into_cstring(debug.file.directory.clone()).as_ptr(), - debug.file.directory.len(), - ); - - let flags = String::new(); - - let compile_unit = LLVMDIBuilderCreateCompileUnit( - di_builder, - LLVMDWARFSourceLanguage::LLVMDWARFSourceLanguageC, - file_ref, - into_cstring(builder.producer.clone()).as_ptr(), - builder.producer.len(), - // is optimized - 0, - into_cstring(flags.clone()).as_ptr(), - flags.len(), - // Runtime version - 0, - // Split filename - into_cstring(debug.file.name.clone()).as_ptr(), - debug.file.name.len(), - LLVMDWARFEmissionKind::LLVMDWARFEmissionKindFull, - // The DWOId if this is a split skeleton compile unit. - 0, - // Whether to emit inline debug info. - true as i32, - // Whether to emit extra debug info for - // profile collection. - false as i32, - // The clang system root (value of -isysroot). - c"".as_ptr(), - 0, - // The SDK name. On Darwin, this is the last component of - // the sysroot. - c"".as_ptr(), - 0, - ); - - // let scope = debug.get_scopes(); - // scopes.insert(scope.borrow().value.clone(), compile_unit); - // for scope in &scope.borrow().inner_scopes { - // dbg!("hello"); - // scope.compile_scope(compile_unit, file_ref, &mut scopes, di_builder); - // } - // dbg!("after!"); - - scopes.insert(DebugScopeValue(Vec::new()), compile_unit); - - let debug = LLVMDebugInformation { - builder: di_builder, - info: debug, - file_ref, - types: &mut types, - metadata: &mut metadata, - scopes: &mut scopes, - locations: &mut locations, - }; - - for ty in debug.info.get_types().borrow().iter() { - let meta_ref = ty.compile_debug(&debug); - debug.types.insert(ty.value.clone(), meta_ref); - } - Some(debug) - } else { - None - }; - - let mut types = HashMap::new(); - for ty in &self.types { - types.insert(ty.value, ty.compile_type(context, &types)); - } - - for constant in &self.constants { - constants.insert( - constant.value, - LLVMValue { - ty: constant.kind.get_type(), - value_ref: constant - .kind - .as_llvm(context.context_ref, context.builder_ref, &constants, &types), - }, - ); - } - - for global in &self.globals { - let initializer = constants.get(&global.initializer).expect("No initializer?"); - let global_value = LLVMAddGlobal( - module_ref, - initializer.ty.as_llvm(context.context_ref, &types), - into_cstring(global.name.clone()).as_ptr(), - ); - LLVMSetInitializer(global_value, initializer.value_ref); - globals.insert(global.value, global_value); - } - - let mut functions = HashMap::new(); - for function in &self.functions { - let func = function.compile_signature(context, module_ref, &types, &mut debug); - functions.insert(function.value, func); - - if let (Some(debug), Some(debug_info)) = (&mut debug, &function.debug_info) { - let scope_refcell = debug.info.get_scope(); - let mut scope = scope_refcell.borrow(); - for i in &debug_info.0 { - scope = Ref::map(scope, |v| v.inner_scopes.get_unchecked(*i)); - } - for scope in &scope.inner_scopes { - scope.compile_scope(func.metadata.unwrap(), debug.file_ref, debug.scopes, debug.builder); - } - } - } - - if let Some(debug) = &mut debug { - for location in debug.info.get_locations().borrow().iter() { - let location_ref = location.compile(context, &debug); - debug.locations.insert(location.value.clone(), location_ref); - } - - for meta in debug.info.get_metadatas().borrow().iter() { - let meta_ref = meta.compile(&debug); - debug.metadata.insert(meta.value.clone(), meta_ref); - } - } - - let mut module = LLVMModule { - builder, - context_ref: context.context_ref, - builder_ref: context.builder_ref, - module_ref, - functions, - types, - blocks: HashMap::new(), - values: HashMap::new(), - constants, - globals, - debug, - }; - - for function in &self.functions { - function.compile(&mut module, self.data.is_main); - } - - if let Some(debug) = &module.debug { - LLVMDIBuilderFinalize(debug.builder); - } - - module_ref - } - } -} - -impl DebugLocationHolder { - unsafe fn compile(&self, context: &LLVMContext, debug: &LLVMDebugInformation) -> LLVMMetadataRef { - unsafe { - LLVMDIBuilderCreateDebugLocation( - context.context_ref, - self.location.pos.line, - self.location.pos.column, - *debug.scopes.get(&self.scope).unwrap(), - null_mut(), - ) - } - } -} - -impl DebugScopeHolder { - unsafe fn compile_scope( - &self, - parent: LLVMMetadataRef, - file: LLVMMetadataRef, - map: &mut HashMap, - di_builder: LLVMDIBuilderRef, - ) { - unsafe { - let scope = match &self.data.kind { - DebugScopeKind::CodegenContext => panic!(), - DebugScopeKind::LexicalScope(data) => LLVMDIBuilderCreateLexicalBlock( - di_builder, - parent, - file, - data.location.pos.line, - data.location.pos.column, - ), - DebugScopeKind::Subprogram(_) => panic!(), - }; - - for inner in &self.inner_scopes { - inner.compile_scope(scope, file, map, di_builder); - } - - map.insert(self.value.clone(), scope); - } - } -} - -impl DebugMetadataHolder { - unsafe fn compile(&self, debug: &LLVMDebugInformation) -> LLVMMetadataRef { - unsafe { - match &self.data { - DebugMetadata::ParamVar(param) => LLVMDIBuilderCreateParameterVariable( - debug.builder, - *debug.scopes.get(&self.location.scope).unwrap(), - into_cstring(param.name.clone()).as_ptr(), - param.name.len(), - param.arg_idx + 1, - debug.file_ref, - self.location.pos.line, - *debug.types.get(¶m.ty).unwrap(), - param.always_preserve as i32, - param.flags.as_llvm(), - ), - DebugMetadata::LocalVar(var) => LLVMDIBuilderCreateAutoVariable( - debug.builder, - *debug.scopes.get(&self.location.scope).unwrap(), - into_cstring(var.name.clone()).as_ptr(), - var.name.len(), - debug.file_ref, - self.location.pos.line, - *debug.types.get(&var.ty).unwrap(), - var.always_preserve as i32, - var.flags.as_llvm(), - 0, - ), - DebugMetadata::VarAssignment => todo!(), - } - } - } -} - -impl DebugTypeHolder { - unsafe fn compile_debug(&self, debug: &LLVMDebugInformation) -> LLVMMetadataRef { - unsafe { - match &self.data { - DebugTypeData::Basic(ty) => LLVMDIBuilderCreateBasicType( - debug.builder, - into_cstring(ty.name.clone()).as_ptr(), - ty.name.len(), - ty.size_bits as u64, - ty.encoding as u32, - ty.flags.as_llvm(), - ), - DebugTypeData::Subprogram(subprogram) => { - let mut params = subprogram - .parameters - .iter() - .map(|p| *debug.types.get(p).unwrap()) - .collect::>(); - LLVMDIBuilderCreateSubroutineType( - debug.builder, - debug.file_ref, - params.as_mut_ptr(), - params.len() as u32, - subprogram.flags.as_llvm(), - ) - } - DebugTypeData::Pointer(ptr) => LLVMDIBuilderCreatePointerType( - debug.builder, - *debug.types.get(&ptr.pointee).unwrap(), - ptr.size_bits, - 0, - 0, - into_cstring(ptr.name.clone()).as_ptr(), - ptr.name.len(), - ), - DebugTypeData::Array(array) => { - let subrange = LLVMDIBuilderGetOrCreateSubrange(debug.builder, 0, array.length as i64); - let mut elements = vec![subrange]; - LLVMDIBuilderCreateArrayType( - debug.builder, - array.size_bits, - 0, - *debug.types.get(&array.element_type).unwrap(), - elements.as_mut_ptr(), - elements.len() as u32, - ) - } - DebugTypeData::Struct(st) => { - let mut elements = st - .fields - .iter() - .map(|field| { - LLVMDIBuilderCreateMemberType( - debug.builder, - *debug.scopes.get(&st.scope).unwrap(), - into_cstring(field.name.clone()).as_ptr(), - field.name.len(), - debug.file_ref, - field.pos.map(|p| p.line).unwrap_or(1), - field.size_bits, - 0, - field.offset, - field.flags.as_llvm(), - *debug.types.get(&field.ty).unwrap(), - ) - }) - .collect::>(); - LLVMDIBuilderCreateStructType( - debug.builder, - *debug.scopes.get(&st.scope).unwrap(), - into_cstring(st.name.clone()).as_ptr(), - st.name.len(), - debug.file_ref, - st.pos.map(|p| p.line).unwrap_or(1), - st.size_bits, - 0, - st.flags.as_llvm(), - null_mut(), // derived from - elements.as_mut_ptr(), - elements.len() as u32, - 0, // Runtime lang - null_mut(), // VTable - null(), // Unique ID - 0, // Unique ID len - ) - } - } - } - } -} - -impl DwarfFlags { - pub fn as_llvm(&self) -> i32 { - 0 - } -} - -impl TypeHolder { - unsafe fn compile_type(&self, context: &LLVMContext, types: &HashMap) -> LLVMTypeRef { - unsafe { - match &self.data.kind { - CustomTypeKind::NamedStruct(named_struct) => { - let mut elem_types = Vec::new(); - for ty in &named_struct.1 { - elem_types.push(ty.as_llvm(context.context_ref, types)); - } - let struct_ty = - LLVMStructCreateNamed(context.context_ref, into_cstring(named_struct.0.clone()).as_ptr()); - LLVMStructSetBody(struct_ty, elem_types.as_mut_ptr(), elem_types.len() as u32, 0); - struct_ty - } - } - } - } -} - -impl FunctionHolder { - unsafe fn compile_signature( - &self, - context: &LLVMContext, - module_ref: LLVMModuleRef, - types: &HashMap, - debug: &mut Option, - ) -> LLVMFunction { - unsafe { - let ret_type = self.data.ret.as_llvm(context.context_ref, types); - let mut param_types: Vec = self - .data - .params - .iter() - .map(|t| t.as_llvm(context.context_ref, types)) - .collect(); - let param_ptr = param_types.as_mut_ptr(); - let param_len = param_types.len(); - - let name = if self.data.flags.is_main { - c"main" - } else { - &into_cstring(&self.data.linkage_name.clone().unwrap_or(self.data.name.clone())) - }; - - let fn_type = LLVMFunctionType(ret_type, param_ptr, param_len as u32, 0); - - let function_ref = LLVMAddFunction(module_ref, name.as_ptr(), fn_type); - - if self.data.flags.inline { - let attribute = LLVMCreateEnumAttribute(context.context_ref, LLVMEnumAttribute::AlwaysInline as u32, 0); - LLVMAddAttributeAtIndex(function_ref, 0, attribute); - } - - let metadata = if let Some(debug) = debug { - if let Some(scope_value) = &self.debug_info { - let scope_data = debug.info.get_scope_data(scope_value).unwrap(); - - let mangled_length_ptr = &mut 0; - let mangled_name = LLVMGetValueName2(function_ref, mangled_length_ptr); - let mangled_length = *mangled_length_ptr; - - let subprogram = match scope_data.kind { - DebugScopeKind::CodegenContext => panic!(), - DebugScopeKind::LexicalScope(_) => panic!(), - DebugScopeKind::Subprogram(subprogram) => LLVMDIBuilderCreateFunction( - debug.builder, - *debug.scopes.get(&scope_data.parent.unwrap()).unwrap(), - into_cstring(subprogram.name.clone()).as_ptr(), - subprogram.name.clone().len(), - mangled_name, - mangled_length, - debug.file_ref, - subprogram.location.pos.line, - *debug.types.get(&subprogram.ty).unwrap(), - subprogram.opts.is_local as i32, - subprogram.opts.is_definition as i32, - subprogram.opts.scope_line, - subprogram.opts.flags.as_llvm(), - subprogram.opts.is_optimized as i32, - ), - }; - - LLVMSetSubprogram(function_ref, subprogram); - debug.scopes.insert(scope_value.clone(), subprogram); - Some(subprogram) - } else { - None - } - } else { - None - }; - - LLVMFunction { - type_ref: fn_type, - value_ref: function_ref, - metadata, - } - } - } - - unsafe fn compile(&self, module: &mut LLVMModule, in_main_module: bool) { - unsafe { - let own_function = *module.functions.get(&self.value).unwrap(); - - if self.data.flags.is_extern { - LLVMSetLinkage(own_function.value_ref, LLVMLinkage::LLVMExternalLinkage); - // TODO Use "available internally" if the other kind of extern - return; - } - - if self.data.flags.is_imported { - if self.data.flags.is_extern { - LLVMSetLinkage(own_function.value_ref, LLVMLinkage::LLVMAvailableExternallyLinkage); - } else { - LLVMSetLinkage(own_function.value_ref, LLVMLinkage::LLVMExternalLinkage); - } - } else { - LLVMSetLinkage(own_function.value_ref, LLVMLinkage::LLVMPrivateLinkage); - } - - if in_main_module && self.data.flags.is_main || self.data.flags.is_pub { - LLVMSetLinkage(own_function.value_ref, LLVMLinkage::LLVMExternalLinkage); - } - - for block in &self.blocks { - if block.data.deleted { - continue; - } - - let block_ref = - LLVMCreateBasicBlockInContext(module.context_ref, into_cstring(&block.data.name).as_ptr()); - LLVMAppendExistingBasicBlock(own_function.value_ref, block_ref); - module.blocks.insert(block.value, block_ref); - } - - for block in &self.blocks { - block.compile(module, &own_function); - } - } - } -} - -impl BlockHolder { - unsafe fn compile(&self, module: &mut LLVMModule, function: &LLVMFunction) { - unsafe { - if self.data.deleted { - return; - } - - let block_ref = *module.blocks.get(&self.value).unwrap(); - LLVMPositionBuilderAtEnd(module.builder_ref, block_ref); - - for instruction in &self.instructions { - let key = instruction.value; - let ret = instruction.compile(module, function, block_ref); - module.values.insert(key, ret); - } - - let term_instr = self - .data - .terminator - .clone() - .expect(&format!("Block {} does not have a terminator!", self.data.name)) - .compile(module, function, block_ref); - - if let Some(location) = &self.data.terminator_location { - LLVMInstructionSetDebugLoc( - term_instr.value_ref, - *module.debug.as_ref().unwrap().locations.get(&location).unwrap(), - ); - } - } - } -} - -impl InstructionHolder { - unsafe fn compile(&self, module: &LLVMModule, function: &LLVMFunction, _block: LLVMBasicBlockRef) -> LLVMValue { - let _ty = self.value.get_type(module.builder).unwrap(); - let name = into_cstring(self.name.clone()); - let val = unsafe { - use super::Instr::*; - match &self.data.kind { - Param(nth) => LLVMGetParam(function.value_ref, *nth as u32), - Constant(val) => val.as_llvm(module.context_ref, module.builder_ref, &module.constants, &module.types), - Add(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildAdd(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - FAdd(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildFAdd(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - Sub(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildSub(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - FSub(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildFSub(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - Mul(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildMul(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - FMul(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildFMul(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - UDiv(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildUDiv(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - SDiv(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildSDiv(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - FDiv(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildFDiv(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - URem(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildURem(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - SRem(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildSRem(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - FRem(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildFRem(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - And(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildAnd(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - ICmp(pred, lhs, rhs) => { - let lhs = module.values.get(&lhs).unwrap(); - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildICmp( - module.builder_ref, - // Signedness from LHS - pred.as_llvm_int(lhs.ty.category().signed()), - lhs.value_ref, - rhs_val, - name.as_ptr(), - ) - } - FCmp(pred, lhs, rhs) => { - let lhs = module.values.get(&lhs).unwrap(); - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildFCmp( - module.builder_ref, - pred.as_llvm_unsorted_float(), - lhs.value_ref, - rhs_val, - name.as_ptr(), - ) - } - FunctionCall(function_value, instruction_values) => { - let fun = module.functions.get(&function_value).unwrap(); - let mut param_list: Vec = instruction_values - .iter() - .map(|i| module.values.get(i).unwrap().value_ref) - .collect(); - - let is_void = module.builder.function_data(&*function_value).ret == Type::Void; - if is_void { - LLVMContextSetDiscardValueNames(module.context_ref, 1); - } - let value = LLVMBuildCall2( - module.builder_ref, - fun.type_ref, - fun.value_ref, - param_list.as_mut_ptr(), - param_list.len() as u32, - name.as_ptr(), - ); - if is_void { - LLVMContextSetDiscardValueNames(module.context_ref, 0); - } - value - } - Phi(values) => { - let mut inc_values = Vec::new(); - let mut inc_blocks = Vec::new(); - for item in values { - inc_values.push(module.values.get(&item).unwrap().value_ref); - inc_blocks.push(*module.blocks.get(&item.0).unwrap()); - } - let phi = LLVMBuildPhi( - module.builder_ref, - _ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ); - LLVMAddIncoming( - phi, - inc_values.as_mut_ptr(), - inc_blocks.as_mut_ptr(), - values.len() as u32, - ); - phi - } - Alloca(ty) => LLVMBuildAlloca( - module.builder_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - Load(ptr, ty) => LLVMBuildLoad2( - module.builder_ref, - ty.as_llvm(module.context_ref, &module.types), - module.values.get(&ptr).unwrap().value_ref, - name.as_ptr(), - ), - Store(ptr, val) => { - let store = LLVMBuildStore( - module.builder_ref, - module.values.get(&val).unwrap().value_ref, - module.values.get(&ptr).unwrap().value_ref, - ); - store - } - ArrayAlloca(ty, len) => LLVMBuildArrayAlloca( - module.builder_ref, - ty.as_llvm(module.context_ref, &module.types), - module.values.get(&len).unwrap().value_ref, - name.as_ptr(), - ), - GetElemPtr(arr, indices) => { - let t = arr.get_type(module.builder).unwrap(); - let Type::Ptr(elem_t) = t else { panic!() }; - - let mut llvm_indices: Vec<_> = indices - .iter() - .map(|idx_elem| module.values.get(idx_elem).unwrap().value_ref) - .collect(); - - LLVMBuildInBoundsGEP2( - module.builder_ref, - elem_t.as_llvm(module.context_ref, &module.types), - module.values.get(arr).unwrap().value_ref, - llvm_indices.as_mut_ptr(), - llvm_indices.len() as u32, - name.as_ptr(), - ) - } - GetStructElemPtr(struct_val, idx) => { - let t = struct_val.get_type(module.builder).unwrap(); - let Type::Ptr(struct_t) = t else { panic!() }; - - LLVMBuildStructGEP2( - module.builder_ref, - struct_t.as_llvm(module.context_ref, &module.types), - module.values.get(struct_val).unwrap().value_ref, - *idx, - name.as_ptr(), - ) - } - ExtractValue(agg_val, idx) => LLVMBuildExtractValue( - module.builder_ref, - module.values.get(agg_val).unwrap().value_ref, - *idx, - name.as_ptr(), - ), - Trunc(instr_val, ty) => LLVMBuildTrunc( - module.builder_ref, - module.values.get(instr_val).unwrap().value_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - ZExt(instr_val, ty) => LLVMBuildZExt( - module.builder_ref, - module.values.get(instr_val).unwrap().value_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - SExt(instr_val, ty) => LLVMBuildSExt( - module.builder_ref, - module.values.get(instr_val).unwrap().value_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - FPTrunc(instr_val, ty) => LLVMBuildFPTrunc( - module.builder_ref, - module.values.get(instr_val).unwrap().value_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - FPExt(instr_val, ty) => LLVMBuildFPExt( - module.builder_ref, - module.values.get(instr_val).unwrap().value_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - FPToUI(instr_val, ty) => LLVMBuildFPToUI( - module.builder_ref, - module.values.get(instr_val).unwrap().value_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - FPToSI(instr_val, ty) => LLVMBuildFPToSI( - module.builder_ref, - module.values.get(instr_val).unwrap().value_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - UIToFP(instr_val, ty) => LLVMBuildUIToFP( - module.builder_ref, - module.values.get(instr_val).unwrap().value_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - SIToFP(instr_val, ty) => LLVMBuildSIToFP( - module.builder_ref, - module.values.get(instr_val).unwrap().value_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - PtrToInt(instr_val, ty) => LLVMBuildPtrToInt( - module.builder_ref, - module.values.get(instr_val).unwrap().value_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - IntToPtr(instr_val, ty) => LLVMBuildIntToPtr( - module.builder_ref, - module.values.get(instr_val).unwrap().value_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - BitCast(instr_val, ty) => LLVMBuildBitCast( - module.builder_ref, - module.values.get(instr_val).unwrap().value_ref, - ty.as_llvm(module.context_ref, &module.types), - name.as_ptr(), - ), - Or(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildOr(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - XOr(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildXor(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - ShiftRightLogical(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildLShr(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - ShiftRightArithmetic(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildAShr(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - ShiftLeft(lhs, rhs) => { - let lhs_val = module.values.get(&lhs).unwrap().value_ref; - let rhs_val = module.values.get(&rhs).unwrap().value_ref; - LLVMBuildShl(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) - } - GetGlobal(global_value) => module.globals.get(global_value).unwrap().clone(), - IsNull(instruction_value) => { - let val = module.values.get(&*instruction_value).unwrap().value_ref; - LLVMBuildIsNull(module.builder_ref, val, name.as_ptr()) - } - } - }; - if let Some(record) = &self.record { - let debug = module.debug.as_ref().unwrap(); - - unsafe { - let mut addr = Vec::::new(); - let expr = LLVMDIBuilderCreateExpression(debug.builder, addr.as_mut_ptr(), addr.len()); - - let location = LLVMDIBuilderCreateDebugLocation( - module.context_ref, - record.location.pos.line, - record.location.pos.column, - *debug.scopes.get(&record.scope).unwrap(), - null_mut(), - ); - - match record.kind { - DebugRecordKind::Declare(instruction_value) => LLVMDIBuilderInsertDeclareRecordBefore( - debug.builder, - module.values.get(&instruction_value).unwrap().value_ref, - *debug.metadata.get(&record.variable).unwrap(), - expr, - location, - val, - ), - DebugRecordKind::Value(instruction_value) => LLVMDIBuilderInsertDbgValueRecordBefore( - debug.builder, - module.values.get(&instruction_value).unwrap().value_ref, - *debug.metadata.get(&record.variable).unwrap(), - expr, - location, - val, - ), - }; - } - } - if let Some(location) = &self.data.location { - unsafe { - match LLVMGetValueKind(val) { - LLVMValueKind::LLVMInstructionValueKind - | LLVMValueKind::LLVMMemoryDefValueKind - | LLVMValueKind::LLVMMemoryUseValueKind - | LLVMValueKind::LLVMMemoryPhiValueKind => { - LLVMInstructionSetDebugLoc( - val, - *module.debug.as_ref().unwrap().locations.get(&location).unwrap(), - ); - } - _ => {} - } - } - } - LLVMValue { - ty: _ty, - value_ref: val, - } - } -} - -impl TerminatorKind { - fn compile(&self, module: &LLVMModule, _function: &LLVMFunction, _block: LLVMBasicBlockRef) -> LLVMValue { - let _ty = self.get_type(module.builder).unwrap(); - let val = unsafe { - match self { - TerminatorKind::Ret(val) => { - let value = module.values.get(val).unwrap(); - LLVMBuildRet(module.builder_ref, value.value_ref) - } - TerminatorKind::RetVoid => LLVMBuildRetVoid(module.builder_ref), - TerminatorKind::Br(block_value) => { - let dest = *module.blocks.get(block_value).unwrap(); - LLVMBuildBr(module.builder_ref, dest) - } - TerminatorKind::CondBr(cond, then_b, else_b) => { - let cond_val = module.values.get(cond).unwrap().value_ref; - let then_bb = *module.blocks.get(then_b).unwrap(); - let else_bb = *module.blocks.get(else_b).unwrap(); - LLVMBuildCondBr(module.builder_ref, cond_val, then_bb, else_bb) - } - } - }; - LLVMValue { - ty: _ty, - value_ref: val, - } - } -} - -impl CmpPredicate { - fn as_llvm_int(&self, signed: bool) -> LLVMIntPredicate { - use CmpPredicate::*; - use LLVMIntPredicate::*; - match (self, signed) { - (LT, true) => LLVMIntSLT, - (LE, true) => LLVMIntSLE, - (GT, true) => LLVMIntSGT, - (GE, true) => LLVMIntSGE, - (LT, false) => LLVMIntULT, - (LE, false) => LLVMIntULE, - (GT, false) => LLVMIntUGT, - (GE, false) => LLVMIntUGE, - (EQ, _) => LLVMIntEQ, - (NE, _) => LLVMIntNE, - } - } - - fn as_llvm_unsorted_float(&self) -> LLVMRealPredicate { - use CmpPredicate::*; - use LLVMRealPredicate::*; - match self { - LT => LLVMRealULT, - LE => LLVMRealULE, - GT => LLVMRealUGT, - GE => LLVMRealUGE, - EQ => LLVMRealUEQ, - NE => LLVMRealUNE, - } - } -} - -impl ConstValueKind { - fn as_llvm( - &self, - context: LLVMContextRef, - builder: LLVMBuilderRef, - constants: &HashMap, - types: &HashMap, - ) -> LLVMValueRef { - unsafe { - let t = self.get_type().as_llvm(context, &types); - match self { - ConstValueKind::Bool(val) => LLVMConstInt(t, *val as u64, 1), - ConstValueKind::I8(val) => LLVMConstInt(t, *val as u64, 1), - ConstValueKind::I16(val) => LLVMConstInt(t, *val as u64, 1), - ConstValueKind::I32(val) => LLVMConstInt(t, *val as u64, 1), - ConstValueKind::I64(val) => LLVMConstInt(t, *val as u64, 1), - ConstValueKind::I128(val) => LLVMConstInt(t, *val as u64, 1), - ConstValueKind::U8(val) => LLVMConstInt(t, *val as u64, 1), - ConstValueKind::U16(val) => LLVMConstInt(t, *val as u64, 1), - ConstValueKind::U32(val) => LLVMConstInt(t, *val as u64, 1), - ConstValueKind::U64(val) => LLVMConstInt(t, *val as u64, 1), - ConstValueKind::U128(val) => LLVMConstInt(t, *val as u64, 1), - ConstValueKind::Str(val) => { - LLVMBuildGlobalString(builder, into_cstring(val).as_ptr(), c"string".as_ptr()) - } - ConstValueKind::F16(val) => LLVMConstReal(t, *val as f64), - ConstValueKind::F32B(val) => LLVMConstReal(t, *val as f64), - ConstValueKind::F32(val) => LLVMConstReal(t, *val as f64), - ConstValueKind::F64(val) => LLVMConstReal(t, *val as f64), - ConstValueKind::F80(val) => LLVMConstReal(t, *val as f64), - ConstValueKind::F128(val) => LLVMConstReal(t, *val as f64), - ConstValueKind::F128PPC(val) => LLVMConstReal(t, *val as f64), - ConstValueKind::Array(constant_values, elem_ty) => { - let mut values = constant_values - .iter() - .map(|v| constants.get(v).unwrap().value_ref) - .collect::>(); - - LLVMConstArray2( - elem_ty.as_llvm(context, &types), - values.as_mut_ptr(), - values.len() as u64, - ) - } - } - } - } -} - -impl Type { - fn as_llvm(&self, context: LLVMContextRef, typemap: &HashMap) -> LLVMTypeRef { - use Type::*; - unsafe { - match self { - I8 | U8 => LLVMInt8TypeInContext(context), - I16 | U16 => LLVMInt16TypeInContext(context), - I32 | U32 => LLVMInt32TypeInContext(context), - I64 | U64 => LLVMInt64TypeInContext(context), - I128 | U128 => LLVMInt128TypeInContext(context), - Bool => LLVMInt1TypeInContext(context), - Void => LLVMVoidTypeInContext(context), - Ptr(ty) => LLVMPointerType(ty.as_llvm(context, typemap), 0), - CustomType(struct_ty) => *typemap.get(struct_ty).unwrap(), - Array(r#type, len) => LLVMArrayType2(r#type.as_llvm(context, typemap), *len), - F16 => LLVMHalfTypeInContext(context), - F32 => LLVMFloatTypeInContext(context), - F32B => LLVMBFloatTypeInContext(context), - F64 => LLVMDoubleTypeInContext(context), - F80 => LLVMX86FP80TypeInContext(context), - F128 => LLVMFP128TypeInContext(context), - F128PPC => LLVMPPCFP128TypeInContext(context), - } - } - } -} - -pub enum LLVMEnumAttribute { - AlwaysInline = 3, -} diff --git a/reid-llvm-lib/src/debug_information.rs b/reid-llvm-lib/src/debug_information.rs deleted file mode 100644 index bb7b994..0000000 --- a/reid-llvm-lib/src/debug_information.rs +++ /dev/null @@ -1,399 +0,0 @@ -use std::{ - cell::{Ref, RefCell, RefMut}, - rc::Rc, -}; - -use crate::builder::InstructionValue; - -/// Represents 1. the compilation context, 2. subprogram or 3. a lexical scope -#[derive(Clone, Hash, PartialEq, Eq)] -pub struct DebugScopeValue(pub Vec); - -#[derive(Clone, Hash, PartialEq, Eq)] -pub struct DebugLocationValue(pub DebugScopeValue, pub usize); - -#[derive(Clone, Copy, Hash, PartialEq, Eq)] -pub struct DebugTypeValue(pub usize); - -#[derive(Clone, Copy, Hash, PartialEq, Eq)] -pub struct DebugMetadataValue(pub usize); - -#[derive(Debug, Clone)] -pub struct DebugFileData { - pub name: String, - pub directory: String, -} - -#[derive(Debug, Clone)] -pub(crate) struct DebugScopeHolder { - pub(crate) value: DebugScopeValue, - pub(crate) data: DebugScopeData, - pub(crate) inner_scopes: Vec, -} - -#[derive(Debug, Clone)] -pub struct DebugMetadataHolder { - pub(crate) location: DebugLocation, - pub(crate) value: DebugMetadataValue, - pub(crate) data: DebugMetadata, -} - -#[derive(Clone)] -pub struct DebugTypeHolder { - pub(crate) value: DebugTypeValue, - pub(crate) data: DebugTypeData, -} - -#[derive(Debug, Clone)] -pub(crate) struct DebugLocationHolder { - pub(crate) scope: DebugScopeValue, - pub(crate) value: DebugLocationValue, - pub(crate) location: DebugLocation, -} - -#[derive(Debug, Clone)] -pub struct DebugInformation { - pub file: DebugFileData, - scope: Rc>, - locations: Rc>>, - metadata: Rc>>, - types: Rc>>, -} - -impl DebugInformation { - pub fn from_file(file: DebugFileData) -> (DebugInformation, DebugScopeValue) { - let scope_value = DebugScopeValue(Vec::new()); - ( - DebugInformation { - file, - scope: Rc::new(RefCell::new(DebugScopeHolder { - value: scope_value.clone(), - inner_scopes: Vec::new(), - data: DebugScopeData { - parent: None, - kind: DebugScopeKind::CodegenContext, - }, - })), - locations: Rc::new(RefCell::new(Vec::new())), - metadata: Rc::new(RefCell::new(Vec::new())), - types: Rc::new(RefCell::new(Vec::new())), - }, - scope_value, - ) - } - - pub fn location(&self, scope_value: &DebugScopeValue, location: DebugLocation) -> DebugLocationValue { - let value = DebugLocationValue(scope_value.clone(), self.locations.borrow().len()); - let location = DebugLocationHolder { - scope: scope_value.clone(), - value: value.clone(), - location, - }; - self.locations.borrow_mut().push(location); - value - } - - pub fn debug_type(&self, kind: DebugTypeData) -> DebugTypeValue { - let mut types = self.types.borrow_mut(); - let value = DebugTypeValue(types.len()); - types.push(DebugTypeHolder { - value: value.clone(), - data: kind, - }); - value - } - - pub fn metadata(&self, location: &DebugLocation, kind: DebugMetadata) -> DebugMetadataValue { - let mut metadata = self.metadata.borrow_mut(); - let value = DebugMetadataValue(metadata.len()); - metadata.push(DebugMetadataHolder { - location: location.clone(), - value: value.clone(), - data: kind, - }); - value - } - - pub fn subprogram(&self, parent: DebugScopeValue, kind: DebugSubprogramData) -> DebugScopeValue { - unsafe { - let mut outer_scope = RefMut::map(self.scope.borrow_mut(), |mut v| { - for i in &parent.0 { - v = v.inner_scopes.get_unchecked_mut(*i); - } - v - }); - - let mut arr = parent.0.clone(); - arr.push(outer_scope.inner_scopes.len()); - let value = DebugScopeValue(arr); - - outer_scope.inner_scopes.push(DebugScopeHolder { - value: value.clone(), - inner_scopes: Vec::new(), - data: DebugScopeData { - parent: Some(parent.clone()), - kind: DebugScopeKind::Subprogram(kind), - }, - }); - value - } - } - pub fn lexical_scope(&self, parent: &DebugScopeValue, data: DebugLexicalScope) -> DebugScopeValue { - unsafe { - let mut outer_scope = RefMut::map(self.scope.borrow_mut(), |mut v| { - for i in &parent.0 { - v = v.inner_scopes.get_unchecked_mut(*i); - } - v - }); - - let mut arr = parent.0.clone(); - arr.push(outer_scope.inner_scopes.len()); - let value = DebugScopeValue(arr); - - outer_scope.inner_scopes.push(DebugScopeHolder { - value: value.clone(), - inner_scopes: Vec::new(), - data: DebugScopeData { - parent: Some(parent.clone()), - kind: DebugScopeKind::LexicalScope(data), - }, - }); - value - } - } - - pub fn get_metadata(&self, value: DebugMetadataValue) -> DebugMetadata { - unsafe { self.metadata.borrow().get_unchecked(value.0).data.clone() } - } - - pub fn get_metadata_location(&self, value: DebugMetadataValue) -> DebugLocation { - unsafe { self.metadata.borrow().get_unchecked(value.0).location.clone() } - } - - pub fn get_scope_data(&self, value: &DebugScopeValue) -> Option { - let scope = Ref::filter_map(self.scope.borrow(), |v: &DebugScopeHolder| { - let mut opt = Some(v); - for i in &value.0 { - if let Some(inner) = opt { - opt = inner.inner_scopes.get(*i); - } - } - opt - }); - - if let Ok(scope) = scope { - Some(scope.data.clone()) - } else { - None - } - } - - pub fn get_type_data(&self, value: DebugTypeValue) -> DebugTypeData { - unsafe { self.types.borrow().get_unchecked(value.0).data.clone() } - } - - pub fn get_location(&self, value: &DebugLocationValue) -> DebugLocation { - unsafe { self.locations.borrow().get_unchecked(value.1).location.clone() } - } - - pub fn get_metadatas(&self) -> Rc>> { - self.metadata.clone() - } - - pub(crate) fn get_scope(&self) -> Rc> { - self.scope.clone() - } - - pub fn get_types(&self) -> Rc>> { - self.types.clone() - } - - pub(crate) fn get_locations(&self) -> Rc>> { - self.locations.clone() - } -} - -#[derive(Clone)] -pub struct DebugLocation { - pub scope: DebugScopeValue, - pub pos: DebugPosition, -} - -#[derive(Clone, Copy)] -pub struct DebugPosition { - pub line: u32, - pub column: u32, -} - -#[derive(Debug, Clone)] -pub enum DebugMetadata { - ParamVar(DebugParamVariable), - LocalVar(DebugLocalVariable), - VarAssignment, -} - -#[derive(Debug, Clone)] -pub struct DebugParamVariable { - pub name: String, - /// the index (starting from 1) of this variable in the subprogram - /// parameters. arg_idx should not conflict with other parameters of the - /// same subprogram. - pub arg_idx: u32, - pub ty: DebugTypeValue, - /// If this variable will be referenced from its containing subprogram, and - /// will survive some optimizations. - pub always_preserve: bool, - pub flags: DwarfFlags, -} - -#[derive(Debug, Clone)] -pub struct DebugLocalVariable { - pub name: String, - pub ty: DebugTypeValue, - pub always_preserve: bool, - pub flags: DwarfFlags, -} - -impl Default for DebugSubprogramOptionals { - fn default() -> Self { - Self { - scope_line: 0, - is_local: false, - is_definition: true, - is_optimized: false, - flags: DwarfFlags, - } - } -} - -#[derive(Debug, Clone)] -pub struct DwarfFlags; - -#[derive(Clone)] -pub enum DebugTypeData { - Basic(DebugBasicType), - Subprogram(DebugSubprogramType), - Pointer(DebugPointerType), - Array(DebugArrayType), - Struct(DebugStructType), -} - -#[derive(Clone)] -pub struct DebugBasicType { - pub name: String, - /// Size of the type. - pub size_bits: u64, - /// DWARF encoding code, e.g., dwarf::DW_ATE_float. - pub encoding: DwarfEncoding, - /// Optional DWARF attributes, e.g., DW_AT_endianity. - pub flags: DwarfFlags, -} - -#[derive(Clone)] -pub struct DebugArrayType { - pub size_bits: u64, - pub align_bits: u32, - pub element_type: DebugTypeValue, - pub length: u64, -} - -#[derive(Clone)] -pub struct DebugPointerType { - pub name: String, - pub pointee: DebugTypeValue, - pub size_bits: u64, -} -#[derive(Clone)] -pub struct DebugStructType { - pub name: String, - pub scope: DebugScopeValue, - pub pos: Option, - pub size_bits: u64, - pub flags: DwarfFlags, - pub fields: Vec, -} - -#[derive(Clone)] -pub struct DebugFieldType { - pub name: String, - pub scope: DebugScopeValue, - pub pos: Option, - pub size_bits: u64, - pub offset: u64, - pub flags: DwarfFlags, - pub ty: DebugTypeValue, -} - -#[derive(Clone)] -pub struct DebugSubprogramType { - pub parameters: Vec, - pub flags: DwarfFlags, -} - -#[derive(Debug, Clone, Copy)] -pub enum DwarfEncoding { - Address = 1, - Boolean = 2, - Float = 4, - Signed = 5, - SignedChar = 6, - Unsigned = 7, - UnsignedChar = 8, -} - -#[derive(Debug, Clone)] -pub struct DebugScopeData { - pub parent: Option, - pub kind: DebugScopeKind, -} - -#[derive(Debug, Clone)] -pub enum DebugScopeKind { - CodegenContext, - LexicalScope(DebugLexicalScope), - Subprogram(DebugSubprogramData), -} - -#[derive(Debug, Clone)] -pub struct DebugLexicalScope { - pub location: DebugLocation, -} - -#[derive(Debug, Clone)] -pub struct DebugSubprogramData { - /// Function name. - pub name: String, - pub outer_scope: DebugScopeValue, - /// Used for line number. - pub location: DebugLocation, - /// Function type. - pub ty: DebugTypeValue, - pub opts: DebugSubprogramOptionals, -} - -#[derive(Debug, Clone)] -pub struct DebugSubprogramOptionals { - /// Set to the beginning of the scope this starts - pub scope_line: u32, - pub is_local: bool, - pub is_definition: bool, - pub is_optimized: bool, - /// These flags are used to emit dwarf attributes. e.g. is this function - /// prototyped or not. - pub flags: DwarfFlags, -} - -#[derive(Clone)] -pub struct InstructionDebugRecordData { - pub scope: DebugScopeValue, - pub variable: DebugMetadataValue, - pub location: DebugLocation, - pub kind: DebugRecordKind, -} - -#[derive(Clone, Copy)] -pub enum DebugRecordKind { - Declare(InstructionValue), - Value(InstructionValue), -} diff --git a/reid-llvm-lib/src/fmt.rs b/reid-llvm-lib/src/fmt.rs deleted file mode 100644 index c9f77a9..0000000 --- a/reid-llvm-lib/src/fmt.rs +++ /dev/null @@ -1,595 +0,0 @@ -//! Debug implementations for relevant types - -use std::{ - fmt::{Debug, Display, Write}, - marker::PhantomData, -}; - -use crate::{ - CmpPredicate, Context, Instr, InstructionData, TerminatorKind, - builder::*, - debug_information::{ - DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocalVariable, DebugLocation, - DebugLocationValue, DebugMetadata, DebugMetadataValue, DebugParamVariable, DebugPointerType, DebugPosition, - DebugRecordKind, DebugScopeValue, DebugStructType, DebugSubprogramType, DebugTypeData, DebugTypeHolder, - DebugTypeValue, - }, - pad_adapter::PadAdapter, -}; - -impl Display for Context { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Display::fmt(&self.builder, f) - } -} - -impl Display for Builder { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "Producer: {}", self.producer)?; - for module in self.modules.borrow().iter() { - if module.data.is_main { - write!(f, "main ")?; - } - writeln!(f, "{} ({:?}) {{", module.data.name, module.value)?; - for function in &module.functions { - let mut state = Default::default(); - let mut inner = PadAdapter::wrap(f, &mut state); - function.builder_fmt(&mut inner, self, &module.debug_information)?; - } - writeln!(f, "}}")?; - } - Ok(()) - } -} - -impl FunctionHolder { - fn builder_fmt( - &self, - f: &mut impl std::fmt::Write, - builder: &Builder, - debug: &Option, - ) -> std::fmt::Result { - if self.data.flags.is_imported { - write!(f, "imported ")?; - } - if self.data.flags.is_extern { - write!(f, "extern ")?; - } - if self.data.flags.is_pub { - write!(f, "pub ")?; - } - if self.data.flags.is_main { - write!(f, "main ")?; - } - let params = self - .data - .params - .iter() - .map(|p| format!("{:?}", p)) - .collect::>() - .join(", "); - write!(f, "fn {}({}) -> {:?} ", self.data.name, params, self.data.ret)?; - - writeln!(f, "{{")?; - let mut state = Default::default(); - let mut inner = PadAdapter::wrap(f, &mut state); - writeln!(inner, "(Value = {:?}) ", self.value)?; - if let Some(debug) = &self.debug_info { - writeln!(inner, "(Debug = {:?})", debug)?; - } - - for block in &self.blocks { - let mut state = Default::default(); - let mut inner = PadAdapter::wrap(&mut inner, &mut state); - block.builder_fmt(&mut inner, builder, debug)?; - } - - writeln!(f, "}}")?; - Ok(()) - } -} - -impl BlockHolder { - fn builder_fmt( - &self, - f: &mut impl std::fmt::Write, - builder: &Builder, - debug: &Option, - ) -> std::fmt::Result { - if self.data.deleted { - write!(f, "deleted ")?; - } - writeln!(f, "{} ({:?}):", self.data.name, self.value)?; - - let mut state = Default::default(); - let mut inner = PadAdapter::wrap(f, &mut state); - - for instr in &self.instructions { - instr.builder_fmt(&mut inner, builder, debug)?; - } - - if let Some(terminator) = &self.data.terminator { - terminator.builder_fmt(&mut inner, builder, debug)?; - } - if let Some(location) = &self.data.terminator_location { - writeln!(inner, " ^ (At {}) ", debug.as_ref().unwrap().get_location(location))?; - } - - Ok(()) - } -} - -impl InstructionHolder { - fn builder_fmt( - &self, - f: &mut impl std::fmt::Write, - _builder: &Builder, - debug: &Option, - ) -> std::fmt::Result { - if let Some(record) = &self.record { - let kind = match record.kind { - DebugRecordKind::Declare(instruction_value) => { - format!("= {:?} (Assign)", instruction_value) - } - DebugRecordKind::Value(instruction_value) => { - format!("= {:?} (Value)", instruction_value) - } - }; - - if let Some(debug) = debug { - writeln!(f, " (Debug {} {})", record.variable.hr(debug), kind)?; - } - } - writeln!(f, "{:?} ({}) = {:?} ", self.value, self.name, self.data.kind)?; - if let Some(debug) = debug { - if let Some(location) = &self.data.location { - writeln!(f, " ^ (At {}) ", debug.get_location(location))?; - } - if let Some(meta) = self.data.meta { - writeln!(f, " ^ (Meta {}) ", meta.hr(debug))?; - } - } - writeln!(f)?; - - Ok(()) - } -} - -impl TerminatorKind { - fn builder_fmt( - &self, - f: &mut impl std::fmt::Write, - _builder: &Builder, - _debug: &Option, - ) -> std::fmt::Result { - match self { - TerminatorKind::Ret(instr) => writeln!(f, "ret {:?}", instr), - TerminatorKind::RetVoid => writeln!(f, "ret void"), - TerminatorKind::Br(block) => writeln!(f, "br {:?}", block), - TerminatorKind::CondBr(instr, lhs, rhs) => { - writeln!(f, "condbr {:?}, {:?} or {:?}", instr, lhs, rhs) - } - } - } -} - -impl DebugMetadataValue { - fn hr(&self, debug: &DebugInformation) -> String { - let kind = match debug.get_metadata(*self) { - DebugMetadata::ParamVar(DebugParamVariable { name, arg_idx, ty, .. }) => { - format!("param {} (idx {}) (type {:?}) ", name, arg_idx, ty) - } - DebugMetadata::LocalVar(DebugLocalVariable { name, ty, .. }) => { - format!("var {} (type {:?}) ", name, ty) - } - DebugMetadata::VarAssignment => todo!(), - }; - format!("{} at {}", kind, debug.get_metadata_location(*self)) - } -} - -impl Display for DebugLocation { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?} on scope {:?}", self.pos, self.scope) - } -} - -impl Display for DebugPosition { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "line {}, col {}", self.line, self.column) - } -} - -impl Debug for Builder { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_list().entries(self.get_modules().borrow().iter()); - Ok(()) - } -} - -pub struct PrintableModule<'ctx> { - pub phantom: PhantomData<&'ctx ()>, - pub module: ModuleHolder, -} - -impl<'ctx> Debug for PrintableModule<'ctx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Debug::fmt(&self.module, f) - } -} - -impl Debug for ModuleHolder { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple(&format!("{}({:#?}) ", self.data.name, self.value)) - .field(&self.functions) - // .field(&self.debug_information) - .finish() - } -} - -impl Debug for FunctionHolder { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple(&format!( - "{}({:?}) -> {:?} ", - self.data.name, self.data.params, self.data.ret - )) - .field(&self.blocks) - .finish() - } -} - -impl Debug for BlockHolder { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let deleted = if self.data.deleted { " (deleted)" } else { "" }; - f.debug_tuple(&format!("{}[{:?}]{} ", &self.data.name, &self.value, deleted)) - .field(&self.instructions) - .field(&self.data.terminator) - .field(&self.data.terminator_location) - .finish() - } -} - -impl Debug for InstructionHolder { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.value.fmt(f)?; - write!(f, " ({})", self.name)?; - f.write_str(" = ")?; - self.data.fmt(f) - } -} - -impl Debug for InstructionData { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.kind.fmt(f)?; - if let Some(location) = &self.location { - write!(f, " ({:?})", location)?; - } - Ok(()) - } -} - -impl Debug for ModuleValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "M[{:0>2}]", self.0) - } -} - -impl Debug for FunctionValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "F[{:0>2}-{:0>2}]", &self.0.0, self.1) - } -} - -impl Debug for BlockValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "B[{:0>2}-{:0>2}-{:0>2}]", &self.0.0.0, &self.0.1, self.1) - } -} - -impl Debug for InstructionValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "%{}.{}.{}.{}", self.0.0.0.0, self.0.0.1, self.0.1, self.1) - } -} - -// impl Debug for InstructionValue { -// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -// write!( -// f, -// "I[{:0>2}-{:0>2}-{:0>2}-{:0>2}]", -// &self.0.0.0.0, &self.0.0.1, &self.0.1, self.1 -// ) -// } -// } - -impl Debug for TypeValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Ty[{:0>2}-{:0>2}]", &self.0.0, self.1) - } -} - -impl Debug for Instr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Instr::Param(nth) => fmt_call(f, &"Param", &nth), - Instr::Constant(c) => c.fmt(f), - Instr::Add(lhs, rhs) => fmt_binop(f, lhs, &"+", rhs), - Instr::FAdd(lhs, rhs) => fmt_binop(f, lhs, &"+", rhs), - Instr::Sub(lhs, rhs) => fmt_binop(f, lhs, &"-", rhs), - Instr::FSub(lhs, rhs) => fmt_binop(f, lhs, &"-", rhs), - Instr::Mul(lhs, rhs) => fmt_binop(f, lhs, &"*", rhs), - Instr::FMul(lhs, rhs) => fmt_binop(f, lhs, &"*", rhs), - Instr::UDiv(lhs, rhs) => fmt_binop(f, lhs, &"/", rhs), - Instr::SDiv(lhs, rhs) => fmt_binop(f, lhs, &"/", rhs), - Instr::FDiv(lhs, rhs) => fmt_binop(f, lhs, &"/", rhs), - Instr::URem(lhs, rhs) => fmt_binop(f, lhs, &"%", rhs), - Instr::SRem(lhs, rhs) => fmt_binop(f, lhs, &"%", rhs), - Instr::FRem(lhs, rhs) => fmt_binop(f, lhs, &"%", rhs), - Instr::And(lhs, rhs) => fmt_binop(f, lhs, &"&&", rhs), - Instr::Phi(val) => fmt_call(f, &"Phi", &val), - Instr::ICmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs), - Instr::FCmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs), - Instr::FunctionCall(fun, params) => fmt_call(f, fun, params), - Instr::Alloca(ty) => write!(f, "alloca<{:?}>", ty), - Instr::Load(val, ty) => write!(f, "load<{:?}>({:?})", ty, val), - Instr::Store(ptr, val) => write!(f, "store({:?} = {:?})", ptr, val), - Instr::ArrayAlloca(ty, instruction_value) => { - write!(f, "array_alloca<{:?}>({:?})", ty, instruction_value) - } - Instr::GetElemPtr(instruction_value, items) => fmt_index( - f, - instruction_value, - &items - .iter() - .map(|expr| format!("{:?}", expr)) - .collect::>() - .join(", "), - ), - Instr::GetStructElemPtr(instruction_value, index) => { - write!(f, "GEP(")?; - fmt_index(f, instruction_value, &index.to_string())?; - write!(f, ")") - } - Instr::ExtractValue(instruction_value, index) => fmt_index(f, instruction_value, &index.to_string()), - Instr::Trunc(instr_val, ty) => { - write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) - } - Instr::ZExt(instr_val, ty) => { - write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) - } - Instr::SExt(instr_val, ty) => { - write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) - } - Instr::FPTrunc(instr_val, ty) => { - write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) - } - Instr::FPExt(instr_val, ty) => { - write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) - } - Instr::FPToUI(instr_val, ty) => { - write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) - } - Instr::FPToSI(instr_val, ty) => { - write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) - } - Instr::UIToFP(instr_val, ty) => { - write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) - } - Instr::SIToFP(instr_val, ty) => { - write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) - } - Instr::PtrToInt(instr_val, ty) => { - write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) - } - Instr::IntToPtr(instr_val, ty) => { - write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) - } - Instr::BitCast(instr_val, ty) => { - write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) - } - Instr::Or(lhs, rhs) => fmt_binop(f, lhs, &"||", rhs), - Instr::XOr(lhs, rhs) => fmt_binop(f, lhs, &"^", rhs), - Instr::ShiftRightLogical(lhs, rhs) => fmt_binop(f, lhs, &">>l", rhs), - Instr::ShiftRightArithmetic(lhs, rhs) => fmt_binop(f, lhs, &">>a", rhs), - Instr::ShiftLeft(lhs, rhs) => fmt_binop(f, lhs, &"<<", rhs), - Instr::GetGlobal(global_value) => write!(f, "global {:?}", global_value), - Instr::IsNull(_) => write!(f, "is_null"), - } - } -} - -fn fmt_binop( - f: &mut std::fmt::Formatter<'_>, - lhs: &impl std::fmt::Debug, - op: &impl std::fmt::Debug, - rhs: &impl std::fmt::Debug, -) -> std::fmt::Result { - lhs.fmt(f)?; - f.write_char(' ')?; - op.fmt(f)?; - f.write_char(' ')?; - rhs.fmt(f) -} - -fn fmt_call( - f: &mut std::fmt::Formatter<'_>, - fun: &impl std::fmt::Debug, - params: &impl std::fmt::Debug, -) -> std::fmt::Result { - fun.fmt(f)?; - f.write_char('(')?; - params.fmt(f)?; - f.write_char(')') -} - -fn fmt_index( - f: &mut std::fmt::Formatter<'_>, - fun: &impl std::fmt::Debug, - params: &impl std::fmt::Debug, -) -> std::fmt::Result { - fun.fmt(f)?; - f.write_char('[')?; - params.fmt(f)?; - f.write_char(']') -} - -impl Debug for CmpPredicate { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::LT => write!(f, "<"), - Self::GT => write!(f, ">"), - Self::LE => write!(f, "<="), - Self::GE => write!(f, ">="), - Self::EQ => write!(f, "=="), - Self::NE => write!(f, "!="), - } - } -} - -impl Debug for TerminatorKind { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Ret(val) => { - write!(f, "Ret ")?; - val.fmt(f) - } - Self::RetVoid => write!(f, "Void Ret"), - Self::Br(val) => { - write!(f, "Br ")?; - val.fmt(f) - } - Self::CondBr(cond, b1, b2) => { - write!(f, "CondBr ")?; - cond.fmt(f)?; - write!(f, " ? ")?; - b1.fmt(f)?; - write!(f, " : ")?; - b2.fmt(f)?; - Ok(()) - } - } - } -} - -impl Debug for DebugTypeHolder { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple(&format!("DebugTypeHolder {:?}", self.value)) - .field(&self.data) - .finish() - } -} - -impl Debug for DebugTypeData { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - DebugTypeData::Basic(ty) => Debug::fmt(ty, f), - DebugTypeData::Subprogram(ty) => Debug::fmt(ty, f), - DebugTypeData::Pointer(ty) => Debug::fmt(ty, f), - DebugTypeData::Array(ty) => Debug::fmt(ty, f), - DebugTypeData::Struct(ty) => Debug::fmt(ty, f), - } - } -} - -impl Debug for DebugBasicType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("BasicType") - .field(&self.name) - .field(&self.size_bits) - .field(&self.encoding) - .field(&self.flags) - .finish() - } -} - -impl Debug for DebugStructType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Struct") - .field("name", &self.name) - .field("scope", &self.scope) - .field("pos", &self.pos) - .field("size_bit", &self.size_bits) - .field("flags", &self.flags) - .field("elements", &self.fields) - .finish() - } -} - -impl Debug for DebugFieldType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct(&format!("Field({})", self.name)) - .field("scope", &self.scope) - .field("pos", &self.pos) - .field("size_bits", &self.size_bits) - .field("offset", &self.offset) - .field("flags", &self.flags) - .field("ty", &self.ty) - .finish() - } -} - -impl Debug for DebugSubprogramType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("Subprogram") - .field(&self.parameters) - .field(&self.flags) - .finish() - } -} - -impl Debug for DebugPointerType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple(&format!("Pointer<{:?}>({})", self.pointee, self.name)) - .field(&self.size_bits) - .finish() - } -} - -impl Debug for DebugArrayType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct(&format!("Array<{:?}>[{}]", self.element_type, self.length)) - .field("size_bits", &self.size_bits) - .field("align_bits", &self.align_bits) - .finish() - } -} - -impl Debug for DebugMetadataValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Meta[{}]", self.0) - } -} - -impl Debug for DebugScopeValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "Scope[{}]", - self.0.iter().map(|v| v.to_string()).collect::>().join(", ") - ) - } -} - -impl Debug for DebugTypeValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Type[{}]", self.0) - } -} - -impl Debug for DebugLocationValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Value[{:?}][{}]", self.0, self.1) - } -} - -impl Debug for DebugLocation { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?} on scope {:?}", self.pos, self.scope) - } -} - -impl Debug for DebugPosition { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "ln {}, col {}", self.line, self.column) - } -} diff --git a/reid-llvm-lib/src/intrinsics.rs b/reid-llvm-lib/src/intrinsics.rs deleted file mode 100644 index b76b443..0000000 --- a/reid-llvm-lib/src/intrinsics.rs +++ /dev/null @@ -1,263 +0,0 @@ -use crate::{CompileResult, Type, TypeCategory, builder::Builder}; - -#[derive(Clone, Debug)] -pub enum LLVMIntrinsic { - Abs(Type), - Max(Type), - Min(Type), - Memcpy(Type), - Sqrt(Type), - PowI(Type, Type), - Pow(Type), - Sin(Type), - Cos(Type), - Tan(Type), - ASin(Type), - ACos(Type), - ATan(Type), - ATan2(Type), - SinH(Type), - CosH(Type), - TanH(Type), - Log(Type), - Log2(Type), - Log10(Type), - Copysign(Type), - Floor(Type), - Ceil(Type), - Trunc(Type), - RoundEven(Type), - Round(Type), -} - -impl LLVMIntrinsic { - pub(crate) fn signature(&self, builder: &Builder) -> CompileResult<(String, Vec, Type)> { - match self { - LLVMIntrinsic::Max(ty) => { - let name = match ty.category() { - TypeCategory::SignedInteger => format!("llvm.smax.{}", ty.llvm_ty_str(builder)), - TypeCategory::UnsignedInteger => format!("llvm.umax.{}", ty.llvm_ty_str(builder)), - TypeCategory::Real => format!("llvm.maximum.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone(), ty.clone()], ty.clone())) - } - LLVMIntrinsic::Min(ty) => { - let name = match ty.category() { - TypeCategory::SignedInteger => format!("llvm.smin.{}", ty.llvm_ty_str(builder)), - TypeCategory::UnsignedInteger => format!("llvm.umin.{}", ty.llvm_ty_str(builder)), - TypeCategory::Real => format!("llvm.minimum.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone(), ty.clone()], ty.clone())) - } - LLVMIntrinsic::Abs(ty) => { - let name = match ty.category() { - TypeCategory::SignedInteger => format!("llvm.abs.{}", ty.llvm_ty_str(builder)), - TypeCategory::UnsignedInteger => format!("llvm.abs.{}", ty.llvm_ty_str(builder)), - TypeCategory::Real => format!("llvm.fabs.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone(), Type::Bool], ty.clone())) - } - LLVMIntrinsic::Memcpy(ty) => { - let name = match ty.category() { - TypeCategory::Ptr => String::from("llvm.memcpy"), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone(), ty.clone(), Type::U64, Type::Bool], Type::Void)) - } - LLVMIntrinsic::Sqrt(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.sqrt.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::PowI(ty1, ty2) => { - let name = match (ty1.category(), ty2.category()) { - (TypeCategory::Real, TypeCategory::SignedInteger) => { - format!("llvm.powi.{}.{}", ty1.llvm_ty_str(builder), ty2.llvm_ty_str(builder)) - } - (TypeCategory::Real, TypeCategory::UnsignedInteger) => { - format!("llvm.powi.{}.{}", ty1.llvm_ty_str(builder), ty2.llvm_ty_str(builder)) - } - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty1.clone(), ty2.clone()], ty1.clone())) - } - LLVMIntrinsic::Pow(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.pow.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone(), ty.clone()], ty.clone())) - } - LLVMIntrinsic::Sin(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.sin.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::Cos(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.cos.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::Tan(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.tan.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::ASin(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.asin.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::ACos(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.acos.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::ATan(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.atan.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::ATan2(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.atan2.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone(), ty.clone()], ty.clone())) - } - LLVMIntrinsic::SinH(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.sinh.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::CosH(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.cosh.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::TanH(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.tanh.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::Log(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.log.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::Log2(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.log2.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::Log10(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.log10.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::Copysign(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.copysign.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::Floor(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.floor.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::Ceil(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.ceil.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::Trunc(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.trunc.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::RoundEven(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.roundeven.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - LLVMIntrinsic::Round(ty) => { - let name = match ty.category() { - TypeCategory::Real => format!("llvm.rint.{}", ty.llvm_ty_str(builder)), - _ => return Err(crate::ErrorKind::Null), - }; - Ok((name, vec![ty.clone()], ty.clone())) - } - } - } -} - -impl Type { - fn llvm_ty_str(&self, builder: &Builder) -> String { - match self { - Type::I8 => String::from("i8"), - Type::I16 => String::from("u16"), - Type::I32 => String::from("i32"), - Type::I64 => String::from("i64"), - Type::I128 => String::from("i128"), - Type::U8 => String::from("i8"), - Type::U16 => String::from("i16"), - Type::U32 => String::from("i32"), - Type::U64 => String::from("i64"), - Type::U128 => String::from("i128"), - Type::F16 => String::from("f16"), - Type::F32B => String::from("f32b"), - Type::F32 => String::from("f32"), - Type::F64 => String::from("f64"), - Type::F80 => String::from("x86_fp80"), - Type::F128 => String::from("fp128"), - Type::F128PPC => String::from("ppc_fp128"), - Type::Bool => String::from("i1"), - Type::Void => String::from("void"), - Type::CustomType(type_value) => { - let ty = unsafe { builder.type_data(type_value) }; - ty.name.clone() - } - Type::Array(ty, len) => format!("[{} x {}]", len, ty.llvm_ty_str(builder)), - Type::Ptr(_) => String::from("ptr"), - } - } -} diff --git a/reid-llvm-lib/src/lib.rs b/reid-llvm-lib/src/lib.rs deleted file mode 100644 index 6a4e735..0000000 --- a/reid-llvm-lib/src/lib.rs +++ /dev/null @@ -1,741 +0,0 @@ -//! Reid LLVM Lib is an ergonomic Rust'y API which is used to produce a -//! Low-Level IR (LLIR) using [`Context`] and [`Builder`]. This Builder can then -//! be used at the end to compile said LLIR into LLVM IR. - -use std::{fmt::Debug, marker::PhantomData}; - -use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue, TypeValue}; -use debug_information::{DebugFileData, DebugInformation, DebugLocationValue, DebugMetadataValue}; -use fmt::PrintableModule; - -use crate::{ - builder::{ConstantValue, GlobalValue}, - debug_information::DebugScopeValue, - intrinsics::LLVMIntrinsic, -}; - -pub mod builder; -pub mod compile; -pub mod debug_information; -mod fmt; -pub mod intrinsics; -mod pad_adapter; -mod util; - -#[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)] -pub enum ErrorKind { - #[error("NULL error, should never occur!")] - 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 = Result; - -#[derive(Debug)] -pub struct Context { - builder: Builder, -} - -impl Context { - pub fn new>(producer: T) -> Context { - Context { - builder: Builder::new(producer.into()), - } - } - - pub fn module<'ctx>(&'ctx self, name: &str, main: bool) -> Module<'ctx> { - let value = self.builder.add_module(ModuleData { - name: name.to_owned(), - is_main: main, - }); - Module { - phantom: PhantomData, - builder: self.builder.clone(), - value, - debug_info: None, - } - } -} - -#[derive(Debug, Clone, Hash)] -pub struct ModuleData { - name: String, - is_main: bool, -} - -#[derive(Clone)] -pub struct Module<'ctx> { - phantom: PhantomData<&'ctx ()>, - builder: Builder, - value: ModuleValue, - debug_info: Option, -} - -impl<'ctx> Module<'ctx> { - pub fn function( - &self, - name: &str, - linkage: Option, - ret: Type, - params: Vec, - flags: FunctionFlags, - ) -> Function<'ctx> { - unsafe { - Function { - phantom: PhantomData, - builder: self.builder.clone(), - value: self.builder.add_function( - &self.value, - FunctionData { - name: name.to_owned(), - linkage_name: linkage, - ret, - params, - flags, - }, - ), - } - } - } - - pub fn intrinsic(&self, intrinsic: LLVMIntrinsic) -> CompileResult { - unsafe { - let (name, params, ret) = intrinsic.signature(&self.builder)?; - Ok(self.builder.add_function( - &self.value, - FunctionData { - name: name.to_owned(), - linkage_name: Some(name.to_owned()), - ret, - params, - flags: FunctionFlags { - is_extern: true, - ..Default::default() - }, - }, - )) - } - } - - pub fn custom_type(&self, ty: CustomTypeKind) -> TypeValue { - unsafe { - let (name, kind) = match &ty { - CustomTypeKind::NamedStruct(NamedStruct(name, _)) => (name.clone(), ty), - }; - self.builder.add_type(&self.value, TypeData { name, kind }) - } - } - - pub fn value(&self) -> ModuleValue { - self.value - } - - pub fn as_printable(&self) -> PrintableModule<'ctx> { - PrintableModule { - phantom: PhantomData, - module: self.builder.find_module(self.value), - } - } - - pub fn create_debug_info(&mut self, file: DebugFileData) -> (DebugInformation, DebugScopeValue) { - let (debug_info, scope_value) = DebugInformation::from_file(file); - self.debug_info = Some(debug_info.clone()); - (debug_info, scope_value) - } - - pub fn get_debug_info(&self) -> &Option { - &self.debug_info - } - - pub fn add_constant(&self, constant: ConstValueKind) -> ConstantValue { - unsafe { self.builder.build_constant(self.value, constant) } - } - - pub fn add_global>(&self, name: T, constant: ConstantValue) -> GlobalValue { - unsafe { self.builder.add_global(self.value, name.into(), constant) } - } -} - -impl<'ctx> Drop for Module<'ctx> { - fn drop(&mut self) { - if let Some(debug_info) = self.debug_info.take() { - self.builder.set_debug_information(&self.value, debug_info); - } - } -} - -#[derive(Debug, Clone, Hash)] -pub struct FunctionData { - name: String, - linkage_name: Option, - ret: Type, - params: Vec, - flags: FunctionFlags, -} - -#[derive(Debug, Clone, Copy, Hash)] -pub struct FunctionFlags { - /// True in the destination module of the import, false in the source module. - pub is_extern: bool, - /// Whether this function is the main function of the module, that should be - /// executed (and linked externally also). - pub is_main: bool, - /// Whether this function should be available externally always. - pub is_pub: bool, - /// If this function is an imported function (either in the source or - /// destination module) - pub is_imported: bool, - /// Whether this function should add "alwaysinline"-attribute. - pub inline: bool, -} - -impl Default for FunctionFlags { - fn default() -> FunctionFlags { - FunctionFlags { - is_extern: false, - is_main: false, - is_pub: false, - is_imported: false, - inline: false, - } - } -} - -pub struct Function<'ctx> { - phantom: PhantomData<&'ctx ()>, - builder: Builder, - value: FunctionValue, -} - -impl<'ctx> Function<'ctx> { - pub fn block(&self, name: &str) -> Block<'ctx> { - unsafe { - Block { - phantom: PhantomData, - builder: self.builder.clone(), - value: self.builder.add_block( - &self.value, - BlockData { - name: name.to_owned(), - terminator: None, - terminator_location: None, - deleted: false, - }, - ), - } - } - } - - pub fn set_debug(&self, subprogram: DebugScopeValue) { - unsafe { - self.builder.set_debug_subprogram(&self.value, subprogram); - } - } - - pub fn value(&self) -> FunctionValue { - self.value - } -} - -#[derive(Debug, Clone, Hash)] -pub struct BlockData { - name: String, - terminator: Option, - terminator_location: Option, - deleted: bool, -} - -#[derive(Clone)] -pub struct Block<'builder> { - phantom: PhantomData<&'builder ()>, - builder: Builder, - value: BlockValue, -} - -impl Instr { - pub fn default_name(&self) -> &str { - match self { - Instr::Param(_) => "param", - Instr::Constant(_) => "const1", - Instr::Add(..) => "add", - Instr::FAdd(..) => "fadd", - Instr::Sub(..) => "sub", - Instr::FSub(..) => "fsub", - Instr::Mul(..) => "mul", - Instr::FMul(..) => "fmul", - Instr::UDiv(..) => "udiv", - Instr::SDiv(..) => "sdiv", - Instr::FDiv(..) => "fdiv", - Instr::URem(..) => "urem", - Instr::SRem(..) => "srem", - Instr::FRem(..) => "frem", - Instr::And(..) => "and", - Instr::Phi(_) => "phi", - Instr::Alloca(_) => "alloca", - Instr::Load(_, _) => "load", - Instr::Store(..) => "store", - Instr::ArrayAlloca(_, _) => "arrayalloca", - Instr::GetElemPtr(..) => "getelemptr", - Instr::GetStructElemPtr(..) => "getstructelemptr", - Instr::ExtractValue(..) => "extractvalue", - Instr::ICmp(..) => "icmp", - Instr::FunctionCall(..) => "call", - Instr::FCmp(_, _, _) => "fcmp", - Instr::Trunc(_, _) => "trunc", - Instr::ZExt(_, _) => "zext", - Instr::SExt(_, _) => "sext", - Instr::FPTrunc(_, _) => "fptrunc", - Instr::FPExt(_, _) => "pfext", - Instr::FPToUI(_, _) => "fptoui", - Instr::FPToSI(_, _) => "fptosi", - Instr::UIToFP(_, _) => "uitofp", - Instr::SIToFP(_, _) => "sitofp", - Instr::PtrToInt(_, _) => "ptrtoint", - Instr::IntToPtr(_, _) => "inttoptr", - Instr::BitCast(_, _) => "bitcast", - Instr::Or(..) => "or", - Instr::XOr(..) => "xor", - Instr::ShiftRightLogical(..) => "lshr", - Instr::ShiftRightArithmetic(..) => "ashr", - Instr::ShiftLeft(..) => "shl", - Instr::GetGlobal(..) => "global", - Instr::IsNull(..) => "is_null", - } - } -} - -impl<'builder> Block<'builder> { - pub fn build_named>(&mut self, name: T, instruction: Instr) -> CompileResult { - unsafe { - self.builder.add_instruction( - &self.value, - InstructionData { - kind: instruction, - location: None, - meta: None, - }, - name.into(), - ) - } - } - - pub fn build(&mut self, instruction: Instr) -> CompileResult { - unsafe { - let name = instruction.default_name().to_owned(); - self.builder.add_instruction( - &self.value, - InstructionData { - kind: instruction, - location: None, - meta: None, - }, - name, - ) - } - } - - pub fn find_function(&mut self, name: &String) -> Option { - unsafe { self.builder.find_function(self.value.0.0, name) } - } - - pub fn set_instr_location(&self, instruction: InstructionValue, location: DebugLocationValue) { - unsafe { - self.builder.add_instruction_location(&instruction, location); - } - } - - pub fn set_instr_metadata(&self, instruction: InstructionValue, location: DebugMetadataValue) { - unsafe { - self.builder.add_instruction_metadata(&instruction, location); - } - } - - pub fn terminate(&mut self, instruction: TerminatorKind) -> CompileResult<()> { - unsafe { self.builder.terminate(&self.value, instruction) } - } - - pub fn set_terminator_location(&mut self, location: DebugLocationValue) -> CompileResult<()> { - unsafe { self.builder.set_terminator_location(&self.value, location) } - } - - /// Delete block if it is unused. Return true if deleted, false if not. - pub fn delete_if_unused(&mut self) -> CompileResult { - unsafe { - if !self.builder.is_block_used(self.value()) { - self.builder.delete_block(&self.value)?; - Ok(true) - } else { - Ok(false) - } - } - } - - pub fn value(&self) -> BlockValue { - self.value - } -} - -#[derive(Clone)] -pub struct InstructionData { - kind: Instr, - location: Option, - meta: Option, -} - -#[derive(Clone, Copy, Hash)] -pub enum CmpPredicate { - LT, - LE, - GT, - GE, - EQ, - NE, -} - -/// https://llvm.org/docs/LangRef.html#instruction-reference -#[derive(Clone)] -pub enum Instr { - Param(usize), - Constant(ConstValueKind), - GetGlobal(GlobalValue), - - /// Add two integers - Add(InstructionValue, InstructionValue), - /// Add two floats - FAdd(InstructionValue, InstructionValue), - /// Subtract two integers - Sub(InstructionValue, InstructionValue), - /// Subtract two floats - FSub(InstructionValue, InstructionValue), - /// Multiply two integers - Mul(InstructionValue, InstructionValue), - /// Multiply two floats - FMul(InstructionValue, InstructionValue), - /// Divide two unsigned integers - UDiv(InstructionValue, InstructionValue), - /// Divide two signed integers - SDiv(InstructionValue, InstructionValue), - /// Divide two floats - FDiv(InstructionValue, InstructionValue), - /// Get the remainder from two unsigned integers - URem(InstructionValue, InstructionValue), - /// Get the remainder from two signed integers - SRem(InstructionValue, InstructionValue), - /// Get the remainder from two floats - FRem(InstructionValue, InstructionValue), - - And(InstructionValue, InstructionValue), - Or(InstructionValue, InstructionValue), - XOr(InstructionValue, InstructionValue), - ShiftRightLogical(InstructionValue, InstructionValue), - ShiftRightArithmetic(InstructionValue, InstructionValue), - ShiftLeft(InstructionValue, InstructionValue), - - Phi(Vec), - - Alloca(Type), - Load(InstructionValue, Type), - Store(InstructionValue, InstructionValue), - ArrayAlloca(Type, InstructionValue), - GetElemPtr(InstructionValue, Vec), - GetStructElemPtr(InstructionValue, u32), - ExtractValue(InstructionValue, u32), - - /// Integer Comparison - ICmp(CmpPredicate, InstructionValue, InstructionValue), - /// FLoat Comparison - FCmp(CmpPredicate, InstructionValue, InstructionValue), - - /// The `trunc` instruction truncates the high order bits in value and - /// converts the remaining bits to ty2. Since the source size must be larger - /// than the destination size, `trunc` cannot be a no-op cast. It will - /// always truncate bits. - Trunc(InstructionValue, Type), - /// The `zext` fills the high order bits of the value with zero bits until - /// it reaches the size of the destination type, ty2. - ZExt(InstructionValue, Type), - /// The `sext` instruction performs a sign extension by copying the sign bit - /// (highest order bit) of the value until it reaches the bit size of the - /// type ty2. - SExt(InstructionValue, Type), - /// The `fptrunc` instruction casts a value from a larger floating-point - /// type to a smaller floating-point type. - FPTrunc(InstructionValue, Type), - /// The `fpext` instruction extends the value from a smaller floating-point - /// type to a larger floating-point type. - FPExt(InstructionValue, Type), - /// The `fptoui` instruction takes a value to cast, which must be a scalar - /// or vector floating-point value, and a type to cast it to ty2, which must - /// be an integer type. - FPToUI(InstructionValue, Type), - /// The `fptosi` instruction takes a value to cast, which must be a scalar - /// or vector floating-point value, and a type to cast it to ty2, which must - /// be an integer type. - FPToSI(InstructionValue, Type), - /// The `uitofp` instruction takes a value to cast, which must be a scalar - /// or vector integer value, and a type to cast it to ty2, which must be an - /// floating-point type. - UIToFP(InstructionValue, Type), - /// The `sitofp` instruction takes a value to cast, which must be a scalar - /// or vector integer value, and a type to cast it to ty2, which must be an - /// floating-point type - SIToFP(InstructionValue, Type), - /// The `ptrtoint` instruction converts value to integer type ty2 by - /// interpreting the all pointer representation bits as an integer - /// (equivalent to a bitcast) and either truncating or zero extending that - /// value to the size of the integer type. - PtrToInt(InstructionValue, Type), - /// The `inttoptr` instruction converts value to type ty2 by applying either - /// a zero extension or a truncation depending on the size of the integer - /// value. - IntToPtr(InstructionValue, Type), - /// The `bitcast` instruction converts value to type ty2. It is always a - /// no-op cast because no bits change with this conversion. - BitCast(InstructionValue, Type), - - /// Check if the given instruction value is a null pointer - IsNull(InstructionValue), - - FunctionCall(FunctionValue, Vec), -} - -#[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd)] -pub enum Type { - I8, - I16, - I32, - I64, - I128, - U8, - U16, - U32, - U64, - U128, - F16, - F32B, - F32, - F64, - F80, - F128, - F128PPC, - Bool, - Void, - CustomType(TypeValue), - Array(Box, u64), - Ptr(Box), -} - -#[derive(Debug, Clone)] -pub enum ConstValueKind { - I8(i8), - I16(i16), - I32(i32), - I64(i64), - I128(i128), - U8(u8), - U16(u16), - U32(u32), - U64(u64), - U128(u128), - Bool(bool), - Str(String), - F16(f32), - F32B(f32), - F32(f32), - F64(f64), - F80(f64), - F128(f64), - F128PPC(f64), - Array(Vec, Type), -} - -#[derive(Clone, Hash)] -pub enum TerminatorKind { - Ret(InstructionValue), - RetVoid, - Br(BlockValue), - CondBr(InstructionValue, BlockValue, BlockValue), -} - -#[derive(Debug, PartialEq, Eq, Clone, Hash)] -pub struct TypeData { - name: String, - kind: CustomTypeKind, -} - -#[derive(Debug, PartialEq, Eq, Clone, Hash)] -pub enum CustomTypeKind { - NamedStruct(NamedStruct), -} - -#[derive(Debug, PartialEq, Eq, Clone, Hash)] -pub struct NamedStruct(pub String, pub Vec); - -impl ConstValueKind { - pub fn get_type(&self) -> Type { - use Type::*; - match self { - ConstValueKind::I8(_) => I8, - ConstValueKind::I16(_) => I16, - ConstValueKind::I32(_) => I32, - ConstValueKind::I64(_) => I64, - ConstValueKind::I128(_) => I128, - ConstValueKind::U8(_) => U8, - ConstValueKind::U16(_) => U16, - ConstValueKind::U32(_) => U32, - ConstValueKind::U64(_) => U64, - ConstValueKind::U128(_) => U128, - ConstValueKind::Str(_) => Type::Ptr(Box::new(U8)), - ConstValueKind::Bool(_) => Bool, - ConstValueKind::F16(_) => F16, - ConstValueKind::F32B(_) => F32B, - ConstValueKind::F32(_) => F32, - ConstValueKind::F64(_) => F64, - ConstValueKind::F80(_) => F80, - ConstValueKind::F128(_) => F128, - ConstValueKind::F128PPC(_) => F128PPC, - ConstValueKind::Array(vals, ty) => Type::Array(Box::new(ty.clone()), vals.len() as u64), - } - } -} - -#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone)] -pub enum TypeCategory { - SignedInteger, - UnsignedInteger, - Void, - Real, - Ptr, - CustomType, - Array, -} - -impl TypeCategory { - pub fn comparable(&self) -> bool { - match self { - TypeCategory::SignedInteger => true, - TypeCategory::UnsignedInteger => true, - TypeCategory::Real => true, - _ => false, - } - } - - pub fn signed(&self) -> bool { - match self { - TypeCategory::SignedInteger => true, - _ => false, - } - } - - pub fn integer(&self) -> bool { - match self { - TypeCategory::SignedInteger => true, - TypeCategory::UnsignedInteger => true, - _ => false, - } - } -} - -impl Type { - pub fn category(&self) -> TypeCategory { - match self { - Type::I8 | Type::I16 | Type::I32 | Type::I64 | Type::I128 => TypeCategory::SignedInteger, - Type::U8 | Type::U16 | Type::U32 | Type::U64 | Type::U128 => TypeCategory::UnsignedInteger, - Type::F16 | Type::F32B | Type::F32 | Type::F64 | Type::F80 | Type::F128 | Type::F128PPC => { - TypeCategory::Real - } - Type::Bool => TypeCategory::UnsignedInteger, - Type::Void => TypeCategory::Void, - Type::CustomType(_) => TypeCategory::CustomType, - Type::Array(_, _) => TypeCategory::Array, - Type::Ptr(_) => TypeCategory::Ptr, - } - } - - pub fn cast_instruction(&self, value: InstructionValue, other: &Type) -> Option { - use Type::*; - match (self, other) { - (I8, I16 | I32 | I64 | I128) => Some(Instr::SExt(value, other.clone())), - (I16, I32 | I64 | I128) => Some(Instr::SExt(value, other.clone())), - (I32, I64 | I128) => Some(Instr::SExt(value, other.clone())), - (I64, I128) => Some(Instr::SExt(value, other.clone())), - (I128 | U128, I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())), - (I64 | U64, I32 | U32 | I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())), - (I32 | U32, I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())), - (I16 | U16, I8 | U8) => Some(Instr::Trunc(value, other.clone())), - (U8 | I8, U8 | I8 | U16 | I16 | U32 | I32 | U64 | I64 | U128 | I128) => { - Some(Instr::ZExt(value, other.clone())) - } - (U16 | I16, U16 | I16 | U32 | I32 | U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())), - (U32 | I32, U32 | I32 | U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())), - (U64 | I64, U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())), - (U128 | I128, U128 | I128) => Some(Instr::ZExt(value, other.clone())), - (U8 | U16 | U32 | U64 | U128, F16 | F32 | F32B | F64 | F80 | F128 | F128PPC) => { - Some(Instr::UIToFP(value, other.clone())) - } - (I8 | I16 | I32 | I64 | I128, F16 | F32 | F32B | F64 | F80 | F128 | F128PPC) => { - Some(Instr::SIToFP(value, other.clone())) - } - (F16 | F32 | F32B | F64 | F80 | F128 | F128PPC, U8 | U16 | U32 | U64 | U128) => { - Some(Instr::FPToUI(value, other.clone())) - } - (F16 | F32 | F32B | F64 | F80 | F128 | F128PPC, I8 | I16 | I32 | I64 | I128) => { - Some(Instr::FPToSI(value, other.clone())) - } - (I128 | U128 | I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8, Ptr(_)) => { - Some(Instr::IntToPtr(value, other.clone())) - } - (Ptr(_), I128 | U128 | I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8) => { - Some(Instr::PtrToInt(value, other.clone())) - } - (F16, F32 | F32B | F64 | F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())), - (F32 | F32B, F64 | F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())), - (F64, F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())), - (F80, F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())), - (F128PPC | F128, F80 | F64 | F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())), - (F80, F64 | F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())), - (F64, F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())), - (F32B | F32, F16) => Some(Instr::FPTrunc(value, other.clone())), - _ => None, - } - } -} - -impl TerminatorKind { - pub(crate) fn get_type(&self, builder: &Builder) -> CompileResult { - use TerminatorKind::*; - match self { - Ret(instr_val) => instr_val.get_type(builder), - RetVoid => Ok(Type::Void), - Br(_) => Ok(Type::Void), - CondBr(_, _, _) => Ok(Type::Void), - } - } -} diff --git a/reid-llvm-lib/src/pad_adapter.rs b/reid-llvm-lib/src/pad_adapter.rs deleted file mode 100644 index 3014fa3..0000000 --- a/reid-llvm-lib/src/pad_adapter.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! Copied from -//! https://github.com/rust-lang/rust/blob/6b3ae3f6e45a33c2d95fa0362c9b2593e567fd34/library/core/src/fmt/builders.rs#L102 - -// Copyright (c) The Rust Project Contributors -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -use std::fmt; - -pub struct PadAdapter<'buf, 'state> { - buf: &'buf mut (dyn fmt::Write + 'buf), - state: &'state mut PadAdapterState, -} - -pub struct PadAdapterState { - on_newline: bool, -} - -impl Default for PadAdapterState { - fn default() -> Self { - PadAdapterState { on_newline: true } - } -} - -impl<'buf, 'state> PadAdapter<'buf, 'state> { - pub fn wrap<'slot, 'fmt: 'buf + 'slot>( - fmt: &'buf mut (dyn fmt::Write + 'buf), - state: &'state mut PadAdapterState, - ) -> Self { - PadAdapter { buf: fmt, state } - } -} - -impl fmt::Write for PadAdapter<'_, '_> { - fn write_str(&mut self, s: &str) -> fmt::Result { - for s in s.split_inclusive('\n') { - if self.state.on_newline { - self.buf.write_str(" ")?; - } - self.state.on_newline = s.ends_with('\n'); - self.buf.write_str(s)?; - } - Ok(()) - } - - fn write_char(&mut self, c: char) -> fmt::Result { - if self.state.on_newline { - self.buf.write_str(" ")?; - } - self.state.on_newline = c == '\n'; - self.buf.write_char(c) - } -} diff --git a/reid-llvm-lib/src/util.rs b/reid-llvm-lib/src/util.rs deleted file mode 100644 index 4df2b83..0000000 --- a/reid-llvm-lib/src/util.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::{ - ffi::{CStr, CString, c_char}, - ptr::null_mut, - string::FromUtf8Error, -}; - -use llvm_sys::{ - core::{LLVMCreateMemoryBufferWithMemoryRange, LLVMDisposeMemoryBuffer, LLVMGetBufferSize, LLVMGetBufferStart}, - error::LLVMDisposeErrorMessage, - prelude::LLVMMemoryBufferRef, -}; - -use crate::{ - CompileResult, ErrorKind, Type, - builder::{Builder, InstructionValue}, -}; - -pub fn into_cstring>(value: T) -> CString { - let string = value.into(); - unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) } -} - -pub fn from_cstring(pointer: *mut c_char) -> Option { - if pointer.is_null() { - None - } else { - unsafe { CStr::from_ptr(pointer).to_str().ok().map(|s| s.to_owned()) } - } -} - -fn cstring_to_err(value: *mut c_char) -> Result<(), String> { - 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 -/// manually. -pub struct ErrorMessageHolder(*mut c_char); - -impl ErrorMessageHolder { - pub fn null() -> Self { - ErrorMessageHolder(null_mut()) - } - - pub fn borrow_mut(&mut self) -> *mut *mut c_char { - &mut self.0 - } - - pub fn into_result(&self) -> Result<(), String> { - cstring_to_err(self.0) - } -} - -impl Drop for ErrorMessageHolder { - fn drop(&mut self) { - unsafe { - if !self.0.is_null() { - LLVMDisposeErrorMessage(self.0); - } - } - } -} - -/// Utility for creating and handling LLVM MemoryBuffers, needed for printing -/// out ASM and .o -files without relying on LLVM's own API. -pub struct MemoryBufferHolder { - pub buffer: LLVMMemoryBufferRef, -} - -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); - MemoryBufferHolder { buffer } - } - } - - pub fn as_buffer(&self) -> Vec { - unsafe { - let start = LLVMGetBufferStart(self.buffer); - let size = LLVMGetBufferSize(self.buffer); - - let mut buff = Vec::with_capacity(size); - for i in 0..size { - buff.push(*start.add(i) as u8); - } - buff - } - } - - pub fn as_string(&self) -> Result { - String::from_utf8(self.as_buffer()) - } -} - -impl Drop for MemoryBufferHolder { - fn drop(&mut self) { - unsafe { - LLVMDisposeMemoryBuffer(self.buffer); - } - } -} - -/// 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 { - 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::TypesIncompatible(lhs_t, rhs_t)) - } -}