Remove the old files
This commit is contained in:
parent
35efa78a56
commit
48ae533f33
@ -1,455 +0,0 @@
|
|||||||
use std::ffi::CString;
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::net::Incoming;
|
|
||||||
use std::ptr::null_mut;
|
|
||||||
|
|
||||||
use llvm_sys::analysis::LLVMVerifyModule;
|
|
||||||
use llvm_sys::target::{
|
|
||||||
LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos,
|
|
||||||
LLVM_InitializeAllTargetMCs, LLVM_InitializeAllTargets, LLVMSetModuleDataLayout,
|
|
||||||
};
|
|
||||||
use llvm_sys::target_machine::{
|
|
||||||
LLVMCodeGenFileType, LLVMCreateTargetDataLayout, LLVMCreateTargetMachine,
|
|
||||||
LLVMGetDefaultTargetTriple, LLVMGetTargetFromTriple, LLVMTargetMachineEmitToFile,
|
|
||||||
};
|
|
||||||
use llvm_sys::{LLVMBuilder, LLVMContext, LLVMIntPredicate, core::*, prelude::*};
|
|
||||||
use types::{BasicType, BasicValue, FunctionType, IntegerType, Value};
|
|
||||||
use util::{ErrorMessageHolder, from_cstring, into_cstring};
|
|
||||||
|
|
||||||
pub mod test;
|
|
||||||
pub mod types;
|
|
||||||
mod util;
|
|
||||||
|
|
||||||
pub enum IntPredicate {
|
|
||||||
SLT,
|
|
||||||
SGT,
|
|
||||||
|
|
||||||
ULT,
|
|
||||||
UGT,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntPredicate {
|
|
||||||
pub fn as_llvm(&self) -> LLVMIntPredicate {
|
|
||||||
match *self {
|
|
||||||
Self::SLT => LLVMIntPredicate::LLVMIntSLT,
|
|
||||||
Self::SGT => LLVMIntPredicate::LLVMIntSGT,
|
|
||||||
Self::ULT => LLVMIntPredicate::LLVMIntULT,
|
|
||||||
Self::UGT => LLVMIntPredicate::LLVMIntUGT,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 type_i1<'a>(&'a self) -> IntegerType<'a> {
|
|
||||||
IntegerType::in_context(&self, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_i8<'a>(&'a self) -> IntegerType<'a> {
|
|
||||||
IntegerType::in_context(&self, 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_i16<'a>(&'a self) -> IntegerType<'a> {
|
|
||||||
IntegerType::in_context(&self, 16)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_i32<'a>(&'a self) -> IntegerType<'a> {
|
|
||||||
IntegerType::in_context(&self, 32)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn module(&self, name: &str) -> Module {
|
|
||||||
Module::with_name(self, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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: &str) -> 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(&'ctx self, fn_type: FunctionType<'ctx>, name: &str) -> Function<'ctx> {
|
|
||||||
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);
|
|
||||||
LLVMSetTarget(self.module_ref, triple);
|
|
||||||
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();
|
|
||||||
|
|
||||||
from_cstring(LLVMPrintModuleToString(self.module_ref)).ok_or("UTF-8 error".to_owned())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Function<'ctx> {
|
|
||||||
module: &'ctx Module<'ctx>,
|
|
||||||
name: CString,
|
|
||||||
fn_type: FunctionType<'ctx>,
|
|
||||||
fn_ref: LLVMValueRef,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> Function<'ctx> {
|
|
||||||
pub fn block<T: Into<String>>(&'ctx self, name: T) -> BasicBlock<'ctx> {
|
|
||||||
BasicBlock::in_function(&self, name.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_param<T: BasicValue<'ctx>>(
|
|
||||||
&'ctx self,
|
|
||||||
nth: usize,
|
|
||||||
param_type: T::BaseType,
|
|
||||||
) -> Result<T, String> {
|
|
||||||
if let Some(actual_type) = self.fn_type.param_types.iter().nth(nth) {
|
|
||||||
if param_type.llvm_type() != *actual_type {
|
|
||||||
return Err(String::from("Wrong type"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(String::from("nth too large"));
|
|
||||||
}
|
|
||||||
unsafe { Ok(T::from_llvm(LLVMGetParam(self.fn_ref, nth as u32))) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BasicBlock<'ctx> {
|
|
||||||
function: &'ctx Function<'ctx>,
|
|
||||||
builder_ref: LLVMBuilderRef,
|
|
||||||
name: String,
|
|
||||||
blockref: LLVMBasicBlockRef,
|
|
||||||
inserted: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> BasicBlock<'ctx> {
|
|
||||||
fn in_function(function: &'ctx Function<'ctx>, name: String) -> BasicBlock<'ctx> {
|
|
||||||
unsafe {
|
|
||||||
let block_name = into_cstring(name.clone());
|
|
||||||
let block_ref = LLVMCreateBasicBlockInContext(
|
|
||||||
function.module.context.context_ref,
|
|
||||||
block_name.as_ptr(),
|
|
||||||
);
|
|
||||||
LLVMAppendExistingBasicBlock(function.fn_ref, block_ref);
|
|
||||||
BasicBlock {
|
|
||||||
function: function,
|
|
||||||
builder_ref: function.module.context.builder_ref,
|
|
||||||
name,
|
|
||||||
blockref: block_ref,
|
|
||||||
inserted: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn integer_compare<T: BasicValue<'ctx>>(
|
|
||||||
&self,
|
|
||||||
lhs: &T,
|
|
||||||
rhs: &T,
|
|
||||||
comparison: &IntPredicate,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<T, ()> {
|
|
||||||
unsafe {
|
|
||||||
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
|
||||||
let value = LLVMBuildICmp(
|
|
||||||
self.builder_ref,
|
|
||||||
comparison.as_llvm(),
|
|
||||||
lhs.llvm_value(),
|
|
||||||
rhs.llvm_value(),
|
|
||||||
into_cstring(name).as_ptr(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(T::from_llvm(value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn call<T: BasicValue<'ctx>>(
|
|
||||||
&self,
|
|
||||||
callee: &Function<'ctx>,
|
|
||||||
params: Vec<Value<'ctx>>,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<T, ()> {
|
|
||||||
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.llvm_type() {
|
|
||||||
return Err(()); // TODO wrong types in parameters
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !T::BaseType::is_type(callee.fn_type.return_type) {
|
|
||||||
return Err(()); // TODO wrong return type
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
let mut param_list: Vec<LLVMValueRef> = params.iter().map(|p| p.llvm_value()).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).as_ptr(),
|
|
||||||
);
|
|
||||||
Ok(T::from_llvm(ret_val))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn add<T: BasicValue<'ctx>>(&self, lhs: &T, rhs: &T, name: &str) -> Result<T, ()> {
|
|
||||||
if lhs.llvm_type() != rhs.llvm_type() {
|
|
||||||
return Err(()); // TODO error
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
|
||||||
let add_value_ref = LLVMBuildAdd(
|
|
||||||
self.builder_ref,
|
|
||||||
lhs.llvm_value(),
|
|
||||||
rhs.llvm_value(),
|
|
||||||
into_cstring(name).as_ptr(),
|
|
||||||
);
|
|
||||||
Ok(T::from_llvm(add_value_ref))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn sub<T: BasicValue<'ctx>>(&self, lhs: &T, rhs: &T, name: &str) -> Result<T, ()> {
|
|
||||||
dbg!(lhs, rhs);
|
|
||||||
dbg!(lhs.llvm_type(), rhs.llvm_type());
|
|
||||||
if lhs.llvm_type() != rhs.llvm_type() {
|
|
||||||
return Err(()); // TODO error
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
|
||||||
let add_value_ref = LLVMBuildSub(
|
|
||||||
self.builder_ref,
|
|
||||||
lhs.llvm_value(),
|
|
||||||
rhs.llvm_value(),
|
|
||||||
into_cstring(name).as_ptr(),
|
|
||||||
);
|
|
||||||
Ok(T::from_llvm(add_value_ref))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn phi<PhiValue: BasicValue<'ctx>>(
|
|
||||||
&self,
|
|
||||||
phi_type: &PhiValue::BaseType,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<PhiBuilder<'ctx, PhiValue>, ()> {
|
|
||||||
unsafe {
|
|
||||||
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
|
||||||
let phi_node = LLVMBuildPhi(
|
|
||||||
self.builder_ref,
|
|
||||||
phi_type.llvm_type(),
|
|
||||||
into_cstring(name).as_ptr(),
|
|
||||||
);
|
|
||||||
Ok(PhiBuilder::new(phi_node))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn br(&mut self, into: &BasicBlock<'ctx>) -> Result<(), ()> {
|
|
||||||
self.try_insert()?;
|
|
||||||
unsafe {
|
|
||||||
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
|
||||||
LLVMBuildBr(self.builder_ref, into.blockref);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn conditional_br<T: BasicValue<'ctx>>(
|
|
||||||
&mut self,
|
|
||||||
condition: &T,
|
|
||||||
lhs: &BasicBlock<'ctx>,
|
|
||||||
rhs: &BasicBlock<'ctx>,
|
|
||||||
) -> Result<(), ()> {
|
|
||||||
self.try_insert()?;
|
|
||||||
unsafe {
|
|
||||||
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
|
||||||
LLVMBuildCondBr(
|
|
||||||
self.builder_ref,
|
|
||||||
condition.llvm_value(),
|
|
||||||
lhs.blockref,
|
|
||||||
rhs.blockref,
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn ret<T: BasicValue<'ctx>>(&mut self, return_value: &T) -> Result<(), ()> {
|
|
||||||
if self.function.fn_type.return_type != return_value.llvm_type() {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
self.try_insert()?;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
LLVMPositionBuilderAtEnd(self.builder_ref, self.blockref);
|
|
||||||
LLVMBuildRet(self.builder_ref, return_value.llvm_value());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_insert(&mut self) -> Result<(), ()> {
|
|
||||||
if self.inserted {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
self.inserted = true;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> Drop for BasicBlock<'ctx> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if !self.inserted {
|
|
||||||
unsafe {
|
|
||||||
LLVMDeleteBasicBlock(self.blockref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PhiBuilder<'ctx, PhiValue: BasicValue<'ctx>> {
|
|
||||||
phi_node: LLVMValueRef,
|
|
||||||
phantom: PhantomData<&'ctx PhiValue>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, PhiValue: BasicValue<'ctx>> PhiBuilder<'ctx, PhiValue> {
|
|
||||||
fn new(phi_node: LLVMValueRef) -> PhiBuilder<'ctx, PhiValue> {
|
|
||||||
PhiBuilder {
|
|
||||||
phi_node,
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_incoming(&self, value: &PhiValue, block: &BasicBlock<'ctx>) -> &Self {
|
|
||||||
let mut values = vec![value.llvm_value()];
|
|
||||||
let mut blocks = vec![block.blockref];
|
|
||||||
unsafe {
|
|
||||||
LLVMAddIncoming(
|
|
||||||
self.phi_node,
|
|
||||||
values.as_mut_ptr(),
|
|
||||||
blocks.as_mut_ptr(),
|
|
||||||
values.len() as u32,
|
|
||||||
);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(&self) -> PhiValue {
|
|
||||||
unsafe { PhiValue::from_llvm(self.phi_node) }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,336 +0,0 @@
|
|||||||
use std::{any::Any, marker::PhantomData, ptr::null_mut};
|
|
||||||
|
|
||||||
use llvm_sys::{
|
|
||||||
LLVMTypeKind,
|
|
||||||
core::*,
|
|
||||||
prelude::{LLVMTypeRef, LLVMValueRef},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{BasicBlock, Context, PhiBuilder};
|
|
||||||
|
|
||||||
pub trait BasicType<'ctx> {
|
|
||||||
fn llvm_type(&self) -> LLVMTypeRef;
|
|
||||||
|
|
||||||
fn is_type(llvm_type: LLVMTypeRef) -> bool
|
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
|
|
||||||
unsafe fn from_llvm(context: &'ctx Context, llvm_type: LLVMTypeRef) -> Self
|
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
|
|
||||||
fn function_type(&self, params: Vec<TypeEnum>) -> FunctionType<'ctx> {
|
|
||||||
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 {
|
|
||||||
phantom: PhantomData,
|
|
||||||
return_type: self.llvm_type(),
|
|
||||||
param_types: typerefs,
|
|
||||||
type_ref: LLVMFunctionType(self.llvm_type(), param_ptr, param_len as u32, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn array_type(&'ctx self, length: u32) -> ArrayType<'ctx>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
ArrayType {
|
|
||||||
phantom: PhantomData,
|
|
||||||
element_type: self.llvm_type(),
|
|
||||||
length,
|
|
||||||
type_ref: unsafe { LLVMArrayType(self.llvm_type(), length) },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> PartialEq for &dyn BasicType<'ctx> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.llvm_type() == other.llvm_type()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> PartialEq<LLVMTypeRef> for &dyn BasicType<'ctx> {
|
|
||||||
fn eq(&self, other: &LLVMTypeRef) -> bool {
|
|
||||||
self.llvm_type() == *other
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct IntegerType<'ctx> {
|
|
||||||
context: &'ctx Context,
|
|
||||||
type_ref: LLVMTypeRef,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> BasicType<'ctx> for IntegerType<'ctx> {
|
|
||||||
fn llvm_type(&self) -> LLVMTypeRef {
|
|
||||||
self.type_ref
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn from_llvm(context: &'ctx Context, llvm_type: LLVMTypeRef) -> Self
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
IntegerType {
|
|
||||||
context,
|
|
||||||
type_ref: llvm_type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_type(llvm_type: LLVMTypeRef) -> bool {
|
|
||||||
unsafe { LLVMGetTypeKind(llvm_type) == LLVMTypeKind::LLVMIntegerTypeKind }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> IntegerType<'ctx> {
|
|
||||||
pub(crate) fn in_context(context: &Context, width: u32) -> IntegerType {
|
|
||||||
let type_ref = unsafe {
|
|
||||||
match width {
|
|
||||||
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, width),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
IntegerType { context, type_ref }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_signed(&self, value: i64) -> IntegerValue<'ctx> {
|
|
||||||
self.from_const(value as u64, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_unsigned(&self, value: i64) -> IntegerValue<'ctx> {
|
|
||||||
self.from_const(value as u64, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_const(&self, value: u64, sign: bool) -> IntegerValue<'ctx> {
|
|
||||||
unsafe {
|
|
||||||
IntegerValue::from_llvm(LLVMConstInt(
|
|
||||||
self.type_ref,
|
|
||||||
value,
|
|
||||||
match sign {
|
|
||||||
true => 1,
|
|
||||||
false => 0,
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct FunctionType<'ctx> {
|
|
||||||
phantom: PhantomData<&'ctx ()>,
|
|
||||||
pub(crate) return_type: LLVMTypeRef,
|
|
||||||
pub(crate) param_types: Vec<LLVMTypeRef>,
|
|
||||||
type_ref: LLVMTypeRef,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> BasicType<'ctx> for FunctionType<'ctx> {
|
|
||||||
fn llvm_type(&self) -> LLVMTypeRef {
|
|
||||||
self.type_ref
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn from_llvm(_context: &'ctx Context, fn_type: LLVMTypeRef) -> Self
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
unsafe {
|
|
||||||
let param_count = LLVMCountParamTypes(fn_type);
|
|
||||||
let param_types_ptr: *mut LLVMTypeRef = null_mut();
|
|
||||||
LLVMGetParamTypes(fn_type, param_types_ptr);
|
|
||||||
let param_types: Vec<LLVMTypeRef> =
|
|
||||||
std::slice::from_raw_parts(param_types_ptr, param_count as usize)
|
|
||||||
.iter()
|
|
||||||
.map(|t| *t)
|
|
||||||
.collect();
|
|
||||||
FunctionType {
|
|
||||||
phantom: PhantomData,
|
|
||||||
return_type: LLVMGetReturnType(fn_type),
|
|
||||||
param_types,
|
|
||||||
type_ref: fn_type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_type(llvm_type: LLVMTypeRef) -> bool {
|
|
||||||
unsafe { LLVMGetTypeKind(llvm_type) == LLVMTypeKind::LLVMFunctionTypeKind }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct ArrayType<'ctx> {
|
|
||||||
phantom: PhantomData<&'ctx ()>,
|
|
||||||
element_type: LLVMTypeRef,
|
|
||||||
length: u32,
|
|
||||||
type_ref: LLVMTypeRef,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> BasicType<'ctx> for ArrayType<'ctx> {
|
|
||||||
fn llvm_type(&self) -> LLVMTypeRef {
|
|
||||||
self.type_ref
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn from_llvm(context: &'ctx Context, llvm_type: LLVMTypeRef) -> Self
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
unsafe {
|
|
||||||
let length = LLVMGetArrayLength(llvm_type);
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_type(llvm_type: LLVMTypeRef) -> bool {
|
|
||||||
unsafe { LLVMGetTypeKind(llvm_type) == LLVMTypeKind::LLVMArrayTypeKind }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum TypeEnum<'ctx> {
|
|
||||||
Integer(IntegerType<'ctx>),
|
|
||||||
Array(ArrayType<'ctx>),
|
|
||||||
Function(FunctionType<'ctx>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> From<IntegerType<'ctx>> for TypeEnum<'ctx> {
|
|
||||||
fn from(int: IntegerType<'ctx>) -> Self {
|
|
||||||
TypeEnum::Integer(int)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> From<ArrayType<'ctx>> for TypeEnum<'ctx> {
|
|
||||||
fn from(arr: ArrayType<'ctx>) -> Self {
|
|
||||||
TypeEnum::Array(arr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> From<FunctionType<'ctx>> for TypeEnum<'ctx> {
|
|
||||||
fn from(func: FunctionType<'ctx>) -> Self {
|
|
||||||
TypeEnum::Function(func)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> TypeEnum<'ctx> {
|
|
||||||
fn inner_basic(&'ctx self) -> &'ctx dyn BasicType<'ctx> {
|
|
||||||
match self {
|
|
||||||
TypeEnum::Integer(integer_type) => integer_type,
|
|
||||||
TypeEnum::Array(array_type) => array_type,
|
|
||||||
TypeEnum::Function(function_type) => function_type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> BasicType<'ctx> for TypeEnum<'ctx> {
|
|
||||||
fn llvm_type(&self) -> LLVMTypeRef {
|
|
||||||
self.inner_basic().llvm_type()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_type(llvm_type: LLVMTypeRef) -> bool
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn from_llvm(context: &'ctx Context, llvm_type: LLVMTypeRef) -> Self
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
unsafe {
|
|
||||||
match LLVMGetTypeKind(llvm_type) {
|
|
||||||
LLVMTypeKind::LLVMIntegerTypeKind => {
|
|
||||||
TypeEnum::Integer(IntegerType::from_llvm(context, llvm_type))
|
|
||||||
}
|
|
||||||
LLVMTypeKind::LLVMArrayTypeKind => {
|
|
||||||
TypeEnum::Array(ArrayType::from_llvm(context, llvm_type))
|
|
||||||
}
|
|
||||||
LLVMTypeKind::LLVMFunctionTypeKind => {
|
|
||||||
TypeEnum::Function(FunctionType::from_llvm(context, llvm_type))
|
|
||||||
}
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait BasicValue<'ctx>: std::fmt::Debug {
|
|
||||||
type BaseType: BasicType<'ctx>;
|
|
||||||
unsafe fn from_llvm(value: LLVMValueRef) -> Self
|
|
||||||
where
|
|
||||||
Self: Sized;
|
|
||||||
fn llvm_value(&self) -> LLVMValueRef;
|
|
||||||
fn llvm_type(&self) -> LLVMTypeRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct IntegerValue<'ctx> {
|
|
||||||
phantom: PhantomData<&'ctx ()>,
|
|
||||||
pub(crate) value_ref: LLVMValueRef,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> BasicValue<'ctx> for IntegerValue<'ctx> {
|
|
||||||
type BaseType = IntegerType<'ctx>;
|
|
||||||
|
|
||||||
unsafe fn from_llvm(value: LLVMValueRef) -> Self {
|
|
||||||
IntegerValue {
|
|
||||||
phantom: PhantomData,
|
|
||||||
value_ref: value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn llvm_value(&self) -> LLVMValueRef {
|
|
||||||
self.value_ref
|
|
||||||
}
|
|
||||||
|
|
||||||
fn llvm_type(&self) -> LLVMTypeRef {
|
|
||||||
unsafe { LLVMTypeOf(self.value_ref) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum Value<'ctx> {
|
|
||||||
Integer(IntegerValue<'ctx>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> BasicValue<'ctx> for Value<'ctx> {
|
|
||||||
type BaseType = TypeEnum<'ctx>;
|
|
||||||
|
|
||||||
unsafe fn from_llvm(value: LLVMValueRef) -> Self
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
unsafe {
|
|
||||||
use LLVMTypeKind::*;
|
|
||||||
|
|
||||||
let llvm_type = LLVMTypeOf(value);
|
|
||||||
let type_kind = LLVMGetTypeKind(llvm_type);
|
|
||||||
match type_kind {
|
|
||||||
LLVMIntegerTypeKind => Value::Integer(IntegerValue::from_llvm(value)),
|
|
||||||
_ => panic!("asd"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn llvm_value(&self) -> LLVMValueRef {
|
|
||||||
match self {
|
|
||||||
Self::Integer(i) => i.llvm_value(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn llvm_type(&self) -> LLVMTypeRef {
|
|
||||||
match self {
|
|
||||||
Self::Integer(i) => i.llvm_type(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> From<IntegerValue<'ctx>> for Value<'ctx> {
|
|
||||||
fn from(value: IntegerValue<'ctx>) -> Self {
|
|
||||||
Value::Integer(value)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user