From 0c6d9885ecd719ce30be66667285014abeb4fcf6 Mon Sep 17 00:00:00 2001 From: sofia Date: Fri, 18 Jul 2025 15:44:12 +0300 Subject: [PATCH] Add debug information compilation for subprograms and their parameters --- reid-llvm-lib/examples/libtest.rs | 4 +- reid-llvm-lib/src/builder.rs | 11 +- reid-llvm-lib/src/compile.rs | 234 ++++++++++++++++++++++++- reid-llvm-lib/src/debug_information.rs | 217 ++++++++++++++++++----- reid-llvm-lib/src/lib.rs | 14 +- reid/examples/testcodegen.rs | 2 +- reid/src/codegen.rs | 174 +++++++++++++----- reid/src/error_raporting.rs | 10 +- reid/src/lib.rs | 6 +- reid/src/mir/linker.rs | 2 +- reid/src/mir/mod.rs | 20 ++- 11 files changed, 580 insertions(+), 114 deletions(-) diff --git a/reid-llvm-lib/examples/libtest.rs b/reid-llvm-lib/examples/libtest.rs index 9389586..0903a8f 100644 --- a/reid-llvm-lib/examples/libtest.rs +++ b/reid-llvm-lib/examples/libtest.rs @@ -4,9 +4,9 @@ fn main() { use ConstValue::*; use Instr::*; - let context = Context::new(); + let context = Context::new("libtest"); - let mut module = context.module("test", true); + let module = context.module("test", true); let main = module.function("main", Type::I32, Vec::new(), FunctionFlags::default()); let mut m_entry = main.block("entry"); diff --git a/reid-llvm-lib/src/builder.rs b/reid-llvm-lib/src/builder.rs index 1ccc3d3..fb4e507 100644 --- a/reid-llvm-lib/src/builder.rs +++ b/reid-llvm-lib/src/builder.rs @@ -8,6 +8,7 @@ use crate::{ TerminatorKind, Type, TypeData, debug_information::{ DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue, + DebugSubprogramValue, }, util::match_types, }; @@ -65,12 +66,14 @@ pub struct InstructionHolder { #[derive(Clone)] pub(crate) struct Builder { modules: Rc>>, + pub(crate) producer: String, } impl Builder { - pub fn new() -> Builder { + pub fn new(producer: String) -> Builder { Builder { modules: Rc::new(RefCell::new(Vec::new())), + producer, } } @@ -193,16 +196,16 @@ impl Builder { } } - pub(crate) unsafe fn add_function_metadata( + pub(crate) unsafe fn set_debug_subprogram( &self, value: &FunctionValue, - metadata: DebugMetadataValue, + subprogram: DebugSubprogramValue, ) { 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) + function.data.debug = Some(subprogram) } } diff --git a/reid-llvm-lib/src/compile.rs b/reid-llvm-lib/src/compile.rs index b49ea16..6bd3ec5 100644 --- a/reid-llvm-lib/src/compile.rs +++ b/reid-llvm-lib/src/compile.rs @@ -8,6 +8,7 @@ use llvm_sys::{ LLVMIntPredicate, LLVMLinkage, analysis::LLVMVerifyModule, core::*, + debuginfo::*, linker::LLVMLinkModules2, prelude::*, target::{ @@ -23,6 +24,7 @@ use llvm_sys::{ use crate::{ CustomTypeKind, builder::{TypeHolder, TypeValue}, + debug_information::*, util::{ErrorMessageHolder, MemoryBufferHolder, from_cstring, into_cstring}, }; @@ -180,12 +182,34 @@ pub struct LLVMModule<'a> { blocks: HashMap, values: HashMap, types: HashMap, + debug: Option>, +} + +impl<'a> Drop for LLVMModule<'a> { + fn drop(&mut self) { + if let Some(LLVMDebugInformation { builder, .. }) = self.debug { + unsafe { + LLVMDisposeDIBuilder(builder); + } + } + } +} + +pub struct LLVMDebugInformation<'a> { + debug: &'a DebugInformation, + builder: LLVMDIBuilderRef, + file_ref: LLVMMetadataRef, + scopes: &'a HashMap, + types: &'a mut HashMap, + subprograms: &'a mut HashMap, + metadata: &'a mut HashMap, } #[derive(Clone, Copy)] pub struct LLVMFunction { type_ref: LLVMTypeRef, value_ref: LLVMValueRef, + metadata: Option, } pub struct LLVMValue { @@ -203,6 +227,80 @@ impl ModuleHolder { // Compile the contents + let mut scopes = HashMap::new(); + let mut types = HashMap::new(); + let mut metadata = HashMap::new(); + let mut subprograms = HashMap::new(); + + let mut debug = if let Some(debug) = &self.debug_information { + let di_builder = LLVMCreateDIBuilder(module_ref); + + let file_ref = LLVMDIBuilderCreateFile( + di_builder, + into_cstring(debug.file.name.clone()).as_ptr(), + debug.file.name.len(), + into_cstring(debug.file.directory.clone()).as_ptr(), + debug.file.directory.len(), + ); + + let flags = String::new(); + + let compile_unit = LLVMDIBuilderCreateCompileUnit( + di_builder, + LLVMDWARFSourceLanguage::LLVMDWARFSourceLanguageC, + file_ref, + into_cstring(builder.producer.clone()).as_ptr(), + builder.producer.len(), + // is optimized + 0, + into_cstring(flags.clone()).as_ptr(), + flags.len(), + // Runtime version + 0, + // Split filename + into_cstring(debug.file.name.clone()).as_ptr(), + debug.file.name.len(), + LLVMDWARFEmissionKind::LLVMDWARFEmissionKindFull, + // The DWOId if this is a split skeleton compile unit. + 0, + // Whether to emit inline debug info. + true as i32, + // Whether to emit extra debug info for + // profile collection. + false as i32, + // The clang system root (value of -isysroot). + c"".as_ptr(), + 0, + // The SDK name. On Darwin, this is the last component of + // the sysroot. + c"".as_ptr(), + 0, + ); + + let scope = debug.get_scopes(); + scope + .borrow() + .compile_scope(compile_unit, file_ref, &mut scopes, di_builder); + + let debug = LLVMDebugInformation { + builder: di_builder, + debug: debug, + file_ref, + types: &mut types, + metadata: &mut metadata, + subprograms: &mut subprograms, + scopes: &scopes, + }; + + for ty in debug.debug.get_types().borrow().iter() { + let meta_ref = ty.compile_debug(&debug); + debug.types.insert(ty.value.clone(), meta_ref); + } + Some(debug) + } else { + None + }; + let mut types = HashMap::new(); for ty in &self.types { types.insert(ty.value, ty.compile_type(context, &types)); @@ -212,10 +310,17 @@ impl ModuleHolder { for function in &self.functions { functions.insert( function.value, - function.compile_signature(context, module_ref, &types), + function.compile_signature(context, module_ref, &types, &debug), ); } + // if let Some(debug) = &mut debug { + // for subprogram in debug.debug.get_subprograms().borrow().iter() { + // let meta_ref = subprogram.compile_debug(&functions, &debug); + // debug.subprograms.insert(subprogram.value.clone(), meta_ref); + // } + // } + let mut module = LLVMModule { builder, context_ref: context.context_ref, @@ -225,17 +330,111 @@ impl ModuleHolder { types, blocks: HashMap::new(), values: HashMap::new(), + debug, }; for function in &self.functions { function.compile(&mut module, self.data.is_main); } + if let Some(debug) = &module.debug { + LLVMDIBuilderFinalize(debug.builder); + } + module_ref } } } +impl DebugScopeHolder { + unsafe fn compile_scope( + &self, + parent: LLVMMetadataRef, + file: LLVMMetadataRef, + map: &mut HashMap, + di_builder: LLVMDIBuilderRef, + ) { + unsafe { + let scope = if let Some(location) = &self.location { + LLVMDIBuilderCreateLexicalBlock( + di_builder, + parent, + file, + location.line, + location.column, + ) + } else { + LLVMDIBuilderCreateLexicalBlockFile(di_builder, parent, file, 0) + }; + + for inner in &self.inner_scopes { + inner.compile_scope(scope, file, map, di_builder); + } + + map.insert(self.value.clone(), scope); + } + } +} + +impl DebugMetadataHolder { + unsafe fn compile_meta(&self, debug: &LLVMDebugInformation) -> LLVMMetadataRef { + unsafe { + match &self.data { + DebugMetadata::ParamVar(param) => LLVMDIBuilderCreateParameterVariable( + debug.builder, + *debug.scopes.get(&self.scope).unwrap(), + into_cstring(param.name.clone()).as_ptr(), + param.name.len(), + param.arg_idx, + debug.file_ref, + param.location.line, + *debug.types.get(¶m.ty).unwrap(), + param.always_preserve as i32, + param.flags.as_llvm(), + ), + DebugMetadata::LocalVar(debug_local_variable) => todo!(), + } + } + } +} + +impl DebugTypeHolder { + unsafe fn compile_debug(&self, debug: &LLVMDebugInformation) -> LLVMMetadataRef { + unsafe { + match &self.data { + DebugTypeData::Basic(ty) => LLVMDIBuilderCreateBasicType( + debug.builder, + into_cstring(ty.name.clone()).as_ptr(), + ty.name.len(), + ty.size_bits as u64, + ty.encoding as u32, + ty.flags.as_llvm(), + ), + DebugTypeData::Subprogram(subprogram) => { + let mut params = subprogram + .parameters + .iter() + .map(|p| *debug.types.get(p).unwrap()) + .collect::>(); + LLVMDIBuilderCreateSubroutineType( + debug.builder, + debug.file_ref, + params.as_mut_ptr(), + params.len() as u32, + subprogram.flags.as_llvm(), + ) + } + } + } + } +} + +impl DwarfFlags { + pub fn as_llvm(&self) -> i32 { + 0 + } +} + impl TypeHolder { unsafe fn compile_type( &self, @@ -268,6 +467,7 @@ impl FunctionHolder { context: &LLVMContext, module_ref: LLVMModuleRef, types: &HashMap, + debug: &Option, ) -> LLVMFunction { unsafe { let ret_type = self.data.ret.as_llvm(context.context_ref, types); @@ -285,9 +485,41 @@ impl FunctionHolder { let function_ref = LLVMAddFunction(module_ref, into_cstring(&self.data.name).as_ptr(), fn_type); + let metadata = if let Some(debug) = debug { + if let Some(value) = &self.data.debug { + let subprogram = debug.debug.get_subprogram_data(&value); + + let mangled_length_ptr = &mut 0; + let mangled_name = LLVMGetValueName2(function_ref, mangled_length_ptr); + let mangled_length = *mangled_length_ptr; + + Some(LLVMDIBuilderCreateFunction( + debug.builder, + *debug.scopes.get(&subprogram.scope).unwrap(), + into_cstring(subprogram.name.clone()).as_ptr(), + subprogram.name.clone().len(), + mangled_name, + mangled_length, + debug.file_ref, + subprogram.location.line, + *debug.types.get(&subprogram.ty).unwrap(), + subprogram.opts.is_local as i32, + subprogram.opts.is_definition as i32, + subprogram.opts.scope_line, + subprogram.opts.flags.as_llvm(), + subprogram.opts.is_optimized as i32, + )) + } else { + None + } + } else { + None + }; + LLVMFunction { type_ref: fn_type, value_ref: function_ref, + metadata, } } } diff --git a/reid-llvm-lib/src/debug_information.rs b/reid-llvm-lib/src/debug_information.rs index 5924b50..03829ba 100644 --- a/reid-llvm-lib/src/debug_information.rs +++ b/reid-llvm-lib/src/debug_information.rs @@ -9,9 +9,15 @@ pub struct DebugScopeValue(pub Vec); #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct DebugLocationValue(pub DebugScopeValue, pub usize); -#[derive(Debug, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub struct DebugTypeValue(pub usize); + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub struct DebugMetadataValue(pub usize); +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub struct DebugSubprogramValue(pub usize); + #[derive(Debug, Clone)] pub struct DebugFileData { pub name: String, @@ -20,17 +26,29 @@ pub struct DebugFileData { #[derive(Debug, Clone)] pub(crate) struct DebugScopeHolder { - value: DebugScopeValue, - location: Option, - inner_scopes: Vec, - locations: Vec, + pub(crate) value: DebugScopeValue, + pub(crate) location: Option, + pub(crate) inner_scopes: Vec, + pub(crate) locations: Vec, } #[derive(Debug, Clone)] pub struct DebugMetadataHolder { - scope: DebugScopeValue, - value: DebugMetadataValue, - data: DebugMetadata, + pub(crate) scope: DebugScopeValue, + pub(crate) value: DebugMetadataValue, + pub(crate) data: DebugMetadata, +} + +#[derive(Debug, Clone)] +pub struct DebugTypeHolder { + pub(crate) value: DebugTypeValue, + pub(crate) data: DebugTypeData, +} + +#[derive(Debug, Clone)] +pub struct DebugSubprogramHolder { + pub(crate) value: DebugSubprogramValue, + pub(crate) data: DebugSubprogramData, } #[derive(Debug, Clone)] @@ -39,17 +57,13 @@ pub(crate) struct DebugLocationHolder { location: DebugLocation, } -#[derive(Debug, Clone)] -pub struct DebugLocation { - pub line: u32, - pub column: u32, -} - #[derive(Debug, Clone)] pub struct DebugInformation { - file: DebugFileData, + pub file: DebugFileData, scope: Rc>, + subprograms: Rc>>, metadata: Rc>>, + types: Rc>>, } impl DebugInformation { @@ -65,6 +79,8 @@ impl DebugInformation { location: None, })), metadata: Rc::new(RefCell::new(Vec::new())), + subprograms: Rc::new(RefCell::new(Vec::new())), + types: Rc::new(RefCell::new(Vec::new())), }, scope_value, ) @@ -120,6 +136,16 @@ impl DebugInformation { } } + 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, scope: &DebugScopeValue, kind: DebugMetadata) -> DebugMetadataValue { let mut metadata = self.metadata.borrow_mut(); let value = DebugMetadataValue(metadata.len()); @@ -130,25 +156,133 @@ impl DebugInformation { }); value } + + fn check_metadata(&self, scope: &DebugScopeValue, metadata: &DebugMetadata) { + match &metadata { + DebugMetadata::ParamVar(debug_param_variable) => todo!(), + DebugMetadata::LocalVar(debug_local_variable) => todo!(), + } + } + + pub fn subprogram(&self, kind: DebugSubprogramData) -> DebugSubprogramValue { + let mut subprogram = self.subprograms.borrow_mut(); + let value = DebugSubprogramValue(subprogram.len()); + subprogram.push(DebugSubprogramHolder { + value: value.clone(), + data: kind, + }); + value + } + + pub fn get_metadata(&self) -> Rc>> { + self.metadata.clone() + } + + pub fn get_scopes(&self) -> Rc> { + self.scope.clone() + } + + pub fn get_subprograms(&self) -> Rc>> { + self.subprograms.clone() + } + + pub fn get_types(&self) -> Rc>> { + self.types.clone() + } + + pub fn get_subprogram_data(&self, value: &DebugSubprogramValue) -> DebugSubprogramData { + unsafe { + self.subprograms + .borrow() + .get_unchecked(value.0) + .data + .clone() + } + } +} + +#[derive(Debug, Clone, Copy, Default)] +pub struct DebugLocation { + pub line: u32, + pub column: u32, } #[derive(Debug, Clone)] pub enum DebugMetadata { - Function(DebugFunction), - BasicType(DebugBasicType), ParamVar(DebugParamVariable), LocalVar(DebugLocalVariable), } #[derive(Debug, Clone)] -pub struct DebugBasicType { +pub struct DebugParamVariable { pub name: String, - pub size_bits: u32, - pub encoding: AteEncoding, + /// 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, + /// Used for line number + pub location: DebugLocation, + 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 enum AteEncoding { +pub struct DebugLocalVariable { + pub name: String, + pub location: DebugLocation, + pub ty: DebugMetadataValue, + pub always_preserve: bool, + pub alignment: u32, +} + +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(Debug, Clone)] +pub enum DebugTypeData { + Basic(DebugBasicType), + Subprogram(DebugSubprogramTypeData), +} + +#[derive(Debug, 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(Debug, Clone)] +pub struct DebugSubprogramTypeData { + pub parameters: Vec, + pub flags: DwarfFlags, +} + +pub struct DebugSubprogramType { + pub params: Vec, + pub flags: DwarfFlags, +} + +#[derive(Debug, Clone, Copy)] +pub enum DwarfEncoding { Address = 1, Boolean = 2, Float = 4, @@ -159,34 +293,25 @@ pub enum AteEncoding { } #[derive(Debug, Clone)] -pub struct DebugFunction { - pub scope: DebugScopeValue, +pub struct DebugSubprogramData { + /// Function name. pub name: String, - pub linkage_name: String, + pub scope: DebugScopeValue, + /// Used for line number. pub location: DebugLocation, - pub return_ty: DebugMetadataValue, + /// 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, - 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, + /// These flags are used to emit dwarf attributes. e.g. is this function + /// prototyped or not. + pub flags: DwarfFlags, } diff --git a/reid-llvm-lib/src/lib.rs b/reid-llvm-lib/src/lib.rs index 8575945..487f491 100644 --- a/reid-llvm-lib/src/lib.rs +++ b/reid-llvm-lib/src/lib.rs @@ -8,7 +8,7 @@ use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue, use debug::PrintableModule; use debug_information::{ DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue, - DebugScopeValue, + DebugScopeValue, DebugSubprogramValue, }; use util::match_types; @@ -24,9 +24,9 @@ pub struct Context { } impl Context { - pub fn new() -> Context { + pub fn new>(producer: T) -> Context { Context { - builder: Builder::new(), + builder: Builder::new(producer.into()), } } @@ -76,7 +76,7 @@ impl<'ctx> Module<'ctx> { ret, params, flags, - meta: None, + debug: None, }, ), } @@ -131,7 +131,7 @@ pub struct FunctionData { ret: Type, params: Vec, flags: FunctionFlags, - meta: Option, + debug: Option, } #[derive(Debug, Clone, Copy, Hash)] @@ -177,9 +177,9 @@ impl<'ctx> Function<'ctx> { } } - pub fn set_metadata(&self, metadata: DebugMetadataValue) { + pub fn set_debug(&self, subprogram: DebugSubprogramValue) { unsafe { - self.builder.add_function_metadata(&self.value, metadata); + self.builder.set_debug_subprogram(&self.value, subprogram); } } diff --git a/reid/examples/testcodegen.rs b/reid/examples/testcodegen.rs index d31c599..8c053ac 100644 --- a/reid/examples/testcodegen.rs +++ b/reid/examples/testcodegen.rs @@ -172,7 +172,7 @@ fn main() { }; println!("test1"); - let context = Context::new(); + let context = Context::new("testcodegen"); let codegen = mir_context.codegen(&context); println!("test2"); diff --git a/reid/src/codegen.rs b/reid/src/codegen.rs index f6c7662..b3f3645 100644 --- a/reid/src/codegen.rs +++ b/reid/src/codegen.rs @@ -4,15 +4,22 @@ use reid_lib::{ builder::{InstructionValue, TypeValue}, compile::CompiledModule, debug_information::{ - AteEncoding, DebugBasicType, DebugFileData, DebugFunction, DebugInformation, DebugLocation, - DebugMetadata, DebugMetadataValue, DebugScopeValue, + DebugBasicType, DebugFileData, DebugInformation, DebugLocation, DebugMetadata, + DebugMetadataValue, DebugParamVariable, DebugScopeValue, DebugSubprogramData, + DebugSubprogramOptionals, DebugSubprogramTypeData, DebugSubprogramValue, DebugTypeData, + DebugTypeValue, DwarfEncoding, DwarfFlags, }, Block, CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module, NamedStruct, TerminatorKind as Term, Type, }; -use crate::mir::{ - self, NamedVariableRef, StructField, StructType, TypeDefinitionKind, TypeKind, VagueLiteral, +use crate::{ + error_raporting::ModuleMap, + lexer::{FullToken, Position}, + mir::{ + self, Metadata, NamedVariableRef, StructField, StructType, TypeDefinitionKind, TypeKind, + VagueLiteral, + }, }; /// Context that contains all of the given modules as complete codegenerated @@ -32,10 +39,24 @@ impl<'ctx> CodegenContext<'ctx> { impl mir::Context { /// Compile MIR [`Context`] into [`CodegenContext`] containing LLIR. - pub fn codegen<'ctx>(&self, context: &'ctx Context) -> CodegenContext<'ctx> { + pub fn codegen<'ctx>( + &self, + context: &'ctx Context, + mod_map: &ModuleMap, + ) -> CodegenContext<'ctx> { let mut modules = Vec::new(); for module in &self.modules { - modules.push(module.codegen(context)); + modules.push( + module.codegen( + context, + mod_map + .module(&module.module_id) + .unwrap() + .tokens + .as_ref() + .unwrap(), + ), + ); } CodegenContext { context } } @@ -53,16 +74,22 @@ impl<'ctx> std::fmt::Debug for ModuleCodegen<'ctx> { pub struct Scope<'ctx, 'a> { context: &'ctx Context, + tokens: &'ctx Vec, module: &'ctx Module<'ctx>, - function: &'ctx Function<'ctx>, + function: &'ctx StackFunction<'ctx>, block: Block<'ctx>, types: &'a HashMap, type_values: &'a HashMap, - functions: &'a HashMap>, + functions: &'a HashMap>, stack_values: HashMap, debug: &'ctx DebugInformation, debug_scope: DebugScopeValue, - debug_const_tys: &'a HashMap, + debug_const_tys: &'a HashMap, +} + +pub struct StackFunction<'ctx> { + ir: Function<'ctx>, + debug: DebugSubprogramValue, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -79,6 +106,7 @@ impl<'ctx, 'a> Scope<'ctx, 'a> { fn with_block(&self, block: Block<'ctx>) -> Scope<'ctx, 'a> { Scope { block, + tokens: self.tokens, function: self.function, context: self.context, module: self.module, @@ -126,7 +154,11 @@ impl Default for State { } impl mir::Module { - fn codegen<'ctx>(&self, context: &'ctx Context) -> ModuleCodegen<'ctx> { + fn codegen<'ctx>( + &self, + context: &'ctx Context, + tokens: &Vec, + ) -> ModuleCodegen<'ctx> { let mut module = context.module(&self.name, self.is_main); let (debug, debug_scope) = if let Some(path) = &self.path { @@ -147,14 +179,12 @@ impl mir::Module { debug_const_types.insert( TypeKind::U32, - debug.metadata( - &debug_scope, - DebugMetadata::BasicType(DebugBasicType { - name: String::from("u32"), - size_bits: 32, - encoding: AteEncoding::Unsigned, - }), - ), + debug.debug_type(DebugTypeData::Basic(DebugBasicType { + name: String::from("u32"), + size_bits: 32, + encoding: DwarfEncoding::Unsigned, + flags: DwarfFlags, + })), ); for typedef in &self.typedefs { @@ -209,15 +239,69 @@ impl mir::Module { }, ), }; - functions.insert(function.name.clone(), func); + + let fn_return_ty = debug_const_types.get(&TypeKind::U32).unwrap(); + + let debug_ty = debug.debug_type(DebugTypeData::Subprogram(DebugSubprogramTypeData { + parameters: vec![*fn_return_ty], + flags: DwarfFlags, + })); + + let subprogram = debug.subprogram(DebugSubprogramData { + name: function.name.clone(), + scope: debug_scope.clone(), + location: DebugLocation { line: 0, column: 0 }, + ty: debug_ty, + opts: DebugSubprogramOptionals { + is_local: !function.is_pub, + is_definition: true, + ..DebugSubprogramOptionals::default() + }, + }); + + func.set_debug(subprogram); + + functions.insert( + function.name.clone(), + StackFunction { + ir: func, + debug: subprogram, + }, + ); } for mir_function in &self.functions { let function = functions.get(&mir_function.name).unwrap(); - let mut entry = function.block("entry"); + let mut entry = function.ir.block("entry"); + + let location = match &mir_function.kind { + mir::FunctionDefinitionKind::Local(_, metadata) => { + metadata.into_debug(tokens).unwrap() + } + mir::FunctionDefinitionKind::Extern(_) => { + // TODO extern should probably still have a meta + DebugLocation { + ..Default::default() + } + } + }; + + let debug_scope = debug.inner_scope(&debug_scope, location); let mut stack_values = HashMap::new(); for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() { + debug.metadata( + &debug_scope, + DebugMetadata::ParamVar(DebugParamVariable { + name: p_name.clone(), + arg_idx: i as u32, + location, + ty: *debug_const_types.get(&TypeKind::U32).unwrap(), + always_preserve: true, + flags: DwarfFlags, + }), + ); + stack_values.insert( p_name.clone(), StackValue( @@ -229,6 +313,7 @@ impl mir::Module { let mut scope = Scope { context, + tokens, module: &module, function, block: entry, @@ -237,9 +322,10 @@ impl mir::Module { type_values: &type_values, stack_values, debug: &debug, - debug_scope: debug_scope.clone(), + debug_scope: debug_scope, debug_const_tys: &debug_const_types, }; + match &mir_function.kind { mir::FunctionDefinitionKind::Local(block, _) => { let state = State::default(); @@ -252,23 +338,6 @@ 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(_) => {} } @@ -444,13 +513,13 @@ impl mir::Expression { Some( scope .block - .build(Instr::FunctionCall(callee.value(), params)) + .build(Instr::FunctionCall(callee.ir.value(), params)) .unwrap(), ) } mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state), mir::ExprKind::Block(block) => { - let mut inner_scope = scope.with_block(scope.function.block("inner")); + let mut inner_scope = scope.with_block(scope.function.ir.block("inner")); if let Some(ret) = block.codegen(&mut inner_scope, state) { inner_scope .block @@ -587,9 +656,9 @@ impl mir::IfExpression { let condition = self.0.codegen(scope, state).unwrap(); // Create blocks - let then_b = scope.function.block("then"); - let mut else_b = scope.function.block("else"); - let after_b = scope.function.block("after"); + let then_b = scope.function.ir.block("then"); + let mut else_b = scope.function.ir.block("else"); + let after_b = scope.function.ir.block("after"); // Store for convenience let then_bb = then_b.value(); @@ -709,3 +778,22 @@ impl TypeKind { } } } + +impl Metadata { + pub fn into_debug(&self, tokens: &Vec) -> Option { + if let Some((start, _)) = self.into_positions(tokens) { + Some(start.into()) + } else { + None + } + } +} + +impl Into for Position { + fn into(self) -> DebugLocation { + DebugLocation { + line: self.1, + column: self.0, + } + } +} diff --git a/reid/src/error_raporting.rs b/reid/src/error_raporting.rs index 673b8b1..76910ef 100644 --- a/reid/src/error_raporting.rs +++ b/reid/src/error_raporting.rs @@ -69,7 +69,7 @@ impl Ord for ErrorKind { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct ErrModule { +pub struct Module { pub name: String, pub tokens: Option>, pub source: Option, @@ -77,7 +77,7 @@ pub struct ErrModule { #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct ModuleMap { - module_map: HashMap, + module_map: HashMap, module_counter: mir::SourceModuleId, } @@ -86,7 +86,7 @@ impl ModuleMap { let id = self.module_counter.increment(); self.module_map.insert( id, - ErrModule { + Module { name: name.into(), tokens: None, source: None, @@ -107,7 +107,7 @@ impl ModuleMap { } } - pub fn get_module(&self, id: &mir::SourceModuleId) -> Option<&ErrModule> { + pub fn module(&self, id: &mir::SourceModuleId) -> Option<&Module> { self.module_map.get(id) } } @@ -177,7 +177,7 @@ impl std::fmt::Display for ReidError { let mut curr_module = None; for error in sorted_errors { let meta = error.get_meta(); - let module = self.map.get_module(&meta.source_module_id).unwrap(); + let module = self.map.module(&meta.source_module_id).unwrap(); let position = if let Some(tokens) = &module.tokens { let range_tokens = meta.range.into_tokens(&tokens); diff --git a/reid/src/lib.rs b/reid/src/lib.rs index 2a98ec5..f288dcd 100644 --- a/reid/src/lib.rs +++ b/reid/src/lib.rs @@ -86,7 +86,7 @@ pub fn compile_module<'map>( path: Option, is_main: bool, ) -> Result { - let module = map.get_module(&module_id).cloned().unwrap(); + let module = map.module(&module_id).cloned().unwrap(); let mut token_stream = TokenStream::from(&tokens); @@ -196,8 +196,8 @@ pub fn compile_and_pass<'map>( perform_all_passes(&mut mir_context, module_map)?; - let mut context = Context::new(); - let codegen_modules = mir_context.codegen(&mut context); + let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION"))); + let codegen_modules = mir_context.codegen(&mut context, &module_map); #[cfg(debug_assertions)] dbg!(&codegen_modules); diff --git a/reid/src/mir/linker.rs b/reid/src/mir/linker.rs index 83d7b51..f9a6d12 100644 --- a/reid/src/mir/linker.rs +++ b/reid/src/mir/linker.rs @@ -87,7 +87,7 @@ impl<'map> Pass for LinkerPass<'map> { for module in context.modules.drain(..) { let tokens = self .module_map - .get_module(&module.module_id) + .module(&module.module_id) .unwrap() .tokens .clone() diff --git a/reid/src/mir/mod.rs b/reid/src/mir/mod.rs index 015936e..f9682ab 100644 --- a/reid/src/mir/mod.rs +++ b/reid/src/mir/mod.rs @@ -4,7 +4,10 @@ use std::{collections::HashMap, path::PathBuf}; -use crate::{lexer::Position, token_stream::TokenRange}; +use crate::{ + lexer::{FullToken, Position}, + token_stream::TokenRange, +}; mod display; pub mod r#impl; @@ -36,6 +39,19 @@ impl Metadata { (self.range.start >= other.range.start && self.range.end <= other.range.end) || (other.range.start >= self.range.start && other.range.end <= self.range.end) } + + pub fn into_positions(&self, tokens: &Vec) -> Option<(Position, Position)> { + let mut iter = tokens + .iter() + .skip(self.range.start) + .take(self.range.end - self.range.start); + if let Some(first) = iter.next() { + let last = iter.last().unwrap(); + Some((first.position, last.position.add(last.token.len() as u32))) + } else { + None + } + } } impl std::ops::Add for Metadata { @@ -248,7 +264,9 @@ pub struct FunctionCall { #[derive(Debug)] pub struct FunctionDefinition { pub name: String, + /// Whether this function is visible to outside modules pub is_pub: bool, + /// Whether this module is from an external module, and has been imported pub is_imported: bool, pub return_type: TypeKind, pub parameters: Vec<(String, TypeKind)>,