Move context.rs to lib.rs
This commit is contained in:
parent
85564c74c9
commit
02d8b37424
@ -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:
|
||||
|
@ -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<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(¶ms) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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<T: Into<String>>(&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<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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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<String, String> {
|
||||
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<T: Into<String>>(&'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<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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
#[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(),
|
||||
),
|
||||
};
|
||||
|
||||
// pub fn less_than(&self, lhs: OpaqueValue, rhs: OpaqueValue) -> Result<IRValue<bool>, ()> {
|
||||
// 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<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(¶ms) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
// }
|
||||
// }
|
||||
#[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))
|
||||
}
|
||||
}
|
||||
|
||||
// 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<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());
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ impl PartialEq for &dyn BasicType {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<LLVMTypeRef> for dyn BasicType {
|
||||
impl PartialEq<LLVMTypeRef> for &dyn BasicType {
|
||||
fn eq(&self, other: &LLVMTypeRef) -> bool {
|
||||
self.llvm_type() == *other
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user