Implement array and struct debug info

This commit is contained in:
Sofia 2025-07-19 20:51:06 +03:00
parent a511331be2
commit c1cc1d28de
8 changed files with 248 additions and 83 deletions

View File

@ -495,6 +495,31 @@ impl DebugTypeHolder {
Vec::new().as_mut_ptr(), Vec::new().as_mut_ptr(),
0, 0,
), ),
DebugTypeData::Struct(st) => {
let mut elements = st
.elements
.iter()
.map(|e| *debug.types.get(e).unwrap())
.collect::<Vec<_>>();
LLVMDIBuilderCreateStructType(
debug.builder,
*debug.programs.get(&st.scope).unwrap(),
into_cstring(st.name.clone()).as_ptr(),
st.name.len(),
debug.file_ref,
st.location.line,
st.size_bits,
st.alignment,
st.flags.as_llvm(),
null_mut(), // derived from
elements.as_mut_ptr(),
elements.len() as u32,
0, // Runtime lang
null_mut(), // VTable
null(), // Unique ID
0, // Unique ID len
)
}
} }
} }
} }

View File

@ -10,7 +10,7 @@ use crate::{
builder::*, builder::*,
debug_information::{ debug_information::{
DebugArrayType, DebugBasicType, DebugLocation, DebugLocationValue, DebugMetadataHolder, DebugArrayType, DebugBasicType, DebugLocation, DebugLocationValue, DebugMetadataHolder,
DebugMetadataValue, DebugPointerType, DebugProgramValue, DebugScopeValue, DebugMetadataValue, DebugPointerType, DebugProgramValue, DebugScopeValue, DebugStructType,
DebugSubprogramType, DebugTypeData, DebugTypeHolder, DebugTypeValue, DebugSubprogramType, DebugTypeData, DebugTypeHolder, DebugTypeValue,
}, },
}; };
@ -243,6 +243,7 @@ impl Debug for DebugTypeData {
DebugTypeData::Subprogram(ty) => Debug::fmt(ty, f), DebugTypeData::Subprogram(ty) => Debug::fmt(ty, f),
DebugTypeData::Pointer(ty) => Debug::fmt(ty, f), DebugTypeData::Pointer(ty) => Debug::fmt(ty, f),
DebugTypeData::Array(ty) => Debug::fmt(ty, f), DebugTypeData::Array(ty) => Debug::fmt(ty, f),
DebugTypeData::Struct(ty) => Debug::fmt(ty, f),
} }
} }
} }
@ -258,6 +259,20 @@ impl Debug for DebugBasicType {
} }
} }
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("location", &self.location)
.field("size_bit", &self.size_bits)
.field("alignment", &self.alignment)
.field("flags", &self.flags)
.field("elements", &self.elements)
.finish()
}
}
impl Debug for DebugSubprogramType { impl Debug for DebugSubprogramType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Subprogram") f.debug_tuple("Subprogram")

View File

@ -260,6 +260,7 @@ pub enum DebugTypeData {
Subprogram(DebugSubprogramType), Subprogram(DebugSubprogramType),
Pointer(DebugPointerType), Pointer(DebugPointerType),
Array(DebugArrayType), Array(DebugArrayType),
Struct(DebugStructType),
} }
#[derive(Clone)] #[derive(Clone)]
@ -287,6 +288,16 @@ pub struct DebugPointerType {
pub pointee: DebugTypeValue, pub pointee: DebugTypeValue,
pub size_bits: u64, pub size_bits: u64,
} }
#[derive(Clone)]
pub struct DebugStructType {
pub name: String,
pub scope: DebugProgramValue,
pub location: DebugLocation,
pub size_bits: u64,
pub alignment: u32,
pub flags: DwarfFlags,
pub elements: Vec<DebugTypeValue>,
}
#[derive(Clone)] #[derive(Clone)]
pub struct DebugSubprogramType { pub struct DebugSubprogramType {

View File

@ -159,19 +159,19 @@ pub enum BlockLevelStatement {
Return(ReturnType, Expression), Return(ReturnType, Expression),
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct TypeDefinition { pub struct TypeDefinition {
name: String, name: String,
kind: TypeDefinitionKind, kind: TypeDefinitionKind,
range: TokenRange, range: TokenRange,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum TypeDefinitionKind { pub enum TypeDefinitionKind {
Struct(Vec<StructDefinitionField>), Struct(Vec<StructDefinitionField>),
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct StructDefinitionField { pub struct StructDefinitionField {
name: String, name: String,
ty: Type, ty: Type,

View File

@ -1,13 +1,14 @@
use std::{collections::HashMap, mem}; use std::{collections::HashMap, fmt::format, mem};
use reid_lib::{ use reid_lib::{
builder::{InstructionValue, TypeValue}, builder::{InstructionValue, TypeValue},
compile::CompiledModule, compile::CompiledModule,
debug_information::{ debug_information::{
DebugBasicType, DebugFileData, DebugInformation, DebugLocalVariable, DebugLocation, DebugArrayType, DebugBasicType, DebugFileData, DebugInformation, DebugLocalVariable,
DebugMetadata, DebugMetadataValue, DebugParamVariable, DebugProgramValue, DebugRecordKind, DebugLocation, DebugMetadata, DebugMetadataValue, DebugParamVariable, DebugPointerType,
DebugScopeValue, DebugSubprogramData, DebugSubprogramOptionals, DebugSubprogramType, DebugProgramValue, DebugRecordKind, DebugScopeValue, DebugStructType, DebugSubprogramData,
DebugTypeData, DebugTypeValue, DwarfEncoding, DwarfFlags, InstructionDebugRecordData, DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, DebugTypeValue,
DwarfEncoding, DwarfFlags, InstructionDebugRecordData,
}, },
Block, CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, Block, CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr,
Module, NamedStruct, TerminatorKind as Term, Type, Module, NamedStruct, TerminatorKind as Term, Type,
@ -17,8 +18,8 @@ use crate::{
error_raporting::ModuleMap, error_raporting::ModuleMap,
lexer::{FullToken, Position}, lexer::{FullToken, Position},
mir::{ mir::{
self, Metadata, NamedVariableRef, StructField, StructType, TypeDefinitionKind, TypeKind, self, Metadata, NamedVariableRef, StructField, StructType, TypeDefinition,
VagueLiteral, TypeDefinitionKind, TypeKind, VagueLiteral,
}, },
}; };
@ -78,7 +79,7 @@ pub struct Scope<'ctx, 'a> {
module: &'ctx Module<'ctx>, module: &'ctx Module<'ctx>,
function: &'ctx StackFunction<'ctx>, function: &'ctx StackFunction<'ctx>,
block: Block<'ctx>, block: Block<'ctx>,
types: &'a HashMap<TypeValue, TypeDefinitionKind>, types: &'a HashMap<TypeValue, TypeDefinition>,
type_values: &'a HashMap<String, TypeValue>, type_values: &'a HashMap<String, TypeValue>,
functions: &'a HashMap<String, StackFunction<'ctx>>, functions: &'a HashMap<String, StackFunction<'ctx>>,
stack_values: HashMap<String, StackValue>, stack_values: HashMap<String, StackValue>,
@ -161,23 +162,11 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
old_block old_block
} }
fn get_typedef(&self, name: &String) -> Option<&TypeDefinitionKind> { fn get_typedef(&self, name: &String) -> Option<&TypeDefinition> {
self.type_values.get(name).and_then(|v| self.types.get(v)) self.type_values.get(name).and_then(|v| self.types.get(v))
} }
} }
impl<'ctx> Debug<'ctx> {
fn get_type(&self, kind: &TypeKind) -> DebugTypeValue {
if let Some(ty) = self.types.get(kind) {
*ty
} else {
let debug_data = kind.debug_type_data();
let ty = self.info.debug_type(debug_data);
ty
}
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
struct State { struct State {
should_load: bool, should_load: bool,
@ -222,23 +211,36 @@ impl mir::Module {
let mut type_values = HashMap::new(); let mut type_values = HashMap::new();
let mut debug_types = HashMap::new(); let mut debug_types = HashMap::new();
{ macro_rules! insert_debug {
use TypeKind::*; ($kind:expr) => {
debug_types.insert(Bool, Bool.get_debug_type(&debug_types, &debug)); debug_types.insert(
debug_types.insert(U8, U8.get_debug_type(&debug_types, &debug)); $kind.clone(),
debug_types.insert(U16, U16.get_debug_type(&debug_types, &debug)); $kind.get_debug_type_hard(
debug_types.insert(U32, U32.get_debug_type(&debug_types, &debug)); compile_unit,
debug_types.insert(U64, U64.get_debug_type(&debug_types, &debug)); &debug,
debug_types.insert(U128, U128.get_debug_type(&debug_types, &debug)); &debug_types,
debug_types.insert(I8, I8.get_debug_type(&debug_types, &debug)); &type_values,
debug_types.insert(I16, I16.get_debug_type(&debug_types, &debug)); &types,
debug_types.insert(I32, I32.get_debug_type(&debug_types, &debug)); tokens,
debug_types.insert(I64, I64.get_debug_type(&debug_types, &debug)); ),
debug_types.insert(I128, I128.get_debug_type(&debug_types, &debug)); )
debug_types.insert(Void, Void.get_debug_type(&debug_types, &debug)); };
debug_types.insert(StringPtr, StringPtr.get_debug_type(&debug_types, &debug));
} }
insert_debug!(&TypeKind::Bool);
insert_debug!(&TypeKind::U8);
insert_debug!(&TypeKind::U16);
insert_debug!(&TypeKind::U32);
insert_debug!(&TypeKind::U64);
insert_debug!(&TypeKind::U128);
insert_debug!(&TypeKind::I8);
insert_debug!(&TypeKind::I16);
insert_debug!(&TypeKind::I32);
insert_debug!(&TypeKind::I64);
insert_debug!(&TypeKind::I128);
insert_debug!(&TypeKind::Void);
insert_debug!(&TypeKind::StringPtr);
for typedef in &self.typedefs { for typedef in &self.typedefs {
let type_value = match &typedef.kind { let type_value = match &typedef.kind {
TypeDefinitionKind::Struct(StructType(fields)) => { TypeDefinitionKind::Struct(StructType(fields)) => {
@ -254,8 +256,9 @@ impl mir::Module {
))) )))
} }
}; };
types.insert(type_value, typedef.kind.clone()); types.insert(type_value, typedef.clone());
type_values.insert(typedef.name.clone(), type_value); type_values.insert(typedef.name.clone(), type_value);
insert_debug!(&TypeKind::CustomType(typedef.name.clone()));
} }
let mut functions = HashMap::new(); let mut functions = HashMap::new();
@ -303,9 +306,14 @@ impl mir::Module {
let debug_scope = if let Some(location) = mir_function.signature().into_debug(tokens) { let debug_scope = if let Some(location) = mir_function.signature().into_debug(tokens) {
// let debug_scope = debug.inner_scope(&outer_scope, location); // let debug_scope = debug.inner_scope(&outer_scope, location);
let fn_param_ty = &mir_function let fn_param_ty = &mir_function.return_type.get_debug_type_hard(
.return_type compile_unit,
.get_debug_type(&debug_types, &debug); &debug,
&debug_types,
&type_values,
&types,
tokens,
);
let debug_ty = debug.debug_type(DebugTypeData::Subprogram(DebugSubprogramType { let debug_ty = debug.debug_type(DebugTypeData::Subprogram(DebugSubprogramType {
parameters: vec![*fn_param_ty], parameters: vec![*fn_param_ty],
@ -358,7 +366,14 @@ impl mir::Module {
name: p_name.clone(), name: p_name.clone(),
arg_idx: i as u32, arg_idx: i as u32,
location, location,
ty: p_ty.get_debug_type(&debug_types, &debug), ty: p_ty.get_debug_type_hard(
*debug_scope,
&debug,
&debug_types,
&type_values,
&types,
tokens,
),
always_preserve: true, always_preserve: true,
flags: DwarfFlags, flags: DwarfFlags,
}), }),
@ -488,7 +503,7 @@ impl mir::Statement {
DebugMetadata::LocalVar(DebugLocalVariable { DebugMetadata::LocalVar(DebugLocalVariable {
name: name.clone(), name: name.clone(),
location, location,
ty: debug.get_type(ty), ty: ty.get_debug_type(debug, scope),
always_preserve: true, always_preserve: true,
alignment: 32, alignment: 32,
flags: DwarfFlags, flags: DwarfFlags,
@ -732,7 +747,7 @@ impl mir::Expression {
panic!("tried accessing non-custom-type"); panic!("tried accessing non-custom-type");
}; };
let TypeDefinitionKind::Struct(struct_ty) = let TypeDefinitionKind::Struct(struct_ty) =
scope.get_typedef(&name).unwrap().clone(); scope.get_typedef(&name).unwrap().kind.clone();
let idx = struct_ty.find_index(field).unwrap(); let idx = struct_ty.find_index(field).unwrap();
let mut value = scope let mut value = scope
@ -931,7 +946,7 @@ impl TypeKind {
fn get_type( fn get_type(
&self, &self,
type_vals: &HashMap<String, TypeValue>, type_vals: &HashMap<String, TypeValue>,
typedefs: &HashMap<TypeValue, TypeDefinitionKind>, typedefs: &HashMap<TypeValue, TypeDefinition>,
) -> Type { ) -> Type {
match &self { match &self {
TypeKind::I8 => Type::I8, TypeKind::I8 => Type::I8,
@ -952,25 +967,127 @@ impl TypeKind {
TypeKind::CustomType(n) => { TypeKind::CustomType(n) => {
let type_val = type_vals.get(n).unwrap().clone(); let type_val = type_vals.get(n).unwrap().clone();
let custom_t = Type::CustomType(type_val); let custom_t = Type::CustomType(type_val);
match typedefs.get(&type_val).unwrap() { match typedefs.get(&type_val).unwrap().kind {
TypeDefinitionKind::Struct(_) => Type::Ptr(Box::new(custom_t)), TypeDefinitionKind::Struct(_) => Type::Ptr(Box::new(custom_t)),
} }
} }
} }
} }
}
fn get_debug_type( impl TypeKind {
fn get_debug_type(&self, debug: &Debug, scope: &Scope) -> DebugTypeValue {
self.get_debug_type_hard(
debug.scope,
debug.info,
debug.types,
scope.type_values,
scope.types,
scope.tokens,
)
}
fn get_debug_type_hard(
&self, &self,
types: &HashMap<TypeKind, DebugTypeValue>, scope: DebugProgramValue,
debug: &DebugInformation, debug_info: &DebugInformation,
debug_types: &HashMap<TypeKind, DebugTypeValue>,
type_values: &HashMap<String, TypeValue>,
types: &HashMap<TypeValue, TypeDefinition>,
tokens: &Vec<FullToken>,
) -> DebugTypeValue { ) -> DebugTypeValue {
if let Some(ty) = types.get(self) { if let Some(ty) = debug_types.get(self) {
*ty return *ty;
} else {
let debug_data = self.debug_type_data();
let ty = debug.debug_type(debug_data);
ty
} }
let name = format!("{}", self);
let data = match self {
TypeKind::StringPtr => DebugTypeData::Pointer(DebugPointerType {
name,
pointee: TypeKind::I8.get_debug_type_hard(
scope,
debug_info,
debug_types,
type_values,
types,
tokens,
),
size_bits: self.size_of(),
}),
TypeKind::Array(type_kind, len) => DebugTypeData::Array(DebugArrayType {
size_bits: type_kind.size_of() * len,
align_bits: type_kind.alignment(),
element_type: type_kind.get_debug_type_hard(
scope,
debug_info,
debug_types,
type_values,
types,
tokens,
),
subscripts: Vec::new(),
}),
TypeKind::CustomType(name) => {
let typedef = types.get(type_values.get(name).unwrap()).unwrap();
match &typedef.kind {
TypeDefinitionKind::Struct(struct_type) => {
let (elements, sizes): (Vec<_>, Vec<_>) = struct_type
.0
.iter()
.map(|t| {
(
t.1.get_debug_type_hard(
scope,
debug_info,
debug_types,
type_values,
types,
tokens,
),
t.1.size_of(),
)
})
.unzip();
let size_bits: u64 = sizes.iter().sum();
{
DebugTypeData::Struct(DebugStructType {
name: name.clone(),
scope: scope,
location: typedef.meta.into_debug(tokens).unwrap(),
size_bits,
alignment: 32,
flags: DwarfFlags,
elements,
})
}
}
}
}
_ => DebugTypeData::Basic(DebugBasicType {
name,
size_bits: self.size_of(),
encoding: match self {
TypeKind::Bool => DwarfEncoding::Boolean,
TypeKind::I8 => DwarfEncoding::SignedChar,
TypeKind::U8 => DwarfEncoding::UnsignedChar,
TypeKind::I16 | TypeKind::I32 | TypeKind::I64 | TypeKind::I128 => {
DwarfEncoding::Signed
}
TypeKind::U16 | TypeKind::U32 | TypeKind::U64 | TypeKind::U128 => {
DwarfEncoding::Unsigned
}
TypeKind::Void => DwarfEncoding::Address,
TypeKind::StringPtr => DwarfEncoding::Address,
TypeKind::Array(_, _) => DwarfEncoding::Address,
TypeKind::CustomType(_) => DwarfEncoding::Address,
TypeKind::Vague(_) => panic!("tried fetching debug-type for vague type!"),
},
flags: DwarfFlags,
}),
};
debug_info.debug_type(data)
} }
} }

View File

@ -45,34 +45,31 @@ impl TypeKind {
TypeKind::U128 => 128, TypeKind::U128 => 128,
TypeKind::Void => 0, TypeKind::Void => 0,
TypeKind::StringPtr => 32, TypeKind::StringPtr => 32,
TypeKind::Array(type_kind, len) => 32, TypeKind::Array(type_kind, len) => type_kind.size_of() * len,
TypeKind::CustomType(_) => 32, TypeKind::CustomType(_) => 32,
TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"), TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"),
} }
} }
pub fn debug_type_data(&self) -> DebugTypeData { pub fn alignment(&self) -> u32 {
DebugTypeData::Basic(DebugBasicType { match self {
name: format!("{}", self), TypeKind::Bool => 1,
size_bits: self.size_of(), TypeKind::I8 => 8,
encoding: match self { TypeKind::U8 => 8,
TypeKind::Bool => DwarfEncoding::Boolean, TypeKind::I16 => 16,
TypeKind::I8 => DwarfEncoding::SignedChar, TypeKind::U16 => 16,
TypeKind::U8 => DwarfEncoding::UnsignedChar, TypeKind::I32 => 32,
TypeKind::I16 | TypeKind::I32 | TypeKind::I64 | TypeKind::I128 => { TypeKind::U32 => 32,
DwarfEncoding::Signed TypeKind::I64 => 64,
} TypeKind::U64 => 64,
TypeKind::U16 | TypeKind::U32 | TypeKind::U64 | TypeKind::U128 => { TypeKind::I128 => 128,
DwarfEncoding::Unsigned TypeKind::U128 => 128,
} TypeKind::Void => 0,
TypeKind::Void => DwarfEncoding::Address, TypeKind::StringPtr => 32,
TypeKind::StringPtr => DwarfEncoding::Address, TypeKind::Array(type_kind, _) => type_kind.alignment(),
TypeKind::Array(_, _) => DwarfEncoding::Address, TypeKind::CustomType(_) => 32,
TypeKind::CustomType(_) => DwarfEncoding::Address, TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"),
TypeKind::Vague(_) => panic!("tried fetching debug-type for vague type!"), }
},
flags: DwarfFlags,
})
} }
} }

View File

@ -315,7 +315,7 @@ pub enum StmtKind {
Expression(Expression), Expression(Expression),
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct TypeDefinition { pub struct TypeDefinition {
pub name: String, pub name: String,
pub kind: TypeDefinitionKind, pub kind: TypeDefinitionKind,

View File

@ -121,7 +121,7 @@ impl Block {
lhs_ref.narrow(&rhs_ref); lhs_ref.narrow(&rhs_ref);
} }
} }
StmtKind::Import(_) => todo!(), StmtKind::Import(_) => panic!(),
StmtKind::Expression(expr) => { StmtKind::Expression(expr) => {
let expr_res = expr.infer_types(&mut state, &inner_refs); let expr_res = expr.infer_types(&mut state, &inner_refs);
state.ok(expr_res, expr.1); state.ok(expr_res, expr.1);