From 85564c74c9635177edfc91c306ddad760cc1d2d9 Mon Sep 17 00:00:00 2001 From: sofia Date: Sat, 28 Jun 2025 00:14:56 +0300 Subject: [PATCH] Rework api --- reid-llvm-lib/examples/libtest.rs | 40 +-- reid-llvm-lib/src/context.rs | 358 +++++++++++++++++++++++ reid-llvm-lib/src/lib.rs | 457 ++++++++++++++---------------- reid-llvm-lib/src/primitives.rs | 70 ----- reid-llvm-lib/src/types.rs | 190 +++++++++++++ 5 files changed, 787 insertions(+), 328 deletions(-) create mode 100644 reid-llvm-lib/src/context.rs delete mode 100644 reid-llvm-lib/src/primitives.rs create mode 100644 reid-llvm-lib/src/types.rs diff --git a/reid-llvm-lib/examples/libtest.rs b/reid-llvm-lib/examples/libtest.rs index 6e2b5ae..c47bbb3 100644 --- a/reid-llvm-lib/examples/libtest.rs +++ b/reid-llvm-lib/examples/libtest.rs @@ -1,4 +1,8 @@ -use reid_lib::*; +use reid_lib::{ + context::{Comparison, Context}, + types::BasicType, + *, +}; pub fn main() { // Notes from inkwell: @@ -7,29 +11,33 @@ pub fn main() { // - Builder could well be it's own struct // - Although, I do like the fact where blocks move the builder by itself.. - let context = IRContext::new(); - let module = IRModule::new(&context, &"hello".to_owned()); + let context = Context::new(); - let mainfunc = IRFunction::new(&module, &"main".to_owned()); + let module = context.module("testmodule"); - let secondary_func = IRFunction::new(&module, &"secondary".to_owned()); + let int_32 = context.integer_type::<32>(); - let secondary_block = IRBlock::new(&context, &"secondaryblock".to_owned()); - secondary_block.ret(&secondary_func, IRValue::from_const(&context, 54).into()); + let secondary = module.add_function(int_32.function_type(&[]), "secondary"); + let s_entry = secondary.block("entry"); + s_entry.ret(&int_32.from_const(54, 1)).unwrap(); - let block = IRBlock::new(&context, &"mainblock".to_owned()); + let function = module.add_function(int_32.function_type(&[]), "main"); - let lhs_1 = IRValue::from_const(&context, 100); - let lhs_2 = block.call(&secondary_func); - let lhs_cmp = block.add(lhs_1.into(), lhs_2.into()).unwrap(); - let rhs_cmp = IRValue::from_const(&context, 200); + let entry = function.block("entry"); - let compare = block.less_than(lhs_cmp.into(), rhs_cmp.into()).unwrap(); + let v1 = int_32.from_const(100, 1); + let v2 = entry.call(&secondary, vec![], "call").unwrap(); + let lhs_cmp = entry.add(&v1, &v2, "add").unwrap(); + let rhs_cmp = int_32.from_const(200, 1); - let (lhs, rhs) = block.cond_br(&mainfunc, compare); + let cond_res = entry + .integer_compare(&lhs_cmp, &rhs_cmp, &Comparison::LessThan, "cmp") + .unwrap(); - lhs.ret(&mainfunc, IRValue::from_const(&context, 123).into()); - rhs.ret(&mainfunc, IRValue::from_const(&context, 456).into()); + let (lhs, rhs) = entry.conditional_br(&cond_res, "lhs", "rhs").unwrap(); + + lhs.ret(&int_32.from_const(123, 1)).unwrap(); + rhs.ret(&int_32.from_const(456, 1)).unwrap(); match module.print_to_string() { Ok(v) => println!("{}", v), diff --git a/reid-llvm-lib/src/context.rs b/reid-llvm-lib/src/context.rs new file mode 100644 index 0000000..584c72a --- /dev/null +++ b/reid-llvm-lib/src/context.rs @@ -0,0 +1,358 @@ +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 0aefe8e..b013484 100644 --- a/reid-llvm-lib/src/lib.rs +++ b/reid-llvm-lib/src/lib.rs @@ -1,6 +1,7 @@ use std::ffi::{CStr, CString}; use std::ptr::null_mut; +use context::Context; use llvm_sys::analysis::LLVMVerifyModule; use llvm_sys::target::{ LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos, @@ -10,280 +11,252 @@ use llvm_sys::target_machine::{ LLVMCodeGenFileType, LLVMCreateTargetDataLayout, LLVMCreateTargetMachine, LLVMGetDefaultTargetTriple, LLVMGetTargetFromTriple, LLVMTargetMachineEmitToFile, }; -use llvm_sys::{ - LLVMBasicBlock, LLVMBuilder, LLVMContext, LLVMModule, LLVMType, LLVMValue, core::*, prelude::*, -}; -use primitives::IRType; +use llvm_sys::{LLVMBasicBlock, LLVMModule, LLVMType, LLVMValue, core::*}; +use types::BasicType; use util::{ErrorMessageHolder, from_cstring, into_cstring}; -pub use primitives::{IRValue, OpaqueIRValue}; +pub use types::OpaqueValue; -mod primitives; +pub mod context; +pub mod types; mod util; -pub struct IRContext { - context: *mut LLVMContext, - builder: *mut LLVMBuilder, -} +// pub struct IRModule<'a> { +// context: &'a Context, +// module: *mut LLVMModule, +// } -impl IRContext { - pub fn new() -> IRContext { - unsafe { - // Set up a context, module and builder in that context. - let context = LLVMContextCreate(); - let builder = LLVMCreateBuilderInContext(context); +// 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); - IRContext { context, builder } - } - } -} +// IRModule { context, module } +// } +// } -impl Drop for IRContext { - fn drop(&mut self) { - // Clean up. Values created in the context mostly get cleaned up there. - unsafe { - LLVMDisposeBuilder(self.builder); - LLVMContextDispose(self.context); - } - } -} +// pub fn print_to_string(&self) -> Result<&str, String> { +// unsafe { +// LLVM_InitializeAllTargets(); +// LLVM_InitializeAllTargetInfos(); +// LLVM_InitializeAllTargetMCs(); +// LLVM_InitializeAllAsmParsers(); +// LLVM_InitializeAllAsmPrinters(); -pub struct IRModule<'a> { - context: &'a IRContext, - module: *mut LLVMModule, -} +// let triple = LLVMGetDefaultTargetTriple(); -impl<'a> IRModule<'a> { - pub fn new(context: &'a IRContext, name: &String) -> IRModule<'a> { - unsafe { - let module = - LLVMModuleCreateWithNameInContext(into_cstring(name).as_ptr(), context.context); +// 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(); - IRModule { context, module } - } - } +// 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, +// ); - pub fn print_to_string(&self) -> Result<&str, String> { - unsafe { - LLVM_InitializeAllTargets(); - LLVM_InitializeAllTargetInfos(); - LLVM_InitializeAllTargetMCs(); - LLVM_InitializeAllAsmParsers(); - LLVM_InitializeAllAsmPrinters(); +// let data_layout = LLVMCreateTargetDataLayout(target_machine); +// LLVMSetModuleDataLayout(self.module, data_layout); - let triple = LLVMGetDefaultTargetTriple(); +// let mut err = ErrorMessageHolder::null(); +// LLVMVerifyModule( +// self.module, +// llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction, +// err.borrow_mut(), +// ); +// err.into_result().unwrap(); - 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 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(); - 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 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(); - let data_layout = LLVMCreateTargetDataLayout(target_machine); - LLVMSetModuleDataLayout(self.module, data_layout); +// Ok(CStr::from_ptr(LLVMPrintModuleToString(self.module)) +// .to_str() +// .expect("UTF8-err")) +// } +// } +// } - let mut err = ErrorMessageHolder::null(); - LLVMVerifyModule( - self.module, - llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction, - err.borrow_mut(), - ); - err.into_result().unwrap(); +// 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 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 struct IRFunction<'a> { +// pub name: String, +// pub module: &'a IRModule<'a>, +// pub function_ref: *mut LLVMValue, +// pub function_type: *mut LLVMType, +// } - 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(); +// 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); - Ok(CStr::from_ptr(LLVMPrintModuleToString(self.module)) - .to_str() - .expect("UTF8-err")) - } - } -} +// let function_ref = +// LLVMAddFunction(module.module, into_cstring(name).as_ptr(), func_type); -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 function_type = +// LLVMFunctionType(return_type, argts.as_mut_ptr(), argts.len() as u32, 0); -pub struct IRFunction<'a> { - pub name: String, - pub module: &'a IRModule<'a>, - pub function_ref: *mut LLVMValue, - pub function_type: *mut LLVMType, -} +// IRFunction { +// name: name.clone(), +// module, +// function_ref, +// function_type, +// } +// } +// } +// } -impl<'a> IRFunction<'a> { - pub fn new(module: &'a IRModule<'a>, name: &String) -> IRFunction<'a> { - unsafe { - // TODO, fix later! - let return_type = LLVMInt8TypeInContext(module.context.context); - let mut argts = []; - let func_type = - LLVMFunctionType(return_type, argts.as_mut_ptr(), argts.len() as u32, 0); +// pub struct IRBlock<'a> { +// context: &'a Context, +// blockref: *mut LLVMBasicBlock, +// inserted: bool, +// } - let function_ref = - LLVMAddFunction(module.module, into_cstring(name).as_ptr(), func_type); +// 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()); - let function_type = - LLVMFunctionType(return_type, argts.as_mut_ptr(), argts.len() as u32, 0); +// IRBlock { +// context, +// blockref, +// inserted: false, +// } +// } +// } - IRFunction { - name: name.clone(), - module, - function_ref, - function_type, - } - } - } -} +// pub fn call(&self, function: &IRFunction) -> OpaqueValue { +// unsafe { +// let builder = self.context.builder_ref; +// LLVMPositionBuilderAtEnd(builder, self.blockref); -pub struct IRBlock<'a> { - context: &'a IRContext, - blockref: *mut LLVMBasicBlock, - inserted: bool, -} +// // Add way to check and use parameters +// let mut args = []; -impl<'a> IRBlock<'a> { - pub fn new(context: &'a IRContext, name: &String) -> IRBlock<'a> { - unsafe { - let blockref = - LLVMCreateBasicBlockInContext(context.context, into_cstring(name).as_ptr()); +// 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) +// } +// } - IRBlock { - context, - blockref, - 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)) +// } +// } +// } - pub fn call(&self, function: &IRFunction) -> OpaqueIRValue { - unsafe { - let builder = self.context.builder; - LLVMPositionBuilderAtEnd(builder, self.blockref); +// pub fn less_than(&self, lhs: OpaqueValue, rhs: OpaqueValue) -> Result, ()> { +// let OpaqueValue(t1, lhs) = lhs; +// let OpaqueValue(t2, rhs) = rhs; - // Add way to check and use parameters - let mut args = []; +// 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)) +// } +// } +// } - let value = LLVMBuildCall2( - builder, - function.function_type, - function.function_ref, - args.as_mut_ptr(), - args.len() as u32, - into_cstring(&function.name).as_ptr(), - ); - OpaqueIRValue(i32::llvm_type(&self.context), value) - } - } +// 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) +// } +// } - pub fn add(&self, lhs: OpaqueIRValue, rhs: OpaqueIRValue) -> Result { - let OpaqueIRValue(t1, lhs) = lhs; - let OpaqueIRValue(t2, rhs) = rhs; - if t1 != t2 { - Err(()) - } else { - unsafe { - let builder = self.context.builder; - LLVMPositionBuilderAtEnd(builder, self.blockref); - let value = LLVMBuildAdd(builder, lhs, rhs, c"add".as_ptr()); - Ok(OpaqueIRValue(t1, value)) - } - } - } +// 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); +// } +// } - pub fn less_than(&self, lhs: OpaqueIRValue, rhs: OpaqueIRValue) -> Result, ()> { - let OpaqueIRValue(t1, lhs) = lhs; - let OpaqueIRValue(t2, rhs) = rhs; +// unsafe fn append(mut self, function: &IRFunction<'a>) { +// unsafe { +// LLVMAppendExistingBasicBlock(function.function_ref, self.blockref); +// self.inserted = true; +// } +// } +// } - if t1 != t2 { - Err(()) - } else { - unsafe { - let builder = self.context.builder; - 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)) - } - } - } - - 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; - LLVMPositionBuilderAtEnd(builder, self.blockref); - LLVMBuildCondBr(builder, value.1.1, lhs.blockref, rhs.blockref); - self.append(function); - (lhs, rhs) - } - } - - pub fn ret(self, function: &IRFunction, value: OpaqueIRValue) { - unsafe { - let builder = self.context.builder; - LLVMPositionBuilderAtEnd(builder, self.blockref); - LLVMBuildRet(builder, value.1); - self.append(function); - } - } - - unsafe fn append(mut self, function: &IRFunction<'a>) { - unsafe { - LLVMAppendExistingBasicBlock(function.function_ref, self.blockref); - self.inserted = true; - } - } -} - -impl<'a> Drop for IRBlock<'a> { - fn drop(&mut self) { - unsafe { - if !self.inserted { - LLVMDeleteBasicBlock(self.blockref); - } - } - } -} +// impl<'a> Drop for IRBlock<'a> { +// fn drop(&mut self) { +// unsafe { +// if !self.inserted { +// LLVMDeleteBasicBlock(self.blockref); +// } +// } +// } +// } diff --git a/reid-llvm-lib/src/primitives.rs b/reid-llvm-lib/src/primitives.rs deleted file mode 100644 index dfa1c41..0000000 --- a/reid-llvm-lib/src/primitives.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::marker::PhantomData; - -use llvm_sys::{ - core::{ - LLVMConstAdd, LLVMConstInt, LLVMInt1TypeInContext, LLVMInt8Type, LLVMInt8TypeInContext, - LLVMInt16TypeInContext, LLVMInt32TypeInContext, LLVMIntTypeInContext, - }, - prelude::{LLVMBool, LLVMTypeRef, LLVMValueRef}, -}; - -use crate::IRContext; - -pub trait IRType { - const SIGNED: LLVMBool; - unsafe fn llvm_type(context: &IRContext) -> LLVMTypeRef; -} - -impl IRType for bool { - const SIGNED: LLVMBool = 0; - unsafe fn llvm_type(context: &IRContext) -> LLVMTypeRef { - unsafe { LLVMInt1TypeInContext(context.context) } - } -} - -impl IRType for i32 { - const SIGNED: LLVMBool = 1; - unsafe fn llvm_type(context: &IRContext) -> LLVMTypeRef { - unsafe { LLVMInt8TypeInContext(context.context) } - } -} - -impl IRType for u32 { - const SIGNED: LLVMBool = 0; - unsafe fn llvm_type(context: &IRContext) -> LLVMTypeRef { - unsafe { LLVMInt32TypeInContext(context.context) } - } -} - -impl IRType for u16 { - const SIGNED: LLVMBool = 0; - unsafe fn llvm_type(context: &IRContext) -> LLVMTypeRef { - unsafe { LLVMInt16TypeInContext(context.context) } - } -} - -pub struct OpaqueIRValue(pub(crate) LLVMTypeRef, pub(crate) LLVMValueRef); - -pub struct IRValue(PhantomData, pub(crate) OpaqueIRValue); - -impl IRValue { - pub(crate) unsafe fn from_runtime(t: LLVMTypeRef, value: LLVMValueRef) -> IRValue { - IRValue(PhantomData, OpaqueIRValue(t, value)) - } -} - -impl> IRValue { - pub fn from_const(context: &IRContext, value: T) -> Self { - unsafe { - let t = T::llvm_type(context); - let value = LLVMConstInt(t, value.into() as u64, T::SIGNED); - IRValue(PhantomData, OpaqueIRValue(t, value)) - } - } -} - -impl From> for OpaqueIRValue { - fn from(value: IRValue) -> Self { - value.1 - } -} diff --git a/reid-llvm-lib/src/types.rs b/reid-llvm-lib/src/types.rs new file mode 100644 index 0000000..5ddac88 --- /dev/null +++ b/reid-llvm-lib/src/types.rs @@ -0,0 +1,190 @@ +use llvm_sys::{ + core::*, + prelude::{LLVMTypeRef, LLVMValueRef}, +}; + +use crate::Context; + +pub trait BasicType { + fn llvm_type(&self) -> LLVMTypeRef; + + fn function_type<'a>(&'a self, params: &'a [&'a dyn BasicType]) -> FunctionType<'a, Self> + where + Self: Sized, + { + unsafe { + let mut typerefs: Vec = params.iter().map(|b| b.llvm_type()).collect(); + let param_ptr = typerefs.as_mut_ptr(); + let param_len = typerefs.len(); + FunctionType { + return_type: self, + param_types: typerefs, + type_ref: LLVMFunctionType(self.llvm_type(), param_ptr, param_len as u32, 0), + } + } + } + + fn array_type(&self, length: u32) -> ArrayType + where + Self: Sized, + { + ArrayType { + element_type: self, + length, + type_ref: unsafe { LLVMArrayType(self.llvm_type(), length) }, + } + } +} + +impl PartialEq for &dyn BasicType { + fn eq(&self, other: &Self) -> bool { + self.llvm_type() == other.llvm_type() + } +} + +impl PartialEq for dyn BasicType { + fn eq(&self, other: &LLVMTypeRef) -> bool { + self.llvm_type() == *other + } +} + +pub struct IntegerType<'ctx, const T: u32> { + context: &'ctx Context, + type_ref: LLVMTypeRef, +} + +impl<'ctx, const T: u32> BasicType for IntegerType<'ctx, T> { + fn llvm_type(&self) -> LLVMTypeRef { + self.type_ref + } +} + +impl<'ctx, const T: u32> IntegerType<'ctx, T> { + pub(crate) fn in_context(context: &Context) -> IntegerType { + let type_ref = unsafe { + match T { + 128 => LLVMInt128TypeInContext(context.context_ref), + 64 => LLVMInt64TypeInContext(context.context_ref), + 32 => LLVMInt32TypeInContext(context.context_ref), + 16 => LLVMInt16TypeInContext(context.context_ref), + 8 => LLVMInt8TypeInContext(context.context_ref), + 1 => LLVMInt1TypeInContext(context.context_ref), + _ => LLVMIntTypeInContext(context.context_ref, T), + } + }; + IntegerType { context, type_ref } + } + + pub fn from_const(&self, value: u64, sign: i32) -> OpaqueValue { + unsafe { + OpaqueValue { + basic_type: self, + value_ref: LLVMConstInt(self.type_ref, value, sign), + } + } + } +} + +pub struct FunctionType<'ctx, ReturnType: BasicType> { + pub(crate) return_type: &'ctx ReturnType, + pub(crate) param_types: Vec, + type_ref: LLVMTypeRef, +} + +impl<'ctx, ReturnType: BasicType> BasicType for FunctionType<'ctx, ReturnType> { + fn llvm_type(&self) -> LLVMTypeRef { + self.type_ref + } +} + +impl<'ctx, ReturnType: BasicType> FunctionType<'ctx, ReturnType> { + pub fn return_type(&self) -> &ReturnType { + self.return_type + } +} + +pub struct ArrayType<'ctx, T: BasicType> { + element_type: &'ctx T, + length: u32, + type_ref: LLVMTypeRef, +} + +impl<'ctx, T: BasicType> BasicType for ArrayType<'ctx, T> { + fn llvm_type(&self) -> LLVMTypeRef { + self.type_ref + } +} + +pub struct OpaqueValue<'ctx> { + pub(crate) basic_type: &'ctx dyn BasicType, + pub(crate) value_ref: LLVMValueRef, +} + +impl<'ctx> OpaqueValue<'ctx> { + pub(crate) fn new( + basic_type: &'ctx dyn BasicType, + value_ref: LLVMValueRef, + ) -> OpaqueValue<'ctx> { + OpaqueValue { + basic_type, + value_ref, + } + } +} + +// pub trait IRType { +// const SIGNED: LLVMBool; +// unsafe fn llvm_type(context: &IRContext) -> LLVMTypeRef; +// } + +// impl IRType for bool { +// const SIGNED: LLVMBool = 0; +// unsafe fn llvm_type(context: &IRContext) -> LLVMTypeRef { +// unsafe { LLVMInt1TypeInContext(context.context) } +// } +// } + +// impl IRType for i32 { +// const SIGNED: LLVMBool = 1; +// unsafe fn llvm_type(context: &IRContext) -> LLVMTypeRef { +// unsafe { LLVMInt32TypeInContext(context.context) } +// } +// } + +// impl IRType for u32 { +// const SIGNED: LLVMBool = 0; +// unsafe fn llvm_type(context: &IRContext) -> LLVMTypeRef { +// unsafe { LLVMInt32TypeInContext(context.context) } +// } +// } + +// impl IRType for u16 { +// const SIGNED: LLVMBool = 0; +// unsafe fn llvm_type(context: &IRContext) -> LLVMTypeRef { +// unsafe { LLVMInt16TypeInContext(context.context) } +// } +// } + +// pub struct IRValue(PhantomData, pub(crate) OpaqueIRValue); + +// impl IRValue { +// pub(crate) unsafe fn from_runtime(t: LLVMTypeRef, value: LLVMValueRef) -> IRValue { +// IRValue(PhantomData, OpaqueIRValue(t, value)) +// } +// } + +// impl> IRValue { +// pub fn from_const(context: &IRContext, value: T) -> Self { +// unsafe { +// let t = T::llvm_type(context); +// let value = LLVMConstInt(t, value.into() as u64, T::SIGNED); +// IRValue(PhantomData, OpaqueIRValue(t, value)) +// } +// } +// } + +// impl From> for OpaqueIRValue { +// fn from(value: IRValue) -> Self { +// value.1 +// } +// }