diff --git a/reid-llvm-lib/src/builder.rs b/reid-llvm-lib/src/builder.rs index 3a3955e..1ccc3d3 100644 --- a/reid-llvm-lib/src/builder.rs +++ b/reid-llvm-lib/src/builder.rs @@ -5,7 +5,11 @@ use std::{cell::RefCell, rc::Rc}; use crate::{ BlockData, CustomTypeKind, FunctionData, Instr, InstructionData, ModuleData, NamedStruct, - TerminatorKind, Type, TypeData, util::match_types, + TerminatorKind, Type, TypeData, + debug_information::{ + DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue, + }, + util::match_types, }; #[derive(Clone, Hash, Copy, PartialEq, Eq)] @@ -29,6 +33,7 @@ pub struct ModuleHolder { pub(crate) data: ModuleData, pub(crate) functions: Vec, pub(crate) types: Vec, + pub(crate) debug_information: Option, } #[derive(Clone)] @@ -76,10 +81,23 @@ impl Builder { data, functions: Vec::new(), types: Vec::new(), + debug_information: None, }); 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(); @@ -145,6 +163,49 @@ impl Builder { } } + 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_function_metadata( + &self, + value: &FunctionValue, + metadata: DebugMetadataValue, + ) { + 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.data.meta = Some(metadata) + } + } + pub(crate) unsafe fn terminate( &self, block: &BlockValue, diff --git a/reid-llvm-lib/src/debug_information.rs b/reid-llvm-lib/src/debug_information.rs new file mode 100644 index 0000000..5924b50 --- /dev/null +++ b/reid-llvm-lib/src/debug_information.rs @@ -0,0 +1,192 @@ +use std::{ + cell::{RefCell, RefMut}, + rc::Rc, +}; + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct DebugScopeValue(pub Vec); + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct DebugLocationValue(pub DebugScopeValue, pub usize); + +#[derive(Debug, Clone, 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 { + value: DebugScopeValue, + location: Option, + inner_scopes: Vec, + locations: Vec, +} + +#[derive(Debug, Clone)] +pub struct DebugMetadataHolder { + scope: DebugScopeValue, + value: DebugMetadataValue, + data: DebugMetadata, +} + +#[derive(Debug, Clone)] +pub(crate) struct DebugLocationHolder { + value: DebugLocationValue, + location: DebugLocation, +} + +#[derive(Debug, Clone)] +pub struct DebugLocation { + pub line: u32, + pub column: u32, +} + +#[derive(Debug, Clone)] +pub struct DebugInformation { + file: DebugFileData, + scope: Rc>, + metadata: Rc>>, +} + +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(), + locations: Vec::new(), + location: None, + })), + metadata: Rc::new(RefCell::new(Vec::new())), + }, + scope_value, + ) + } + + pub fn inner_scope( + &self, + parent: &DebugScopeValue, + location: DebugLocation, + ) -> 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(parent.0.len()); + let value = DebugScopeValue(arr); + + outer_scope.inner_scopes.push(DebugScopeHolder { + value: value.clone(), + inner_scopes: Vec::new(), + locations: Vec::new(), + location: Some(location), + }); + value + } + } + + pub fn location( + &self, + scope_value: &DebugScopeValue, + line: u32, + column: u32, + ) -> DebugLocationValue { + unsafe { + let mut scope = RefMut::map(self.scope.borrow_mut(), |mut v| { + for i in &scope_value.0 { + v = v.inner_scopes.get_unchecked_mut(*i); + } + v + }); + let value = DebugLocationValue(scope_value.clone(), scope.locations.len()); + let location = DebugLocationHolder { + value: value.clone(), + location: DebugLocation { line, column }, + }; + scope.locations.push(location); + value + } + } + + pub fn metadata(&self, scope: &DebugScopeValue, kind: DebugMetadata) -> DebugMetadataValue { + let mut metadata = self.metadata.borrow_mut(); + let value = DebugMetadataValue(metadata.len()); + metadata.push(DebugMetadataHolder { + scope: scope.clone(), + value: value.clone(), + data: kind, + }); + value + } +} + +#[derive(Debug, Clone)] +pub enum DebugMetadata { + Function(DebugFunction), + BasicType(DebugBasicType), + ParamVar(DebugParamVariable), + LocalVar(DebugLocalVariable), +} + +#[derive(Debug, Clone)] +pub struct DebugBasicType { + pub name: String, + pub size_bits: u32, + pub encoding: AteEncoding, +} + +#[derive(Debug, Clone)] +pub enum AteEncoding { + Address = 1, + Boolean = 2, + Float = 4, + Signed = 5, + SignedChar = 6, + Unsigned = 7, + UnsignedChar = 8, +} + +#[derive(Debug, Clone)] +pub struct DebugFunction { + pub scope: DebugScopeValue, + pub name: String, + pub linkage_name: String, + pub location: DebugLocation, + pub return_ty: DebugMetadataValue, + pub is_local: bool, + pub is_definition: bool, + pub is_optimized: bool, + pub scope_line: u32, +} + +#[derive(Debug, Clone)] +pub struct DebugParamVariable { + pub scope: DebugScopeValue, + pub name: String, + pub arg_idx: u32, + pub location: DebugLocation, + pub ty: DebugMetadataValue, + pub always_preserve: bool, +} + +#[derive(Debug, Clone)] +pub struct DebugLocalVariable { + pub scope: DebugScopeValue, + pub name: String, + pub location: DebugLocation, + pub ty: DebugMetadataValue, + pub always_preserve: bool, + pub alignment: u32, +} diff --git a/reid-llvm-lib/src/lib.rs b/reid-llvm-lib/src/lib.rs index a4c870f..8575945 100644 --- a/reid-llvm-lib/src/lib.rs +++ b/reid-llvm-lib/src/lib.rs @@ -6,15 +6,18 @@ use std::{fmt::Debug, marker::PhantomData}; use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue, TypeValue}; use debug::PrintableModule; +use debug_information::{ + DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue, + DebugScopeValue, +}; use util::match_types; pub mod builder; pub mod compile; mod debug; +pub mod debug_information; mod util; -// pub struct InstructionValue(BlockValue, usize); - #[derive(Debug)] pub struct Context { builder: Builder, @@ -36,6 +39,7 @@ impl Context { phantom: PhantomData, builder: self.builder.clone(), value, + debug_info: None, } } } @@ -50,11 +54,12 @@ pub struct Module<'ctx> { phantom: PhantomData<&'ctx ()>, builder: Builder, value: ModuleValue, + debug_info: Option, } impl<'ctx> Module<'ctx> { pub fn function( - &mut self, + &self, name: &str, ret: Type, params: Vec, @@ -71,13 +76,14 @@ impl<'ctx> Module<'ctx> { ret, params, flags, + meta: None, }, ), } } } - pub fn custom_type(&mut self, ty: CustomTypeKind) -> TypeValue { + pub fn custom_type(&self, ty: CustomTypeKind) -> TypeValue { unsafe { let (name, kind) = match &ty { CustomTypeKind::NamedStruct(NamedStruct(name, _)) => (name.clone(), ty), @@ -96,6 +102,27 @@ impl<'ctx> Module<'ctx> { module: self.builder.find_module(self.value), } } + + pub fn create_debug_info( + &mut self, + file: DebugFileData, + ) -> (DebugInformation, DebugScopeValue) { + let (debug_info, scope) = DebugInformation::from_file(file); + self.debug_info = Some(debug_info.clone()); + (debug_info, scope) + } + + pub fn get_debug_info(&self) -> &Option { + &self.debug_info + } +} + +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)] @@ -104,6 +131,7 @@ pub struct FunctionData { ret: Type, params: Vec, flags: FunctionFlags, + meta: Option, } #[derive(Debug, Clone, Copy, Hash)] @@ -149,6 +177,12 @@ impl<'ctx> Function<'ctx> { } } + pub fn set_metadata(&self, metadata: DebugMetadataValue) { + unsafe { + self.builder.add_function_metadata(&self.value, metadata); + } + } + pub fn value(&self) -> FunctionValue { self.value } @@ -169,9 +203,29 @@ pub struct Block<'builder> { impl<'builder> Block<'builder> { pub fn build(&mut self, instruction: Instr) -> Result { + unsafe { + self.builder.add_instruction( + &self.value, + InstructionData { + kind: instruction, + location: None, + meta: None, + }, + ) + } + } + + pub fn set_instr_location(&self, instruction: InstructionValue, location: DebugLocationValue) { unsafe { self.builder - .add_instruction(&self.value, InstructionData { kind: instruction }) + .add_instruction_location(&instruction, location); + } + } + + pub fn set_instr_metadata(&self, instruction: InstructionValue, location: DebugMetadataValue) { + unsafe { + self.builder + .add_instruction_metadata(&instruction, location); } } @@ -196,9 +250,11 @@ impl<'builder> Block<'builder> { } } -#[derive(Clone, Hash)] +#[derive(Clone)] pub struct InstructionData { kind: Instr, + location: Option, + meta: Option, } #[derive(Clone, Copy, Hash)] diff --git a/reid/src/codegen.rs b/reid/src/codegen.rs index a85078c..f6c7662 100644 --- a/reid/src/codegen.rs +++ b/reid/src/codegen.rs @@ -3,6 +3,10 @@ use std::{collections::HashMap, mem}; use reid_lib::{ builder::{InstructionValue, TypeValue}, compile::CompiledModule, + debug_information::{ + AteEncoding, DebugBasicType, DebugFileData, DebugFunction, DebugInformation, DebugLocation, + DebugMetadata, DebugMetadataValue, DebugScopeValue, + }, Block, CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module, NamedStruct, TerminatorKind as Term, Type, }; @@ -56,6 +60,9 @@ pub struct Scope<'ctx, 'a> { type_values: &'a HashMap, functions: &'a HashMap>, stack_values: HashMap, + debug: &'ctx DebugInformation, + debug_scope: DebugScopeValue, + debug_const_tys: &'a HashMap, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -79,6 +86,9 @@ impl<'ctx, 'a> Scope<'ctx, 'a> { types: self.types, type_values: self.type_values, stack_values: self.stack_values.clone(), + debug: self.debug, + debug_scope: self.debug_scope.clone(), + debug_const_tys: self.debug_const_tys, } } @@ -119,8 +129,33 @@ impl mir::Module { fn codegen<'ctx>(&self, context: &'ctx Context) -> ModuleCodegen<'ctx> { let mut module = context.module(&self.name, self.is_main); + let (debug, debug_scope) = if let Some(path) = &self.path { + module.create_debug_info(DebugFileData { + name: path.file_name().unwrap().to_str().unwrap().to_owned(), + directory: path.parent().unwrap().to_str().unwrap().to_owned(), + }) + } else { + module.create_debug_info(DebugFileData { + name: self.name.clone(), + directory: String::new(), + }) + }; + let mut types = HashMap::new(); let mut type_values = HashMap::new(); + let mut debug_const_types = HashMap::new(); + + debug_const_types.insert( + TypeKind::U32, + debug.metadata( + &debug_scope, + DebugMetadata::BasicType(DebugBasicType { + name: String::from("u32"), + size_bits: 32, + encoding: AteEncoding::Unsigned, + }), + ), + ); for typedef in &self.typedefs { let type_value = match &typedef.kind { @@ -201,6 +236,9 @@ impl mir::Module { types: &types, type_values: &type_values, stack_values, + debug: &debug, + debug_scope: debug_scope.clone(), + debug_const_tys: &debug_const_types, }; match &mir_function.kind { mir::FunctionDefinitionKind::Local(block, _) => { @@ -214,6 +252,23 @@ impl mir::Module { scope.block.terminate(Term::RetVoid).ok(); } } + + let fn_return_ty = debug_const_types.get(&TypeKind::U32).unwrap(); + + scope.function.set_metadata(scope.debug.metadata( + &scope.debug_scope, + DebugMetadata::Function(DebugFunction { + scope: scope.debug_scope.clone(), + name: mir_function.name.clone(), + linkage_name: String::new(), + location: DebugLocation { line: 0, column: 0 }, + return_ty: fn_return_ty.clone(), + is_local: true, + is_definition: true, + is_optimized: false, + scope_line: 0, + }), + )); } mir::FunctionDefinitionKind::Extern(_) => {} } diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index 7294a1b..015936e 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -61,7 +61,7 @@ impl TokenRange { } } -#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, PartialOrd, Ord)] +#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, PartialOrd, Ord, Hash)] pub enum TypeKind { #[error("bool")] Bool, @@ -99,7 +99,7 @@ pub enum TypeKind { Vague(#[from] VagueType), } -#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error, PartialOrd, Ord, Hash)] pub enum VagueType { #[error("Unknown")] Unknown,