Rework api
This commit is contained in:
parent
54f25481f4
commit
85564c74c9
@ -1,4 +1,8 @@
|
|||||||
use reid_lib::*;
|
use reid_lib::{
|
||||||
|
context::{Comparison, Context},
|
||||||
|
types::BasicType,
|
||||||
|
*,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
// Notes from inkwell:
|
// Notes from inkwell:
|
||||||
@ -7,29 +11,33 @@ pub fn main() {
|
|||||||
// - Builder could well be it's own struct
|
// - Builder could well be it's own struct
|
||||||
// - Although, I do like the fact where blocks move the builder by itself..
|
// - Although, I do like the fact where blocks move the builder by itself..
|
||||||
|
|
||||||
let context = IRContext::new();
|
let context = Context::new();
|
||||||
let module = IRModule::new(&context, &"hello".to_owned());
|
|
||||||
|
|
||||||
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());
|
let secondary = module.add_function(int_32.function_type(&[]), "secondary");
|
||||||
secondary_block.ret(&secondary_func, IRValue::from_const(&context, 54).into());
|
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 entry = function.block("entry");
|
||||||
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 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());
|
let (lhs, rhs) = entry.conditional_br(&cond_res, "lhs", "rhs").unwrap();
|
||||||
rhs.ret(&mainfunc, IRValue::from_const(&context, 456).into());
|
|
||||||
|
lhs.ret(&int_32.from_const(123, 1)).unwrap();
|
||||||
|
rhs.ret(&int_32.from_const(456, 1)).unwrap();
|
||||||
|
|
||||||
match module.print_to_string() {
|
match module.print_to_string() {
|
||||||
Ok(v) => println!("{}", v),
|
Ok(v) => println!("{}", v),
|
||||||
|
358
reid-llvm-lib/src/context.rs
Normal file
358
reid-llvm-lib/src/context.rs
Normal 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(¶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,6 +1,7 @@
|
|||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
|
|
||||||
|
use context::Context;
|
||||||
use llvm_sys::analysis::LLVMVerifyModule;
|
use llvm_sys::analysis::LLVMVerifyModule;
|
||||||
use llvm_sys::target::{
|
use llvm_sys::target::{
|
||||||
LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos,
|
LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos,
|
||||||
@ -10,280 +11,252 @@ use llvm_sys::target_machine::{
|
|||||||
LLVMCodeGenFileType, LLVMCreateTargetDataLayout, LLVMCreateTargetMachine,
|
LLVMCodeGenFileType, LLVMCreateTargetDataLayout, LLVMCreateTargetMachine,
|
||||||
LLVMGetDefaultTargetTriple, LLVMGetTargetFromTriple, LLVMTargetMachineEmitToFile,
|
LLVMGetDefaultTargetTriple, LLVMGetTargetFromTriple, LLVMTargetMachineEmitToFile,
|
||||||
};
|
};
|
||||||
use llvm_sys::{
|
use llvm_sys::{LLVMBasicBlock, LLVMModule, LLVMType, LLVMValue, core::*};
|
||||||
LLVMBasicBlock, LLVMBuilder, LLVMContext, LLVMModule, LLVMType, LLVMValue, core::*, prelude::*,
|
use types::BasicType;
|
||||||
};
|
|
||||||
use primitives::IRType;
|
|
||||||
use util::{ErrorMessageHolder, from_cstring, into_cstring};
|
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;
|
mod util;
|
||||||
|
|
||||||
pub struct IRContext {
|
// pub struct IRModule<'a> {
|
||||||
context: *mut LLVMContext,
|
// context: &'a Context,
|
||||||
builder: *mut LLVMBuilder,
|
// module: *mut LLVMModule,
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl IRContext {
|
// impl<'a> IRModule<'a> {
|
||||||
pub fn new() -> IRContext {
|
// pub fn new(context: &'a Context, name: &String) -> IRModule<'a> {
|
||||||
unsafe {
|
// unsafe {
|
||||||
// Set up a context, module and builder in that context.
|
// let module =
|
||||||
let context = LLVMContextCreate();
|
// LLVMModuleCreateWithNameInContext(into_cstring(name).as_ptr(), context.context_ref);
|
||||||
let builder = LLVMCreateBuilderInContext(context);
|
|
||||||
|
|
||||||
IRContext { context, builder }
|
// IRModule { context, module }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for IRContext {
|
// pub fn print_to_string(&self) -> Result<&str, String> {
|
||||||
fn drop(&mut self) {
|
// unsafe {
|
||||||
// Clean up. Values created in the context mostly get cleaned up there.
|
// LLVM_InitializeAllTargets();
|
||||||
unsafe {
|
// LLVM_InitializeAllTargetInfos();
|
||||||
LLVMDisposeBuilder(self.builder);
|
// LLVM_InitializeAllTargetMCs();
|
||||||
LLVMContextDispose(self.context);
|
// LLVM_InitializeAllAsmParsers();
|
||||||
}
|
// LLVM_InitializeAllAsmPrinters();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IRModule<'a> {
|
// let triple = LLVMGetDefaultTargetTriple();
|
||||||
context: &'a IRContext,
|
|
||||||
module: *mut LLVMModule,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IRModule<'a> {
|
// let mut target: _ = null_mut();
|
||||||
pub fn new(context: &'a IRContext, name: &String) -> IRModule<'a> {
|
// let mut err = ErrorMessageHolder::null();
|
||||||
unsafe {
|
// LLVMGetTargetFromTriple(triple, &mut target, err.borrow_mut());
|
||||||
let module =
|
// println!("{:?}, {:?}", from_cstring(triple), target);
|
||||||
LLVMModuleCreateWithNameInContext(into_cstring(name).as_ptr(), context.context);
|
// 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> {
|
// let data_layout = LLVMCreateTargetDataLayout(target_machine);
|
||||||
unsafe {
|
// LLVMSetModuleDataLayout(self.module, data_layout);
|
||||||
LLVM_InitializeAllTargets();
|
|
||||||
LLVM_InitializeAllTargetInfos();
|
|
||||||
LLVM_InitializeAllTargetMCs();
|
|
||||||
LLVM_InitializeAllAsmParsers();
|
|
||||||
LLVM_InitializeAllAsmPrinters();
|
|
||||||
|
|
||||||
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();
|
||||||
let mut err = ErrorMessageHolder::null();
|
// LLVMTargetMachineEmitToFile(
|
||||||
LLVMGetTargetFromTriple(triple, &mut target, err.borrow_mut());
|
// target_machine,
|
||||||
println!("{:?}, {:?}", from_cstring(triple), target);
|
// self.module,
|
||||||
err.into_result().unwrap();
|
// CString::new("hello.asm").unwrap().into_raw(),
|
||||||
|
// LLVMCodeGenFileType::LLVMAssemblyFile,
|
||||||
|
// err.borrow_mut(),
|
||||||
|
// );
|
||||||
|
// err.into_result().unwrap();
|
||||||
|
|
||||||
let target_machine = LLVMCreateTargetMachine(
|
// let mut err = ErrorMessageHolder::null();
|
||||||
target,
|
// LLVMTargetMachineEmitToFile(
|
||||||
triple,
|
// target_machine,
|
||||||
c"generic".as_ptr(),
|
// self.module,
|
||||||
c"".as_ptr(),
|
// CString::new("hello.o").unwrap().into_raw(),
|
||||||
llvm_sys::target_machine::LLVMCodeGenOptLevel::LLVMCodeGenLevelNone,
|
// LLVMCodeGenFileType::LLVMObjectFile,
|
||||||
llvm_sys::target_machine::LLVMRelocMode::LLVMRelocDefault,
|
// err.borrow_mut(),
|
||||||
llvm_sys::target_machine::LLVMCodeModel::LLVMCodeModelDefault,
|
// );
|
||||||
);
|
// err.into_result().unwrap();
|
||||||
|
|
||||||
let data_layout = LLVMCreateTargetDataLayout(target_machine);
|
// Ok(CStr::from_ptr(LLVMPrintModuleToString(self.module))
|
||||||
LLVMSetModuleDataLayout(self.module, data_layout);
|
// .to_str()
|
||||||
|
// .expect("UTF8-err"))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
let mut err = ErrorMessageHolder::null();
|
// impl<'a> Drop for IRModule<'a> {
|
||||||
LLVMVerifyModule(
|
// fn drop(&mut self) {
|
||||||
self.module,
|
// // Clean up. Values created in the context mostly get cleaned up there.
|
||||||
llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction,
|
// unsafe {
|
||||||
err.borrow_mut(),
|
// LLVMDisposeModule(self.module);
|
||||||
);
|
// }
|
||||||
err.into_result().unwrap();
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
let mut err = ErrorMessageHolder::null();
|
// pub struct IRFunction<'a> {
|
||||||
LLVMTargetMachineEmitToFile(
|
// pub name: String,
|
||||||
target_machine,
|
// pub module: &'a IRModule<'a>,
|
||||||
self.module,
|
// pub function_ref: *mut LLVMValue,
|
||||||
CString::new("hello.asm").unwrap().into_raw(),
|
// pub function_type: *mut LLVMType,
|
||||||
LLVMCodeGenFileType::LLVMAssemblyFile,
|
// }
|
||||||
err.borrow_mut(),
|
|
||||||
);
|
|
||||||
err.into_result().unwrap();
|
|
||||||
|
|
||||||
let mut err = ErrorMessageHolder::null();
|
// impl<'a> IRFunction<'a> {
|
||||||
LLVMTargetMachineEmitToFile(
|
// pub fn new(module: &'a IRModule<'a>, name: &String) -> IRFunction<'a> {
|
||||||
target_machine,
|
// unsafe {
|
||||||
self.module,
|
// // TODO, fix later!
|
||||||
CString::new("hello.o").unwrap().into_raw(),
|
// let return_type = LLVMInt128TypeInContext(module.context.context_ref);
|
||||||
LLVMCodeGenFileType::LLVMObjectFile,
|
// let mut argts = [];
|
||||||
err.borrow_mut(),
|
// let func_type =
|
||||||
);
|
// LLVMFunctionType(return_type, argts.as_mut_ptr(), argts.len() as u32, 0);
|
||||||
err.into_result().unwrap();
|
|
||||||
|
|
||||||
Ok(CStr::from_ptr(LLVMPrintModuleToString(self.module))
|
// let function_ref =
|
||||||
.to_str()
|
// LLVMAddFunction(module.module, into_cstring(name).as_ptr(), func_type);
|
||||||
.expect("UTF8-err"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Drop for IRModule<'a> {
|
// let function_type =
|
||||||
fn drop(&mut self) {
|
// LLVMFunctionType(return_type, argts.as_mut_ptr(), argts.len() as u32, 0);
|
||||||
// Clean up. Values created in the context mostly get cleaned up there.
|
|
||||||
unsafe {
|
|
||||||
LLVMDisposeModule(self.module);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IRFunction<'a> {
|
// IRFunction {
|
||||||
pub name: String,
|
// name: name.clone(),
|
||||||
pub module: &'a IRModule<'a>,
|
// module,
|
||||||
pub function_ref: *mut LLVMValue,
|
// function_ref,
|
||||||
pub function_type: *mut LLVMType,
|
// function_type,
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
impl<'a> IRFunction<'a> {
|
// pub struct IRBlock<'a> {
|
||||||
pub fn new(module: &'a IRModule<'a>, name: &String) -> IRFunction<'a> {
|
// context: &'a Context,
|
||||||
unsafe {
|
// blockref: *mut LLVMBasicBlock,
|
||||||
// TODO, fix later!
|
// inserted: bool,
|
||||||
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);
|
|
||||||
|
|
||||||
let function_ref =
|
// impl<'a> IRBlock<'a> {
|
||||||
LLVMAddFunction(module.module, into_cstring(name).as_ptr(), func_type);
|
// 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 =
|
// IRBlock {
|
||||||
LLVMFunctionType(return_type, argts.as_mut_ptr(), argts.len() as u32, 0);
|
// context,
|
||||||
|
// blockref,
|
||||||
|
// inserted: false,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
IRFunction {
|
// pub fn call(&self, function: &IRFunction) -> OpaqueValue {
|
||||||
name: name.clone(),
|
// unsafe {
|
||||||
module,
|
// let builder = self.context.builder_ref;
|
||||||
function_ref,
|
// LLVMPositionBuilderAtEnd(builder, self.blockref);
|
||||||
function_type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IRBlock<'a> {
|
// // Add way to check and use parameters
|
||||||
context: &'a IRContext,
|
// let mut args = [];
|
||||||
blockref: *mut LLVMBasicBlock,
|
|
||||||
inserted: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IRBlock<'a> {
|
// let value = LLVMBuildCall2(
|
||||||
pub fn new(context: &'a IRContext, name: &String) -> IRBlock<'a> {
|
// builder,
|
||||||
unsafe {
|
// function.function_type,
|
||||||
let blockref =
|
// function.function_ref,
|
||||||
LLVMCreateBasicBlockInContext(context.context, into_cstring(name).as_ptr());
|
// args.as_mut_ptr(),
|
||||||
|
// args.len() as u32,
|
||||||
|
// into_cstring(&function.name).as_ptr(),
|
||||||
|
// );
|
||||||
|
// OpaqueValue(i32::llvm_type(&self.context), value)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
IRBlock {
|
// pub fn add(&self, lhs: OpaqueValue, rhs: OpaqueValue) -> Result<OpaqueValue, ()> {
|
||||||
context,
|
// let OpaqueValue(t1, lhs) = lhs;
|
||||||
blockref,
|
// let OpaqueValue(t2, rhs) = rhs;
|
||||||
inserted: false,
|
// 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 {
|
// pub fn less_than(&self, lhs: OpaqueValue, rhs: OpaqueValue) -> Result<IRValue<bool>, ()> {
|
||||||
unsafe {
|
// let OpaqueValue(t1, lhs) = lhs;
|
||||||
let builder = self.context.builder;
|
// let OpaqueValue(t2, rhs) = rhs;
|
||||||
LLVMPositionBuilderAtEnd(builder, self.blockref);
|
|
||||||
|
|
||||||
// Add way to check and use parameters
|
// if t1 != t2 {
|
||||||
let mut args = [];
|
// 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(
|
// pub fn cond_br(
|
||||||
builder,
|
// self,
|
||||||
function.function_type,
|
// function: &IRFunction,
|
||||||
function.function_ref,
|
// value: IRValue<bool>,
|
||||||
args.as_mut_ptr(),
|
// ) -> (IRBlock<'a>, IRBlock<'a>) {
|
||||||
args.len() as u32,
|
// let lhs = IRBlock::new(self.context, &"lhs".to_owned());
|
||||||
into_cstring(&function.name).as_ptr(),
|
// let rhs = IRBlock::new(self.context, &"rhs".to_owned());
|
||||||
);
|
// unsafe {
|
||||||
OpaqueIRValue(i32::llvm_type(&self.context), value)
|
// 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, ()> {
|
// pub fn ret(self, function: &IRFunction, value: OpaqueValue) {
|
||||||
let OpaqueIRValue(t1, lhs) = lhs;
|
// unsafe {
|
||||||
let OpaqueIRValue(t2, rhs) = rhs;
|
// let builder = self.context.builder_ref;
|
||||||
if t1 != t2 {
|
// LLVMPositionBuilderAtEnd(builder, self.blockref);
|
||||||
Err(())
|
// LLVMBuildRet(builder, value.1);
|
||||||
} else {
|
// self.append(function);
|
||||||
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 less_than(&self, lhs: OpaqueIRValue, rhs: OpaqueIRValue) -> Result<IRValue<bool>, ()> {
|
// unsafe fn append(mut self, function: &IRFunction<'a>) {
|
||||||
let OpaqueIRValue(t1, lhs) = lhs;
|
// unsafe {
|
||||||
let OpaqueIRValue(t2, rhs) = rhs;
|
// LLVMAppendExistingBasicBlock(function.function_ref, self.blockref);
|
||||||
|
// self.inserted = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
if t1 != t2 {
|
// impl<'a> Drop for IRBlock<'a> {
|
||||||
Err(())
|
// fn drop(&mut self) {
|
||||||
} else {
|
// unsafe {
|
||||||
unsafe {
|
// if !self.inserted {
|
||||||
let builder = self.context.builder;
|
// LLVMDeleteBasicBlock(self.blockref);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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
190
reid-llvm-lib/src/types.rs
Normal 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
|
||||||
|
// }
|
||||||
|
// }
|
Loading…
Reference in New Issue
Block a user