Add debug information compilation for subprograms and their parameters

This commit is contained in:
Sofia 2025-07-18 15:44:12 +03:00
parent 9bb4f97e6b
commit 0c6d9885ec
11 changed files with 580 additions and 114 deletions

View File

@ -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");

View File

@ -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<RefCell<Vec<ModuleHolder>>>,
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)
}
}

View File

@ -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<BlockValue, LLVMBasicBlockRef>,
values: HashMap<InstructionValue, LLVMValue>,
types: HashMap<TypeValue, LLVMTypeRef>,
debug: Option<LLVMDebugInformation<'a>>,
}
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<DebugScopeValue, LLVMMetadataRef>,
types: &'a mut HashMap<DebugTypeValue, LLVMMetadataRef>,
subprograms: &'a mut HashMap<DebugSubprogramValue, LLVMMetadataRef>,
metadata: &'a mut HashMap<DebugMetadataValue, LLVMMetadataRef>,
}
#[derive(Clone, Copy)]
pub struct LLVMFunction {
type_ref: LLVMTypeRef,
value_ref: LLVMValueRef,
metadata: Option<LLVMMetadataRef>,
}
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<DebugScopeValue, LLVMMetadataRef>,
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(&param.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::<Vec<_>>();
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<TypeValue, LLVMTypeRef>,
debug: &Option<LLVMDebugInformation>,
) -> 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,
}
}
}

View File

@ -9,9 +9,15 @@ pub struct DebugScopeValue(pub Vec<usize>);
#[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<DebugLocation>,
inner_scopes: Vec<DebugScopeHolder>,
locations: Vec<DebugLocationHolder>,
pub(crate) value: DebugScopeValue,
pub(crate) location: Option<DebugLocation>,
pub(crate) inner_scopes: Vec<DebugScopeHolder>,
pub(crate) locations: Vec<DebugLocationHolder>,
}
#[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<RefCell<DebugScopeHolder>>,
subprograms: Rc<RefCell<Vec<DebugSubprogramHolder>>>,
metadata: Rc<RefCell<Vec<DebugMetadataHolder>>>,
types: Rc<RefCell<Vec<DebugTypeHolder>>>,
}
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<RefCell<Vec<DebugMetadataHolder>>> {
self.metadata.clone()
}
pub fn get_scopes(&self) -> Rc<RefCell<DebugScopeHolder>> {
self.scope.clone()
}
pub fn get_subprograms(&self) -> Rc<RefCell<Vec<DebugSubprogramHolder>>> {
self.subprograms.clone()
}
pub fn get_types(&self) -> Rc<RefCell<Vec<DebugTypeHolder>>> {
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<DebugTypeValue>,
pub flags: DwarfFlags,
}
pub struct DebugSubprogramType {
pub params: Vec<DebugSubprogramValue>,
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,
}

View File

@ -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<T: Into<String>>(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<Type>,
flags: FunctionFlags,
meta: Option<DebugMetadataValue>,
debug: Option<DebugSubprogramValue>,
}
#[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);
}
}

View File

@ -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");

View File

@ -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<FullToken>,
module: &'ctx Module<'ctx>,
function: &'ctx Function<'ctx>,
function: &'ctx StackFunction<'ctx>,
block: Block<'ctx>,
types: &'a HashMap<TypeValue, TypeDefinitionKind>,
type_values: &'a HashMap<String, TypeValue>,
functions: &'a HashMap<String, Function<'ctx>>,
functions: &'a HashMap<String, StackFunction<'ctx>>,
stack_values: HashMap<String, StackValue>,
debug: &'ctx DebugInformation,
debug_scope: DebugScopeValue,
debug_const_tys: &'a HashMap<TypeKind, DebugMetadataValue>,
debug_const_tys: &'a HashMap<TypeKind, DebugTypeValue>,
}
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<FullToken>,
) -> 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<FullToken>) -> Option<DebugLocation> {
if let Some((start, _)) = self.into_positions(tokens) {
Some(start.into())
} else {
None
}
}
}
impl Into<DebugLocation> for Position {
fn into(self) -> DebugLocation {
DebugLocation {
line: self.1,
column: self.0,
}
}
}

View File

@ -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<Vec<FullToken>>,
pub source: Option<String>,
@ -77,7 +77,7 @@ pub struct ErrModule {
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ModuleMap {
module_map: HashMap<mir::SourceModuleId, ErrModule>,
module_map: HashMap<mir::SourceModuleId, Module>,
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);

View File

@ -86,7 +86,7 @@ pub fn compile_module<'map>(
path: Option<PathBuf>,
is_main: bool,
) -> Result<mir::Module, ReidError> {
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);

View File

@ -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()

View File

@ -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<FullToken>) -> 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)>,