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 util::{ErrorMessageHolder, from_cstring, into_cstring}; | ||||
| 
 | ||||
| pub mod test; | ||||
| pub mod types; | ||||
| 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