From 02d8b3742470ea88537087e6f65a71c8fbe41d3f Mon Sep 17 00:00:00 2001 From: sofia Date: Sat, 28 Jun 2025 18:49:54 +0300 Subject: [PATCH] Move context.rs to lib.rs --- reid-llvm-lib/examples/libtest.rs | 6 +- reid-llvm-lib/src/context.rs | 358 -------------------- reid-llvm-lib/src/lib.rs | 522 ++++++++++++++++++------------ reid-llvm-lib/src/types.rs | 2 +- 4 files changed, 310 insertions(+), 578 deletions(-) delete mode 100644 reid-llvm-lib/src/context.rs diff --git a/reid-llvm-lib/examples/libtest.rs b/reid-llvm-lib/examples/libtest.rs index c47bbb3..7cb8ced 100644 --- a/reid-llvm-lib/examples/libtest.rs +++ b/reid-llvm-lib/examples/libtest.rs @@ -1,8 +1,4 @@ -use reid_lib::{ - context::{Comparison, Context}, - types::BasicType, - *, -}; +use reid_lib::{Comparison, Context, types::BasicType}; pub fn main() { // Notes from inkwell: diff --git a/reid-llvm-lib/src/context.rs b/reid-llvm-lib/src/context.rs deleted file mode 100644 index 584c72a..0000000 --- a/reid-llvm-lib/src/context.rs +++ /dev/null @@ -1,358 +0,0 @@ -use std::{ffi::CString, ptr::null_mut}; - -use llvm_sys::{ - LLVMBuilder, LLVMContext, - analysis::LLVMVerifyModule, - core::*, - prelude::*, - target::{ - LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos, - LLVM_InitializeAllTargetMCs, LLVM_InitializeAllTargets, LLVMSetModuleDataLayout, - }, - target_machine::{ - LLVMCodeGenFileType, LLVMCreateTargetDataLayout, LLVMCreateTargetMachine, - LLVMGetDefaultTargetTriple, LLVMGetTargetFromTriple, LLVMTargetMachineEmitToFile, - }, -}; - -use crate::{ - OpaqueValue, - types::{BasicType, FunctionType, IntegerType}, - util::{ErrorMessageHolder, from_cstring, into_cstring}, -}; - -pub enum Comparison { - LessThan, -} - -pub struct Context { - pub(crate) context_ref: *mut LLVMContext, - pub(crate) builder_ref: *mut LLVMBuilder, -} - -impl Context { - pub fn new() -> Context { - unsafe { - // Set up a context, module and builder in that context. - let context = LLVMContextCreate(); - let builder = LLVMCreateBuilderInContext(context); - - Context { - context_ref: context, - builder_ref: builder, - } - } - } - - pub fn integer_type<'a, const T: u32>(&'a self) -> IntegerType<'a, T> { - IntegerType::in_context(&self) - } - - pub fn module>(&self, name: T) -> Module { - Module::with_name(self, name.into()) - } -} - -impl Drop for Context { - fn drop(&mut self) { - // Clean up. Values created in the context mostly get cleaned up there. - unsafe { - LLVMDisposeBuilder(self.builder_ref); - LLVMContextDispose(self.context_ref); - } - } -} - -pub struct Module<'ctx> { - context: &'ctx Context, - module_ref: LLVMModuleRef, - name: CString, -} - -impl<'ctx> Module<'ctx> { - fn with_name(context: &'ctx Context, name: String) -> Module<'ctx> { - unsafe { - let cstring_name = into_cstring(name); - let module_ref = - LLVMModuleCreateWithNameInContext(cstring_name.as_ptr(), context.context_ref); - Module { - context, - module_ref, - name: cstring_name, - } - } - } - - pub fn add_function>( - &self, - fn_type: FunctionType<'ctx, ReturnType>, - name: T, - ) -> Function<'_, ReturnType> { - unsafe { - let name_cstring = into_cstring(name); - let function_ref = - LLVMAddFunction(self.module_ref, name_cstring.as_ptr(), fn_type.llvm_type()); - Function { - module: self, - fn_type, - name: name_cstring, - fn_ref: function_ref, - } - } - } - - pub fn print_to_string(&self) -> Result { - 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()); - println!("{:?}, {:?}", from_cstring(triple), target); - err.into_result().unwrap(); - - let target_machine = LLVMCreateTargetMachine( - target, - triple, - c"generic".as_ptr(), - c"".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); - LLVMSetModuleDataLayout(self.module_ref, data_layout); - - let mut err = ErrorMessageHolder::null(); - LLVMVerifyModule( - self.module_ref, - llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction, - err.borrow_mut(), - ); - err.into_result().unwrap(); - - let mut err = ErrorMessageHolder::null(); - LLVMTargetMachineEmitToFile( - target_machine, - self.module_ref, - CString::new("hello.asm").unwrap().into_raw(), - LLVMCodeGenFileType::LLVMAssemblyFile, - err.borrow_mut(), - ); - err.into_result().unwrap(); - - let mut err = ErrorMessageHolder::null(); - LLVMTargetMachineEmitToFile( - target_machine, - self.module_ref, - CString::new("hello.o").unwrap().into_raw(), - LLVMCodeGenFileType::LLVMObjectFile, - err.borrow_mut(), - ); - err.into_result().unwrap(); - - Ok(from_cstring(LLVMPrintModuleToString(self.module_ref)).expect("UTF8-err")) - } - } -} - -impl<'a> Drop for Module<'a> { - fn drop(&mut self) { - // Clean up. Values created in the context mostly get cleaned up there. - unsafe { - LLVMDisposeModule(self.module_ref); - } - } -} - -pub struct Function<'ctx, ReturnType: BasicType> { - module: &'ctx Module<'ctx>, - name: CString, - fn_type: FunctionType<'ctx, ReturnType>, - fn_ref: LLVMValueRef, -} - -impl<'ctx, ReturnType: BasicType> Function<'ctx, ReturnType> { - pub fn block>(&'ctx self, name: T) -> BasicBlock<'ctx, ReturnType> { - BasicBlock::in_function(&self, name.into()) - } -} - -pub struct BasicBlock<'ctx, ReturnType: BasicType> { - function: &'ctx Function<'ctx, ReturnType>, - builder_ref: LLVMBuilderRef, - name: CString, - blockref: LLVMBasicBlockRef, - inserted: bool, -} - -impl<'ctx, ReturnType: BasicType> BasicBlock<'ctx, ReturnType> { - fn in_function( - function: &'ctx Function, - name: String, - ) -> BasicBlock<'ctx, ReturnType> { - unsafe { - let block_name = into_cstring(name); - let block_ref = LLVMCreateBasicBlockInContext( - function.module.context.context_ref, - block_name.as_ptr(), - ); - BasicBlock { - function: function, - builder_ref: function.module.context.builder_ref, - name: block_name, - blockref: block_ref, - inserted: false, - } - } - } - - #[must_use] - pub fn integer_compare>( - &self, - lhs: &'ctx OpaqueValue<'ctx>, - rhs: &'ctx OpaqueValue<'ctx>, - comparison: &Comparison, - name: T, - ) -> Result, ()> { - if lhs.basic_type != rhs.basic_type { - return Err(()); // TODO invalid amount of parameters - } - unsafe { - LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref); - let value = match comparison { - Comparison::LessThan => LLVMBuildICmp( - self.builder_ref, - llvm_sys::LLVMIntPredicate::LLVMIntSLT, - lhs.value_ref, - rhs.value_ref, - into_cstring(name.into()).as_ptr(), - ), - }; - - Ok(OpaqueValue::new(lhs.basic_type, value)) - } - } - - #[must_use] - pub fn call>( - &self, - callee: &'ctx Function<'ctx, ReturnType>, - params: Vec<&'ctx OpaqueValue<'ctx>>, - name: T, - ) -> Result, ()> { - if params.len() != callee.fn_type.param_types.len() { - return Err(()); // TODO invalid amount of parameters - } - for (t1, t2) in callee.fn_type.param_types.iter().zip(¶ms) { - if t1 != &t2.basic_type.llvm_type() { - return Err(()); // TODO wrong types in parameters - } - } - unsafe { - let mut param_list: Vec = params.iter().map(|p| p.value_ref).collect(); - LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref); - let ret_val = LLVMBuildCall2( - self.builder_ref, - callee.fn_type.llvm_type(), - callee.fn_ref, - param_list.as_mut_ptr(), - param_list.len() as u32, - into_cstring(name.into()).as_ptr(), - ); - Ok(OpaqueValue::new(callee.fn_type.return_type, ret_val)) - } - } - - #[must_use] - pub fn add>( - &self, - lhs: &OpaqueValue<'ctx>, - rhs: &OpaqueValue<'ctx>, - name: T, - ) -> Result, ()> { - if lhs.basic_type != rhs.basic_type { - return Err(()); // TODO error - } - unsafe { - LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref); - let add_value_ref = LLVMBuildAdd( - self.builder_ref, - lhs.value_ref, - rhs.value_ref, - into_cstring(name.into()).as_ptr(), - ); - Ok(OpaqueValue::new(lhs.basic_type, add_value_ref)) - } - } - - #[must_use] - pub fn br(self, into: BasicBlock<'ctx, ReturnType>) -> Result<(), ()> { - unsafe { - LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref); - LLVMBuildBr(self.builder_ref, into.blockref); - self.terminate(); - Ok(()) - } - } - - #[must_use] - pub fn conditional_br, U: Into>( - self, - condition: &OpaqueValue<'ctx>, - lhs_name: T, - rhs_name: U, - ) -> Result<(BasicBlock<'ctx, ReturnType>, BasicBlock<'ctx, ReturnType>), ()> { - unsafe { - let lhs = BasicBlock::in_function(&self.function, lhs_name.into()); - let rhs = BasicBlock::in_function(&self.function, rhs_name.into()); - - LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref); - LLVMBuildCondBr( - self.builder_ref, - condition.value_ref, - lhs.blockref, - rhs.blockref, - ); - self.terminate(); - Ok((lhs, rhs)) - } - } - - #[must_use] - pub fn ret(self, return_value: &OpaqueValue<'ctx>) -> Result<(), ()> { - if self.function.fn_type.return_type().llvm_type() != return_value.basic_type.llvm_type() { - return Err(()); - } - unsafe { - LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref); - LLVMBuildRet(self.builder_ref, return_value.value_ref); - self.terminate(); - Ok(()) - } - } - - unsafe fn terminate(mut self) { - unsafe { - LLVMAppendExistingBasicBlock(self.function.fn_ref, self.blockref); - self.inserted = true; - } - } -} - -impl<'ctx, ReturnType: BasicType> Drop for BasicBlock<'ctx, ReturnType> { - fn drop(&mut self) { - if !self.inserted { - unsafe { - LLVMDeleteBasicBlock(self.blockref); - } - } - } -} diff --git a/reid-llvm-lib/src/lib.rs b/reid-llvm-lib/src/lib.rs index b013484..a55b630 100644 --- a/reid-llvm-lib/src/lib.rs +++ b/reid-llvm-lib/src/lib.rs @@ -1,7 +1,6 @@ -use std::ffi::{CStr, CString}; +use std::ffi::CString; use std::ptr::null_mut; -use context::Context; use llvm_sys::analysis::LLVMVerifyModule; use llvm_sys::target::{ LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos, @@ -11,252 +10,347 @@ use llvm_sys::target_machine::{ LLVMCodeGenFileType, LLVMCreateTargetDataLayout, LLVMCreateTargetMachine, LLVMGetDefaultTargetTriple, LLVMGetTargetFromTriple, LLVMTargetMachineEmitToFile, }; -use llvm_sys::{LLVMBasicBlock, LLVMModule, LLVMType, LLVMValue, core::*}; -use types::BasicType; +use llvm_sys::{LLVMBuilder, LLVMContext, core::*, prelude::*}; +use types::{BasicType, FunctionType, IntegerType}; use util::{ErrorMessageHolder, from_cstring, into_cstring}; pub use types::OpaqueValue; -pub mod context; pub mod types; mod util; -// pub struct IRModule<'a> { -// context: &'a Context, -// module: *mut LLVMModule, -// } +pub enum Comparison { + LessThan, +} -// impl<'a> IRModule<'a> { -// pub fn new(context: &'a Context, name: &String) -> IRModule<'a> { -// unsafe { -// let module = -// LLVMModuleCreateWithNameInContext(into_cstring(name).as_ptr(), context.context_ref); +pub struct Context { + pub(crate) context_ref: *mut LLVMContext, + pub(crate) builder_ref: *mut LLVMBuilder, +} -// IRModule { context, module } -// } -// } +impl Context { + pub fn new() -> Context { + unsafe { + // Set up a context, module and builder in that context. + let context = LLVMContextCreate(); + let builder = LLVMCreateBuilderInContext(context); -// pub fn print_to_string(&self) -> Result<&str, String> { -// unsafe { -// LLVM_InitializeAllTargets(); -// LLVM_InitializeAllTargetInfos(); -// LLVM_InitializeAllTargetMCs(); -// LLVM_InitializeAllAsmParsers(); -// LLVM_InitializeAllAsmPrinters(); + Context { + context_ref: context, + builder_ref: builder, + } + } + } -// let triple = LLVMGetDefaultTargetTriple(); + pub fn integer_type<'a, const T: u32>(&'a self) -> IntegerType<'a, T> { + IntegerType::in_context(&self) + } -// let mut target: _ = null_mut(); -// let mut err = ErrorMessageHolder::null(); -// LLVMGetTargetFromTriple(triple, &mut target, err.borrow_mut()); -// println!("{:?}, {:?}", from_cstring(triple), target); -// err.into_result().unwrap(); + pub fn module>(&self, name: T) -> Module { + Module::with_name(self, name.into()) + } +} -// let target_machine = LLVMCreateTargetMachine( -// target, -// triple, -// c"generic".as_ptr(), -// c"".as_ptr(), -// llvm_sys::target_machine::LLVMCodeGenOptLevel::LLVMCodeGenLevelNone, -// llvm_sys::target_machine::LLVMRelocMode::LLVMRelocDefault, -// llvm_sys::target_machine::LLVMCodeModel::LLVMCodeModelDefault, -// ); +impl Drop for Context { + fn drop(&mut self) { + // Clean up. Values created in the context mostly get cleaned up there. + unsafe { + LLVMDisposeBuilder(self.builder_ref); + LLVMContextDispose(self.context_ref); + } + } +} -// let data_layout = LLVMCreateTargetDataLayout(target_machine); -// LLVMSetModuleDataLayout(self.module, data_layout); +pub struct Module<'ctx> { + context: &'ctx Context, + module_ref: LLVMModuleRef, + name: CString, +} -// let mut err = ErrorMessageHolder::null(); -// LLVMVerifyModule( -// self.module, -// llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction, -// err.borrow_mut(), -// ); -// err.into_result().unwrap(); +impl<'ctx> Module<'ctx> { + fn with_name(context: &'ctx Context, name: String) -> Module<'ctx> { + unsafe { + let cstring_name = into_cstring(name); + let module_ref = + LLVMModuleCreateWithNameInContext(cstring_name.as_ptr(), context.context_ref); + Module { + context, + module_ref, + name: cstring_name, + } + } + } -// let mut err = ErrorMessageHolder::null(); -// LLVMTargetMachineEmitToFile( -// target_machine, -// self.module, -// CString::new("hello.asm").unwrap().into_raw(), -// LLVMCodeGenFileType::LLVMAssemblyFile, -// err.borrow_mut(), -// ); -// err.into_result().unwrap(); + pub fn add_function>( + &self, + fn_type: FunctionType<'ctx, ReturnType>, + name: T, + ) -> Function<'_, ReturnType> { + unsafe { + let name_cstring = into_cstring(name); + let function_ref = + LLVMAddFunction(self.module_ref, name_cstring.as_ptr(), fn_type.llvm_type()); + Function { + module: self, + fn_type, + name: name_cstring, + fn_ref: function_ref, + } + } + } -// let mut err = ErrorMessageHolder::null(); -// LLVMTargetMachineEmitToFile( -// target_machine, -// self.module, -// CString::new("hello.o").unwrap().into_raw(), -// LLVMCodeGenFileType::LLVMObjectFile, -// err.borrow_mut(), -// ); -// err.into_result().unwrap(); + pub fn print_to_string(&self) -> Result { + unsafe { + LLVM_InitializeAllTargets(); + LLVM_InitializeAllTargetInfos(); + LLVM_InitializeAllTargetMCs(); + LLVM_InitializeAllAsmParsers(); + LLVM_InitializeAllAsmPrinters(); -// Ok(CStr::from_ptr(LLVMPrintModuleToString(self.module)) -// .to_str() -// .expect("UTF8-err")) -// } -// } -// } + let triple = LLVMGetDefaultTargetTriple(); -// impl<'a> Drop for IRModule<'a> { -// fn drop(&mut self) { -// // Clean up. Values created in the context mostly get cleaned up there. -// unsafe { -// LLVMDisposeModule(self.module); -// } -// } -// } + let mut target: _ = null_mut(); + let mut err = ErrorMessageHolder::null(); + LLVMGetTargetFromTriple(triple, &mut target, err.borrow_mut()); + println!("{:?}, {:?}", from_cstring(triple), target); + err.into_result().unwrap(); -// pub struct IRFunction<'a> { -// pub name: String, -// pub module: &'a IRModule<'a>, -// pub function_ref: *mut LLVMValue, -// pub function_type: *mut LLVMType, -// } + let target_machine = LLVMCreateTargetMachine( + target, + triple, + c"generic".as_ptr(), + c"".as_ptr(), + llvm_sys::target_machine::LLVMCodeGenOptLevel::LLVMCodeGenLevelNone, + llvm_sys::target_machine::LLVMRelocMode::LLVMRelocDefault, + llvm_sys::target_machine::LLVMCodeModel::LLVMCodeModelDefault, + ); -// impl<'a> IRFunction<'a> { -// pub fn new(module: &'a IRModule<'a>, name: &String) -> IRFunction<'a> { -// unsafe { -// // TODO, fix later! -// let return_type = LLVMInt128TypeInContext(module.context.context_ref); -// let mut argts = []; -// let func_type = -// LLVMFunctionType(return_type, argts.as_mut_ptr(), argts.len() as u32, 0); + let data_layout = LLVMCreateTargetDataLayout(target_machine); + LLVMSetModuleDataLayout(self.module_ref, data_layout); -// let function_ref = -// LLVMAddFunction(module.module, into_cstring(name).as_ptr(), func_type); + let mut err = ErrorMessageHolder::null(); + LLVMVerifyModule( + self.module_ref, + llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction, + err.borrow_mut(), + ); + err.into_result().unwrap(); -// let function_type = -// LLVMFunctionType(return_type, argts.as_mut_ptr(), argts.len() as u32, 0); + let mut err = ErrorMessageHolder::null(); + LLVMTargetMachineEmitToFile( + target_machine, + self.module_ref, + CString::new("hello.asm").unwrap().into_raw(), + LLVMCodeGenFileType::LLVMAssemblyFile, + err.borrow_mut(), + ); + err.into_result().unwrap(); -// IRFunction { -// name: name.clone(), -// module, -// function_ref, -// function_type, -// } -// } -// } -// } + let mut err = ErrorMessageHolder::null(); + LLVMTargetMachineEmitToFile( + target_machine, + self.module_ref, + CString::new("hello.o").unwrap().into_raw(), + LLVMCodeGenFileType::LLVMObjectFile, + err.borrow_mut(), + ); + err.into_result().unwrap(); -// pub struct IRBlock<'a> { -// context: &'a Context, -// blockref: *mut LLVMBasicBlock, -// inserted: bool, -// } + Ok(from_cstring(LLVMPrintModuleToString(self.module_ref)).expect("UTF8-err")) + } + } +} -// impl<'a> IRBlock<'a> { -// pub fn new(context: &'a Context, name: &String) -> IRBlock<'a> { -// unsafe { -// let blockref = -// LLVMCreateBasicBlockInContext(context.context_ref, into_cstring(name).as_ptr()); +impl<'a> Drop for Module<'a> { + fn drop(&mut self) { + // Clean up. Values created in the context mostly get cleaned up there. + unsafe { + LLVMDisposeModule(self.module_ref); + } + } +} -// IRBlock { -// context, -// blockref, -// inserted: false, -// } -// } -// } +pub struct Function<'ctx, ReturnType: BasicType> { + module: &'ctx Module<'ctx>, + name: CString, + fn_type: FunctionType<'ctx, ReturnType>, + fn_ref: LLVMValueRef, +} -// pub fn call(&self, function: &IRFunction) -> OpaqueValue { -// unsafe { -// let builder = self.context.builder_ref; -// LLVMPositionBuilderAtEnd(builder, self.blockref); +impl<'ctx, ReturnType: BasicType> Function<'ctx, ReturnType> { + pub fn block>(&'ctx self, name: T) -> BasicBlock<'ctx, ReturnType> { + BasicBlock::in_function(&self, name.into()) + } +} -// // Add way to check and use parameters -// let mut args = []; +pub struct BasicBlock<'ctx, ReturnType: BasicType> { + function: &'ctx Function<'ctx, ReturnType>, + builder_ref: LLVMBuilderRef, + name: CString, + blockref: LLVMBasicBlockRef, + inserted: bool, +} -// let value = LLVMBuildCall2( -// builder, -// function.function_type, -// function.function_ref, -// args.as_mut_ptr(), -// args.len() as u32, -// into_cstring(&function.name).as_ptr(), -// ); -// OpaqueValue(i32::llvm_type(&self.context), value) -// } -// } +impl<'ctx, ReturnType: BasicType> BasicBlock<'ctx, ReturnType> { + fn in_function( + function: &'ctx Function, + name: String, + ) -> BasicBlock<'ctx, ReturnType> { + unsafe { + let block_name = into_cstring(name); + let block_ref = LLVMCreateBasicBlockInContext( + function.module.context.context_ref, + block_name.as_ptr(), + ); + BasicBlock { + function: function, + builder_ref: function.module.context.builder_ref, + name: block_name, + blockref: block_ref, + inserted: false, + } + } + } -// pub fn add(&self, lhs: OpaqueValue, rhs: OpaqueValue) -> Result { -// let OpaqueValue(t1, lhs) = lhs; -// let OpaqueValue(t2, rhs) = rhs; -// if t1 != t2 { -// Err(()) -// } else { -// unsafe { -// let builder = self.context.builder_ref; -// LLVMPositionBuilderAtEnd(builder, self.blockref); -// let value = LLVMBuildAdd(builder, lhs, rhs, c"add".as_ptr()); -// Ok(OpaqueValue(t1, value)) -// } -// } -// } + #[must_use] + pub fn integer_compare>( + &self, + lhs: &'ctx OpaqueValue<'ctx>, + rhs: &'ctx OpaqueValue<'ctx>, + comparison: &Comparison, + name: T, + ) -> Result, ()> { + if lhs.basic_type != rhs.basic_type { + return Err(()); // TODO invalid amount of parameters + } + unsafe { + LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref); + let value = match comparison { + Comparison::LessThan => LLVMBuildICmp( + self.builder_ref, + llvm_sys::LLVMIntPredicate::LLVMIntSLT, + lhs.value_ref, + rhs.value_ref, + into_cstring(name.into()).as_ptr(), + ), + }; -// pub fn less_than(&self, lhs: OpaqueValue, rhs: OpaqueValue) -> Result, ()> { -// let OpaqueValue(t1, lhs) = lhs; -// let OpaqueValue(t2, rhs) = rhs; + Ok(OpaqueValue::new(lhs.basic_type, value)) + } + } -// if t1 != t2 { -// Err(()) -// } else { -// unsafe { -// let builder = self.context.builder_ref; -// LLVMPositionBuilderAtEnd(builder, self.blockref); -// let value = LLVMBuildICmp( -// builder, -// llvm_sys::LLVMIntPredicate::LLVMIntSLT, -// lhs, -// rhs, -// c"asd".as_ptr(), -// ); -// Ok(IRValue::from_runtime(bool::llvm_type(&self.context), value)) -// } -// } -// } + #[must_use] + pub fn call>( + &self, + callee: &'ctx Function<'ctx, ReturnType>, + params: Vec<&'ctx OpaqueValue<'ctx>>, + name: T, + ) -> Result, ()> { + if params.len() != callee.fn_type.param_types.len() { + return Err(()); // TODO invalid amount of parameters + } + for (t1, t2) in callee.fn_type.param_types.iter().zip(¶ms) { + if t1 != &t2.basic_type.llvm_type() { + return Err(()); // TODO wrong types in parameters + } + } + unsafe { + let mut param_list: Vec = params.iter().map(|p| p.value_ref).collect(); + LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref); + let ret_val = LLVMBuildCall2( + self.builder_ref, + callee.fn_type.llvm_type(), + callee.fn_ref, + param_list.as_mut_ptr(), + param_list.len() as u32, + into_cstring(name.into()).as_ptr(), + ); + Ok(OpaqueValue::new(callee.fn_type.return_type, ret_val)) + } + } -// pub fn cond_br( -// self, -// function: &IRFunction, -// value: IRValue, -// ) -> (IRBlock<'a>, IRBlock<'a>) { -// let lhs = IRBlock::new(self.context, &"lhs".to_owned()); -// let rhs = IRBlock::new(self.context, &"rhs".to_owned()); -// unsafe { -// let builder = self.context.builder_ref; -// LLVMPositionBuilderAtEnd(builder, self.blockref); -// LLVMBuildCondBr(builder, value.1.1, lhs.blockref, rhs.blockref); -// self.append(function); -// (lhs, rhs) -// } -// } + #[must_use] + pub fn add>( + &self, + lhs: &OpaqueValue<'ctx>, + rhs: &OpaqueValue<'ctx>, + name: T, + ) -> Result, ()> { + if lhs.basic_type != rhs.basic_type { + return Err(()); // TODO error + } + unsafe { + LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref); + let add_value_ref = LLVMBuildAdd( + self.builder_ref, + lhs.value_ref, + rhs.value_ref, + into_cstring(name.into()).as_ptr(), + ); + Ok(OpaqueValue::new(lhs.basic_type, add_value_ref)) + } + } -// pub fn ret(self, function: &IRFunction, value: OpaqueValue) { -// unsafe { -// let builder = self.context.builder_ref; -// LLVMPositionBuilderAtEnd(builder, self.blockref); -// LLVMBuildRet(builder, value.1); -// self.append(function); -// } -// } + #[must_use] + pub fn br(self, into: BasicBlock<'ctx, ReturnType>) -> Result<(), ()> { + unsafe { + LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref); + LLVMBuildBr(self.builder_ref, into.blockref); + self.terminate(); + Ok(()) + } + } -// unsafe fn append(mut self, function: &IRFunction<'a>) { -// unsafe { -// LLVMAppendExistingBasicBlock(function.function_ref, self.blockref); -// self.inserted = true; -// } -// } -// } + #[must_use] + pub fn conditional_br, U: Into>( + self, + condition: &OpaqueValue<'ctx>, + lhs_name: T, + rhs_name: U, + ) -> Result<(BasicBlock<'ctx, ReturnType>, BasicBlock<'ctx, ReturnType>), ()> { + unsafe { + let lhs = BasicBlock::in_function(&self.function, lhs_name.into()); + let rhs = BasicBlock::in_function(&self.function, rhs_name.into()); -// impl<'a> Drop for IRBlock<'a> { -// fn drop(&mut self) { -// unsafe { -// if !self.inserted { -// LLVMDeleteBasicBlock(self.blockref); -// } -// } -// } -// } + LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref); + LLVMBuildCondBr( + self.builder_ref, + condition.value_ref, + lhs.blockref, + rhs.blockref, + ); + self.terminate(); + Ok((lhs, rhs)) + } + } + + #[must_use] + pub fn ret(self, return_value: &OpaqueValue<'ctx>) -> Result<(), ()> { + if self.function.fn_type.return_type().llvm_type() != return_value.basic_type.llvm_type() { + return Err(()); + } + unsafe { + LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref); + LLVMBuildRet(self.builder_ref, return_value.value_ref); + self.terminate(); + Ok(()) + } + } + + unsafe fn terminate(mut self) { + unsafe { + LLVMAppendExistingBasicBlock(self.function.fn_ref, self.blockref); + self.inserted = true; + } + } +} + +impl<'ctx, ReturnType: BasicType> Drop for BasicBlock<'ctx, ReturnType> { + fn drop(&mut self) { + if !self.inserted { + unsafe { + LLVMDeleteBasicBlock(self.blockref); + } + } + } +} diff --git a/reid-llvm-lib/src/types.rs b/reid-llvm-lib/src/types.rs index 5ddac88..c288150 100644 --- a/reid-llvm-lib/src/types.rs +++ b/reid-llvm-lib/src/types.rs @@ -42,7 +42,7 @@ impl PartialEq for &dyn BasicType { } } -impl PartialEq for dyn BasicType { +impl PartialEq for &dyn BasicType { fn eq(&self, other: &LLVMTypeRef) -> bool { self.llvm_type() == *other }