//! This module contains simply [`Builder`] and it's related utility Values. //! Builder is the actual struct being modified when building the LLIR. use std::{cell::RefCell, rc::Rc}; use crate::{ BlockData, ConstValue, FunctionData, InstructionData, InstructionKind, ModuleData, TerminatorKind, Type, util::match_types, }; #[derive(Clone, Hash, Copy, PartialEq, Eq)] pub struct ModuleValue(pub(crate) usize); #[derive(Clone, Hash, Copy, PartialEq, Eq)] pub struct FunctionValue(pub(crate) ModuleValue, pub(crate) usize); #[derive(Clone, Hash, Copy, PartialEq, Eq)] pub struct BlockValue(pub(crate) FunctionValue, pub(crate) usize); #[derive(Clone, Hash, Copy, PartialEq, Eq)] pub struct InstructionValue(pub(crate) BlockValue, pub(crate) usize); #[derive(Clone)] pub struct ModuleHolder { pub(crate) value: ModuleValue, pub(crate) data: ModuleData, pub(crate) functions: Vec, } #[derive(Clone)] pub struct FunctionHolder { pub(crate) value: FunctionValue, pub(crate) data: FunctionData, pub(crate) blocks: Vec, } #[derive(Clone)] pub struct BlockHolder { pub(crate) value: BlockValue, pub(crate) data: BlockData, pub(crate) instructions: Vec, } #[derive(Clone)] pub struct InstructionHolder { pub(crate) value: InstructionValue, pub(crate) data: InstructionData, } #[derive(Clone)] pub(crate) struct Builder { modules: Rc>>, } 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 { 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(()) } } } #[allow(dead_code)] 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() } } #[allow(dead_code)] 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>> { self.modules.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(|_| ()), Mult(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), And(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(()) } 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(()) } } } } } impl InstructionValue { pub(crate) fn get_type(&self, builder: &Builder) -> Result { use InstructionKind::*; 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), Mult(lhs, rhs) => match_types(lhs, rhs, &builder), And(lhs, rhs) => match_types(lhs, rhs, &builder), ICmp(_, _, _) => 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)), } } } } impl ConstValue { pub fn get_type(&self) -> Type { use Type::*; match self { ConstValue::I8(_) => I8, ConstValue::I16(_) => I16, ConstValue::I32(_) => I32, ConstValue::I64(_) => I64, ConstValue::I128(_) => I128, ConstValue::U8(_) => U8, ConstValue::U16(_) => U16, ConstValue::U32(_) => U32, ConstValue::U64(_) => U64, ConstValue::U128(_) => U128, ConstValue::Bool(_) => Bool, } } } impl Type { pub fn comparable(&self) -> bool { match self { Type::I8 => true, Type::I16 => true, Type::I32 => true, Type::I64 => true, Type::I128 => true, Type::U8 => true, Type::U16 => true, Type::U32 => true, Type::U64 => true, Type::U128 => true, Type::Bool => true, Type::Void => false, } } pub fn signed(&self) -> bool { match self { Type::I8 => true, Type::I16 => true, Type::I32 => true, Type::I64 => true, Type::I128 => true, Type::U8 => false, Type::U16 => false, Type::U32 => false, Type::U64 => false, Type::U128 => false, Type::Bool => false, Type::Void => false, } } } impl TerminatorKind { pub(crate) fn get_type(&self, builder: &Builder) -> Result { use TerminatorKind::*; match self { Ret(instr_val) => instr_val.get_type(builder), Branch(_) => Ok(Type::Void), CondBr(_, _, _) => Ok(Type::Void), } } }