Remove reid-llvm-lib, move to own git repo
This commit is contained in:
		
							parent
							
								
									663f327ccf
								
							
						
					
					
						commit
						d5a4168b0d
					
				| @ -1,12 +0,0 @@ | |||||||
| [package] |  | ||||||
| name = "reid-lib" |  | ||||||
| version = "1.0.0-beta.4" |  | ||||||
| edition = "2024" |  | ||||||
| 
 |  | ||||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |  | ||||||
| 
 |  | ||||||
| [dependencies] |  | ||||||
| ## LLVM Bindings |  | ||||||
| llvm-sys = {version ="201.0.1" } |  | ||||||
| ## Make it easier to generate errors |  | ||||||
| thiserror = "1.0.44" |  | ||||||
| @ -1,56 +0,0 @@ | |||||||
| use reid_lib::{CmpPredicate, ConstValueKind, Context, FunctionFlags, Instr, TerminatorKind, Type}; |  | ||||||
| 
 |  | ||||||
| fn main() { |  | ||||||
|     use ConstValueKind::*; |  | ||||||
|     use Instr::*; |  | ||||||
| 
 |  | ||||||
|     let context = Context::new("libtest"); |  | ||||||
| 
 |  | ||||||
|     let module = context.module("test", true); |  | ||||||
| 
 |  | ||||||
|     let main = module.function("main", None, Type::I32, Vec::new(), FunctionFlags::default()); |  | ||||||
|     let mut m_entry = main.block("entry"); |  | ||||||
| 
 |  | ||||||
|     let fibonacci = module.function("fibonacci", None, Type::I32, vec![Type::I32], FunctionFlags::default()); |  | ||||||
| 
 |  | ||||||
|     let arg = m_entry.build_named("const", Constant(I32(5))).unwrap(); |  | ||||||
|     let fibonacci_call = m_entry |  | ||||||
|         .build_named("const", 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_named("const", Constant(I32(3))).unwrap(); |  | ||||||
|     let param_n = f_entry.build_named("param", Param(0)).unwrap(); |  | ||||||
|     let cond = f_entry |  | ||||||
|         .build_named("cmp", ICmp(CmpPredicate::LT, 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_named("const", Constant(I32(1))).unwrap(); |  | ||||||
|     then_b.terminate(TerminatorKind::Ret(ret_const)).unwrap(); |  | ||||||
| 
 |  | ||||||
|     let const_1 = else_b.build_named("const", Constant(I32(1))).unwrap(); |  | ||||||
|     let const_2 = else_b.build_named("const", Constant(I32(2))).unwrap(); |  | ||||||
|     let param_1 = else_b.build_named("sub", Sub(param_n, const_1)).unwrap(); |  | ||||||
|     let param_2 = else_b.build_named("sub", Sub(param_n, const_2)).unwrap(); |  | ||||||
|     let call_1 = else_b |  | ||||||
|         .build_named("fibonacci", FunctionCall(fibonacci.value(), vec![param_1])) |  | ||||||
|         .unwrap(); |  | ||||||
|     let call_2 = else_b |  | ||||||
|         .build_named("fibonacci", FunctionCall(fibonacci.value(), vec![param_2])) |  | ||||||
|         .unwrap(); |  | ||||||
| 
 |  | ||||||
|     let add = else_b.build_named("add", Add(call_1, call_2)).unwrap(); |  | ||||||
| 
 |  | ||||||
|     else_b.terminate(TerminatorKind::Ret(add)).unwrap(); |  | ||||||
| 
 |  | ||||||
|     context.compile(None, Vec::new()); |  | ||||||
| } |  | ||||||
| @ -1,835 +0,0 @@ | |||||||
| //! 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::{ |  | ||||||
|     Block, BlockData, CompileResult, ConstValueKind, CustomTypeKind, ErrorKind, FunctionData, Instr, InstructionData, |  | ||||||
|     ModuleData, NamedStruct, TerminatorKind, Type, TypeCategory, TypeData, |  | ||||||
|     debug_information::{ |  | ||||||
|         DebugInformation, DebugLocationValue, DebugMetadataValue, DebugScopeValue, InstructionDebugRecordData, |  | ||||||
|     }, |  | ||||||
|     util::match_types, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Hash, Copy, PartialEq, Eq, PartialOrd)] |  | ||||||
| pub struct ModuleValue(pub(crate) usize); |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Hash, Copy, PartialEq, Eq, PartialOrd)] |  | ||||||
| pub struct TypeValue(pub(crate) ModuleValue, pub(crate) usize); |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Hash, Copy, PartialEq, Eq, PartialOrd)] |  | ||||||
| pub struct FunctionValue(pub(crate) ModuleValue, pub(crate) usize); |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Hash, Copy, PartialEq, Eq, PartialOrd)] |  | ||||||
| pub struct BlockValue(pub(crate) FunctionValue, pub(crate) usize); |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Hash, Copy, PartialEq, Eq, PartialOrd)] |  | ||||||
| pub struct InstructionValue(pub(crate) BlockValue, pub(crate) usize); |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)] |  | ||||||
| pub struct ConstantValue(pub(crate) ModuleValue, pub(crate) usize); |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)] |  | ||||||
| pub struct GlobalValue(pub(crate) ModuleValue, pub(crate) usize); |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct ModuleHolder { |  | ||||||
|     pub(crate) value: ModuleValue, |  | ||||||
|     pub(crate) data: ModuleData, |  | ||||||
|     pub(crate) functions: Vec<FunctionHolder>, |  | ||||||
|     pub(crate) types: Vec<TypeHolder>, |  | ||||||
|     pub(crate) debug_information: Option<DebugInformation>, |  | ||||||
|     pub(crate) constants: Vec<ConstantValueHolder>, |  | ||||||
|     pub(crate) globals: Vec<GlobalValueHolder>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct ConstantValueHolder { |  | ||||||
|     pub(crate) value: ConstantValue, |  | ||||||
|     pub(crate) kind: ConstValueKind, |  | ||||||
| } |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct GlobalValueHolder { |  | ||||||
|     pub(crate) value: GlobalValue, |  | ||||||
|     pub(crate) name: String, |  | ||||||
|     pub(crate) initializer: ConstantValue, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct TypeHolder { |  | ||||||
|     pub(crate) value: TypeValue, |  | ||||||
|     pub(crate) data: TypeData, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct FunctionHolder { |  | ||||||
|     pub(crate) value: FunctionValue, |  | ||||||
|     pub(crate) data: FunctionData, |  | ||||||
|     pub(crate) blocks: Vec<BlockHolder>, |  | ||||||
|     /// Debug scope value of this current function
 |  | ||||||
|     pub(crate) debug_info: Option<DebugScopeValue>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct BlockHolder { |  | ||||||
|     pub(crate) value: BlockValue, |  | ||||||
|     pub(crate) data: BlockData, |  | ||||||
|     pub(crate) instructions: Vec<InstructionHolder>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct InstructionHolder { |  | ||||||
|     pub(crate) value: InstructionValue, |  | ||||||
|     pub(crate) data: InstructionData, |  | ||||||
|     pub(crate) name: String, |  | ||||||
|     pub(crate) record: Option<InstructionDebugRecordData>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub(crate) struct Builder { |  | ||||||
|     pub(crate) modules: Rc<RefCell<Vec<ModuleHolder>>>, |  | ||||||
|     pub(crate) producer: String, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Builder { |  | ||||||
|     pub fn new(producer: String) -> Builder { |  | ||||||
|         Builder { |  | ||||||
|             modules: Rc::new(RefCell::new(Vec::new())), |  | ||||||
|             producer, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     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(), |  | ||||||
|             types: Vec::new(), |  | ||||||
|             debug_information: None, |  | ||||||
|             constants: Vec::new(), |  | ||||||
|             globals: Vec::new(), |  | ||||||
|         }); |  | ||||||
|         value |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) fn set_debug_information(&self, mod_val: &ModuleValue, debug_info: DebugInformation) { |  | ||||||
|         unsafe { |  | ||||||
|             let mut modules = self.modules.borrow_mut(); |  | ||||||
|             let module = modules.get_unchecked_mut(mod_val.0); |  | ||||||
|             module.debug_information = Some(debug_info); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) unsafe fn add_type(&self, mod_val: &ModuleValue, data: TypeData) -> TypeValue { |  | ||||||
|         unsafe { |  | ||||||
|             let mut modules = self.modules.borrow_mut(); |  | ||||||
|             let module = modules.get_unchecked_mut(mod_val.0); |  | ||||||
|             let value = TypeValue(module.value, module.types.len()); |  | ||||||
|             module.types.push(TypeHolder { value, data }); |  | ||||||
|             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(), |  | ||||||
|                 debug_info: None, |  | ||||||
|             }); |  | ||||||
|             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, |  | ||||||
|         name: String, |  | ||||||
|     ) -> CompileResult<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, |  | ||||||
|                 name, |  | ||||||
|                 record: None, |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|             // 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 build_constant(&self, module: ModuleValue, kind: ConstValueKind) -> ConstantValue { |  | ||||||
|         unsafe { |  | ||||||
|             let mut modules = self.modules.borrow_mut(); |  | ||||||
|             let module = modules.get_unchecked_mut(module.0); |  | ||||||
|             let value = ConstantValue(module.value, module.constants.len()); |  | ||||||
|             module.constants.push(ConstantValueHolder { value, kind }); |  | ||||||
|             value |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) unsafe fn add_global( |  | ||||||
|         &self, |  | ||||||
|         module: ModuleValue, |  | ||||||
|         name: String, |  | ||||||
|         initializer: ConstantValue, |  | ||||||
|     ) -> GlobalValue { |  | ||||||
|         unsafe { |  | ||||||
|             let mut modules = self.modules.borrow_mut(); |  | ||||||
|             let module = modules.get_unchecked_mut(module.0); |  | ||||||
|             let value = GlobalValue(module.value, module.globals.len()); |  | ||||||
|             module.globals.push(GlobalValueHolder { |  | ||||||
|                 value, |  | ||||||
|                 name, |  | ||||||
|                 initializer, |  | ||||||
|             }); |  | ||||||
|             value |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) unsafe fn find_function(&self, module: ModuleValue, name: &String) -> Option<FunctionValue> { |  | ||||||
|         unsafe { |  | ||||||
|             let mut modules = self.modules.borrow_mut(); |  | ||||||
|             let module = modules.get_unchecked_mut(module.0); |  | ||||||
|             module.functions.iter().find(|f| f.data.name == *name).map(|f| f.value) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) unsafe fn add_instruction_location(&self, value: &InstructionValue, location: DebugLocationValue) { |  | ||||||
|         unsafe { |  | ||||||
|             let mut modules = self.modules.borrow_mut(); |  | ||||||
|             let module = modules.get_unchecked_mut(value.0.0.0.0); |  | ||||||
|             let function = module.functions.get_unchecked_mut(value.0.0.1); |  | ||||||
|             let block = function.blocks.get_unchecked_mut(value.0.1); |  | ||||||
|             let instr = block.instructions.get_unchecked_mut(value.1); |  | ||||||
|             instr.data.location = Some(location) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) unsafe fn add_instruction_metadata(&self, value: &InstructionValue, metadata: DebugMetadataValue) { |  | ||||||
|         unsafe { |  | ||||||
|             let mut modules = self.modules.borrow_mut(); |  | ||||||
|             let module = modules.get_unchecked_mut(value.0.0.0.0); |  | ||||||
|             let function = module.functions.get_unchecked_mut(value.0.0.1); |  | ||||||
|             let block = function.blocks.get_unchecked_mut(value.0.1); |  | ||||||
|             let instr = block.instructions.get_unchecked_mut(value.1); |  | ||||||
|             instr.data.meta = Some(metadata) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) unsafe fn add_instruction_record(&self, value: &InstructionValue, record: InstructionDebugRecordData) { |  | ||||||
|         unsafe { |  | ||||||
|             let mut modules = self.modules.borrow_mut(); |  | ||||||
|             let module = modules.get_unchecked_mut(value.0.0.0.0); |  | ||||||
|             let function = module.functions.get_unchecked_mut(value.0.0.1); |  | ||||||
|             let block = function.blocks.get_unchecked_mut(value.0.1); |  | ||||||
|             let instr = block.instructions.get_unchecked_mut(value.1); |  | ||||||
|             instr.record = Some(record) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) unsafe fn set_debug_subprogram(&self, value: &FunctionValue, subprogram: DebugScopeValue) { |  | ||||||
|         unsafe { |  | ||||||
|             let mut modules = self.modules.borrow_mut(); |  | ||||||
|             let module = modules.get_unchecked_mut(value.0.0); |  | ||||||
|             let function = module.functions.get_unchecked_mut(value.1); |  | ||||||
|             function.debug_info = Some(subprogram) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) unsafe fn terminate(&self, block: &BlockValue, value: TerminatorKind) -> CompileResult<()> { |  | ||||||
|         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(ErrorKind::BlockAlreadyTerminated) |  | ||||||
|             } else { |  | ||||||
|                 block.data.terminator = Some(value); |  | ||||||
|                 Ok(()) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) unsafe fn set_terminator_location( |  | ||||||
|         &self, |  | ||||||
|         block: &BlockValue, |  | ||||||
|         location: DebugLocationValue, |  | ||||||
|     ) -> CompileResult<()> { |  | ||||||
|         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_location { |  | ||||||
|                 Err(ErrorKind::BlockTerminatorLocated) |  | ||||||
|             } else { |  | ||||||
|                 block.data.terminator_location = Some(location); |  | ||||||
|                 Ok(()) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) unsafe fn delete_block(&self, block: &BlockValue) -> CompileResult<()> { |  | ||||||
|         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); |  | ||||||
|             block.data.deleted = true; |  | ||||||
|             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) unsafe fn type_data(&self, value: &TypeValue) -> TypeData { |  | ||||||
|         unsafe { |  | ||||||
|             self.modules |  | ||||||
|                 .borrow() |  | ||||||
|                 .get_unchecked(value.0.0) |  | ||||||
|                 .types |  | ||||||
|                 .get_unchecked(value.1) |  | ||||||
|                 .data |  | ||||||
|                 .clone() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) fn find_module<'ctx>(&'ctx self, value: ModuleValue) -> ModuleHolder { |  | ||||||
|         unsafe { self.modules.borrow().get_unchecked(value.0).clone() } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) fn get_modules(&self) -> Rc<RefCell<Vec<ModuleHolder>>> { |  | ||||||
|         self.modules.clone() |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) fn get_global_initializer(&self, value: GlobalValue) -> ConstantValue { |  | ||||||
|         unsafe { |  | ||||||
|             let modules = self.modules.borrow(); |  | ||||||
|             let module = modules.get_unchecked(value.0.0); |  | ||||||
|             let global = module.globals.get_unchecked(value.1); |  | ||||||
|             global.initializer |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) fn get_const_kind(&self, value: ConstantValue) -> ConstValueKind { |  | ||||||
|         unsafe { |  | ||||||
|             let modules = self.modules.borrow(); |  | ||||||
|             let module = modules.get_unchecked(value.0.0); |  | ||||||
|             let constant = module.constants.get_unchecked(value.1); |  | ||||||
|             constant.kind.clone() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn check_instruction(&self, instruction: &InstructionValue) -> CompileResult<()> { |  | ||||||
|         unsafe { |  | ||||||
|             match self.instr_data(&instruction).kind { |  | ||||||
|                 Instr::Param(_) => Ok(()), |  | ||||||
|                 Instr::Constant(_) => Ok(()), |  | ||||||
|                 Instr::Add(lhs, rhs) => { |  | ||||||
|                     if match_types(&lhs, &rhs, &self)?.category().integer() { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeNotInteger(lhs, lhs.get_type(&self)?)) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::FAdd(lhs, rhs) => { |  | ||||||
|                     if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeWrongCategory( |  | ||||||
|                             lhs, |  | ||||||
|                             lhs.get_type(&self)?, |  | ||||||
|                             TypeCategory::Real, |  | ||||||
|                         )) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::Sub(lhs, rhs) => { |  | ||||||
|                     if match_types(&lhs, &rhs, &self)?.category().integer() { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeNotInteger(lhs, lhs.get_type(&self)?)) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::FSub(lhs, rhs) => { |  | ||||||
|                     if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeWrongCategory( |  | ||||||
|                             lhs, |  | ||||||
|                             lhs.get_type(&self)?, |  | ||||||
|                             TypeCategory::Real, |  | ||||||
|                         )) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::Mul(lhs, rhs) => { |  | ||||||
|                     if match_types(&lhs, &rhs, &self)?.category().integer() { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeNotInteger(lhs, lhs.get_type(&self)?)) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::FMul(lhs, rhs) => { |  | ||||||
|                     if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeWrongCategory( |  | ||||||
|                             lhs, |  | ||||||
|                             lhs.get_type(&self)?, |  | ||||||
|                             TypeCategory::Real, |  | ||||||
|                         )) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::UDiv(lhs, rhs) => { |  | ||||||
|                     if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::UnsignedInteger { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeWrongCategory( |  | ||||||
|                             lhs, |  | ||||||
|                             lhs.get_type(&self)?, |  | ||||||
|                             TypeCategory::UnsignedInteger, |  | ||||||
|                         )) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::SDiv(lhs, rhs) => { |  | ||||||
|                     if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::SignedInteger { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeWrongCategory( |  | ||||||
|                             lhs, |  | ||||||
|                             lhs.get_type(&self)?, |  | ||||||
|                             TypeCategory::SignedInteger, |  | ||||||
|                         )) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::FDiv(lhs, rhs) => { |  | ||||||
|                     if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeWrongCategory( |  | ||||||
|                             lhs, |  | ||||||
|                             lhs.get_type(&self)?, |  | ||||||
|                             TypeCategory::Real, |  | ||||||
|                         )) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::URem(lhs, rhs) => { |  | ||||||
|                     if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::UnsignedInteger { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeWrongCategory( |  | ||||||
|                             lhs, |  | ||||||
|                             lhs.get_type(&self)?, |  | ||||||
|                             TypeCategory::UnsignedInteger, |  | ||||||
|                         )) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::SRem(lhs, rhs) => { |  | ||||||
|                     if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::SignedInteger { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeWrongCategory( |  | ||||||
|                             lhs, |  | ||||||
|                             lhs.get_type(&self)?, |  | ||||||
|                             TypeCategory::SignedInteger, |  | ||||||
|                         )) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::FRem(lhs, rhs) => { |  | ||||||
|                     if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeWrongCategory( |  | ||||||
|                             lhs, |  | ||||||
|                             lhs.get_type(&self)?, |  | ||||||
|                             TypeCategory::Real, |  | ||||||
|                         )) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::And(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), |  | ||||||
|                 Instr::Or(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), |  | ||||||
|                 Instr::XOr(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), |  | ||||||
|                 Instr::ICmp(_, lhs, rhs) => { |  | ||||||
|                     let t = match_types(&lhs, &rhs, self)?; |  | ||||||
|                     if t.category().comparable() || !t.category().integer() { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeNotComparable(lhs, t)) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::FCmp(_, lhs, rhs) => { |  | ||||||
|                     let t = match_types(&lhs, &rhs, self)?; |  | ||||||
|                     if t.category().comparable() || t.category() != TypeCategory::Real { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeNotComparable(lhs, t)) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::FunctionCall(fun, params) => { |  | ||||||
|                     let param_types = self.function_data(&fun).params; |  | ||||||
|                     if param_types.len() != params.len() { |  | ||||||
|                         return Err(ErrorKind::InvalidLenParams(params.len(), param_types.len())); |  | ||||||
|                     } |  | ||||||
|                     for (a, b) in param_types.iter().zip(params) { |  | ||||||
|                         if *a != b.get_type(&self)? { |  | ||||||
|                             return Err(ErrorKind::TypesIncompatible(a.clone(), b.get_type(&self)?)); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     Ok(()) |  | ||||||
|                 } |  | ||||||
|                 Instr::Phi(vals) => { |  | ||||||
|                     let mut iter = vals.iter(); |  | ||||||
|                     // TODO error: Phi must contain at least one item
 |  | ||||||
| 
 |  | ||||||
|                     // TODO error: compile can actually crash here if any of the
 |  | ||||||
|                     // incoming values come from blocks that are added later
 |  | ||||||
|                     // than the one where this one exists.
 |  | ||||||
| 
 |  | ||||||
|                     let first = iter.next().ok_or(ErrorKind::EmptyPhiList)?; |  | ||||||
|                     for item in iter { |  | ||||||
|                         match_types(first, item, &self)?; |  | ||||||
|                     } |  | ||||||
|                     Ok(()) |  | ||||||
|                 } |  | ||||||
|                 Instr::Alloca(_) => Ok(()), |  | ||||||
|                 Instr::Load(ptr, load_ty) => { |  | ||||||
|                     let ptr_ty = ptr.get_type(&self)?; |  | ||||||
|                     if let Type::Ptr(ptr_ty_inner) = ptr_ty { |  | ||||||
|                         if *ptr_ty_inner == load_ty { |  | ||||||
|                             Ok(()) |  | ||||||
|                         } else { |  | ||||||
|                             Err(ErrorKind::TypesIncompatible(*ptr_ty_inner, load_ty)) |  | ||||||
|                         } |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::NotPointer(ptr, ptr_ty)) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::Store(ptr, _) => { |  | ||||||
|                     let ty = ptr.get_type(&self)?; |  | ||||||
|                     if let Type::Ptr(_) = ty { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::NotPointer(ptr, ty)) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::ArrayAlloca(_, val) => { |  | ||||||
|                     if val.get_type(self)?.category() == TypeCategory::UnsignedInteger { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::TypeWrongCategory( |  | ||||||
|                             val, |  | ||||||
|                             val.get_type(self)?, |  | ||||||
|                             TypeCategory::UnsignedInteger, |  | ||||||
|                         )) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::GetElemPtr(ptr_val, _) => { |  | ||||||
|                     let ptr_ty = ptr_val.get_type(&self)?; |  | ||||||
|                     match ptr_ty { |  | ||||||
|                         Type::Ptr(_) => Ok(()), |  | ||||||
|                         _ => Err(ErrorKind::NotPointer(ptr_val, ptr_ty)), |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::GetStructElemPtr(ptr_val, idx) => { |  | ||||||
|                     let ptr_ty = ptr_val.get_type(&self)?; |  | ||||||
|                     if let Type::Ptr(ty) = ptr_ty { |  | ||||||
|                         if let Type::CustomType(val) = *ty { |  | ||||||
|                             match self.type_data(&val).kind { |  | ||||||
|                                 CustomTypeKind::NamedStruct(NamedStruct(_, fields)) => { |  | ||||||
|                                     if fields.len() <= idx as usize { |  | ||||||
|                                         return Err(ErrorKind::NoSuchField(*ty, idx)); |  | ||||||
|                                     } |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                             Ok(()) |  | ||||||
|                         } else { |  | ||||||
|                             Err(ErrorKind::NotStruct(ptr_val, *ty)) |  | ||||||
|                         } |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::NotPointer(ptr_val, ptr_ty)) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::ExtractValue(val, _) => { |  | ||||||
|                     let val_ty = val.get_type(&self)?; |  | ||||||
|                     match val_ty { |  | ||||||
|                         Type::CustomType(custom) => match self.type_data(&custom).kind { |  | ||||||
|                             CustomTypeKind::NamedStruct(_) => Ok(()), |  | ||||||
|                         }, |  | ||||||
|                         Type::Array(_, _) => Ok(()), |  | ||||||
|                         _ => Err(ErrorKind::NotExtractable(val, val_ty)), |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Instr::Trunc(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), |  | ||||||
|                 Instr::ZExt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), |  | ||||||
|                 Instr::SExt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), |  | ||||||
|                 Instr::FPTrunc(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), |  | ||||||
|                 Instr::FPExt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), |  | ||||||
|                 Instr::FPToUI(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), |  | ||||||
|                 Instr::FPToSI(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), |  | ||||||
|                 Instr::UIToFP(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), |  | ||||||
|                 Instr::SIToFP(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), |  | ||||||
|                 Instr::PtrToInt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), |  | ||||||
|                 Instr::IntToPtr(instr, ty) => instr.cast_to(self, &ty).map(|_| ()), |  | ||||||
|                 Instr::BitCast(..) => Ok(()), |  | ||||||
|                 Instr::ShiftRightLogical(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), |  | ||||||
|                 Instr::ShiftRightArithmetic(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), |  | ||||||
|                 Instr::ShiftLeft(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()), |  | ||||||
|                 Instr::GetGlobal(_) => Ok(()), |  | ||||||
|                 Instr::IsNull(val) => { |  | ||||||
|                     let val_ty = val.get_type(&self)?; |  | ||||||
|                     if let Type::Ptr(_) = val_ty { |  | ||||||
|                         Ok(()) |  | ||||||
|                     } else { |  | ||||||
|                         Err(ErrorKind::NotPointer(val, val_ty)) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn is_block_used(&self, block_v: BlockValue) -> bool { |  | ||||||
|         unsafe { |  | ||||||
|             let modules = self.modules.borrow(); |  | ||||||
|             let module = modules.get_unchecked(block_v.0.0.0); |  | ||||||
|             let function = module.functions.get_unchecked(block_v.0.1); |  | ||||||
|             let block = function.blocks.get_unchecked(block_v.1); |  | ||||||
| 
 |  | ||||||
|             if block.instructions.len() > 0 || block.data.terminator.is_some() { |  | ||||||
|                 return true; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             for other in &function.blocks { |  | ||||||
|                 if let Some(term) = &other.data.terminator { |  | ||||||
|                     match term { |  | ||||||
|                         TerminatorKind::Ret(_) => {} |  | ||||||
|                         TerminatorKind::RetVoid => {} |  | ||||||
|                         TerminatorKind::Br(other_val) => { |  | ||||||
|                             if other_val == &block_v { |  | ||||||
|                                 return true; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         TerminatorKind::CondBr(_, then_other_v, else_other_v) => { |  | ||||||
|                             if then_other_v == &block_v || else_other_v == &block_v { |  | ||||||
|                                 return true; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             false |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl InstructionValue { |  | ||||||
|     pub fn with_location(self, block: &Block, location: DebugLocationValue) -> InstructionValue { |  | ||||||
|         unsafe { |  | ||||||
|             block.builder.add_instruction_location(&self, location); |  | ||||||
|         } |  | ||||||
|         self |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn maybe_location(self, block: &mut Block, location: Option<DebugLocationValue>) -> InstructionValue { |  | ||||||
|         unsafe { |  | ||||||
|             if let Some(location) = location { |  | ||||||
|                 block.builder.add_instruction_location(&self, location); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         self |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn add_record(&self, block: &mut Block, record: InstructionDebugRecordData) { |  | ||||||
|         unsafe { |  | ||||||
|             block.builder.add_instruction_record(self, record); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) fn get_type(&self, builder: &Builder) -> CompileResult<Type> { |  | ||||||
|         use Instr::*; |  | ||||||
|         unsafe { |  | ||||||
|             match &builder.instr_data(self).kind { |  | ||||||
|                 Param(nth) => builder |  | ||||||
|                     .function_data(&self.0.0) |  | ||||||
|                     .params |  | ||||||
|                     .get(*nth) |  | ||||||
|                     .cloned() |  | ||||||
|                     .ok_or(ErrorKind::NoSuchParam(self.0.0, *nth)), |  | ||||||
|                 Constant(c) => Ok(c.get_type()), |  | ||||||
|                 Add(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 FAdd(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 Sub(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 FSub(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 Mul(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 FMul(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 UDiv(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 SDiv(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 FDiv(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 URem(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 SRem(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 FRem(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 And(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 Or(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 XOr(lhs, rhs) => match_types(lhs, rhs, &builder), |  | ||||||
|                 ICmp(_, _, _) => Ok(Type::Bool), |  | ||||||
|                 FCmp(_, _, _) => Ok(Type::Bool), |  | ||||||
|                 FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret), |  | ||||||
|                 Phi(values) => values |  | ||||||
|                     .first() |  | ||||||
|                     .ok_or(ErrorKind::EmptyPhiList) |  | ||||||
|                     .and_then(|v| v.get_type(&builder)), |  | ||||||
|                 Alloca(ty) => Ok(Type::Ptr(Box::new(ty.clone()))), |  | ||||||
|                 Load(_, ty) => Ok(ty.clone()), |  | ||||||
|                 Store(_, value) => value.get_type(builder), |  | ||||||
|                 ArrayAlloca(ty, _) => Ok(Type::Ptr(Box::new(ty.clone()))), |  | ||||||
|                 GetElemPtr(instr, _) => { |  | ||||||
|                     let instr_ty = instr.get_type(builder)?; |  | ||||||
|                     let Type::Ptr(inner_ty) = &instr_ty else { |  | ||||||
|                         panic!("GetStructElemPtr on non-pointer! ({:?})", &instr_ty) |  | ||||||
|                     }; |  | ||||||
|                     match *inner_ty.clone() { |  | ||||||
|                         Type::Array(elem_ty, _) => Ok(Type::Ptr(Box::new(*elem_ty.clone()))), |  | ||||||
|                         _ => Ok(instr_ty), |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 GetStructElemPtr(instr, idx) => { |  | ||||||
|                     let instr_ty = instr.get_type(builder)?; |  | ||||||
|                     let Type::Ptr(inner_ty) = instr_ty else { |  | ||||||
|                         panic!("GetStructElemPtr on non-pointer! ({:?})", &instr_ty) |  | ||||||
|                     }; |  | ||||||
|                     let Type::CustomType(ty_value) = *inner_ty else { |  | ||||||
|                         panic!("GetStructElemPtr on non-struct! ({:?})", &inner_ty) |  | ||||||
|                     }; |  | ||||||
|                     let field_ty = match builder.type_data(&ty_value).kind { |  | ||||||
|                         CustomTypeKind::NamedStruct(NamedStruct(_, fields)) => { |  | ||||||
|                             fields.get_unchecked(*idx as usize).clone() |  | ||||||
|                         } |  | ||||||
|                     }; |  | ||||||
|                     Ok(Type::Ptr(Box::new(field_ty))) |  | ||||||
|                 } |  | ||||||
|                 ExtractValue(instr, idx) => { |  | ||||||
|                     let instr_ty = instr.get_type(builder)?; |  | ||||||
|                     Ok(match instr_ty { |  | ||||||
|                         Type::CustomType(struct_ty) => { |  | ||||||
|                             let data = builder.type_data(&struct_ty); |  | ||||||
|                             match data.kind { |  | ||||||
|                                 CustomTypeKind::NamedStruct(named_struct) => { |  | ||||||
|                                     named_struct.1.get(*idx as usize).unwrap().clone() |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         Type::Array(elem_ty, _) => *elem_ty.clone(), |  | ||||||
|                         _ => return Err(ErrorKind::NotExtractable(*instr, instr_ty)), |  | ||||||
|                     }) |  | ||||||
|                 } |  | ||||||
|                 Trunc(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), |  | ||||||
|                 ZExt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), |  | ||||||
|                 SExt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), |  | ||||||
|                 FPTrunc(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), |  | ||||||
|                 FPExt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), |  | ||||||
|                 FPToUI(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), |  | ||||||
|                 FPToSI(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), |  | ||||||
|                 UIToFP(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), |  | ||||||
|                 SIToFP(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), |  | ||||||
|                 PtrToInt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), |  | ||||||
|                 IntToPtr(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()), |  | ||||||
|                 BitCast(_, ty) => Ok(ty.clone()), |  | ||||||
|                 ShiftRightLogical(lhs, _) => lhs.get_type(builder), |  | ||||||
|                 ShiftRightArithmetic(lhs, _) => lhs.get_type(builder), |  | ||||||
|                 ShiftLeft(lhs, _) => lhs.get_type(builder), |  | ||||||
|                 GetGlobal(global_value) => { |  | ||||||
|                     let constant = builder.get_global_initializer(*global_value); |  | ||||||
|                     let kind = builder.get_const_kind(constant); |  | ||||||
|                     Ok(kind.get_type()) |  | ||||||
|                 } |  | ||||||
|                 IsNull(_) => Ok(Type::Bool), |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn cast_to(&self, builder: &Builder, ty: &Type) -> CompileResult<Instr> { |  | ||||||
|         let own_type = self.get_type(builder)?; |  | ||||||
|         own_type |  | ||||||
|             .cast_instruction(*self, &ty) |  | ||||||
|             .ok_or(ErrorKind::ImpossibleCast(own_type, ty.clone())) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,399 +0,0 @@ | |||||||
| use std::{ |  | ||||||
|     cell::{Ref, RefCell, RefMut}, |  | ||||||
|     rc::Rc, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| use crate::builder::InstructionValue; |  | ||||||
| 
 |  | ||||||
| /// Represents 1. the compilation context, 2. subprogram or 3. a lexical scope
 |  | ||||||
| #[derive(Clone, Hash, PartialEq, Eq)] |  | ||||||
| pub struct DebugScopeValue(pub Vec<usize>); |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Hash, PartialEq, Eq)] |  | ||||||
| pub struct DebugLocationValue(pub DebugScopeValue, pub usize); |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Copy, Hash, PartialEq, Eq)] |  | ||||||
| pub struct DebugTypeValue(pub usize); |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Copy, Hash, PartialEq, Eq)] |  | ||||||
| pub struct DebugMetadataValue(pub usize); |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub struct DebugFileData { |  | ||||||
|     pub name: String, |  | ||||||
|     pub directory: String, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub(crate) struct DebugScopeHolder { |  | ||||||
|     pub(crate) value: DebugScopeValue, |  | ||||||
|     pub(crate) data: DebugScopeData, |  | ||||||
|     pub(crate) inner_scopes: Vec<DebugScopeHolder>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub struct DebugMetadataHolder { |  | ||||||
|     pub(crate) location: DebugLocation, |  | ||||||
|     pub(crate) value: DebugMetadataValue, |  | ||||||
|     pub(crate) data: DebugMetadata, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct DebugTypeHolder { |  | ||||||
|     pub(crate) value: DebugTypeValue, |  | ||||||
|     pub(crate) data: DebugTypeData, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub(crate) struct DebugLocationHolder { |  | ||||||
|     pub(crate) scope: DebugScopeValue, |  | ||||||
|     pub(crate) value: DebugLocationValue, |  | ||||||
|     pub(crate) location: DebugLocation, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub struct DebugInformation { |  | ||||||
|     pub file: DebugFileData, |  | ||||||
|     scope: Rc<RefCell<DebugScopeHolder>>, |  | ||||||
|     locations: Rc<RefCell<Vec<DebugLocationHolder>>>, |  | ||||||
|     metadata: Rc<RefCell<Vec<DebugMetadataHolder>>>, |  | ||||||
|     types: Rc<RefCell<Vec<DebugTypeHolder>>>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl DebugInformation { |  | ||||||
|     pub fn from_file(file: DebugFileData) -> (DebugInformation, DebugScopeValue) { |  | ||||||
|         let scope_value = DebugScopeValue(Vec::new()); |  | ||||||
|         ( |  | ||||||
|             DebugInformation { |  | ||||||
|                 file, |  | ||||||
|                 scope: Rc::new(RefCell::new(DebugScopeHolder { |  | ||||||
|                     value: scope_value.clone(), |  | ||||||
|                     inner_scopes: Vec::new(), |  | ||||||
|                     data: DebugScopeData { |  | ||||||
|                         parent: None, |  | ||||||
|                         kind: DebugScopeKind::CodegenContext, |  | ||||||
|                     }, |  | ||||||
|                 })), |  | ||||||
|                 locations: Rc::new(RefCell::new(Vec::new())), |  | ||||||
|                 metadata: Rc::new(RefCell::new(Vec::new())), |  | ||||||
|                 types: Rc::new(RefCell::new(Vec::new())), |  | ||||||
|             }, |  | ||||||
|             scope_value, |  | ||||||
|         ) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn location(&self, scope_value: &DebugScopeValue, location: DebugLocation) -> DebugLocationValue { |  | ||||||
|         let value = DebugLocationValue(scope_value.clone(), self.locations.borrow().len()); |  | ||||||
|         let location = DebugLocationHolder { |  | ||||||
|             scope: scope_value.clone(), |  | ||||||
|             value: value.clone(), |  | ||||||
|             location, |  | ||||||
|         }; |  | ||||||
|         self.locations.borrow_mut().push(location); |  | ||||||
|         value |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn debug_type(&self, kind: DebugTypeData) -> DebugTypeValue { |  | ||||||
|         let mut types = self.types.borrow_mut(); |  | ||||||
|         let value = DebugTypeValue(types.len()); |  | ||||||
|         types.push(DebugTypeHolder { |  | ||||||
|             value: value.clone(), |  | ||||||
|             data: kind, |  | ||||||
|         }); |  | ||||||
|         value |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn metadata(&self, location: &DebugLocation, kind: DebugMetadata) -> DebugMetadataValue { |  | ||||||
|         let mut metadata = self.metadata.borrow_mut(); |  | ||||||
|         let value = DebugMetadataValue(metadata.len()); |  | ||||||
|         metadata.push(DebugMetadataHolder { |  | ||||||
|             location: location.clone(), |  | ||||||
|             value: value.clone(), |  | ||||||
|             data: kind, |  | ||||||
|         }); |  | ||||||
|         value |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn subprogram(&self, parent: DebugScopeValue, kind: DebugSubprogramData) -> DebugScopeValue { |  | ||||||
|         unsafe { |  | ||||||
|             let mut outer_scope = RefMut::map(self.scope.borrow_mut(), |mut v| { |  | ||||||
|                 for i in &parent.0 { |  | ||||||
|                     v = v.inner_scopes.get_unchecked_mut(*i); |  | ||||||
|                 } |  | ||||||
|                 v |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|             let mut arr = parent.0.clone(); |  | ||||||
|             arr.push(outer_scope.inner_scopes.len()); |  | ||||||
|             let value = DebugScopeValue(arr); |  | ||||||
| 
 |  | ||||||
|             outer_scope.inner_scopes.push(DebugScopeHolder { |  | ||||||
|                 value: value.clone(), |  | ||||||
|                 inner_scopes: Vec::new(), |  | ||||||
|                 data: DebugScopeData { |  | ||||||
|                     parent: Some(parent.clone()), |  | ||||||
|                     kind: DebugScopeKind::Subprogram(kind), |  | ||||||
|                 }, |  | ||||||
|             }); |  | ||||||
|             value |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     pub fn lexical_scope(&self, parent: &DebugScopeValue, data: DebugLexicalScope) -> DebugScopeValue { |  | ||||||
|         unsafe { |  | ||||||
|             let mut outer_scope = RefMut::map(self.scope.borrow_mut(), |mut v| { |  | ||||||
|                 for i in &parent.0 { |  | ||||||
|                     v = v.inner_scopes.get_unchecked_mut(*i); |  | ||||||
|                 } |  | ||||||
|                 v |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|             let mut arr = parent.0.clone(); |  | ||||||
|             arr.push(outer_scope.inner_scopes.len()); |  | ||||||
|             let value = DebugScopeValue(arr); |  | ||||||
| 
 |  | ||||||
|             outer_scope.inner_scopes.push(DebugScopeHolder { |  | ||||||
|                 value: value.clone(), |  | ||||||
|                 inner_scopes: Vec::new(), |  | ||||||
|                 data: DebugScopeData { |  | ||||||
|                     parent: Some(parent.clone()), |  | ||||||
|                     kind: DebugScopeKind::LexicalScope(data), |  | ||||||
|                 }, |  | ||||||
|             }); |  | ||||||
|             value |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn get_metadata(&self, value: DebugMetadataValue) -> DebugMetadata { |  | ||||||
|         unsafe { self.metadata.borrow().get_unchecked(value.0).data.clone() } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn get_metadata_location(&self, value: DebugMetadataValue) -> DebugLocation { |  | ||||||
|         unsafe { self.metadata.borrow().get_unchecked(value.0).location.clone() } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn get_scope_data(&self, value: &DebugScopeValue) -> Option<DebugScopeData> { |  | ||||||
|         let scope = Ref::filter_map(self.scope.borrow(), |v: &DebugScopeHolder| { |  | ||||||
|             let mut opt = Some(v); |  | ||||||
|             for i in &value.0 { |  | ||||||
|                 if let Some(inner) = opt { |  | ||||||
|                     opt = inner.inner_scopes.get(*i); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             opt |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         if let Ok(scope) = scope { |  | ||||||
|             Some(scope.data.clone()) |  | ||||||
|         } else { |  | ||||||
|             None |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn get_type_data(&self, value: DebugTypeValue) -> DebugTypeData { |  | ||||||
|         unsafe { self.types.borrow().get_unchecked(value.0).data.clone() } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn get_location(&self, value: &DebugLocationValue) -> DebugLocation { |  | ||||||
|         unsafe { self.locations.borrow().get_unchecked(value.1).location.clone() } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn get_metadatas(&self) -> Rc<RefCell<Vec<DebugMetadataHolder>>> { |  | ||||||
|         self.metadata.clone() |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) fn get_scope(&self) -> Rc<RefCell<DebugScopeHolder>> { |  | ||||||
|         self.scope.clone() |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn get_types(&self) -> Rc<RefCell<Vec<DebugTypeHolder>>> { |  | ||||||
|         self.types.clone() |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) fn get_locations(&self) -> Rc<RefCell<Vec<DebugLocationHolder>>> { |  | ||||||
|         self.locations.clone() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct DebugLocation { |  | ||||||
|     pub scope: DebugScopeValue, |  | ||||||
|     pub pos: DebugPosition, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Copy)] |  | ||||||
| pub struct DebugPosition { |  | ||||||
|     pub line: u32, |  | ||||||
|     pub column: u32, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub enum DebugMetadata { |  | ||||||
|     ParamVar(DebugParamVariable), |  | ||||||
|     LocalVar(DebugLocalVariable), |  | ||||||
|     VarAssignment, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub struct DebugParamVariable { |  | ||||||
|     pub name: String, |  | ||||||
|     /// the index (starting from 1) of this variable in the subprogram
 |  | ||||||
|     /// parameters. arg_idx should not conflict with other parameters of the
 |  | ||||||
|     /// same subprogram.
 |  | ||||||
|     pub arg_idx: u32, |  | ||||||
|     pub ty: DebugTypeValue, |  | ||||||
|     /// If this variable will be referenced from its containing subprogram, and
 |  | ||||||
|     /// will survive some optimizations.
 |  | ||||||
|     pub always_preserve: bool, |  | ||||||
|     pub flags: DwarfFlags, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub struct DebugLocalVariable { |  | ||||||
|     pub name: String, |  | ||||||
|     pub ty: DebugTypeValue, |  | ||||||
|     pub always_preserve: bool, |  | ||||||
|     pub flags: DwarfFlags, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Default for DebugSubprogramOptionals { |  | ||||||
|     fn default() -> Self { |  | ||||||
|         Self { |  | ||||||
|             scope_line: 0, |  | ||||||
|             is_local: false, |  | ||||||
|             is_definition: true, |  | ||||||
|             is_optimized: false, |  | ||||||
|             flags: DwarfFlags, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub struct DwarfFlags; |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub enum DebugTypeData { |  | ||||||
|     Basic(DebugBasicType), |  | ||||||
|     Subprogram(DebugSubprogramType), |  | ||||||
|     Pointer(DebugPointerType), |  | ||||||
|     Array(DebugArrayType), |  | ||||||
|     Struct(DebugStructType), |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct DebugBasicType { |  | ||||||
|     pub name: String, |  | ||||||
|     /// Size of the type.
 |  | ||||||
|     pub size_bits: u64, |  | ||||||
|     /// DWARF encoding code, e.g., dwarf::DW_ATE_float.
 |  | ||||||
|     pub encoding: DwarfEncoding, |  | ||||||
|     /// Optional DWARF attributes, e.g., DW_AT_endianity.
 |  | ||||||
|     pub flags: DwarfFlags, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct DebugArrayType { |  | ||||||
|     pub size_bits: u64, |  | ||||||
|     pub align_bits: u32, |  | ||||||
|     pub element_type: DebugTypeValue, |  | ||||||
|     pub length: u64, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct DebugPointerType { |  | ||||||
|     pub name: String, |  | ||||||
|     pub pointee: DebugTypeValue, |  | ||||||
|     pub size_bits: u64, |  | ||||||
| } |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct DebugStructType { |  | ||||||
|     pub name: String, |  | ||||||
|     pub scope: DebugScopeValue, |  | ||||||
|     pub pos: Option<DebugPosition>, |  | ||||||
|     pub size_bits: u64, |  | ||||||
|     pub flags: DwarfFlags, |  | ||||||
|     pub fields: Vec<DebugFieldType>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct DebugFieldType { |  | ||||||
|     pub name: String, |  | ||||||
|     pub scope: DebugScopeValue, |  | ||||||
|     pub pos: Option<DebugPosition>, |  | ||||||
|     pub size_bits: u64, |  | ||||||
|     pub offset: u64, |  | ||||||
|     pub flags: DwarfFlags, |  | ||||||
|     pub ty: DebugTypeValue, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct DebugSubprogramType { |  | ||||||
|     pub parameters: Vec<DebugTypeValue>, |  | ||||||
|     pub flags: DwarfFlags, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone, Copy)] |  | ||||||
| pub enum DwarfEncoding { |  | ||||||
|     Address = 1, |  | ||||||
|     Boolean = 2, |  | ||||||
|     Float = 4, |  | ||||||
|     Signed = 5, |  | ||||||
|     SignedChar = 6, |  | ||||||
|     Unsigned = 7, |  | ||||||
|     UnsignedChar = 8, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub struct DebugScopeData { |  | ||||||
|     pub parent: Option<DebugScopeValue>, |  | ||||||
|     pub kind: DebugScopeKind, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub enum DebugScopeKind { |  | ||||||
|     CodegenContext, |  | ||||||
|     LexicalScope(DebugLexicalScope), |  | ||||||
|     Subprogram(DebugSubprogramData), |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub struct DebugLexicalScope { |  | ||||||
|     pub location: DebugLocation, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub struct DebugSubprogramData { |  | ||||||
|     /// Function name.
 |  | ||||||
|     pub name: String, |  | ||||||
|     pub outer_scope: DebugScopeValue, |  | ||||||
|     /// Used for line number.
 |  | ||||||
|     pub location: DebugLocation, |  | ||||||
|     /// Function type.
 |  | ||||||
|     pub ty: DebugTypeValue, |  | ||||||
|     pub opts: DebugSubprogramOptionals, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub struct DebugSubprogramOptionals { |  | ||||||
|     /// Set to the beginning of the scope this starts
 |  | ||||||
|     pub scope_line: u32, |  | ||||||
|     pub is_local: bool, |  | ||||||
|     pub is_definition: bool, |  | ||||||
|     pub is_optimized: bool, |  | ||||||
|     /// These flags are used to emit dwarf attributes. e.g. is this function
 |  | ||||||
|     /// prototyped or not.
 |  | ||||||
|     pub flags: DwarfFlags, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct InstructionDebugRecordData { |  | ||||||
|     pub scope: DebugScopeValue, |  | ||||||
|     pub variable: DebugMetadataValue, |  | ||||||
|     pub location: DebugLocation, |  | ||||||
|     pub kind: DebugRecordKind, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Copy)] |  | ||||||
| pub enum DebugRecordKind { |  | ||||||
|     Declare(InstructionValue), |  | ||||||
|     Value(InstructionValue), |  | ||||||
| } |  | ||||||
| @ -1,595 +0,0 @@ | |||||||
| //! Debug implementations for relevant types
 |  | ||||||
| 
 |  | ||||||
| use std::{ |  | ||||||
|     fmt::{Debug, Display, Write}, |  | ||||||
|     marker::PhantomData, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| use crate::{ |  | ||||||
|     CmpPredicate, Context, Instr, InstructionData, TerminatorKind, |  | ||||||
|     builder::*, |  | ||||||
|     debug_information::{ |  | ||||||
|         DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocalVariable, DebugLocation, |  | ||||||
|         DebugLocationValue, DebugMetadata, DebugMetadataValue, DebugParamVariable, DebugPointerType, DebugPosition, |  | ||||||
|         DebugRecordKind, DebugScopeValue, DebugStructType, DebugSubprogramType, DebugTypeData, DebugTypeHolder, |  | ||||||
|         DebugTypeValue, |  | ||||||
|     }, |  | ||||||
|     pad_adapter::PadAdapter, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| impl Display for Context { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         Display::fmt(&self.builder, f) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Display for Builder { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         writeln!(f, "Producer: {}", self.producer)?; |  | ||||||
|         for module in self.modules.borrow().iter() { |  | ||||||
|             if module.data.is_main { |  | ||||||
|                 write!(f, "main ")?; |  | ||||||
|             } |  | ||||||
|             writeln!(f, "{} ({:?}) {{", module.data.name, module.value)?; |  | ||||||
|             for function in &module.functions { |  | ||||||
|                 let mut state = Default::default(); |  | ||||||
|                 let mut inner = PadAdapter::wrap(f, &mut state); |  | ||||||
|                 function.builder_fmt(&mut inner, self, &module.debug_information)?; |  | ||||||
|             } |  | ||||||
|             writeln!(f, "}}")?; |  | ||||||
|         } |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl FunctionHolder { |  | ||||||
|     fn builder_fmt( |  | ||||||
|         &self, |  | ||||||
|         f: &mut impl std::fmt::Write, |  | ||||||
|         builder: &Builder, |  | ||||||
|         debug: &Option<DebugInformation>, |  | ||||||
|     ) -> std::fmt::Result { |  | ||||||
|         if self.data.flags.is_imported { |  | ||||||
|             write!(f, "imported ")?; |  | ||||||
|         } |  | ||||||
|         if self.data.flags.is_extern { |  | ||||||
|             write!(f, "extern ")?; |  | ||||||
|         } |  | ||||||
|         if self.data.flags.is_pub { |  | ||||||
|             write!(f, "pub ")?; |  | ||||||
|         } |  | ||||||
|         if self.data.flags.is_main { |  | ||||||
|             write!(f, "main ")?; |  | ||||||
|         } |  | ||||||
|         let params = self |  | ||||||
|             .data |  | ||||||
|             .params |  | ||||||
|             .iter() |  | ||||||
|             .map(|p| format!("{:?}", p)) |  | ||||||
|             .collect::<Vec<_>>() |  | ||||||
|             .join(", "); |  | ||||||
|         write!(f, "fn {}({}) -> {:?} ", self.data.name, params, self.data.ret)?; |  | ||||||
| 
 |  | ||||||
|         writeln!(f, "{{")?; |  | ||||||
|         let mut state = Default::default(); |  | ||||||
|         let mut inner = PadAdapter::wrap(f, &mut state); |  | ||||||
|         writeln!(inner, "(Value = {:?}) ", self.value)?; |  | ||||||
|         if let Some(debug) = &self.debug_info { |  | ||||||
|             writeln!(inner, "(Debug = {:?})", debug)?; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         for block in &self.blocks { |  | ||||||
|             let mut state = Default::default(); |  | ||||||
|             let mut inner = PadAdapter::wrap(&mut inner, &mut state); |  | ||||||
|             block.builder_fmt(&mut inner, builder, debug)?; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         writeln!(f, "}}")?; |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl BlockHolder { |  | ||||||
|     fn builder_fmt( |  | ||||||
|         &self, |  | ||||||
|         f: &mut impl std::fmt::Write, |  | ||||||
|         builder: &Builder, |  | ||||||
|         debug: &Option<DebugInformation>, |  | ||||||
|     ) -> std::fmt::Result { |  | ||||||
|         if self.data.deleted { |  | ||||||
|             write!(f, "deleted ")?; |  | ||||||
|         } |  | ||||||
|         writeln!(f, "{} ({:?}):", self.data.name, self.value)?; |  | ||||||
| 
 |  | ||||||
|         let mut state = Default::default(); |  | ||||||
|         let mut inner = PadAdapter::wrap(f, &mut state); |  | ||||||
| 
 |  | ||||||
|         for instr in &self.instructions { |  | ||||||
|             instr.builder_fmt(&mut inner, builder, debug)?; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if let Some(terminator) = &self.data.terminator { |  | ||||||
|             terminator.builder_fmt(&mut inner, builder, debug)?; |  | ||||||
|         } |  | ||||||
|         if let Some(location) = &self.data.terminator_location { |  | ||||||
|             writeln!(inner, "  ^  (At {}) ", debug.as_ref().unwrap().get_location(location))?; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl InstructionHolder { |  | ||||||
|     fn builder_fmt( |  | ||||||
|         &self, |  | ||||||
|         f: &mut impl std::fmt::Write, |  | ||||||
|         _builder: &Builder, |  | ||||||
|         debug: &Option<DebugInformation>, |  | ||||||
|     ) -> std::fmt::Result { |  | ||||||
|         if let Some(record) = &self.record { |  | ||||||
|             let kind = match record.kind { |  | ||||||
|                 DebugRecordKind::Declare(instruction_value) => { |  | ||||||
|                     format!("= {:?} (Assign)", instruction_value) |  | ||||||
|                 } |  | ||||||
|                 DebugRecordKind::Value(instruction_value) => { |  | ||||||
|                     format!("= {:?} (Value)", instruction_value) |  | ||||||
|                 } |  | ||||||
|             }; |  | ||||||
| 
 |  | ||||||
|             if let Some(debug) = debug { |  | ||||||
|                 writeln!(f, "  (Debug {} {})", record.variable.hr(debug), kind)?; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         writeln!(f, "{:?} ({}) = {:?} ", self.value, self.name, self.data.kind)?; |  | ||||||
|         if let Some(debug) = debug { |  | ||||||
|             if let Some(location) = &self.data.location { |  | ||||||
|                 writeln!(f, "  ^  (At {}) ", debug.get_location(location))?; |  | ||||||
|             } |  | ||||||
|             if let Some(meta) = self.data.meta { |  | ||||||
|                 writeln!(f, "  ^  (Meta {}) ", meta.hr(debug))?; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         writeln!(f)?; |  | ||||||
| 
 |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl TerminatorKind { |  | ||||||
|     fn builder_fmt( |  | ||||||
|         &self, |  | ||||||
|         f: &mut impl std::fmt::Write, |  | ||||||
|         _builder: &Builder, |  | ||||||
|         _debug: &Option<DebugInformation>, |  | ||||||
|     ) -> std::fmt::Result { |  | ||||||
|         match self { |  | ||||||
|             TerminatorKind::Ret(instr) => writeln!(f, "ret {:?}", instr), |  | ||||||
|             TerminatorKind::RetVoid => writeln!(f, "ret void"), |  | ||||||
|             TerminatorKind::Br(block) => writeln!(f, "br {:?}", block), |  | ||||||
|             TerminatorKind::CondBr(instr, lhs, rhs) => { |  | ||||||
|                 writeln!(f, "condbr {:?}, {:?} or {:?}", instr, lhs, rhs) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl DebugMetadataValue { |  | ||||||
|     fn hr(&self, debug: &DebugInformation) -> String { |  | ||||||
|         let kind = match debug.get_metadata(*self) { |  | ||||||
|             DebugMetadata::ParamVar(DebugParamVariable { name, arg_idx, ty, .. }) => { |  | ||||||
|                 format!("param {} (idx {}) (type {:?}) ", name, arg_idx, ty) |  | ||||||
|             } |  | ||||||
|             DebugMetadata::LocalVar(DebugLocalVariable { name, ty, .. }) => { |  | ||||||
|                 format!("var {} (type {:?}) ", name, ty) |  | ||||||
|             } |  | ||||||
|             DebugMetadata::VarAssignment => todo!(), |  | ||||||
|         }; |  | ||||||
|         format!("{} at {}", kind, debug.get_metadata_location(*self)) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Display for DebugLocation { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!(f, "{:?} on scope {:?}", self.pos, self.scope) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Display for DebugPosition { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!(f, "line {}, col {}", self.line, self.column) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for Builder { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         f.debug_list().entries(self.get_modules().borrow().iter()); |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub struct PrintableModule<'ctx> { |  | ||||||
|     pub phantom: PhantomData<&'ctx ()>, |  | ||||||
|     pub module: ModuleHolder, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<'ctx> Debug for PrintableModule<'ctx> { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         Debug::fmt(&self.module, f) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for ModuleHolder { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         f.debug_tuple(&format!("{}({:#?}) ", self.data.name, self.value)) |  | ||||||
|             .field(&self.functions) |  | ||||||
|             // .field(&self.debug_information)
 |  | ||||||
|             .finish() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for FunctionHolder { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         f.debug_tuple(&format!( |  | ||||||
|             "{}({:?}) -> {:?} ", |  | ||||||
|             self.data.name, self.data.params, self.data.ret |  | ||||||
|         )) |  | ||||||
|         .field(&self.blocks) |  | ||||||
|         .finish() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for BlockHolder { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         let deleted = if self.data.deleted { " (deleted)" } else { "" }; |  | ||||||
|         f.debug_tuple(&format!("{}[{:?}]{} ", &self.data.name, &self.value, deleted)) |  | ||||||
|             .field(&self.instructions) |  | ||||||
|             .field(&self.data.terminator) |  | ||||||
|             .field(&self.data.terminator_location) |  | ||||||
|             .finish() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for InstructionHolder { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         self.value.fmt(f)?; |  | ||||||
|         write!(f, " ({})", self.name)?; |  | ||||||
|         f.write_str(" = ")?; |  | ||||||
|         self.data.fmt(f) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for InstructionData { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         self.kind.fmt(f)?; |  | ||||||
|         if let Some(location) = &self.location { |  | ||||||
|             write!(f, " ({:?})", location)?; |  | ||||||
|         } |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for ModuleValue { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!(f, "M[{:0>2}]", self.0) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for FunctionValue { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!(f, "F[{:0>2}-{:0>2}]", &self.0.0, self.1) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for BlockValue { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!(f, "B[{:0>2}-{:0>2}-{:0>2}]", &self.0.0.0, &self.0.1, self.1) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for InstructionValue { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!(f, "%{}.{}.{}.{}", self.0.0.0.0, self.0.0.1, self.0.1, self.1) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // impl Debug for InstructionValue {
 |  | ||||||
| //     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 |  | ||||||
| //         write!(
 |  | ||||||
| //             f,
 |  | ||||||
| //             "I[{:0>2}-{:0>2}-{:0>2}-{:0>2}]",
 |  | ||||||
| //             &self.0.0.0.0, &self.0.0.1, &self.0.1, self.1
 |  | ||||||
| //         )
 |  | ||||||
| //     }
 |  | ||||||
| // }
 |  | ||||||
| 
 |  | ||||||
| impl Debug for TypeValue { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!(f, "Ty[{:0>2}-{:0>2}]", &self.0.0, self.1) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for Instr { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         match self { |  | ||||||
|             Instr::Param(nth) => fmt_call(f, &"Param", &nth), |  | ||||||
|             Instr::Constant(c) => c.fmt(f), |  | ||||||
|             Instr::Add(lhs, rhs) => fmt_binop(f, lhs, &"+", rhs), |  | ||||||
|             Instr::FAdd(lhs, rhs) => fmt_binop(f, lhs, &"+", rhs), |  | ||||||
|             Instr::Sub(lhs, rhs) => fmt_binop(f, lhs, &"-", rhs), |  | ||||||
|             Instr::FSub(lhs, rhs) => fmt_binop(f, lhs, &"-", rhs), |  | ||||||
|             Instr::Mul(lhs, rhs) => fmt_binop(f, lhs, &"*", rhs), |  | ||||||
|             Instr::FMul(lhs, rhs) => fmt_binop(f, lhs, &"*", rhs), |  | ||||||
|             Instr::UDiv(lhs, rhs) => fmt_binop(f, lhs, &"/", rhs), |  | ||||||
|             Instr::SDiv(lhs, rhs) => fmt_binop(f, lhs, &"/", rhs), |  | ||||||
|             Instr::FDiv(lhs, rhs) => fmt_binop(f, lhs, &"/", rhs), |  | ||||||
|             Instr::URem(lhs, rhs) => fmt_binop(f, lhs, &"%", rhs), |  | ||||||
|             Instr::SRem(lhs, rhs) => fmt_binop(f, lhs, &"%", rhs), |  | ||||||
|             Instr::FRem(lhs, rhs) => fmt_binop(f, lhs, &"%", rhs), |  | ||||||
|             Instr::And(lhs, rhs) => fmt_binop(f, lhs, &"&&", rhs), |  | ||||||
|             Instr::Phi(val) => fmt_call(f, &"Phi", &val), |  | ||||||
|             Instr::ICmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs), |  | ||||||
|             Instr::FCmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs), |  | ||||||
|             Instr::FunctionCall(fun, params) => fmt_call(f, fun, params), |  | ||||||
|             Instr::Alloca(ty) => write!(f, "alloca<{:?}>", ty), |  | ||||||
|             Instr::Load(val, ty) => write!(f, "load<{:?}>({:?})", ty, val), |  | ||||||
|             Instr::Store(ptr, val) => write!(f, "store({:?} = {:?})", ptr, val), |  | ||||||
|             Instr::ArrayAlloca(ty, instruction_value) => { |  | ||||||
|                 write!(f, "array_alloca<{:?}>({:?})", ty, instruction_value) |  | ||||||
|             } |  | ||||||
|             Instr::GetElemPtr(instruction_value, items) => fmt_index( |  | ||||||
|                 f, |  | ||||||
|                 instruction_value, |  | ||||||
|                 &items |  | ||||||
|                     .iter() |  | ||||||
|                     .map(|expr| format!("{:?}", expr)) |  | ||||||
|                     .collect::<Vec<_>>() |  | ||||||
|                     .join(", "), |  | ||||||
|             ), |  | ||||||
|             Instr::GetStructElemPtr(instruction_value, index) => { |  | ||||||
|                 write!(f, "GEP(")?; |  | ||||||
|                 fmt_index(f, instruction_value, &index.to_string())?; |  | ||||||
|                 write!(f, ")") |  | ||||||
|             } |  | ||||||
|             Instr::ExtractValue(instruction_value, index) => fmt_index(f, instruction_value, &index.to_string()), |  | ||||||
|             Instr::Trunc(instr_val, ty) => { |  | ||||||
|                 write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) |  | ||||||
|             } |  | ||||||
|             Instr::ZExt(instr_val, ty) => { |  | ||||||
|                 write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) |  | ||||||
|             } |  | ||||||
|             Instr::SExt(instr_val, ty) => { |  | ||||||
|                 write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) |  | ||||||
|             } |  | ||||||
|             Instr::FPTrunc(instr_val, ty) => { |  | ||||||
|                 write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) |  | ||||||
|             } |  | ||||||
|             Instr::FPExt(instr_val, ty) => { |  | ||||||
|                 write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) |  | ||||||
|             } |  | ||||||
|             Instr::FPToUI(instr_val, ty) => { |  | ||||||
|                 write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) |  | ||||||
|             } |  | ||||||
|             Instr::FPToSI(instr_val, ty) => { |  | ||||||
|                 write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) |  | ||||||
|             } |  | ||||||
|             Instr::UIToFP(instr_val, ty) => { |  | ||||||
|                 write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) |  | ||||||
|             } |  | ||||||
|             Instr::SIToFP(instr_val, ty) => { |  | ||||||
|                 write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) |  | ||||||
|             } |  | ||||||
|             Instr::PtrToInt(instr_val, ty) => { |  | ||||||
|                 write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) |  | ||||||
|             } |  | ||||||
|             Instr::IntToPtr(instr_val, ty) => { |  | ||||||
|                 write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) |  | ||||||
|             } |  | ||||||
|             Instr::BitCast(instr_val, ty) => { |  | ||||||
|                 write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name()) |  | ||||||
|             } |  | ||||||
|             Instr::Or(lhs, rhs) => fmt_binop(f, lhs, &"||", rhs), |  | ||||||
|             Instr::XOr(lhs, rhs) => fmt_binop(f, lhs, &"^", rhs), |  | ||||||
|             Instr::ShiftRightLogical(lhs, rhs) => fmt_binop(f, lhs, &">>l", rhs), |  | ||||||
|             Instr::ShiftRightArithmetic(lhs, rhs) => fmt_binop(f, lhs, &">>a", rhs), |  | ||||||
|             Instr::ShiftLeft(lhs, rhs) => fmt_binop(f, lhs, &"<<", rhs), |  | ||||||
|             Instr::GetGlobal(global_value) => write!(f, "global {:?}", global_value), |  | ||||||
|             Instr::IsNull(_) => write!(f, "is_null"), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn fmt_binop( |  | ||||||
|     f: &mut std::fmt::Formatter<'_>, |  | ||||||
|     lhs: &impl std::fmt::Debug, |  | ||||||
|     op: &impl std::fmt::Debug, |  | ||||||
|     rhs: &impl std::fmt::Debug, |  | ||||||
| ) -> std::fmt::Result { |  | ||||||
|     lhs.fmt(f)?; |  | ||||||
|     f.write_char(' ')?; |  | ||||||
|     op.fmt(f)?; |  | ||||||
|     f.write_char(' ')?; |  | ||||||
|     rhs.fmt(f) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn fmt_call( |  | ||||||
|     f: &mut std::fmt::Formatter<'_>, |  | ||||||
|     fun: &impl std::fmt::Debug, |  | ||||||
|     params: &impl std::fmt::Debug, |  | ||||||
| ) -> std::fmt::Result { |  | ||||||
|     fun.fmt(f)?; |  | ||||||
|     f.write_char('(')?; |  | ||||||
|     params.fmt(f)?; |  | ||||||
|     f.write_char(')') |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn fmt_index( |  | ||||||
|     f: &mut std::fmt::Formatter<'_>, |  | ||||||
|     fun: &impl std::fmt::Debug, |  | ||||||
|     params: &impl std::fmt::Debug, |  | ||||||
| ) -> std::fmt::Result { |  | ||||||
|     fun.fmt(f)?; |  | ||||||
|     f.write_char('[')?; |  | ||||||
|     params.fmt(f)?; |  | ||||||
|     f.write_char(']') |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for CmpPredicate { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         match self { |  | ||||||
|             Self::LT => write!(f, "<"), |  | ||||||
|             Self::GT => write!(f, ">"), |  | ||||||
|             Self::LE => write!(f, "<="), |  | ||||||
|             Self::GE => write!(f, ">="), |  | ||||||
|             Self::EQ => write!(f, "=="), |  | ||||||
|             Self::NE => write!(f, "!="), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for TerminatorKind { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         match self { |  | ||||||
|             Self::Ret(val) => { |  | ||||||
|                 write!(f, "Ret ")?; |  | ||||||
|                 val.fmt(f) |  | ||||||
|             } |  | ||||||
|             Self::RetVoid => write!(f, "Void Ret"), |  | ||||||
|             Self::Br(val) => { |  | ||||||
|                 write!(f, "Br ")?; |  | ||||||
|                 val.fmt(f) |  | ||||||
|             } |  | ||||||
|             Self::CondBr(cond, b1, b2) => { |  | ||||||
|                 write!(f, "CondBr ")?; |  | ||||||
|                 cond.fmt(f)?; |  | ||||||
|                 write!(f, " ? ")?; |  | ||||||
|                 b1.fmt(f)?; |  | ||||||
|                 write!(f, " : ")?; |  | ||||||
|                 b2.fmt(f)?; |  | ||||||
|                 Ok(()) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugTypeHolder { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         f.debug_tuple(&format!("DebugTypeHolder {:?}", self.value)) |  | ||||||
|             .field(&self.data) |  | ||||||
|             .finish() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugTypeData { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         match self { |  | ||||||
|             DebugTypeData::Basic(ty) => Debug::fmt(ty, f), |  | ||||||
|             DebugTypeData::Subprogram(ty) => Debug::fmt(ty, f), |  | ||||||
|             DebugTypeData::Pointer(ty) => Debug::fmt(ty, f), |  | ||||||
|             DebugTypeData::Array(ty) => Debug::fmt(ty, f), |  | ||||||
|             DebugTypeData::Struct(ty) => Debug::fmt(ty, f), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugBasicType { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         f.debug_tuple("BasicType") |  | ||||||
|             .field(&self.name) |  | ||||||
|             .field(&self.size_bits) |  | ||||||
|             .field(&self.encoding) |  | ||||||
|             .field(&self.flags) |  | ||||||
|             .finish() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugStructType { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         f.debug_struct("Struct") |  | ||||||
|             .field("name", &self.name) |  | ||||||
|             .field("scope", &self.scope) |  | ||||||
|             .field("pos", &self.pos) |  | ||||||
|             .field("size_bit", &self.size_bits) |  | ||||||
|             .field("flags", &self.flags) |  | ||||||
|             .field("elements", &self.fields) |  | ||||||
|             .finish() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugFieldType { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         f.debug_struct(&format!("Field({})", self.name)) |  | ||||||
|             .field("scope", &self.scope) |  | ||||||
|             .field("pos", &self.pos) |  | ||||||
|             .field("size_bits", &self.size_bits) |  | ||||||
|             .field("offset", &self.offset) |  | ||||||
|             .field("flags", &self.flags) |  | ||||||
|             .field("ty", &self.ty) |  | ||||||
|             .finish() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugSubprogramType { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         f.debug_tuple("Subprogram") |  | ||||||
|             .field(&self.parameters) |  | ||||||
|             .field(&self.flags) |  | ||||||
|             .finish() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugPointerType { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         f.debug_tuple(&format!("Pointer<{:?}>({})", self.pointee, self.name)) |  | ||||||
|             .field(&self.size_bits) |  | ||||||
|             .finish() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugArrayType { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         f.debug_struct(&format!("Array<{:?}>[{}]", self.element_type, self.length)) |  | ||||||
|             .field("size_bits", &self.size_bits) |  | ||||||
|             .field("align_bits", &self.align_bits) |  | ||||||
|             .finish() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugMetadataValue { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!(f, "Meta[{}]", self.0) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugScopeValue { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!( |  | ||||||
|             f, |  | ||||||
|             "Scope[{}]", |  | ||||||
|             self.0.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", ") |  | ||||||
|         ) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugTypeValue { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!(f, "Type[{}]", self.0) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugLocationValue { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!(f, "Value[{:?}][{}]", self.0, self.1) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugLocation { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!(f, "{:?} on scope {:?}", self.pos, self.scope) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Debug for DebugPosition { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         write!(f, "ln {}, col {}", self.line, self.column) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,263 +0,0 @@ | |||||||
| use crate::{CompileResult, Type, TypeCategory, builder::Builder}; |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Debug)] |  | ||||||
| pub enum LLVMIntrinsic { |  | ||||||
|     Abs(Type), |  | ||||||
|     Max(Type), |  | ||||||
|     Min(Type), |  | ||||||
|     Memcpy(Type), |  | ||||||
|     Sqrt(Type), |  | ||||||
|     PowI(Type, Type), |  | ||||||
|     Pow(Type), |  | ||||||
|     Sin(Type), |  | ||||||
|     Cos(Type), |  | ||||||
|     Tan(Type), |  | ||||||
|     ASin(Type), |  | ||||||
|     ACos(Type), |  | ||||||
|     ATan(Type), |  | ||||||
|     ATan2(Type), |  | ||||||
|     SinH(Type), |  | ||||||
|     CosH(Type), |  | ||||||
|     TanH(Type), |  | ||||||
|     Log(Type), |  | ||||||
|     Log2(Type), |  | ||||||
|     Log10(Type), |  | ||||||
|     Copysign(Type), |  | ||||||
|     Floor(Type), |  | ||||||
|     Ceil(Type), |  | ||||||
|     Trunc(Type), |  | ||||||
|     RoundEven(Type), |  | ||||||
|     Round(Type), |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl LLVMIntrinsic { |  | ||||||
|     pub(crate) fn signature(&self, builder: &Builder) -> CompileResult<(String, Vec<Type>, Type)> { |  | ||||||
|         match self { |  | ||||||
|             LLVMIntrinsic::Max(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::SignedInteger => format!("llvm.smax.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     TypeCategory::UnsignedInteger => format!("llvm.umax.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     TypeCategory::Real => format!("llvm.maximum.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone(), ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Min(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::SignedInteger => format!("llvm.smin.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     TypeCategory::UnsignedInteger => format!("llvm.umin.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     TypeCategory::Real => format!("llvm.minimum.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone(), ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Abs(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::SignedInteger => format!("llvm.abs.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     TypeCategory::UnsignedInteger => format!("llvm.abs.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     TypeCategory::Real => format!("llvm.fabs.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone(), Type::Bool], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Memcpy(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Ptr => String::from("llvm.memcpy"), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone(), ty.clone(), Type::U64, Type::Bool], Type::Void)) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Sqrt(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.sqrt.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::PowI(ty1, ty2) => { |  | ||||||
|                 let name = match (ty1.category(), ty2.category()) { |  | ||||||
|                     (TypeCategory::Real, TypeCategory::SignedInteger) => { |  | ||||||
|                         format!("llvm.powi.{}.{}", ty1.llvm_ty_str(builder), ty2.llvm_ty_str(builder)) |  | ||||||
|                     } |  | ||||||
|                     (TypeCategory::Real, TypeCategory::UnsignedInteger) => { |  | ||||||
|                         format!("llvm.powi.{}.{}", ty1.llvm_ty_str(builder), ty2.llvm_ty_str(builder)) |  | ||||||
|                     } |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty1.clone(), ty2.clone()], ty1.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Pow(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.pow.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone(), ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Sin(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.sin.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Cos(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.cos.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Tan(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.tan.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::ASin(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.asin.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::ACos(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.acos.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::ATan(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.atan.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::ATan2(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.atan2.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone(), ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::SinH(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.sinh.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::CosH(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.cosh.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::TanH(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.tanh.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Log(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.log.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Log2(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.log2.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Log10(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.log10.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Copysign(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.copysign.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Floor(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.floor.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Ceil(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.ceil.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Trunc(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.trunc.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::RoundEven(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.roundeven.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|             LLVMIntrinsic::Round(ty) => { |  | ||||||
|                 let name = match ty.category() { |  | ||||||
|                     TypeCategory::Real => format!("llvm.rint.{}", ty.llvm_ty_str(builder)), |  | ||||||
|                     _ => return Err(crate::ErrorKind::Null), |  | ||||||
|                 }; |  | ||||||
|                 Ok((name, vec![ty.clone()], ty.clone())) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Type { |  | ||||||
|     fn llvm_ty_str(&self, builder: &Builder) -> String { |  | ||||||
|         match self { |  | ||||||
|             Type::I8 => String::from("i8"), |  | ||||||
|             Type::I16 => String::from("u16"), |  | ||||||
|             Type::I32 => String::from("i32"), |  | ||||||
|             Type::I64 => String::from("i64"), |  | ||||||
|             Type::I128 => String::from("i128"), |  | ||||||
|             Type::U8 => String::from("i8"), |  | ||||||
|             Type::U16 => String::from("i16"), |  | ||||||
|             Type::U32 => String::from("i32"), |  | ||||||
|             Type::U64 => String::from("i64"), |  | ||||||
|             Type::U128 => String::from("i128"), |  | ||||||
|             Type::F16 => String::from("f16"), |  | ||||||
|             Type::F32B => String::from("f32b"), |  | ||||||
|             Type::F32 => String::from("f32"), |  | ||||||
|             Type::F64 => String::from("f64"), |  | ||||||
|             Type::F80 => String::from("x86_fp80"), |  | ||||||
|             Type::F128 => String::from("fp128"), |  | ||||||
|             Type::F128PPC => String::from("ppc_fp128"), |  | ||||||
|             Type::Bool => String::from("i1"), |  | ||||||
|             Type::Void => String::from("void"), |  | ||||||
|             Type::CustomType(type_value) => { |  | ||||||
|                 let ty = unsafe { builder.type_data(type_value) }; |  | ||||||
|                 ty.name.clone() |  | ||||||
|             } |  | ||||||
|             Type::Array(ty, len) => format!("[{} x {}]", len, ty.llvm_ty_str(builder)), |  | ||||||
|             Type::Ptr(_) => String::from("ptr"), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,741 +0,0 @@ | |||||||
| //! Reid LLVM Lib is an ergonomic Rust'y API which is used to produce a
 |  | ||||||
| //! Low-Level IR (LLIR) using [`Context`] and [`Builder`]. This Builder can then
 |  | ||||||
| //! be used at the end to compile said LLIR into LLVM IR.
 |  | ||||||
| 
 |  | ||||||
| use std::{fmt::Debug, marker::PhantomData}; |  | ||||||
| 
 |  | ||||||
| use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue, TypeValue}; |  | ||||||
| use debug_information::{DebugFileData, DebugInformation, DebugLocationValue, DebugMetadataValue}; |  | ||||||
| use fmt::PrintableModule; |  | ||||||
| 
 |  | ||||||
| use crate::{ |  | ||||||
|     builder::{ConstantValue, GlobalValue}, |  | ||||||
|     debug_information::DebugScopeValue, |  | ||||||
|     intrinsics::LLVMIntrinsic, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| pub mod builder; |  | ||||||
| pub mod compile; |  | ||||||
| pub mod debug_information; |  | ||||||
| mod fmt; |  | ||||||
| pub mod intrinsics; |  | ||||||
| mod pad_adapter; |  | ||||||
| mod util; |  | ||||||
| 
 |  | ||||||
| #[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)] |  | ||||||
| pub enum ErrorKind { |  | ||||||
|     #[error("NULL error, should never occur!")] |  | ||||||
|     Null, |  | ||||||
|     #[error("Types {0:?} and {1:?} incompatible")] |  | ||||||
|     TypesIncompatible(Type, Type), |  | ||||||
|     #[error("Phi list of values is empty")] |  | ||||||
|     EmptyPhiList, |  | ||||||
|     #[error("Type {1:?} of value {0:?} is not extractable")] |  | ||||||
|     NotExtractable(InstructionValue, Type), |  | ||||||
|     #[error("Type {0:?} is not castable to {1:?}")] |  | ||||||
|     ImpossibleCast(Type, Type), |  | ||||||
|     #[error("Block is already terminated")] |  | ||||||
|     BlockAlreadyTerminated, |  | ||||||
|     #[error("Block terminator already has a location")] |  | ||||||
|     BlockTerminatorLocated, |  | ||||||
|     #[error("Value {0:?} must be an integer type. Is {1:?}")] |  | ||||||
|     TypeNotInteger(InstructionValue, Type), |  | ||||||
|     #[error("Value {0:?} must be a {2:?} type. Is {1:?}")] |  | ||||||
|     TypeWrongCategory(InstructionValue, Type, TypeCategory), |  | ||||||
|     #[error("Value {0:?} must be comparable, was {1:?}")] |  | ||||||
|     TypeNotComparable(InstructionValue, Type), |  | ||||||
|     #[error("Got {0:?} parameters, expected {1:?}")] |  | ||||||
|     InvalidLenParams(usize, usize), |  | ||||||
|     #[error("Value {0:?} is not a pointer, is {1:?}")] |  | ||||||
|     NotPointer(InstructionValue, Type), |  | ||||||
|     #[error("Value {0:?} is not a struct, is {1:?}")] |  | ||||||
|     NotStruct(InstructionValue, Type), |  | ||||||
|     #[error("Struct {0:?} has no such field as {1:?}")] |  | ||||||
|     NoSuchField(Type, u32), |  | ||||||
|     #[error("Function {0:?} has no such parameter as {1:?}")] |  | ||||||
|     NoSuchParam(FunctionValue, usize), |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub type CompileResult<T> = Result<T, ErrorKind>; |  | ||||||
| 
 |  | ||||||
| #[derive(Debug)] |  | ||||||
| pub struct Context { |  | ||||||
|     builder: Builder, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Context { |  | ||||||
|     pub fn new<T: Into<String>>(producer: T) -> Context { |  | ||||||
|         Context { |  | ||||||
|             builder: Builder::new(producer.into()), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn module<'ctx>(&'ctx self, name: &str, main: bool) -> Module<'ctx> { |  | ||||||
|         let value = self.builder.add_module(ModuleData { |  | ||||||
|             name: name.to_owned(), |  | ||||||
|             is_main: main, |  | ||||||
|         }); |  | ||||||
|         Module { |  | ||||||
|             phantom: PhantomData, |  | ||||||
|             builder: self.builder.clone(), |  | ||||||
|             value, |  | ||||||
|             debug_info: None, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone, Hash)] |  | ||||||
| pub struct ModuleData { |  | ||||||
|     name: String, |  | ||||||
|     is_main: bool, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct Module<'ctx> { |  | ||||||
|     phantom: PhantomData<&'ctx ()>, |  | ||||||
|     builder: Builder, |  | ||||||
|     value: ModuleValue, |  | ||||||
|     debug_info: Option<DebugInformation>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<'ctx> Module<'ctx> { |  | ||||||
|     pub fn function( |  | ||||||
|         &self, |  | ||||||
|         name: &str, |  | ||||||
|         linkage: Option<String>, |  | ||||||
|         ret: Type, |  | ||||||
|         params: Vec<Type>, |  | ||||||
|         flags: FunctionFlags, |  | ||||||
|     ) -> Function<'ctx> { |  | ||||||
|         unsafe { |  | ||||||
|             Function { |  | ||||||
|                 phantom: PhantomData, |  | ||||||
|                 builder: self.builder.clone(), |  | ||||||
|                 value: self.builder.add_function( |  | ||||||
|                     &self.value, |  | ||||||
|                     FunctionData { |  | ||||||
|                         name: name.to_owned(), |  | ||||||
|                         linkage_name: linkage, |  | ||||||
|                         ret, |  | ||||||
|                         params, |  | ||||||
|                         flags, |  | ||||||
|                     }, |  | ||||||
|                 ), |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn intrinsic(&self, intrinsic: LLVMIntrinsic) -> CompileResult<FunctionValue> { |  | ||||||
|         unsafe { |  | ||||||
|             let (name, params, ret) = intrinsic.signature(&self.builder)?; |  | ||||||
|             Ok(self.builder.add_function( |  | ||||||
|                 &self.value, |  | ||||||
|                 FunctionData { |  | ||||||
|                     name: name.to_owned(), |  | ||||||
|                     linkage_name: Some(name.to_owned()), |  | ||||||
|                     ret, |  | ||||||
|                     params, |  | ||||||
|                     flags: FunctionFlags { |  | ||||||
|                         is_extern: true, |  | ||||||
|                         ..Default::default() |  | ||||||
|                     }, |  | ||||||
|                 }, |  | ||||||
|             )) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn custom_type(&self, ty: CustomTypeKind) -> TypeValue { |  | ||||||
|         unsafe { |  | ||||||
|             let (name, kind) = match &ty { |  | ||||||
|                 CustomTypeKind::NamedStruct(NamedStruct(name, _)) => (name.clone(), ty), |  | ||||||
|             }; |  | ||||||
|             self.builder.add_type(&self.value, TypeData { name, kind }) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn value(&self) -> ModuleValue { |  | ||||||
|         self.value |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn as_printable(&self) -> PrintableModule<'ctx> { |  | ||||||
|         PrintableModule { |  | ||||||
|             phantom: PhantomData, |  | ||||||
|             module: self.builder.find_module(self.value), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn create_debug_info(&mut self, file: DebugFileData) -> (DebugInformation, DebugScopeValue) { |  | ||||||
|         let (debug_info, scope_value) = DebugInformation::from_file(file); |  | ||||||
|         self.debug_info = Some(debug_info.clone()); |  | ||||||
|         (debug_info, scope_value) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn get_debug_info(&self) -> &Option<DebugInformation> { |  | ||||||
|         &self.debug_info |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn add_constant(&self, constant: ConstValueKind) -> ConstantValue { |  | ||||||
|         unsafe { self.builder.build_constant(self.value, constant) } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn add_global<T: Into<String>>(&self, name: T, constant: ConstantValue) -> GlobalValue { |  | ||||||
|         unsafe { self.builder.add_global(self.value, name.into(), constant) } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<'ctx> Drop for Module<'ctx> { |  | ||||||
|     fn drop(&mut self) { |  | ||||||
|         if let Some(debug_info) = self.debug_info.take() { |  | ||||||
|             self.builder.set_debug_information(&self.value, debug_info); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone, Hash)] |  | ||||||
| pub struct FunctionData { |  | ||||||
|     name: String, |  | ||||||
|     linkage_name: Option<String>, |  | ||||||
|     ret: Type, |  | ||||||
|     params: Vec<Type>, |  | ||||||
|     flags: FunctionFlags, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone, Copy, Hash)] |  | ||||||
| pub struct FunctionFlags { |  | ||||||
|     /// True in the destination module of the import, false in the source module.
 |  | ||||||
|     pub is_extern: bool, |  | ||||||
|     /// Whether this function is the main function of the module, that should be
 |  | ||||||
|     /// executed (and linked externally also).
 |  | ||||||
|     pub is_main: bool, |  | ||||||
|     /// Whether this function should be available externally always.
 |  | ||||||
|     pub is_pub: bool, |  | ||||||
|     /// If this function is an imported function (either in the source or
 |  | ||||||
|     /// destination module)
 |  | ||||||
|     pub is_imported: bool, |  | ||||||
|     /// Whether this function should add "alwaysinline"-attribute.
 |  | ||||||
|     pub inline: bool, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Default for FunctionFlags { |  | ||||||
|     fn default() -> FunctionFlags { |  | ||||||
|         FunctionFlags { |  | ||||||
|             is_extern: false, |  | ||||||
|             is_main: false, |  | ||||||
|             is_pub: false, |  | ||||||
|             is_imported: false, |  | ||||||
|             inline: false, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub struct Function<'ctx> { |  | ||||||
|     phantom: PhantomData<&'ctx ()>, |  | ||||||
|     builder: Builder, |  | ||||||
|     value: FunctionValue, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<'ctx> Function<'ctx> { |  | ||||||
|     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, |  | ||||||
|                         terminator_location: None, |  | ||||||
|                         deleted: false, |  | ||||||
|                     }, |  | ||||||
|                 ), |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn set_debug(&self, subprogram: DebugScopeValue) { |  | ||||||
|         unsafe { |  | ||||||
|             self.builder.set_debug_subprogram(&self.value, subprogram); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn value(&self) -> FunctionValue { |  | ||||||
|         self.value |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone, Hash)] |  | ||||||
| pub struct BlockData { |  | ||||||
|     name: String, |  | ||||||
|     terminator: Option<TerminatorKind>, |  | ||||||
|     terminator_location: Option<DebugLocationValue>, |  | ||||||
|     deleted: bool, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct Block<'builder> { |  | ||||||
|     phantom: PhantomData<&'builder ()>, |  | ||||||
|     builder: Builder, |  | ||||||
|     value: BlockValue, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Instr { |  | ||||||
|     pub fn default_name(&self) -> &str { |  | ||||||
|         match self { |  | ||||||
|             Instr::Param(_) => "param", |  | ||||||
|             Instr::Constant(_) => "const1", |  | ||||||
|             Instr::Add(..) => "add", |  | ||||||
|             Instr::FAdd(..) => "fadd", |  | ||||||
|             Instr::Sub(..) => "sub", |  | ||||||
|             Instr::FSub(..) => "fsub", |  | ||||||
|             Instr::Mul(..) => "mul", |  | ||||||
|             Instr::FMul(..) => "fmul", |  | ||||||
|             Instr::UDiv(..) => "udiv", |  | ||||||
|             Instr::SDiv(..) => "sdiv", |  | ||||||
|             Instr::FDiv(..) => "fdiv", |  | ||||||
|             Instr::URem(..) => "urem", |  | ||||||
|             Instr::SRem(..) => "srem", |  | ||||||
|             Instr::FRem(..) => "frem", |  | ||||||
|             Instr::And(..) => "and", |  | ||||||
|             Instr::Phi(_) => "phi", |  | ||||||
|             Instr::Alloca(_) => "alloca", |  | ||||||
|             Instr::Load(_, _) => "load", |  | ||||||
|             Instr::Store(..) => "store", |  | ||||||
|             Instr::ArrayAlloca(_, _) => "arrayalloca", |  | ||||||
|             Instr::GetElemPtr(..) => "getelemptr", |  | ||||||
|             Instr::GetStructElemPtr(..) => "getstructelemptr", |  | ||||||
|             Instr::ExtractValue(..) => "extractvalue", |  | ||||||
|             Instr::ICmp(..) => "icmp", |  | ||||||
|             Instr::FunctionCall(..) => "call", |  | ||||||
|             Instr::FCmp(_, _, _) => "fcmp", |  | ||||||
|             Instr::Trunc(_, _) => "trunc", |  | ||||||
|             Instr::ZExt(_, _) => "zext", |  | ||||||
|             Instr::SExt(_, _) => "sext", |  | ||||||
|             Instr::FPTrunc(_, _) => "fptrunc", |  | ||||||
|             Instr::FPExt(_, _) => "pfext", |  | ||||||
|             Instr::FPToUI(_, _) => "fptoui", |  | ||||||
|             Instr::FPToSI(_, _) => "fptosi", |  | ||||||
|             Instr::UIToFP(_, _) => "uitofp", |  | ||||||
|             Instr::SIToFP(_, _) => "sitofp", |  | ||||||
|             Instr::PtrToInt(_, _) => "ptrtoint", |  | ||||||
|             Instr::IntToPtr(_, _) => "inttoptr", |  | ||||||
|             Instr::BitCast(_, _) => "bitcast", |  | ||||||
|             Instr::Or(..) => "or", |  | ||||||
|             Instr::XOr(..) => "xor", |  | ||||||
|             Instr::ShiftRightLogical(..) => "lshr", |  | ||||||
|             Instr::ShiftRightArithmetic(..) => "ashr", |  | ||||||
|             Instr::ShiftLeft(..) => "shl", |  | ||||||
|             Instr::GetGlobal(..) => "global", |  | ||||||
|             Instr::IsNull(..) => "is_null", |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<'builder> Block<'builder> { |  | ||||||
|     pub fn build_named<T: Into<String>>(&mut self, name: T, instruction: Instr) -> CompileResult<InstructionValue> { |  | ||||||
|         unsafe { |  | ||||||
|             self.builder.add_instruction( |  | ||||||
|                 &self.value, |  | ||||||
|                 InstructionData { |  | ||||||
|                     kind: instruction, |  | ||||||
|                     location: None, |  | ||||||
|                     meta: None, |  | ||||||
|                 }, |  | ||||||
|                 name.into(), |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn build(&mut self, instruction: Instr) -> CompileResult<InstructionValue> { |  | ||||||
|         unsafe { |  | ||||||
|             let name = instruction.default_name().to_owned(); |  | ||||||
|             self.builder.add_instruction( |  | ||||||
|                 &self.value, |  | ||||||
|                 InstructionData { |  | ||||||
|                     kind: instruction, |  | ||||||
|                     location: None, |  | ||||||
|                     meta: None, |  | ||||||
|                 }, |  | ||||||
|                 name, |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn find_function(&mut self, name: &String) -> Option<FunctionValue> { |  | ||||||
|         unsafe { self.builder.find_function(self.value.0.0, name) } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn set_instr_location(&self, instruction: InstructionValue, location: DebugLocationValue) { |  | ||||||
|         unsafe { |  | ||||||
|             self.builder.add_instruction_location(&instruction, location); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn set_instr_metadata(&self, instruction: InstructionValue, location: DebugMetadataValue) { |  | ||||||
|         unsafe { |  | ||||||
|             self.builder.add_instruction_metadata(&instruction, location); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn terminate(&mut self, instruction: TerminatorKind) -> CompileResult<()> { |  | ||||||
|         unsafe { self.builder.terminate(&self.value, instruction) } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn set_terminator_location(&mut self, location: DebugLocationValue) -> CompileResult<()> { |  | ||||||
|         unsafe { self.builder.set_terminator_location(&self.value, location) } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Delete block if it is unused. Return true if deleted, false if not.
 |  | ||||||
|     pub fn delete_if_unused(&mut self) -> CompileResult<bool> { |  | ||||||
|         unsafe { |  | ||||||
|             if !self.builder.is_block_used(self.value()) { |  | ||||||
|                 self.builder.delete_block(&self.value)?; |  | ||||||
|                 Ok(true) |  | ||||||
|             } else { |  | ||||||
|                 Ok(false) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn value(&self) -> BlockValue { |  | ||||||
|         self.value |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub struct InstructionData { |  | ||||||
|     kind: Instr, |  | ||||||
|     location: Option<DebugLocationValue>, |  | ||||||
|     meta: Option<DebugMetadataValue>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Copy, Hash)] |  | ||||||
| pub enum CmpPredicate { |  | ||||||
|     LT, |  | ||||||
|     LE, |  | ||||||
|     GT, |  | ||||||
|     GE, |  | ||||||
|     EQ, |  | ||||||
|     NE, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// https://llvm.org/docs/LangRef.html#instruction-reference
 |  | ||||||
| #[derive(Clone)] |  | ||||||
| pub enum Instr { |  | ||||||
|     Param(usize), |  | ||||||
|     Constant(ConstValueKind), |  | ||||||
|     GetGlobal(GlobalValue), |  | ||||||
| 
 |  | ||||||
|     /// Add two integers
 |  | ||||||
|     Add(InstructionValue, InstructionValue), |  | ||||||
|     /// Add two floats
 |  | ||||||
|     FAdd(InstructionValue, InstructionValue), |  | ||||||
|     /// Subtract two integers
 |  | ||||||
|     Sub(InstructionValue, InstructionValue), |  | ||||||
|     /// Subtract two floats
 |  | ||||||
|     FSub(InstructionValue, InstructionValue), |  | ||||||
|     /// Multiply two integers
 |  | ||||||
|     Mul(InstructionValue, InstructionValue), |  | ||||||
|     /// Multiply two floats
 |  | ||||||
|     FMul(InstructionValue, InstructionValue), |  | ||||||
|     /// Divide two unsigned integers
 |  | ||||||
|     UDiv(InstructionValue, InstructionValue), |  | ||||||
|     /// Divide two signed integers
 |  | ||||||
|     SDiv(InstructionValue, InstructionValue), |  | ||||||
|     /// Divide two floats
 |  | ||||||
|     FDiv(InstructionValue, InstructionValue), |  | ||||||
|     /// Get the remainder from two unsigned integers
 |  | ||||||
|     URem(InstructionValue, InstructionValue), |  | ||||||
|     /// Get the remainder from two signed integers
 |  | ||||||
|     SRem(InstructionValue, InstructionValue), |  | ||||||
|     /// Get the remainder from two floats
 |  | ||||||
|     FRem(InstructionValue, InstructionValue), |  | ||||||
| 
 |  | ||||||
|     And(InstructionValue, InstructionValue), |  | ||||||
|     Or(InstructionValue, InstructionValue), |  | ||||||
|     XOr(InstructionValue, InstructionValue), |  | ||||||
|     ShiftRightLogical(InstructionValue, InstructionValue), |  | ||||||
|     ShiftRightArithmetic(InstructionValue, InstructionValue), |  | ||||||
|     ShiftLeft(InstructionValue, InstructionValue), |  | ||||||
| 
 |  | ||||||
|     Phi(Vec<InstructionValue>), |  | ||||||
| 
 |  | ||||||
|     Alloca(Type), |  | ||||||
|     Load(InstructionValue, Type), |  | ||||||
|     Store(InstructionValue, InstructionValue), |  | ||||||
|     ArrayAlloca(Type, InstructionValue), |  | ||||||
|     GetElemPtr(InstructionValue, Vec<InstructionValue>), |  | ||||||
|     GetStructElemPtr(InstructionValue, u32), |  | ||||||
|     ExtractValue(InstructionValue, u32), |  | ||||||
| 
 |  | ||||||
|     /// Integer Comparison
 |  | ||||||
|     ICmp(CmpPredicate, InstructionValue, InstructionValue), |  | ||||||
|     /// FLoat Comparison
 |  | ||||||
|     FCmp(CmpPredicate, InstructionValue, InstructionValue), |  | ||||||
| 
 |  | ||||||
|     /// The `trunc` instruction truncates the high order bits in value and
 |  | ||||||
|     /// converts the remaining bits to ty2. Since the source size must be larger
 |  | ||||||
|     /// than the destination size, `trunc` cannot be a no-op cast. It will
 |  | ||||||
|     /// always truncate bits.
 |  | ||||||
|     Trunc(InstructionValue, Type), |  | ||||||
|     /// The `zext` fills the high order bits of the value with zero bits until
 |  | ||||||
|     /// it reaches the size of the destination type, ty2.
 |  | ||||||
|     ZExt(InstructionValue, Type), |  | ||||||
|     /// The `sext` instruction performs a sign extension by copying the sign bit
 |  | ||||||
|     /// (highest order bit) of the value until it reaches the bit size of the
 |  | ||||||
|     /// type ty2.
 |  | ||||||
|     SExt(InstructionValue, Type), |  | ||||||
|     /// The `fptrunc` instruction casts a value from a larger floating-point
 |  | ||||||
|     /// type to a smaller floating-point type.
 |  | ||||||
|     FPTrunc(InstructionValue, Type), |  | ||||||
|     /// The `fpext` instruction extends the value from a smaller floating-point
 |  | ||||||
|     /// type to a larger floating-point type.
 |  | ||||||
|     FPExt(InstructionValue, Type), |  | ||||||
|     /// The `fptoui` instruction takes a value to cast, which must be a scalar
 |  | ||||||
|     /// or vector floating-point value, and a type to cast it to ty2, which must
 |  | ||||||
|     /// be an integer type.
 |  | ||||||
|     FPToUI(InstructionValue, Type), |  | ||||||
|     /// The `fptosi` instruction takes a value to cast, which must be a scalar
 |  | ||||||
|     /// or vector floating-point value, and a type to cast it to ty2, which must
 |  | ||||||
|     /// be an integer type.
 |  | ||||||
|     FPToSI(InstructionValue, Type), |  | ||||||
|     /// The `uitofp` instruction takes a value to cast, which must be a scalar
 |  | ||||||
|     /// or vector integer value, and a type to cast it to ty2, which must be an
 |  | ||||||
|     /// floating-point type.
 |  | ||||||
|     UIToFP(InstructionValue, Type), |  | ||||||
|     /// The `sitofp` instruction takes a value to cast, which must be a scalar
 |  | ||||||
|     /// or vector integer value, and a type to cast it to ty2, which must be an
 |  | ||||||
|     /// floating-point type
 |  | ||||||
|     SIToFP(InstructionValue, Type), |  | ||||||
|     /// The `ptrtoint` instruction converts value to integer type ty2 by
 |  | ||||||
|     /// interpreting the all pointer representation bits as an integer
 |  | ||||||
|     /// (equivalent to a bitcast) and either truncating or zero extending that
 |  | ||||||
|     /// value to the size of the integer type.
 |  | ||||||
|     PtrToInt(InstructionValue, Type), |  | ||||||
|     /// The `inttoptr` instruction converts value to type ty2 by applying either
 |  | ||||||
|     /// a zero extension or a truncation depending on the size of the integer
 |  | ||||||
|     /// value.
 |  | ||||||
|     IntToPtr(InstructionValue, Type), |  | ||||||
|     /// The `bitcast` instruction converts value to type ty2. It is always a
 |  | ||||||
|     /// no-op cast because no bits change with this conversion.
 |  | ||||||
|     BitCast(InstructionValue, Type), |  | ||||||
| 
 |  | ||||||
|     /// Check if the given instruction value is a null pointer
 |  | ||||||
|     IsNull(InstructionValue), |  | ||||||
| 
 |  | ||||||
|     FunctionCall(FunctionValue, Vec<InstructionValue>), |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd)] |  | ||||||
| pub enum Type { |  | ||||||
|     I8, |  | ||||||
|     I16, |  | ||||||
|     I32, |  | ||||||
|     I64, |  | ||||||
|     I128, |  | ||||||
|     U8, |  | ||||||
|     U16, |  | ||||||
|     U32, |  | ||||||
|     U64, |  | ||||||
|     U128, |  | ||||||
|     F16, |  | ||||||
|     F32B, |  | ||||||
|     F32, |  | ||||||
|     F64, |  | ||||||
|     F80, |  | ||||||
|     F128, |  | ||||||
|     F128PPC, |  | ||||||
|     Bool, |  | ||||||
|     Void, |  | ||||||
|     CustomType(TypeValue), |  | ||||||
|     Array(Box<Type>, u64), |  | ||||||
|     Ptr(Box<Type>), |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| pub enum ConstValueKind { |  | ||||||
|     I8(i8), |  | ||||||
|     I16(i16), |  | ||||||
|     I32(i32), |  | ||||||
|     I64(i64), |  | ||||||
|     I128(i128), |  | ||||||
|     U8(u8), |  | ||||||
|     U16(u16), |  | ||||||
|     U32(u32), |  | ||||||
|     U64(u64), |  | ||||||
|     U128(u128), |  | ||||||
|     Bool(bool), |  | ||||||
|     Str(String), |  | ||||||
|     F16(f32), |  | ||||||
|     F32B(f32), |  | ||||||
|     F32(f32), |  | ||||||
|     F64(f64), |  | ||||||
|     F80(f64), |  | ||||||
|     F128(f64), |  | ||||||
|     F128PPC(f64), |  | ||||||
|     Array(Vec<ConstantValue>, Type), |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Clone, Hash)] |  | ||||||
| pub enum TerminatorKind { |  | ||||||
|     Ret(InstructionValue), |  | ||||||
|     RetVoid, |  | ||||||
|     Br(BlockValue), |  | ||||||
|     CondBr(InstructionValue, BlockValue, BlockValue), |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, PartialEq, Eq, Clone, Hash)] |  | ||||||
| pub struct TypeData { |  | ||||||
|     name: String, |  | ||||||
|     kind: CustomTypeKind, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, PartialEq, Eq, Clone, Hash)] |  | ||||||
| pub enum CustomTypeKind { |  | ||||||
|     NamedStruct(NamedStruct), |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, PartialEq, Eq, Clone, Hash)] |  | ||||||
| pub struct NamedStruct(pub String, pub Vec<Type>); |  | ||||||
| 
 |  | ||||||
| impl ConstValueKind { |  | ||||||
|     pub fn get_type(&self) -> Type { |  | ||||||
|         use Type::*; |  | ||||||
|         match self { |  | ||||||
|             ConstValueKind::I8(_) => I8, |  | ||||||
|             ConstValueKind::I16(_) => I16, |  | ||||||
|             ConstValueKind::I32(_) => I32, |  | ||||||
|             ConstValueKind::I64(_) => I64, |  | ||||||
|             ConstValueKind::I128(_) => I128, |  | ||||||
|             ConstValueKind::U8(_) => U8, |  | ||||||
|             ConstValueKind::U16(_) => U16, |  | ||||||
|             ConstValueKind::U32(_) => U32, |  | ||||||
|             ConstValueKind::U64(_) => U64, |  | ||||||
|             ConstValueKind::U128(_) => U128, |  | ||||||
|             ConstValueKind::Str(_) => Type::Ptr(Box::new(U8)), |  | ||||||
|             ConstValueKind::Bool(_) => Bool, |  | ||||||
|             ConstValueKind::F16(_) => F16, |  | ||||||
|             ConstValueKind::F32B(_) => F32B, |  | ||||||
|             ConstValueKind::F32(_) => F32, |  | ||||||
|             ConstValueKind::F64(_) => F64, |  | ||||||
|             ConstValueKind::F80(_) => F80, |  | ||||||
|             ConstValueKind::F128(_) => F128, |  | ||||||
|             ConstValueKind::F128PPC(_) => F128PPC, |  | ||||||
|             ConstValueKind::Array(vals, ty) => Type::Array(Box::new(ty.clone()), vals.len() as u64), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone)] |  | ||||||
| pub enum TypeCategory { |  | ||||||
|     SignedInteger, |  | ||||||
|     UnsignedInteger, |  | ||||||
|     Void, |  | ||||||
|     Real, |  | ||||||
|     Ptr, |  | ||||||
|     CustomType, |  | ||||||
|     Array, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl TypeCategory { |  | ||||||
|     pub fn comparable(&self) -> bool { |  | ||||||
|         match self { |  | ||||||
|             TypeCategory::SignedInteger => true, |  | ||||||
|             TypeCategory::UnsignedInteger => true, |  | ||||||
|             TypeCategory::Real => true, |  | ||||||
|             _ => false, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn signed(&self) -> bool { |  | ||||||
|         match self { |  | ||||||
|             TypeCategory::SignedInteger => true, |  | ||||||
|             _ => false, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn integer(&self) -> bool { |  | ||||||
|         match self { |  | ||||||
|             TypeCategory::SignedInteger => true, |  | ||||||
|             TypeCategory::UnsignedInteger => true, |  | ||||||
|             _ => false, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Type { |  | ||||||
|     pub fn category(&self) -> TypeCategory { |  | ||||||
|         match self { |  | ||||||
|             Type::I8 | Type::I16 | Type::I32 | Type::I64 | Type::I128 => TypeCategory::SignedInteger, |  | ||||||
|             Type::U8 | Type::U16 | Type::U32 | Type::U64 | Type::U128 => TypeCategory::UnsignedInteger, |  | ||||||
|             Type::F16 | Type::F32B | Type::F32 | Type::F64 | Type::F80 | Type::F128 | Type::F128PPC => { |  | ||||||
|                 TypeCategory::Real |  | ||||||
|             } |  | ||||||
|             Type::Bool => TypeCategory::UnsignedInteger, |  | ||||||
|             Type::Void => TypeCategory::Void, |  | ||||||
|             Type::CustomType(_) => TypeCategory::CustomType, |  | ||||||
|             Type::Array(_, _) => TypeCategory::Array, |  | ||||||
|             Type::Ptr(_) => TypeCategory::Ptr, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn cast_instruction(&self, value: InstructionValue, other: &Type) -> Option<Instr> { |  | ||||||
|         use Type::*; |  | ||||||
|         match (self, other) { |  | ||||||
|             (I8, I16 | I32 | I64 | I128) => Some(Instr::SExt(value, other.clone())), |  | ||||||
|             (I16, I32 | I64 | I128) => Some(Instr::SExt(value, other.clone())), |  | ||||||
|             (I32, I64 | I128) => Some(Instr::SExt(value, other.clone())), |  | ||||||
|             (I64, I128) => Some(Instr::SExt(value, other.clone())), |  | ||||||
|             (I128 | U128, I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())), |  | ||||||
|             (I64 | U64, I32 | U32 | I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())), |  | ||||||
|             (I32 | U32, I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())), |  | ||||||
|             (I16 | U16, I8 | U8) => Some(Instr::Trunc(value, other.clone())), |  | ||||||
|             (U8 | I8, U8 | I8 | U16 | I16 | U32 | I32 | U64 | I64 | U128 | I128) => { |  | ||||||
|                 Some(Instr::ZExt(value, other.clone())) |  | ||||||
|             } |  | ||||||
|             (U16 | I16, U16 | I16 | U32 | I32 | U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())), |  | ||||||
|             (U32 | I32, U32 | I32 | U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())), |  | ||||||
|             (U64 | I64, U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())), |  | ||||||
|             (U128 | I128, U128 | I128) => Some(Instr::ZExt(value, other.clone())), |  | ||||||
|             (U8 | U16 | U32 | U64 | U128, F16 | F32 | F32B | F64 | F80 | F128 | F128PPC) => { |  | ||||||
|                 Some(Instr::UIToFP(value, other.clone())) |  | ||||||
|             } |  | ||||||
|             (I8 | I16 | I32 | I64 | I128, F16 | F32 | F32B | F64 | F80 | F128 | F128PPC) => { |  | ||||||
|                 Some(Instr::SIToFP(value, other.clone())) |  | ||||||
|             } |  | ||||||
|             (F16 | F32 | F32B | F64 | F80 | F128 | F128PPC, U8 | U16 | U32 | U64 | U128) => { |  | ||||||
|                 Some(Instr::FPToUI(value, other.clone())) |  | ||||||
|             } |  | ||||||
|             (F16 | F32 | F32B | F64 | F80 | F128 | F128PPC, I8 | I16 | I32 | I64 | I128) => { |  | ||||||
|                 Some(Instr::FPToSI(value, other.clone())) |  | ||||||
|             } |  | ||||||
|             (I128 | U128 | I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8, Ptr(_)) => { |  | ||||||
|                 Some(Instr::IntToPtr(value, other.clone())) |  | ||||||
|             } |  | ||||||
|             (Ptr(_), I128 | U128 | I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8) => { |  | ||||||
|                 Some(Instr::PtrToInt(value, other.clone())) |  | ||||||
|             } |  | ||||||
|             (F16, F32 | F32B | F64 | F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())), |  | ||||||
|             (F32 | F32B, F64 | F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())), |  | ||||||
|             (F64, F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())), |  | ||||||
|             (F80, F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())), |  | ||||||
|             (F128PPC | F128, F80 | F64 | F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())), |  | ||||||
|             (F80, F64 | F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())), |  | ||||||
|             (F64, F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())), |  | ||||||
|             (F32B | F32, F16) => Some(Instr::FPTrunc(value, other.clone())), |  | ||||||
|             _ => None, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl TerminatorKind { |  | ||||||
|     pub(crate) fn get_type(&self, builder: &Builder) -> CompileResult<Type> { |  | ||||||
|         use TerminatorKind::*; |  | ||||||
|         match self { |  | ||||||
|             Ret(instr_val) => instr_val.get_type(builder), |  | ||||||
|             RetVoid => Ok(Type::Void), |  | ||||||
|             Br(_) => Ok(Type::Void), |  | ||||||
|             CondBr(_, _, _) => Ok(Type::Void), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,69 +0,0 @@ | |||||||
| //! Copied from
 |  | ||||||
| //! https://github.com/rust-lang/rust/blob/6b3ae3f6e45a33c2d95fa0362c9b2593e567fd34/library/core/src/fmt/builders.rs#L102
 |  | ||||||
| 
 |  | ||||||
| // Copyright (c) The Rust Project Contributors
 |  | ||||||
| //
 |  | ||||||
| // Permission is hereby granted, free of charge, to any person obtaining a copy
 |  | ||||||
| // of this software and associated documentation files (the "Software"), to deal
 |  | ||||||
| // in the Software without restriction, including without limitation the rights
 |  | ||||||
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 |  | ||||||
| // copies of the Software, and to permit persons to whom the Software is
 |  | ||||||
| // furnished to do so, subject to the following conditions:
 |  | ||||||
| //
 |  | ||||||
| // The above copyright notice and this permission notice shall be included in
 |  | ||||||
| // all copies or substantial portions of the Software.
 |  | ||||||
| //
 |  | ||||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 |  | ||||||
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 |  | ||||||
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 |  | ||||||
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 |  | ||||||
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 |  | ||||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 |  | ||||||
| // SOFTWARE.
 |  | ||||||
| 
 |  | ||||||
| use std::fmt; |  | ||||||
| 
 |  | ||||||
| pub struct PadAdapter<'buf, 'state> { |  | ||||||
|     buf: &'buf mut (dyn fmt::Write + 'buf), |  | ||||||
|     state: &'state mut PadAdapterState, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub struct PadAdapterState { |  | ||||||
|     on_newline: bool, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Default for PadAdapterState { |  | ||||||
|     fn default() -> Self { |  | ||||||
|         PadAdapterState { on_newline: true } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<'buf, 'state> PadAdapter<'buf, 'state> { |  | ||||||
|     pub fn wrap<'slot, 'fmt: 'buf + 'slot>( |  | ||||||
|         fmt: &'buf mut (dyn fmt::Write + 'buf), |  | ||||||
|         state: &'state mut PadAdapterState, |  | ||||||
|     ) -> Self { |  | ||||||
|         PadAdapter { buf: fmt, state } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl fmt::Write for PadAdapter<'_, '_> { |  | ||||||
|     fn write_str(&mut self, s: &str) -> fmt::Result { |  | ||||||
|         for s in s.split_inclusive('\n') { |  | ||||||
|             if self.state.on_newline { |  | ||||||
|                 self.buf.write_str("    ")?; |  | ||||||
|             } |  | ||||||
|             self.state.on_newline = s.ends_with('\n'); |  | ||||||
|             self.buf.write_str(s)?; |  | ||||||
|         } |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn write_char(&mut self, c: char) -> fmt::Result { |  | ||||||
|         if self.state.on_newline { |  | ||||||
|             self.buf.write_str("    ")?; |  | ||||||
|         } |  | ||||||
|         self.state.on_newline = c == '\n'; |  | ||||||
|         self.buf.write_char(c) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,115 +0,0 @@ | |||||||
| use std::{ |  | ||||||
|     ffi::{CStr, CString, c_char}, |  | ||||||
|     ptr::null_mut, |  | ||||||
|     string::FromUtf8Error, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| use llvm_sys::{ |  | ||||||
|     core::{LLVMCreateMemoryBufferWithMemoryRange, LLVMDisposeMemoryBuffer, LLVMGetBufferSize, LLVMGetBufferStart}, |  | ||||||
|     error::LLVMDisposeErrorMessage, |  | ||||||
|     prelude::LLVMMemoryBufferRef, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| use crate::{ |  | ||||||
|     CompileResult, ErrorKind, Type, |  | ||||||
|     builder::{Builder, InstructionValue}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| pub fn into_cstring<T: Into<String>>(value: T) -> CString { |  | ||||||
|     let string = value.into(); |  | ||||||
|     unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub fn from_cstring(pointer: *mut c_char) -> Option<String> { |  | ||||||
|     if pointer.is_null() { |  | ||||||
|         None |  | ||||||
|     } else { |  | ||||||
|         unsafe { CStr::from_ptr(pointer).to_str().ok().map(|s| s.to_owned()) } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn cstring_to_err(value: *mut c_char) -> Result<(), String> { |  | ||||||
|     from_cstring(value).filter(|s| !s.is_empty()).map_or(Ok(()), |s| Err(s)) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Utility struct for LLVM's Error Messages, which need to be disposed
 |  | ||||||
| /// manually.
 |  | ||||||
| pub struct ErrorMessageHolder(*mut c_char); |  | ||||||
| 
 |  | ||||||
| impl ErrorMessageHolder { |  | ||||||
|     pub fn null() -> Self { |  | ||||||
|         ErrorMessageHolder(null_mut()) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn borrow_mut(&mut self) -> *mut *mut c_char { |  | ||||||
|         &mut self.0 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn into_result(&self) -> Result<(), String> { |  | ||||||
|         cstring_to_err(self.0) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Drop for ErrorMessageHolder { |  | ||||||
|     fn drop(&mut self) { |  | ||||||
|         unsafe { |  | ||||||
|             if !self.0.is_null() { |  | ||||||
|                 LLVMDisposeErrorMessage(self.0); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Utility for creating and handling LLVM MemoryBuffers, needed for printing
 |  | ||||||
| /// out ASM and .o -files without relying on LLVM's own API.
 |  | ||||||
| pub struct MemoryBufferHolder { |  | ||||||
|     pub buffer: LLVMMemoryBufferRef, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl MemoryBufferHolder { |  | ||||||
|     pub fn empty(name: &str) -> MemoryBufferHolder { |  | ||||||
|         let array = [0i8; 0]; |  | ||||||
|         unsafe { |  | ||||||
|             let buffer = |  | ||||||
|                 LLVMCreateMemoryBufferWithMemoryRange(array.as_ptr(), array.len(), into_cstring(name).as_ptr(), 0); |  | ||||||
|             MemoryBufferHolder { buffer } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn as_buffer(&self) -> Vec<u8> { |  | ||||||
|         unsafe { |  | ||||||
|             let start = LLVMGetBufferStart(self.buffer); |  | ||||||
|             let size = LLVMGetBufferSize(self.buffer); |  | ||||||
| 
 |  | ||||||
|             let mut buff = Vec::with_capacity(size); |  | ||||||
|             for i in 0..size { |  | ||||||
|                 buff.push(*start.add(i) as u8); |  | ||||||
|             } |  | ||||||
|             buff |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn as_string(&self) -> Result<String, FromUtf8Error> { |  | ||||||
|         String::from_utf8(self.as_buffer()) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Drop for MemoryBufferHolder { |  | ||||||
|     fn drop(&mut self) { |  | ||||||
|         unsafe { |  | ||||||
|             LLVMDisposeMemoryBuffer(self.buffer); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Make sure types for given instructions match. Return Ok(type) if they do,
 |  | ||||||
| /// and error otherwise.
 |  | ||||||
| pub fn match_types(lhs: &InstructionValue, rhs: &InstructionValue, builder: &Builder) -> CompileResult<Type> { |  | ||||||
|     let lhs_t = lhs.get_type(&builder)?; |  | ||||||
|     let rhs_t = rhs.get_type(&builder)?; |  | ||||||
|     if lhs_t == rhs_t { |  | ||||||
|         Ok(lhs_t) |  | ||||||
|     } else { |  | ||||||
|         Err(ErrorKind::TypesIncompatible(lhs_t, rhs_t)) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user