Make a more Rusty LLIR for the lib that is compiled to LLVM IR
This commit is contained in:
parent
454cefafc9
commit
58117d86e4
60
reid-llvm-lib/examples/test.rs
Normal file
60
reid-llvm-lib/examples/test.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
use reid_lib::test::{ConstValue, Context, InstructionKind, IntPredicate, TerminatorKind, Type};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
use ConstValue::*;
|
||||||
|
use InstructionKind::*;
|
||||||
|
|
||||||
|
let context = Context::new();
|
||||||
|
|
||||||
|
let mut module = context.module("test");
|
||||||
|
|
||||||
|
let mut main = module.function("main", Type::I32, Vec::new());
|
||||||
|
let mut m_entry = main.block("entry");
|
||||||
|
|
||||||
|
let mut fibonacci = module.function("fibonacci", Type::I32, vec![Type::I32]);
|
||||||
|
|
||||||
|
let arg = m_entry.build(Constant(I32(5))).unwrap();
|
||||||
|
let fibonacci_call = m_entry
|
||||||
|
.build(FunctionCall(fibonacci.value(), vec![arg]))
|
||||||
|
.unwrap();
|
||||||
|
m_entry
|
||||||
|
.terminate(TerminatorKind::Ret(fibonacci_call))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut f_entry = fibonacci.block("entry");
|
||||||
|
|
||||||
|
let num_3 = f_entry.build(Constant(I32(3))).unwrap();
|
||||||
|
let param_n = f_entry.build(Param(0)).unwrap();
|
||||||
|
let cond = f_entry
|
||||||
|
.build(ICmp(IntPredicate::LessThan, param_n, num_3))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut then_b = fibonacci.block("then");
|
||||||
|
let mut else_b = fibonacci.block("else");
|
||||||
|
|
||||||
|
f_entry
|
||||||
|
.terminate(TerminatorKind::CondBr(cond, then_b.value(), else_b.value()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let ret_const = then_b.build(Constant(I32(1))).unwrap();
|
||||||
|
then_b.terminate(TerminatorKind::Ret(ret_const)).unwrap();
|
||||||
|
|
||||||
|
let const_1 = else_b.build(Constant(I32(1))).unwrap();
|
||||||
|
let const_2 = else_b.build(Constant(I32(2))).unwrap();
|
||||||
|
let param_1 = else_b.build(Sub(param_n, const_1)).unwrap();
|
||||||
|
let param_2 = else_b.build(Sub(param_n, const_2)).unwrap();
|
||||||
|
let call_1 = else_b
|
||||||
|
.build(FunctionCall(fibonacci.value(), vec![param_1]))
|
||||||
|
.unwrap();
|
||||||
|
let call_2 = else_b
|
||||||
|
.build(FunctionCall(fibonacci.value(), vec![param_2]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let add = else_b.build(Add(call_1, call_2)).unwrap();
|
||||||
|
|
||||||
|
else_b.terminate(TerminatorKind::Ret(add)).unwrap();
|
||||||
|
|
||||||
|
dbg!(&context);
|
||||||
|
|
||||||
|
context.compile();
|
||||||
|
}
|
@ -16,6 +16,7 @@ use llvm_sys::{LLVMBuilder, LLVMContext, LLVMIntPredicate, core::*, prelude::*};
|
|||||||
use types::{BasicType, BasicValue, FunctionType, IntegerType, Value};
|
use types::{BasicType, BasicValue, FunctionType, IntegerType, Value};
|
||||||
use util::{ErrorMessageHolder, from_cstring, into_cstring};
|
use util::{ErrorMessageHolder, from_cstring, into_cstring};
|
||||||
|
|
||||||
|
pub mod test;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
334
reid-llvm-lib/src/test/builder.rs
Normal file
334
reid-llvm-lib/src/test/builder.rs
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
use std::{cell::RefCell, marker::PhantomData, rc::Rc};
|
||||||
|
|
||||||
|
use crate::test::{ConstValue, InstructionKind, TerminatorKind, Type};
|
||||||
|
|
||||||
|
use super::{BlockData, FunctionData, InstructionData, ModuleData, util::match_types};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)]
|
||||||
|
pub struct ModuleValue(usize);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)]
|
||||||
|
pub struct FunctionValue(ModuleValue, usize);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)]
|
||||||
|
pub struct BlockValue(FunctionValue, usize);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)]
|
||||||
|
pub struct InstructionValue(BlockValue, usize);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ModuleHolder {
|
||||||
|
pub(crate) value: ModuleValue,
|
||||||
|
pub(crate) data: ModuleData,
|
||||||
|
pub(crate) functions: Vec<FunctionHolder>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct FunctionHolder {
|
||||||
|
pub(crate) value: FunctionValue,
|
||||||
|
pub(crate) data: FunctionData,
|
||||||
|
pub(crate) blocks: Vec<BlockHolder>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct BlockHolder {
|
||||||
|
pub(crate) value: BlockValue,
|
||||||
|
pub(crate) data: BlockData,
|
||||||
|
pub(crate) instructions: Vec<InstructionHolder>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct InstructionHolder {
|
||||||
|
pub(crate) value: InstructionValue,
|
||||||
|
pub(crate) data: InstructionData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Builder {
|
||||||
|
modules: Rc<RefCell<Vec<ModuleHolder>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Builder {
|
||||||
|
pub fn new() -> Builder {
|
||||||
|
Builder {
|
||||||
|
modules: Rc::new(RefCell::new(Vec::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_module(&self, data: ModuleData) -> ModuleValue {
|
||||||
|
let value = ModuleValue(self.modules.borrow().len());
|
||||||
|
self.modules.borrow_mut().push(ModuleHolder {
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
functions: Vec::new(),
|
||||||
|
});
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn add_function(
|
||||||
|
&self,
|
||||||
|
mod_val: &ModuleValue,
|
||||||
|
data: FunctionData,
|
||||||
|
) -> FunctionValue {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(mod_val.0);
|
||||||
|
let value = FunctionValue(module.value, module.functions.len());
|
||||||
|
module.functions.push(FunctionHolder {
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
blocks: Vec::new(),
|
||||||
|
});
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn add_block(&self, fun_val: &FunctionValue, data: BlockData) -> BlockValue {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(fun_val.0.0);
|
||||||
|
let function = module.functions.get_unchecked_mut(fun_val.1);
|
||||||
|
let value = BlockValue(function.value, function.blocks.len());
|
||||||
|
function.blocks.push(BlockHolder {
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
instructions: Vec::new(),
|
||||||
|
});
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn add_instruction(
|
||||||
|
&self,
|
||||||
|
block_val: &BlockValue,
|
||||||
|
data: InstructionData,
|
||||||
|
) -> Result<InstructionValue, ()> {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(block_val.0.0.0);
|
||||||
|
let function = module.functions.get_unchecked_mut(block_val.0.1);
|
||||||
|
let block = function.blocks.get_unchecked_mut(block_val.1);
|
||||||
|
let value = InstructionValue(block.value, block.instructions.len());
|
||||||
|
block.instructions.push(InstructionHolder { value, data });
|
||||||
|
|
||||||
|
// Drop modules so that it is no longer mutable borrowed
|
||||||
|
// (check_instruction requires an immutable borrow).
|
||||||
|
drop(modules);
|
||||||
|
|
||||||
|
self.check_instruction(&value)?;
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn terminate(
|
||||||
|
&self,
|
||||||
|
block: &BlockValue,
|
||||||
|
value: TerminatorKind,
|
||||||
|
) -> Result<(), ()> {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(block.0.0.0);
|
||||||
|
let function = module.functions.get_unchecked_mut(block.0.1);
|
||||||
|
let block = function.blocks.get_unchecked_mut(block.1);
|
||||||
|
if let Some(_) = &block.data.terminator {
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
block.data.terminator = Some(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn module_data(&self, value: &ModuleValue) -> ModuleData {
|
||||||
|
unsafe { self.modules.borrow().get_unchecked(value.0).data.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn function_data(&self, value: &FunctionValue) -> FunctionData {
|
||||||
|
unsafe {
|
||||||
|
self.modules
|
||||||
|
.borrow()
|
||||||
|
.get_unchecked(value.0.0)
|
||||||
|
.functions
|
||||||
|
.get_unchecked(value.1)
|
||||||
|
.data
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn block_data(&self, value: &BlockValue) -> BlockData {
|
||||||
|
unsafe {
|
||||||
|
self.modules
|
||||||
|
.borrow()
|
||||||
|
.get_unchecked(value.0.0.0)
|
||||||
|
.functions
|
||||||
|
.get_unchecked(value.0.1)
|
||||||
|
.blocks
|
||||||
|
.get_unchecked(value.1)
|
||||||
|
.data
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn instr_data(&self, value: &InstructionValue) -> InstructionData {
|
||||||
|
unsafe {
|
||||||
|
self.modules
|
||||||
|
.borrow()
|
||||||
|
.get_unchecked(value.0.0.0.0)
|
||||||
|
.functions
|
||||||
|
.get_unchecked(value.0.0.1)
|
||||||
|
.blocks
|
||||||
|
.get_unchecked(value.0.1)
|
||||||
|
.instructions
|
||||||
|
.get_unchecked(value.1)
|
||||||
|
.data
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_modules(&self) -> Rc<RefCell<Vec<ModuleHolder>>> {
|
||||||
|
self.modules.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub(crate) fn get_functions(&self, module: ModuleValue) -> Vec<(FunctionValue, FunctionData)> {
|
||||||
|
// unsafe {
|
||||||
|
// self.modules
|
||||||
|
// .borrow()
|
||||||
|
// .get_unchecked(module.0)
|
||||||
|
// .2
|
||||||
|
// .iter()
|
||||||
|
// .map(|h| (h.0, h.1.clone()))
|
||||||
|
// .collect()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub(crate) fn get_blocks(&self, function: FunctionValue) -> Vec<(BlockValue, BlockData)> {
|
||||||
|
// unsafe {
|
||||||
|
// self.modules
|
||||||
|
// .borrow()
|
||||||
|
// .get_unchecked(function.0.0)
|
||||||
|
// .2
|
||||||
|
// .get_unchecked(function.1)
|
||||||
|
// .2
|
||||||
|
// .iter()
|
||||||
|
// .map(|h| (h.0, h.1.clone()))
|
||||||
|
// .collect()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub(crate) fn get_instructions(
|
||||||
|
// &self,
|
||||||
|
// block: BlockValue,
|
||||||
|
// ) -> (
|
||||||
|
// Vec<(InstructionValue, InstructionData)>,
|
||||||
|
// Option<TerminatorKind>,
|
||||||
|
// ) {
|
||||||
|
// unsafe {
|
||||||
|
// let modules = self.modules.borrow();
|
||||||
|
// let block = modules
|
||||||
|
// .get_unchecked(block.0.0.0)
|
||||||
|
// .2
|
||||||
|
// .get_unchecked(block.0.1)
|
||||||
|
// .2
|
||||||
|
// .get_unchecked(block.1);
|
||||||
|
// (
|
||||||
|
// block.2.iter().map(|h| (h.0, h.1.clone())).collect(),
|
||||||
|
// block.1.terminator.clone(),
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn check_instruction(&self, instruction: &InstructionValue) -> Result<(), ()> {
|
||||||
|
use super::InstructionKind::*;
|
||||||
|
unsafe {
|
||||||
|
match self.instr_data(&instruction).kind {
|
||||||
|
Param(_) => Ok(()),
|
||||||
|
Constant(_) => Ok(()),
|
||||||
|
Add(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()),
|
||||||
|
Sub(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()),
|
||||||
|
ICmp(_, lhs, rhs) => {
|
||||||
|
let t = match_types(&lhs, &rhs, self)?;
|
||||||
|
if t.comparable() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(()) // TODO error: Types not comparable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FunctionCall(fun, params) => {
|
||||||
|
let param_types = self.function_data(&fun).params;
|
||||||
|
if param_types.len() != params.len() {
|
||||||
|
return Err(()); // TODO error: invalid amount of params
|
||||||
|
}
|
||||||
|
for (a, b) in param_types.iter().zip(params) {
|
||||||
|
if *a != b.get_type(&self)? {
|
||||||
|
return Err(()); // TODO error: params do not match
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstructionValue {
|
||||||
|
pub fn get_type(&self, builder: &Builder) -> Result<Type, ()> {
|
||||||
|
use InstructionKind::*;
|
||||||
|
use Type::*;
|
||||||
|
unsafe {
|
||||||
|
match &builder.instr_data(self).kind {
|
||||||
|
Param(nth) => builder
|
||||||
|
.function_data(&self.0.0)
|
||||||
|
.params
|
||||||
|
.get(*nth)
|
||||||
|
.copied()
|
||||||
|
.ok_or(()),
|
||||||
|
Constant(c) => Ok(c.get_type()),
|
||||||
|
Add(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
Sub(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
ICmp(pred, lhs, rhs) => Ok(Type::Bool),
|
||||||
|
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConstValue {
|
||||||
|
pub fn get_type(&self) -> Type {
|
||||||
|
use Type::*;
|
||||||
|
match self {
|
||||||
|
ConstValue::I32(_) => I32,
|
||||||
|
ConstValue::U32(_) => U32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Type {
|
||||||
|
pub fn comparable(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Type::I32 => true,
|
||||||
|
Type::U32 => true,
|
||||||
|
Type::Bool => true,
|
||||||
|
Type::Void => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signed(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Type::I32 => true,
|
||||||
|
Type::U32 => false,
|
||||||
|
Type::Bool => false,
|
||||||
|
Type::Void => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TerminatorKind {
|
||||||
|
pub fn get_type(&self, builder: &Builder) -> Result<Type, ()> {
|
||||||
|
use TerminatorKind::*;
|
||||||
|
match self {
|
||||||
|
Ret(instr_val) => instr_val.get_type(builder),
|
||||||
|
Branch(_) => Ok(Type::Void),
|
||||||
|
CondBr(_, _, _) => Ok(Type::Void),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
364
reid-llvm-lib/src/test/compile.rs
Normal file
364
reid-llvm-lib/src/test/compile.rs
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
use std::{collections::HashMap, ffi::CString, hash::Hash, process::Termination, ptr::null_mut};
|
||||||
|
|
||||||
|
use llvm_sys::{
|
||||||
|
LLVMIntPredicate,
|
||||||
|
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::util::{ErrorMessageHolder, from_cstring, into_cstring};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
ConstValue, Context, Function, IntPredicate, Module, TerminatorKind, Type,
|
||||||
|
builder::{
|
||||||
|
BlockHolder, BlockValue, Builder, FunctionHolder, FunctionValue, InstructionHolder,
|
||||||
|
InstructionValue, ModuleHolder,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct LLVMContext {
|
||||||
|
context_ref: LLVMContextRef,
|
||||||
|
builder_ref: LLVMBuilderRef,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
pub fn compile(&self) {
|
||||||
|
unsafe {
|
||||||
|
let context_ref = LLVMContextCreate();
|
||||||
|
|
||||||
|
let context = LLVMContext {
|
||||||
|
context_ref,
|
||||||
|
builder_ref: LLVMCreateBuilderInContext(context_ref),
|
||||||
|
};
|
||||||
|
|
||||||
|
for holder in self.builder.get_modules().borrow().iter() {
|
||||||
|
holder.compile(&context, &self.builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVMDisposeBuilder(context.builder_ref);
|
||||||
|
LLVMContextDispose(context.context_ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LLVMModule<'a> {
|
||||||
|
builder: &'a Builder,
|
||||||
|
context_ref: LLVMContextRef,
|
||||||
|
builder_ref: LLVMBuilderRef,
|
||||||
|
module_ref: LLVMModuleRef,
|
||||||
|
functions: HashMap<FunctionValue, LLVMFunction>,
|
||||||
|
blocks: HashMap<BlockValue, LLVMBasicBlockRef>,
|
||||||
|
values: HashMap<InstructionValue, LLVMValue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct LLVMFunction {
|
||||||
|
type_ref: LLVMTypeRef,
|
||||||
|
value_ref: LLVMValueRef,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LLVMValue {
|
||||||
|
ty: Type,
|
||||||
|
value_ref: LLVMValueRef,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleHolder {
|
||||||
|
fn compile(&self, context: &LLVMContext, builder: &Builder) {
|
||||||
|
unsafe {
|
||||||
|
let module_ref = LLVMModuleCreateWithNameInContext(
|
||||||
|
into_cstring(&self.data.name).as_ptr(),
|
||||||
|
context.context_ref,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Compile the contents
|
||||||
|
|
||||||
|
let mut functions = HashMap::new();
|
||||||
|
|
||||||
|
for function in &self.functions {
|
||||||
|
functions.insert(
|
||||||
|
function.value,
|
||||||
|
function.compile_signature(context, module_ref),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut module = LLVMModule {
|
||||||
|
builder,
|
||||||
|
context_ref: context.context_ref,
|
||||||
|
builder_ref: context.builder_ref,
|
||||||
|
module_ref,
|
||||||
|
functions,
|
||||||
|
blocks: HashMap::new(),
|
||||||
|
values: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for function in &self.functions {
|
||||||
|
function.compile(&mut module);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(module_ref, triple);
|
||||||
|
LLVMSetModuleDataLayout(module_ref, data_layout);
|
||||||
|
|
||||||
|
let mut err = ErrorMessageHolder::null();
|
||||||
|
LLVMVerifyModule(
|
||||||
|
module_ref,
|
||||||
|
llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction,
|
||||||
|
err.borrow_mut(),
|
||||||
|
);
|
||||||
|
err.into_result().unwrap();
|
||||||
|
|
||||||
|
let mut err = ErrorMessageHolder::null();
|
||||||
|
LLVMTargetMachineEmitToFile(
|
||||||
|
target_machine,
|
||||||
|
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,
|
||||||
|
module_ref,
|
||||||
|
CString::new("hello.o").unwrap().into_raw(),
|
||||||
|
LLVMCodeGenFileType::LLVMObjectFile,
|
||||||
|
err.borrow_mut(),
|
||||||
|
);
|
||||||
|
err.into_result().unwrap();
|
||||||
|
|
||||||
|
let module_str = from_cstring(LLVMPrintModuleToString(module_ref));
|
||||||
|
println!("{}", module_str.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionHolder {
|
||||||
|
unsafe fn compile_signature(
|
||||||
|
&self,
|
||||||
|
context: &LLVMContext,
|
||||||
|
module_ref: LLVMModuleRef,
|
||||||
|
) -> LLVMFunction {
|
||||||
|
unsafe {
|
||||||
|
let ret_type = self.data.ret.as_llvm(context.context_ref);
|
||||||
|
let mut param_types: Vec<LLVMTypeRef> = self
|
||||||
|
.data
|
||||||
|
.params
|
||||||
|
.iter()
|
||||||
|
.map(|t| t.as_llvm(context.context_ref))
|
||||||
|
.collect();
|
||||||
|
let param_ptr = param_types.as_mut_ptr();
|
||||||
|
let param_len = param_types.len();
|
||||||
|
|
||||||
|
let fn_type = LLVMFunctionType(ret_type, param_ptr, param_len as u32, 0);
|
||||||
|
|
||||||
|
let function_ref =
|
||||||
|
LLVMAddFunction(module_ref, into_cstring(&self.data.name).as_ptr(), fn_type);
|
||||||
|
|
||||||
|
LLVMFunction {
|
||||||
|
type_ref: fn_type,
|
||||||
|
value_ref: function_ref,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn compile(&self, module: &mut LLVMModule) {
|
||||||
|
unsafe {
|
||||||
|
let own_function = *module.functions.get(&self.value).unwrap();
|
||||||
|
|
||||||
|
for block in &self.blocks {
|
||||||
|
let block_ref = LLVMCreateBasicBlockInContext(
|
||||||
|
module.context_ref,
|
||||||
|
into_cstring(&self.data.name).as_ptr(),
|
||||||
|
);
|
||||||
|
LLVMAppendExistingBasicBlock(own_function.value_ref, block_ref);
|
||||||
|
module.blocks.insert(block.value, block_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
for block in &self.blocks {
|
||||||
|
block.compile(module, &own_function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockHolder {
|
||||||
|
unsafe fn compile(&self, module: &mut LLVMModule, function: &LLVMFunction) {
|
||||||
|
unsafe {
|
||||||
|
let block_ref = *module.blocks.get(&self.value).unwrap();
|
||||||
|
LLVMPositionBuilderAtEnd(module.builder_ref, block_ref);
|
||||||
|
|
||||||
|
for instruction in &self.instructions {
|
||||||
|
let key = instruction.value;
|
||||||
|
let ret = instruction.compile(module, function, block_ref);
|
||||||
|
module.values.insert(key, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.data
|
||||||
|
.terminator
|
||||||
|
.clone()
|
||||||
|
.expect(&format!(
|
||||||
|
"Block {} does not have a terminator!",
|
||||||
|
self.data.name
|
||||||
|
))
|
||||||
|
.compile(module, function, block_ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstructionHolder {
|
||||||
|
unsafe fn compile(
|
||||||
|
&self,
|
||||||
|
module: &LLVMModule,
|
||||||
|
function: &LLVMFunction,
|
||||||
|
block: LLVMBasicBlockRef,
|
||||||
|
) -> LLVMValue {
|
||||||
|
let ty = self.value.get_type(module.builder).unwrap();
|
||||||
|
let val = unsafe {
|
||||||
|
use super::InstructionKind::*;
|
||||||
|
match &self.data.kind {
|
||||||
|
Param(nth) => LLVMGetParam(function.value_ref, *nth as u32),
|
||||||
|
Constant(val) => val.as_llvm(module.context_ref),
|
||||||
|
Add(lhs, rhs) => {
|
||||||
|
let lhs_val = module.values.get(&lhs).unwrap().value_ref;
|
||||||
|
let rhs_val = module.values.get(&rhs).unwrap().value_ref;
|
||||||
|
LLVMBuildAdd(module.builder_ref, lhs_val, rhs_val, c"add".as_ptr())
|
||||||
|
}
|
||||||
|
Sub(lhs, rhs) => {
|
||||||
|
let lhs_val = module.values.get(&lhs).unwrap().value_ref;
|
||||||
|
let rhs_val = module.values.get(&rhs).unwrap().value_ref;
|
||||||
|
LLVMBuildSub(module.builder_ref, lhs_val, rhs_val, c"sub".as_ptr())
|
||||||
|
}
|
||||||
|
ICmp(pred, lhs, rhs) => {
|
||||||
|
let lhs_val = module.values.get(&lhs).unwrap().value_ref;
|
||||||
|
let rhs_val = module.values.get(&rhs).unwrap().value_ref;
|
||||||
|
LLVMBuildICmp(
|
||||||
|
module.builder_ref,
|
||||||
|
pred.as_llvm(ty.signed()),
|
||||||
|
lhs_val,
|
||||||
|
rhs_val,
|
||||||
|
c"icmp".as_ptr(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
FunctionCall(function_value, instruction_values) => {
|
||||||
|
let fun = module.functions.get(&function_value).unwrap();
|
||||||
|
let mut param_list: Vec<LLVMValueRef> = instruction_values
|
||||||
|
.iter()
|
||||||
|
.map(|i| module.values.get(i).unwrap().value_ref)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
LLVMBuildCall2(
|
||||||
|
module.builder_ref,
|
||||||
|
fun.type_ref,
|
||||||
|
fun.value_ref,
|
||||||
|
param_list.as_mut_ptr(),
|
||||||
|
param_list.len() as u32,
|
||||||
|
c"call".as_ptr(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
LLVMValue { ty, value_ref: val }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TerminatorKind {
|
||||||
|
fn compile(
|
||||||
|
&self,
|
||||||
|
module: &LLVMModule,
|
||||||
|
function: &LLVMFunction,
|
||||||
|
block: LLVMBasicBlockRef,
|
||||||
|
) -> LLVMValue {
|
||||||
|
let ty = self.get_type(module.builder).unwrap();
|
||||||
|
let val = unsafe {
|
||||||
|
match self {
|
||||||
|
TerminatorKind::Ret(val) => {
|
||||||
|
let value = module.values.get(val).unwrap();
|
||||||
|
LLVMBuildRet(module.builder_ref, value.value_ref)
|
||||||
|
}
|
||||||
|
TerminatorKind::Branch(block_value) => {
|
||||||
|
let dest = *module.blocks.get(block_value).unwrap();
|
||||||
|
LLVMBuildBr(module.builder_ref, dest)
|
||||||
|
}
|
||||||
|
TerminatorKind::CondBr(cond, then_b, else_b) => {
|
||||||
|
let cond_val = module.values.get(cond).unwrap().value_ref;
|
||||||
|
let then_bb = *module.blocks.get(then_b).unwrap();
|
||||||
|
let else_bb = *module.blocks.get(else_b).unwrap();
|
||||||
|
LLVMBuildCondBr(module.builder_ref, cond_val, then_bb, else_bb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
LLVMValue { ty, value_ref: val }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntPredicate {
|
||||||
|
fn as_llvm(&self, signed: bool) -> LLVMIntPredicate {
|
||||||
|
use IntPredicate::*;
|
||||||
|
use LLVMIntPredicate::*;
|
||||||
|
match (self, signed) {
|
||||||
|
(LessThan, true) => LLVMIntSLT,
|
||||||
|
(GreaterThan, true) => LLVMIntSGT,
|
||||||
|
(LessThan, false) => LLVMIntULT,
|
||||||
|
(GreaterThan, false) => LLVMIntUGT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConstValue {
|
||||||
|
fn as_llvm(&self, context: LLVMContextRef) -> LLVMValueRef {
|
||||||
|
unsafe {
|
||||||
|
let t = self.get_type().as_llvm(context);
|
||||||
|
match *self {
|
||||||
|
ConstValue::I32(val) => LLVMConstInt(t, val as u64, 1),
|
||||||
|
ConstValue::U32(val) => LLVMConstInt(t, val as u64, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Type {
|
||||||
|
fn as_llvm(&self, context: LLVMContextRef) -> LLVMTypeRef {
|
||||||
|
unsafe {
|
||||||
|
match self {
|
||||||
|
Type::I32 => LLVMInt32TypeInContext(context),
|
||||||
|
Type::U32 => LLVMInt32TypeInContext(context),
|
||||||
|
Type::Bool => LLVMInt1TypeInContext(context),
|
||||||
|
Type::Void => LLVMVoidType(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
230
reid-llvm-lib/src/test/mod.rs
Normal file
230
reid-llvm-lib/src/test/mod.rs
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue};
|
||||||
|
|
||||||
|
mod builder;
|
||||||
|
mod compile;
|
||||||
|
mod util;
|
||||||
|
|
||||||
|
// pub struct InstructionValue(BlockValue, usize);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Context {
|
||||||
|
builder: Builder,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
pub fn new() -> Context {
|
||||||
|
Context {
|
||||||
|
builder: Builder::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn module<'ctx>(&'ctx self, name: &str) -> Module<'ctx> {
|
||||||
|
let value = self.builder.add_module(ModuleData {
|
||||||
|
name: name.to_owned(),
|
||||||
|
});
|
||||||
|
Module {
|
||||||
|
phantom: PhantomData,
|
||||||
|
builder: self.builder.clone(),
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct ModuleData {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Module<'ctx> {
|
||||||
|
phantom: PhantomData<&'ctx ()>,
|
||||||
|
builder: Builder,
|
||||||
|
value: ModuleValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> Module<'ctx> {
|
||||||
|
pub fn function(&mut self, name: &str, ret: Type, params: Vec<Type>) -> Function<'ctx> {
|
||||||
|
unsafe {
|
||||||
|
Function {
|
||||||
|
phantom: PhantomData,
|
||||||
|
builder: self.builder.clone(),
|
||||||
|
value: self.builder.add_function(
|
||||||
|
&self.value,
|
||||||
|
FunctionData {
|
||||||
|
name: name.to_owned(),
|
||||||
|
ret,
|
||||||
|
params,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> ModuleValue {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct FunctionData {
|
||||||
|
name: String,
|
||||||
|
ret: Type,
|
||||||
|
params: Vec<Type>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Function<'ctx> {
|
||||||
|
phantom: PhantomData<&'ctx ()>,
|
||||||
|
builder: Builder,
|
||||||
|
value: FunctionValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> Function<'ctx> {
|
||||||
|
pub fn block(&mut self, name: &str) -> Block<'ctx> {
|
||||||
|
unsafe {
|
||||||
|
Block {
|
||||||
|
phantom: PhantomData,
|
||||||
|
builder: self.builder.clone(),
|
||||||
|
value: self.builder.add_block(
|
||||||
|
&self.value,
|
||||||
|
BlockData {
|
||||||
|
name: name.to_owned(),
|
||||||
|
terminator: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> FunctionValue {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct BlockData {
|
||||||
|
name: String,
|
||||||
|
terminator: Option<TerminatorKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Block<'builder> {
|
||||||
|
phantom: PhantomData<&'builder ()>,
|
||||||
|
builder: Builder,
|
||||||
|
value: BlockValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'builder> Block<'builder> {
|
||||||
|
pub fn build(&mut self, instruction: InstructionKind) -> Result<InstructionValue, ()> {
|
||||||
|
unsafe {
|
||||||
|
self.builder
|
||||||
|
.add_instruction(&self.value, InstructionData { kind: instruction })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn terminate(&mut self, instruction: TerminatorKind) -> Result<(), ()> {
|
||||||
|
unsafe { self.builder.terminate(&self.value, instruction) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> BlockValue {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct InstructionData {
|
||||||
|
kind: InstructionKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Hash)]
|
||||||
|
pub enum IntPredicate {
|
||||||
|
LessThan,
|
||||||
|
GreaterThan,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub enum InstructionKind {
|
||||||
|
Param(usize),
|
||||||
|
Constant(ConstValue),
|
||||||
|
Add(InstructionValue, InstructionValue),
|
||||||
|
Sub(InstructionValue, InstructionValue),
|
||||||
|
|
||||||
|
/// Integer Comparison
|
||||||
|
ICmp(IntPredicate, InstructionValue, InstructionValue),
|
||||||
|
|
||||||
|
FunctionCall(FunctionValue, Vec<InstructionValue>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||||
|
pub enum Type {
|
||||||
|
I32,
|
||||||
|
U32,
|
||||||
|
Bool,
|
||||||
|
Void,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub enum ConstValue {
|
||||||
|
I32(i32),
|
||||||
|
U32(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub enum TerminatorKind {
|
||||||
|
Ret(InstructionValue),
|
||||||
|
Branch(BlockValue),
|
||||||
|
CondBr(InstructionValue, BlockValue, BlockValue),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
use ConstValue::*;
|
||||||
|
use InstructionKind::*;
|
||||||
|
|
||||||
|
let context = Context::new();
|
||||||
|
|
||||||
|
let mut module = context.module("test");
|
||||||
|
|
||||||
|
let mut main = module.function("main", Type::I32, Vec::new());
|
||||||
|
let mut m_entry = main.block("entry");
|
||||||
|
|
||||||
|
let mut fibonacci = module.function("fibonacci", Type::I32, vec![Type::I32]);
|
||||||
|
|
||||||
|
let arg = m_entry.build(Constant(I32(5))).unwrap();
|
||||||
|
m_entry
|
||||||
|
.build(FunctionCall(fibonacci.value, vec![arg]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut f_entry = fibonacci.block("entry");
|
||||||
|
|
||||||
|
let num_3 = f_entry.build(Constant(I32(3))).unwrap();
|
||||||
|
let param_n = f_entry.build(Param(0)).unwrap();
|
||||||
|
let cond = f_entry
|
||||||
|
.build(ICmp(IntPredicate::LessThan, param_n, num_3))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut then_b = fibonacci.block("then");
|
||||||
|
let mut else_b = fibonacci.block("else");
|
||||||
|
|
||||||
|
f_entry
|
||||||
|
.terminate(TerminatorKind::CondBr(cond, then_b.value, else_b.value))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let ret_const = then_b.build(Constant(I32(1))).unwrap();
|
||||||
|
then_b.terminate(TerminatorKind::Ret(ret_const)).unwrap();
|
||||||
|
|
||||||
|
let const_1 = else_b.build(Constant(I32(1))).unwrap();
|
||||||
|
let const_2 = else_b.build(Constant(I32(2))).unwrap();
|
||||||
|
let param_1 = else_b.build(Sub(param_n, const_1)).unwrap();
|
||||||
|
let param_2 = else_b.build(Sub(param_n, const_2)).unwrap();
|
||||||
|
let call_1 = else_b
|
||||||
|
.build(FunctionCall(fibonacci.value, vec![param_1]))
|
||||||
|
.unwrap();
|
||||||
|
let call_2 = else_b
|
||||||
|
.build(FunctionCall(fibonacci.value, vec![param_2]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let add = else_b.build(Add(call_1, call_2)).unwrap();
|
||||||
|
|
||||||
|
else_b.terminate(TerminatorKind::Ret(add)).unwrap();
|
||||||
|
|
||||||
|
dbg!(context);
|
||||||
|
}
|
18
reid-llvm-lib/src/test/util.rs
Normal file
18
reid-llvm-lib/src/test/util.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use super::{
|
||||||
|
Type,
|
||||||
|
builder::{Builder, InstructionValue},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn match_types(
|
||||||
|
lhs: &InstructionValue,
|
||||||
|
rhs: &InstructionValue,
|
||||||
|
builder: &Builder,
|
||||||
|
) -> Result<Type, ()> {
|
||||||
|
let lhs_type = lhs.get_type(&builder);
|
||||||
|
let rhs_type = rhs.get_type(&builder);
|
||||||
|
if let (Ok(lhs_t), Ok(rhs_t)) = (lhs_type, rhs_type) {
|
||||||
|
if lhs_t == rhs_t { Ok(lhs_t) } else { Err(()) }
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user