Rework api

This commit is contained in:
Sofia 2025-06-28 00:14:56 +03:00
parent 54f25481f4
commit 85564c74c9
5 changed files with 787 additions and 328 deletions

View File

@ -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),

View File

@ -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<T: Into<String>>(&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<ReturnType: BasicType, T: Into<String>>(
&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<String, String> {
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<T: Into<String>>(&'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<ReturnType>,
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<T: Into<String>>(
&self,
lhs: &'ctx OpaqueValue<'ctx>,
rhs: &'ctx OpaqueValue<'ctx>,
comparison: &Comparison,
name: T,
) -> Result<OpaqueValue<'ctx>, ()> {
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<T: Into<String>>(
&self,
callee: &'ctx Function<'ctx, ReturnType>,
params: Vec<&'ctx OpaqueValue<'ctx>>,
name: T,
) -> Result<OpaqueValue<'ctx>, ()> {
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(&params) {
if t1 != &t2.basic_type.llvm_type() {
return Err(()); // TODO wrong types in parameters
}
}
unsafe {
let mut param_list: Vec<LLVMValueRef> = 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<T: Into<String>>(
&self,
lhs: &OpaqueValue<'ctx>,
rhs: &OpaqueValue<'ctx>,
name: T,
) -> Result<OpaqueValue<'ctx>, ()> {
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<T: Into<String>, U: Into<String>>(
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);
}
}
}
}

View File

@ -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<OpaqueValue, ()> {
// 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<IRValue<bool>, ()> {
// 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<bool>,
// ) -> (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<OpaqueIRValue, ()> {
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<IRValue<bool>, ()> {
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<bool>,
) -> (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);
// }
// }
// }
// }

View File

@ -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<T: IRType>(PhantomData<T>, pub(crate) OpaqueIRValue);
impl<T: IRType> IRValue<T> {
pub(crate) unsafe fn from_runtime(t: LLVMTypeRef, value: LLVMValueRef) -> IRValue<T> {
IRValue(PhantomData, OpaqueIRValue(t, value))
}
}
impl<T: IRType + Into<i64>> IRValue<T> {
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<T: IRType> From<IRValue<T>> for OpaqueIRValue {
fn from(value: IRValue<T>) -> Self {
value.1
}
}

190
reid-llvm-lib/src/types.rs Normal file
View File

@ -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<LLVMTypeRef> = 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<Self>
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<LLVMTypeRef> 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<T> {
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<LLVMTypeRef>,
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<T: IRType>(PhantomData<T>, pub(crate) OpaqueIRValue);
// impl<T: IRType> IRValue<T> {
// pub(crate) unsafe fn from_runtime(t: LLVMTypeRef, value: LLVMValueRef) -> IRValue<T> {
// IRValue(PhantomData, OpaqueIRValue(t, value))
// }
// }
// impl<T: IRType + Into<i64>> IRValue<T> {
// 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<T: IRType> From<IRValue<T>> for OpaqueIRValue {
// fn from(value: IRValue<T>) -> Self {
// value.1
// }
// }