diff --git a/reid-llvm-lib/examples/libtest.rs b/reid-llvm-lib/examples/libtest.rs index 7fa3f81..d37e9ee 100644 --- a/reid-llvm-lib/examples/libtest.rs +++ b/reid-llvm-lib/examples/libtest.rs @@ -1,105 +1,60 @@ -use reid_lib::{ - Context, IntPredicate, - types::{BasicType, IntegerValue, Value}, -}; +use reid_lib::{ConstValue, Context, InstructionKind, IntPredicate, TerminatorKind, Type}; -pub fn main() { - // Notes from inkwell: - // - Creating new values should probably just be functions in the context - // - Creating functions should probably be functions from module - // - Builder could well be it's own struct - // - Although, I do like the fact where blocks move the builder by itself.. +fn main() { + use ConstValue::*; + use InstructionKind::*; let context = Context::new(); - let module = context.module("testmodule"); + let mut module = context.module("test"); - let int_32 = context.type_i32(); + let main = module.function("main", Type::I32, Vec::new()); + let mut m_entry = main.block("entry"); - let fibonacci = module.add_function(int_32.function_type(vec![int_32.into()]), "fibonacci"); - let mut f_main = fibonacci.block("main"); + let fibonacci = module.function("fibonacci", Type::I32, vec![Type::I32]); - let param = fibonacci - .get_param::(0, int_32.into()) + let arg = m_entry.build(Constant(I32(5))).unwrap(); + let fibonacci_call = m_entry + .build(FunctionCall(fibonacci.value(), vec![arg])) .unwrap(); - let mut cmp = f_main - .integer_compare(¶m, &int_32.from_unsigned(3), &IntPredicate::ULT, "cmp") + m_entry + .terminate(TerminatorKind::Ret(fibonacci_call)) .unwrap(); - let mut done = fibonacci.block("done"); - let mut recurse = fibonacci.block("recurse"); - f_main.conditional_br(&cmp, &done, &recurse).unwrap(); + let mut f_entry = fibonacci.block("entry"); - done.ret(&int_32.from_unsigned(1)).unwrap(); - - let minus_one = recurse - .sub(¶m, &int_32.from_unsigned(1), "minus_one") - .unwrap(); - let minus_two = recurse - .sub(¶m, &int_32.from_unsigned(2), "minus_two") - .unwrap(); - let one: IntegerValue = recurse - .call(&fibonacci, vec![Value::Integer(minus_one)], "call_one") - .unwrap(); - let two = recurse - .call(&fibonacci, vec![Value::Integer(minus_two)], "call_two") + 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 add = recurse.add(&one, &two, "add").unwrap(); + let mut then_b = fibonacci.block("then"); + let mut else_b = fibonacci.block("else"); - recurse.ret(&add).unwrap(); - - let main_f = module.add_function(int_32.function_type(Vec::new()), "main"); - - let mut main_b = main_f.block("main"); - let call: IntegerValue = main_b - .call( - &fibonacci, - vec![Value::Integer(int_32.from_unsigned(8))], - "fib_call", - ) + f_entry + .terminate(TerminatorKind::CondBr(cond, then_b.value(), else_b.value())) .unwrap(); - main_b.ret(&call).unwrap(); - // let secondary = module.add_function(int_32.function_type(&[]), "secondary"); - // let s_entry = secondary.block("entry"); - // s_entry.ret(&int_32.from_signed(54)).unwrap(); + let ret_const = then_b.build(Constant(I32(1))).unwrap(); + then_b.terminate(TerminatorKind::Ret(ret_const)).unwrap(); - // let function = module.add_function(int_32.function_type(&[]), "main"); + 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 entry = function.block("entry"); + let add = else_b.build(Add(call_1, call_2)).unwrap(); - // let call = entry.call(&secondary, vec![], "call").unwrap(); - // let add = entry.add(&int_32.from_signed(100), &call, "add").unwrap(); - // let rhs_cmp = int_32.from_signed(200); + else_b.terminate(TerminatorKind::Ret(add)).unwrap(); - // let cond_res = entry - // .integer_compare(&add, &rhs_cmp, &IntPredicate::SLT, "cmp") - // .unwrap(); + dbg!(&context); - // let (lhs, rhs) = entry.conditional_br(&cond_res, "lhs", "rhs").unwrap(); - - // let left = lhs.add(&call, &int_32.from_signed(20), "add").unwrap(); - // let right = rhs.add(&call, &int_32.from_signed(30), "add").unwrap(); - - // let final_block = function.block("final"); - // let phi = final_block - // .phi::(&int_32, "phi") - // .unwrap() - // .add_incoming(&left, &lhs) - // .add_incoming(&right, &rhs) - // .build(); - - // lhs.br(&final_block).unwrap(); - // rhs.br(&final_block).unwrap(); - - // let val = final_block - // .add(&phi, &int_32.from_signed(11), "add") - // .unwrap(); - // final_block.ret(&val).unwrap(); - - match module.print_to_string() { - Ok(v) => println!("{}", v), - Err(e) => println!("Err: {:?}", e), - } + context.compile(); } diff --git a/reid-llvm-lib/examples/test.rs b/reid-llvm-lib/examples/test.rs deleted file mode 100644 index 2490faf..0000000 --- a/reid-llvm-lib/examples/test.rs +++ /dev/null @@ -1,60 +0,0 @@ -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(); -} diff --git a/reid-llvm-lib/src/test/builder.rs b/reid-llvm-lib/src/builder.rs similarity index 92% rename from reid-llvm-lib/src/test/builder.rs rename to reid-llvm-lib/src/builder.rs index f28cb63..a9faa3c 100644 --- a/reid-llvm-lib/src/test/builder.rs +++ b/reid-llvm-lib/src/builder.rs @@ -1,8 +1,9 @@ use std::{cell::RefCell, marker::PhantomData, rc::Rc}; -use crate::test::{ConstValue, InstructionKind, TerminatorKind, Type}; - -use super::{BlockData, FunctionData, InstructionData, ModuleData, util::match_types}; +use crate::{ + BlockData, ConstValue, FunctionData, InstructionData, InstructionKind, ModuleData, + TerminatorKind, Type, util::match_types, +}; #[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)] pub struct ModuleValue(usize); @@ -14,7 +15,7 @@ pub struct FunctionValue(ModuleValue, usize); pub struct BlockValue(FunctionValue, usize); #[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)] -pub struct InstructionValue(BlockValue, usize); +pub struct InstructionValue(pub(crate) BlockValue, usize); #[derive(Debug, Clone)] pub struct ModuleHolder { @@ -265,6 +266,15 @@ impl Builder { } Ok(()) } + Phi(vals) => { + let mut iter = vals.iter(); + // TODO error: Phi must contain at least one item + let first = iter.next().ok_or(())?; + for item in iter { + match_types(first, item, &self)?; + } + Ok(()) + } } } } @@ -287,6 +297,7 @@ impl InstructionValue { 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), + Phi(values) => values.first().ok_or(()).and_then(|v| v.get_type(&builder)), } } } @@ -297,6 +308,7 @@ impl ConstValue { use Type::*; match self { ConstValue::I32(_) => I32, + ConstValue::I16(_) => I16, ConstValue::U32(_) => U32, } } @@ -306,6 +318,7 @@ impl Type { pub fn comparable(&self) -> bool { match self { Type::I32 => true, + Type::I16 => true, Type::U32 => true, Type::Bool => true, Type::Void => false, @@ -315,6 +328,7 @@ impl Type { pub fn signed(&self) -> bool { match self { Type::I32 => true, + Type::I16 => true, Type::U32 => false, Type::Bool => false, Type::Void => false, diff --git a/reid-llvm-lib/src/test/compile.rs b/reid-llvm-lib/src/compile.rs similarity index 92% rename from reid-llvm-lib/src/test/compile.rs rename to reid-llvm-lib/src/compile.rs index 28f77ed..39430a0 100644 --- a/reid-llvm-lib/src/test/compile.rs +++ b/reid-llvm-lib/src/compile.rs @@ -289,6 +289,26 @@ impl InstructionHolder { c"call".as_ptr(), ) } + Phi(values) => { + let mut inc_values = Vec::new(); + let mut inc_blocks = Vec::new(); + for item in values { + inc_values.push(module.values.get(&item).unwrap().value_ref); + inc_blocks.push(*module.blocks.get(&item.0).unwrap()); + } + let phi = LLVMBuildPhi( + module.builder_ref, + ty.as_llvm(module.context_ref), + c"phi".as_ptr(), + ); + LLVMAddIncoming( + phi, + inc_values.as_mut_ptr(), + inc_blocks.as_mut_ptr(), + values.len() as u32, + ); + phi + } } }; LLVMValue { ty, value_ref: val } @@ -344,7 +364,8 @@ impl ConstValue { 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), + ConstValue::I16(val) => LLVMConstInt(t, val as u64, 1), + ConstValue::U32(val) => LLVMConstInt(t, val as u64, 0), } } } @@ -355,6 +376,7 @@ impl Type { unsafe { match self { Type::I32 => LLVMInt32TypeInContext(context), + Type::I16 => LLVMInt16TypeInContext(context), Type::U32 => LLVMInt32TypeInContext(context), Type::Bool => LLVMInt1TypeInContext(context), Type::Void => LLVMVoidType(), diff --git a/reid-llvm-lib/src/lib.rs b/reid-llvm-lib/src/lib.rs index 25d307f..534b4e8 100644 --- a/reid-llvm-lib/src/lib.rs +++ b/reid-llvm-lib/src/lib.rs @@ -1,455 +1,233 @@ -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}; +use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue}; -pub mod test; -pub mod types; +pub mod builder; +pub mod compile; 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 InstructionValue(BlockValue, usize); +#[derive(Debug)] pub struct Context { - pub(crate) context_ref: *mut LLVMContext, - pub(crate) builder_ref: *mut LLVMBuilder, + builder: Builder, } 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, - } + Context { + builder: Builder::new(), } } - 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) + 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, + } } } -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); - } - } +#[derive(Debug, Clone, Hash)] +pub struct ModuleData { + name: String, } pub struct Module<'ctx> { - context: &'ctx Context, - module_ref: LLVMModuleRef, - name: CString, + phantom: PhantomData<&'ctx ()>, + builder: Builder, + value: ModuleValue, } impl<'ctx> Module<'ctx> { - fn with_name(context: &'ctx Context, name: &str) -> Module<'ctx> { + pub fn function(&mut self, name: &str, ret: Type, params: Vec) -> Function<'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, + phantom: PhantomData, + builder: self.builder.clone(), + value: self.builder.add_function( + &self.value, + FunctionData { + name: name.to_owned(), + ret, + params, + }, + ), } } } - pub fn print_to_string(&self) -> Result { - 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()) - } + pub fn value(&self) -> ModuleValue { + self.value } } -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(Debug, Clone, Hash)] +pub struct FunctionData { + name: String, + ret: Type, + params: Vec, } -#[derive(Clone)] pub struct Function<'ctx> { - module: &'ctx Module<'ctx>, - name: CString, - fn_type: FunctionType<'ctx>, - fn_ref: LLVMValueRef, + phantom: PhantomData<&'ctx ()>, + builder: Builder, + value: FunctionValue, } impl<'ctx> Function<'ctx> { - pub fn block>(&'ctx self, name: T) -> BasicBlock<'ctx> { - BasicBlock::in_function(&self, name.into()) + pub fn block(&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 get_param>( - &'ctx self, - nth: usize, - param_type: T::BaseType, - ) -> Result { - 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 fn value(&self) -> FunctionValue { + self.value } } -pub struct BasicBlock<'ctx> { - function: &'ctx Function<'ctx>, - builder_ref: LLVMBuilderRef, +#[derive(Debug, Clone, Hash)] +pub struct BlockData { name: String, - blockref: LLVMBasicBlockRef, - inserted: bool, + terminator: Option, } -impl<'ctx> BasicBlock<'ctx> { - fn in_function(function: &'ctx Function<'ctx>, name: String) -> BasicBlock<'ctx> { +pub struct Block<'builder> { + phantom: PhantomData<&'builder ()>, + builder: Builder, + value: BlockValue, +} + +impl<'builder> Block<'builder> { + pub fn build(&mut self, instruction: InstructionKind) -> Result { 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, - } + self.builder + .add_instruction(&self.value, InstructionData { kind: instruction }) } } - #[must_use] - pub fn integer_compare>( - &self, - lhs: &T, - rhs: &T, - comparison: &IntPredicate, - name: &str, - ) -> Result { - 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)) - } + pub fn terminate(&mut self, instruction: TerminatorKind) -> Result<(), ()> { + unsafe { self.builder.terminate(&self.value, instruction) } } - #[must_use] - pub fn call>( - &self, - callee: &Function<'ctx>, - params: Vec>, - name: &str, - ) -> Result { - 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 = 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>(&self, lhs: &T, rhs: &T, name: &str) -> Result { - 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>(&self, lhs: &T, rhs: &T, name: &str) -> Result { - 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>( - &self, - phi_type: &PhiValue::BaseType, - name: &str, - ) -> Result, ()> { - 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>( - &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>(&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(()) + pub fn value(&self) -> BlockValue { + self.value } } -impl<'ctx> Drop for BasicBlock<'ctx> { - fn drop(&mut self) { - if !self.inserted { - unsafe { - LLVMDeleteBasicBlock(self.blockref); - } - } - } +#[derive(Debug, Clone, Hash)] +pub struct InstructionData { + kind: InstructionKind, } -pub struct PhiBuilder<'ctx, PhiValue: BasicValue<'ctx>> { - phi_node: LLVMValueRef, - phantom: PhantomData<&'ctx PhiValue>, +#[derive(Debug, Clone, Copy, Hash)] +pub enum IntPredicate { + LessThan, + GreaterThan, } -impl<'ctx, PhiValue: BasicValue<'ctx>> PhiBuilder<'ctx, PhiValue> { - fn new(phi_node: LLVMValueRef) -> PhiBuilder<'ctx, PhiValue> { - PhiBuilder { - phi_node, - phantom: PhantomData, - } - } +#[derive(Debug, Clone, Hash)] +pub enum InstructionKind { + Param(usize), + Constant(ConstValue), + Add(InstructionValue, InstructionValue), + Sub(InstructionValue, InstructionValue), + Phi(Vec), - 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 - } - } + /// Integer Comparison + ICmp(IntPredicate, InstructionValue, InstructionValue), - pub fn build(&self) -> PhiValue { - unsafe { PhiValue::from_llvm(self.phi_node) } - } + FunctionCall(FunctionValue, Vec), +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +pub enum Type { + I32, + I16, + U32, + Bool, + Void, +} + +#[derive(Debug, Clone, Hash)] +pub enum ConstValue { + I32(i32), + I16(i16), + 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); } diff --git a/reid-llvm-lib/src/old/lib.rs b/reid-llvm-lib/src/old/lib.rs new file mode 100644 index 0000000..25d307f --- /dev/null +++ b/reid-llvm-lib/src/old/lib.rs @@ -0,0 +1,455 @@ +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 { + 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>(&'ctx self, name: T) -> BasicBlock<'ctx> { + BasicBlock::in_function(&self, name.into()) + } + + pub fn get_param>( + &'ctx self, + nth: usize, + param_type: T::BaseType, + ) -> Result { + 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>( + &self, + lhs: &T, + rhs: &T, + comparison: &IntPredicate, + name: &str, + ) -> Result { + 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>( + &self, + callee: &Function<'ctx>, + params: Vec>, + name: &str, + ) -> Result { + 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 = 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>(&self, lhs: &T, rhs: &T, name: &str) -> Result { + 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>(&self, lhs: &T, rhs: &T, name: &str) -> Result { + 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>( + &self, + phi_type: &PhiValue::BaseType, + name: &str, + ) -> Result, ()> { + 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>( + &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>(&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) } + } +} diff --git a/reid-llvm-lib/src/types.rs b/reid-llvm-lib/src/old/types.rs similarity index 100% rename from reid-llvm-lib/src/types.rs rename to reid-llvm-lib/src/old/types.rs diff --git a/reid-llvm-lib/src/test/mod.rs b/reid-llvm-lib/src/test/mod.rs deleted file mode 100644 index 429d1ca..0000000 --- a/reid-llvm-lib/src/test/mod.rs +++ /dev/null @@ -1,230 +0,0 @@ -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) -> 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, -} - -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, -} - -pub struct Block<'builder> { - phantom: PhantomData<&'builder ()>, - builder: Builder, - value: BlockValue, -} - -impl<'builder> Block<'builder> { - pub fn build(&mut self, instruction: InstructionKind) -> Result { - 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), -} - -#[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); -} diff --git a/reid-llvm-lib/src/test/util.rs b/reid-llvm-lib/src/test/util.rs deleted file mode 100644 index 22670d3..0000000 --- a/reid-llvm-lib/src/test/util.rs +++ /dev/null @@ -1,18 +0,0 @@ -use super::{ - Type, - builder::{Builder, InstructionValue}, -}; - -pub fn match_types( - lhs: &InstructionValue, - rhs: &InstructionValue, - builder: &Builder, -) -> Result { - 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(()) - } -} diff --git a/reid-llvm-lib/src/util.rs b/reid-llvm-lib/src/util.rs index ec8b00f..574fb11 100644 --- a/reid-llvm-lib/src/util.rs +++ b/reid-llvm-lib/src/util.rs @@ -5,6 +5,11 @@ use std::{ use llvm_sys::error::LLVMDisposeErrorMessage; +use crate::{ + Type, + builder::{Builder, InstructionValue}, +}; + pub fn into_cstring>(value: T) -> CString { let string = value.into(); unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) } @@ -49,3 +54,17 @@ impl Drop for ErrorMessageHolder { } } } + +pub fn match_types( + lhs: &InstructionValue, + rhs: &InstructionValue, + builder: &Builder, +) -> Result { + 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(()) + } +} diff --git a/reid/examples/reid/fibonacci.reid b/reid/examples/reid/fibonacci.reid index 11faa1b..30160b7 100644 --- a/reid/examples/reid/fibonacci.reid +++ b/reid/examples/reid/fibonacci.reid @@ -1,6 +1,6 @@ // Main fn main() { - return fibonacci(10); + return fibonacci(3); } // Fibonacci diff --git a/reid/examples/testcodegen.rs b/reid/examples/testcodegen.rs index ba59bd9..9dc3c51 100644 --- a/reid/examples/testcodegen.rs +++ b/reid/examples/testcodegen.rs @@ -164,8 +164,9 @@ fn main() { println!("test3"); - match codegen_module.module.print_to_string() { - Ok(v) => println!("{}", v), - Err(e) => println!("Err: {:?}", e), - } + codegen_module.context.compile(); + // match codegen_module.module.print_to_string() { + // Ok(v) => println!("{}", v), + // Err(e) => println!("Err: {:?}", e), + // } } diff --git a/reid/src/codegen.rs b/reid/src/codegen.rs index e03065a..f641408 100644 --- a/reid/src/codegen.rs +++ b/reid/src/codegen.rs @@ -1,35 +1,35 @@ use std::{collections::HashMap, mem, ops::Deref}; -use crate::mir::{self, types::ReturnType, TypeKind, VariableReference}; use reid_lib::{ - types::{BasicType, BasicValue, IntegerValue, TypeEnum, Value}, - BasicBlock, Context, Function, IntPredicate, Module, + builder::{FunctionValue, InstructionValue}, + Block, ConstValue, Context, Function, InstructionKind, IntPredicate, Module, TerminatorKind, + Type, }; +use crate::mir::{self, types::ReturnType, TypeKind, VariableReference}; + pub struct ModuleCodegen<'ctx> { - context: &'ctx Context, + pub context: &'ctx Context, pub module: Module<'ctx>, } impl mir::Module { pub fn codegen<'ctx>(&self, context: &'ctx Context) -> ModuleCodegen<'ctx> { - let module = context.module(&self.name); + let mut module = context.module(&self.name); let mut functions = HashMap::new(); for function in &self.functions { - let ret_type = function.return_type().unwrap().get_type(&context); - let fn_type = ret_type.function_type( - function - .parameters - .iter() - .map(|(_, p)| p.get_type(&context)) - .collect(), - ); + let ret_type = function.return_type().unwrap().get_type(); + let param_types: Vec = function + .parameters + .iter() + .map(|(_, p)| p.get_type()) + .collect(); let func = match &function.kind { mir::FunctionDefinitionKind::Local(_, _) => { - module.add_function(fn_type, &function.name) + module.function(&function.name, ret_type, param_types) } mir::FunctionDefinitionKind::Extern(_) => todo!(), }; @@ -38,12 +38,13 @@ impl mir::Module { for mir_function in &self.functions { let function = functions.get(&mir_function.name).unwrap(); + let mut entry = function.block("entry"); let mut stack_values = HashMap::new(); for (i, (p_name, p_type)) in mir_function.parameters.iter().enumerate() { stack_values.insert( p_name.clone(), - function.get_param(i, p_type.get_type(&context)).unwrap(), + entry.build(InstructionKind::Param(i)).unwrap(), ); } @@ -51,14 +52,14 @@ impl mir::Module { context, module: &module, function, - block: function.block("entry"), - functions: functions.clone(), + block: entry, + functions: &functions, stack_values, }; match &mir_function.kind { mir::FunctionDefinitionKind::Local(block, _) => { if let Some(ret) = block.codegen(&mut scope) { - scope.block.ret(&ret).unwrap(); + scope.block.terminate(TerminatorKind::Ret(ret)).unwrap(); } } mir::FunctionDefinitionKind::Extern(_) => {} @@ -69,21 +70,21 @@ impl mir::Module { } } -pub struct Scope<'ctx> { +pub struct Scope<'ctx, 'a> { context: &'ctx Context, module: &'ctx Module<'ctx>, function: &'ctx Function<'ctx>, - block: BasicBlock<'ctx>, - functions: HashMap>, - stack_values: HashMap>, + block: Block<'ctx>, + functions: &'a HashMap>, + stack_values: HashMap, } -impl<'ctx> Scope<'ctx> { - pub fn with_block(&self, block: BasicBlock<'ctx>) -> Scope<'ctx> { +impl<'ctx, 'a> Scope<'ctx, 'a> { + pub fn with_block(&self, block: Block<'ctx>) -> Scope<'ctx, 'a> { Scope { block, - context: self.context, function: self.function, + context: self.context, module: self.module, functions: self.functions.clone(), stack_values: self.stack_values.clone(), @@ -92,7 +93,7 @@ impl<'ctx> Scope<'ctx> { /// Takes the block out from this scope, swaps the given block in it's place /// and returns the old block. - pub fn swap_block(&mut self, block: BasicBlock<'ctx>) -> BasicBlock<'ctx> { + pub fn swap_block(&mut self, block: Block<'ctx>) -> Block<'ctx> { let mut old_block = block; mem::swap(&mut self.block, &mut old_block); old_block @@ -100,7 +101,7 @@ impl<'ctx> Scope<'ctx> { } impl mir::Statement { - pub fn codegen<'ctx>(&self, scope: &mut Scope<'ctx>) -> Option> { + pub fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option { match &self.0 { mir::StmtKind::Let(VariableReference(_, name, _), expression) => { let value = expression.codegen(scope).unwrap(); @@ -115,7 +116,7 @@ impl mir::Statement { } impl mir::IfExpression { - pub fn codegen<'ctx>(&self, scope: &mut Scope<'ctx>) -> Option> { + pub fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option { let condition = self.0.codegen(scope).unwrap(); // Create blocks @@ -125,55 +126,62 @@ impl mir::IfExpression { let mut then_scope = scope.with_block(then_bb); let then_res = self.1.codegen(&mut then_scope); - then_scope.block.br(&scope.block).ok(); + then_scope + .block + .terminate(TerminatorKind::Branch(scope.block.value())) + .ok(); let else_bb = scope.function.block("else"); let mut else_scope = scope.with_block(else_bb); - let else_opt = if let Some(else_block) = &self.2 { + let else_res = if let Some(else_block) = &self.2 { before_bb - .conditional_br(&condition, &then_scope.block, &else_scope.block) + .terminate(TerminatorKind::CondBr( + condition, + then_scope.block.value(), + else_scope.block.value(), + )) .unwrap(); let opt = else_block.codegen(&mut else_scope); if let Some(ret) = opt { - else_scope.block.br(&scope.block).ok(); - Some((else_scope.block, ret)) + else_scope + .block + .terminate(TerminatorKind::Branch(scope.block.value())) + .ok(); + Some(ret) } else { None } } else { - else_scope.block.br(&scope.block).unwrap(); + else_scope + .block + .terminate(TerminatorKind::Branch(scope.block.value())) + .unwrap(); before_bb - .conditional_br(&condition, &then_scope.block, &scope.block) + .terminate(TerminatorKind::CondBr( + condition, + then_scope.block.value(), + scope.block.value(), + )) .unwrap(); None }; - if then_res.is_none() && else_opt.is_none() { + if then_res.is_none() && else_res.is_none() { None - } else if let Ok(ret_type) = self.1.return_type() { - let phi = scope - .block - .phi(&ret_type.get_type(scope.context), "phi") - .unwrap(); - if let Some(then_ret) = then_res { - phi.add_incoming(&then_ret, &then_scope.block); - } - if let Some((else_bb, else_ret)) = else_opt { - phi.add_incoming(&else_ret, &else_bb); - } - - Some(phi.build()) } else { - None + let mut inc = Vec::from(then_res.as_slice()); + inc.extend(else_res); + + Some(scope.block.build(InstructionKind::Phi(vec![])).unwrap()) } } } impl mir::Expression { - pub fn codegen<'ctx>(&self, scope: &mut Scope<'ctx>) -> Option> { + pub fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option { match &self.0 { mir::ExprKind::Variable(varref) => { let v = scope @@ -182,20 +190,24 @@ impl mir::Expression { .expect("Variable reference not found?!"); Some(v.clone()) } - mir::ExprKind::Literal(lit) => Some(lit.codegen(scope.context)), + mir::ExprKind::Literal(lit) => Some(lit.as_const(&mut scope.block)), mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => { let lhs = lhs_exp.codegen(scope).expect("lhs has no return value"); let rhs = rhs_exp.codegen(scope).expect("rhs has no return value"); Some(match binop { - mir::BinaryOperator::Add => scope.block.add(&lhs, &rhs, "add").unwrap(), - mir::BinaryOperator::Minus => scope.block.sub(&lhs, &rhs, "sub").unwrap(), + mir::BinaryOperator::Add => { + scope.block.build(InstructionKind::Add(lhs, rhs)).unwrap() + } + mir::BinaryOperator::Minus => { + scope.block.build(InstructionKind::Sub(lhs, rhs)).unwrap() + } mir::BinaryOperator::Mult => todo!(), mir::BinaryOperator::And => todo!(), mir::BinaryOperator::Logic(l) => { let ret_type = lhs_exp.return_type().expect("No ret type in lhs?"); scope .block - .integer_compare(&lhs, &rhs, &l.int_predicate(ret_type.signed()), "cmp") + .build(InstructionKind::ICmp(l.int_predicate(), lhs, rhs)) .unwrap() } }) @@ -210,13 +222,21 @@ impl mir::Expression { .functions .get(&call.name) .expect("function not found!"); - Some(scope.block.call(callee, params, "call").unwrap()) + Some( + scope + .block + .build(InstructionKind::FunctionCall(callee.value(), params)) + .unwrap(), + ) } mir::ExprKind::If(if_expression) => if_expression.codegen(scope), mir::ExprKind::Block(block) => { let mut inner_scope = scope.with_block(scope.function.block("inner")); if let Some(ret) = block.codegen(&mut inner_scope) { - inner_scope.block.br(&scope.block); + inner_scope + .block + .terminate(TerminatorKind::Branch(scope.block.value())) + .unwrap(); Some(ret) } else { None @@ -227,18 +247,16 @@ impl mir::Expression { } impl mir::LogicOperator { - fn int_predicate(&self, signed: bool) -> IntPredicate { - match (self, signed) { - (mir::LogicOperator::LessThan, true) => IntPredicate::SLT, - (mir::LogicOperator::GreaterThan, true) => IntPredicate::SGT, - (mir::LogicOperator::LessThan, false) => IntPredicate::ULT, - (mir::LogicOperator::GreaterThan, false) => IntPredicate::UGT, + fn int_predicate(&self) -> IntPredicate { + match self { + mir::LogicOperator::LessThan => IntPredicate::LessThan, + mir::LogicOperator::GreaterThan => IntPredicate::GreaterThan, } } } impl mir::Block { - pub fn codegen<'ctx>(&self, mut scope: &mut Scope<'ctx>) -> Option> { + pub fn codegen<'ctx, 'a>(&self, mut scope: &mut Scope<'ctx, 'a>) -> Option { for stmt in &self.statements { stmt.codegen(&mut scope); } @@ -247,7 +265,7 @@ impl mir::Block { let ret = expr.codegen(&mut scope).unwrap(); match kind { mir::ReturnKind::Hard => { - scope.block.ret(&ret).unwrap(); + scope.block.terminate(TerminatorKind::Ret(ret)).unwrap(); None } mir::ReturnKind::Soft => Some(ret), @@ -259,20 +277,23 @@ impl mir::Block { } impl mir::Literal { - pub fn codegen<'ctx>(&self, context: &'ctx Context) -> Value<'ctx> { - let val: IntegerValue<'ctx> = match *self { - mir::Literal::I32(val) => context.type_i32().from_signed(val as i64), - mir::Literal::I16(val) => context.type_i16().from_signed(val as i64), - }; - Value::Integer(val) + pub fn as_const(&self, block: &mut Block) -> InstructionValue { + block.build(self.as_const_kind()).unwrap() + } + + pub fn as_const_kind(&self) -> InstructionKind { + InstructionKind::Constant(match *self { + mir::Literal::I32(val) => ConstValue::I32(val), + mir::Literal::I16(val) => ConstValue::I16(val), + }) } } impl TypeKind { - fn get_type<'ctx>(&self, context: &'ctx Context) -> TypeEnum<'ctx> { + fn get_type(&self) -> Type { match &self { - TypeKind::I32 => TypeEnum::Integer(context.type_i32()), - TypeKind::I16 => TypeEnum::Integer(context.type_i16()), + TypeKind::I32 => Type::I32, + TypeKind::I16 => Type::I16, TypeKind::Void => panic!("Void not a supported type"), } } diff --git a/reid/src/lib.rs b/reid/src/lib.rs index deed507..95ec4d4 100644 --- a/reid/src/lib.rs +++ b/reid/src/lib.rs @@ -50,10 +50,15 @@ pub fn compile(source: &str) -> Result { dbg!(&mir_module); let mut context = Context::new(); - let cogegen_module = mir_module.codegen(&mut context); + let codegen_module = mir_module.codegen(&mut context); - Ok(match cogegen_module.module.print_to_string() { - Ok(v) => v, - Err(e) => panic!("Err: {:?}", e), - }) + dbg!(&codegen_module.context); + codegen_module.context.compile(); + + Ok(String::new()) + + // Ok(match cogegen_module.module.print_to_string() { + // Ok(v) => v, + // Err(e) => panic!("Err: {:?}", e), + // }) }