Fix a bunch of bugs with debug information and stuff

This commit is contained in:
Sofia 2025-07-22 19:16:45 +03:00
parent 78a1e9f06b
commit 81ce1dfc2e
6 changed files with 236 additions and 173 deletions

View File

@ -389,6 +389,7 @@ impl Builder {
return Err(()); // TODO error: invalid amount of params
}
for (a, b) in param_types.iter().zip(params) {
dbg!(&a, &b.get_type(&self));
if *a != b.get_type(&self)? {
return Err(()); // TODO error: params do not match
}
@ -478,7 +479,7 @@ impl Builder {
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(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
Instr::BitCast(instr, ty) => Ok(()),
}
}
}
@ -628,7 +629,7 @@ impl InstructionValue {
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(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
BitCast(_, ty) => Ok(ty.clone()),
}
}
}

View File

@ -376,8 +376,8 @@ impl DebugLocationHolder {
unsafe {
LLVMDIBuilderCreateDebugLocation(
context.context_ref,
self.location.line,
self.location.column,
self.location.pos.line,
self.location.pos.column,
*debug.programs.get(&self.program).unwrap(),
null_mut(),
)
@ -399,8 +399,8 @@ impl DebugScopeHolder {
di_builder,
parent,
file,
location.line,
location.column,
location.pos.line,
location.pos.column,
)
} else {
LLVMDIBuilderCreateLexicalBlockFile(di_builder, parent, file, 0)
@ -426,7 +426,7 @@ impl DebugMetadataHolder {
param.name.len(),
param.arg_idx + 1,
debug.file_ref,
self.location.line,
self.location.pos.line,
*debug.types.get(&param.ty).unwrap(),
param.always_preserve as i32,
param.flags.as_llvm(),
@ -437,7 +437,7 @@ impl DebugMetadataHolder {
into_cstring(var.name.clone()).as_ptr(),
var.name.len(),
debug.file_ref,
self.location.line,
self.location.pos.line,
*debug.types.get(&var.ty).unwrap(),
var.always_preserve as i32,
var.flags.as_llvm(),
@ -504,11 +504,11 @@ impl DebugTypeHolder {
.map(|field| {
LLVMDIBuilderCreateMemberType(
debug.builder,
*debug.programs.get(&st.location.scope).unwrap(),
*debug.programs.get(&st.scope).unwrap(),
into_cstring(field.name.clone()).as_ptr(),
field.name.len(),
debug.file_ref,
field.location.line,
field.pos.map(|p| p.line).unwrap_or(1),
field.size_bits,
0,
1,
@ -519,11 +519,11 @@ impl DebugTypeHolder {
.collect::<Vec<_>>();
LLVMDIBuilderCreateStructType(
debug.builder,
*debug.programs.get(&st.location.scope).unwrap(),
*debug.programs.get(&st.scope).unwrap(),
into_cstring(st.name.clone()).as_ptr(),
st.name.len(),
debug.file_ref,
st.location.line,
st.pos.map(|p| p.line).unwrap_or(1),
st.size_bits,
0,
st.flags.as_llvm(),
@ -617,7 +617,7 @@ impl FunctionHolder {
mangled_name,
mangled_length,
debug.file_ref,
subprogram.location.line,
subprogram.location.pos.line,
*debug.types.get(&subprogram.ty).unwrap(),
subprogram.opts.is_local as i32,
subprogram.opts.is_definition as i32,
@ -1027,8 +1027,8 @@ impl InstructionHolder {
let location = LLVMDIBuilderCreateDebugLocation(
module.context_ref,
record.location.line,
record.location.column,
record.location.pos.line,
record.location.pos.column,
*debug.programs.get(&record.scope).unwrap(),
null_mut(),
);

View File

@ -225,6 +225,11 @@ impl DebugInformation {
#[derive(Clone, Copy)]
pub struct DebugLocation {
pub scope: DebugProgramValue,
pub pos: DebugPosition,
}
#[derive(Clone, Copy)]
pub struct DebugPosition {
pub line: u32,
pub column: u32,
}
@ -310,7 +315,8 @@ pub struct DebugPointerType {
#[derive(Clone)]
pub struct DebugStructType {
pub name: String,
pub location: DebugLocation,
pub scope: DebugProgramValue,
pub pos: Option<DebugPosition>,
pub size_bits: u64,
pub flags: DwarfFlags,
pub fields: Vec<DebugFieldType>,
@ -319,7 +325,8 @@ pub struct DebugStructType {
#[derive(Clone)]
pub struct DebugFieldType {
pub name: String,
pub location: DebugLocation,
pub scope: DebugProgramValue,
pub pos: Option<DebugPosition>,
pub size_bits: u64,
pub offset: u64,
pub flags: DwarfFlags,

View File

@ -11,8 +11,8 @@ use crate::{
debug_information::{
DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocalVariable,
DebugLocation, DebugLocationValue, DebugMetadata, DebugMetadataValue, DebugParamVariable,
DebugPointerType, DebugProgramValue, DebugRecordKind, DebugScopeValue, DebugStructType,
DebugSubprogramType, DebugTypeData, DebugTypeHolder, DebugTypeValue,
DebugPointerType, DebugPosition, DebugProgramValue, DebugRecordKind, DebugScopeValue,
DebugStructType, DebugSubprogramType, DebugTypeData, DebugTypeHolder, DebugTypeValue,
},
pad_adapter::PadAdapter,
};
@ -171,6 +171,12 @@ impl DebugMetadataValue {
}
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)
}
@ -484,7 +490,8 @@ impl Debug for DebugStructType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Struct")
.field("name", &self.name)
.field("location", &self.location)
.field("scope", &self.scope)
.field("pos", &self.pos)
.field("size_bit", &self.size_bits)
.field("flags", &self.flags)
.field("elements", &self.fields)
@ -495,7 +502,8 @@ impl Debug for DebugStructType {
impl Debug for DebugFieldType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(&format!("Field({})", self.name))
.field("location", &self.location)
.field("scope", &self.scope)
.field("pos", &self.pos)
.field("size_bits", &self.size_bits)
.field("offset", &self.offset)
.field("flags", &self.flags)
@ -569,6 +577,12 @@ impl Debug for DebugLocationValue {
}
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)
}

View File

@ -521,7 +521,7 @@ impl ConstValue {
ConstValue::U32(_) => U32,
ConstValue::U64(_) => U64,
ConstValue::U128(_) => U128,
ConstValue::Str(_) => Type::Ptr(Box::new(I8)),
ConstValue::Str(_) => Type::Ptr(Box::new(U8)),
ConstValue::Bool(_) => Bool,
ConstValue::F16(_) => F16,
ConstValue::F32B(_) => F32B,

View File

@ -6,7 +6,7 @@ use reid_lib::{
debug_information::{
DebugArrayType, DebugBasicType, DebugFieldType, DebugFileData, DebugInformation,
DebugLocalVariable, DebugLocation, DebugMetadata, DebugParamVariable, DebugPointerType,
DebugProgramValue, DebugRecordKind, DebugStructType, DebugSubprogramData,
DebugPosition, DebugProgramValue, DebugRecordKind, DebugStructType, DebugSubprogramData,
DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, DebugTypeValue,
DwarfEncoding, DwarfFlags, InstructionDebugRecordData,
},
@ -57,6 +57,8 @@ impl mir::Context {
#[derive(Clone)]
struct ModuleCodegen<'ctx> {
module: Module<'ctx>,
tokens: &'ctx Vec<FullToken>,
debug_types: Option<HashMap<TypeKind, DebugTypeValue>>,
type_values: HashMap<TypeKey, TypeValue>,
}
@ -194,7 +196,7 @@ impl Default for State {
impl mir::Module {
fn codegen<'ctx>(
&self,
&'ctx self,
context: &'ctx Context,
modules: HashMap<SourceModuleId, ModuleCodegen<'ctx>>,
) -> ModuleCodegen<'ctx> {
@ -227,7 +229,9 @@ impl mir::Module {
&debug_types,
&type_values,
&types,
tokens,
self.module_id,
&self.tokens,
&modules,
),
)
};
@ -247,29 +251,23 @@ impl mir::Module {
insert_debug!(&TypeKind::Void);
insert_debug!(&TypeKind::Char);
for typedef in &self.typedefs {
let mut typedefs = self.typedefs.clone();
typedefs.sort_by(|a, b| b.source_module.cmp(&a.source_module));
for typedef in typedefs {
let type_key = TypeKey(typedef.name.clone(), typedef.source_module);
let type_value = if typedef.source_module != self.module_id {
*modules
.get(&typedef.source_module)
.unwrap()
.type_values
.get(&type_key)
.unwrap()
} else {
match &typedef.kind {
TypeDefinitionKind::Struct(StructType(fields)) => {
module.custom_type(CustomTypeKind::NamedStruct(NamedStruct(
typedef.name.clone(),
fields
.iter()
// TODO: Reorder custom-type definitions such that
// inner types get evaluated first. Otherwise this
// will cause a panic!
.map(|StructField(_, t, _)| t.get_type(&type_values, &types))
.collect(),
)))
}
let type_value = match &typedef.kind {
TypeDefinitionKind::Struct(StructType(fields)) => {
module.custom_type(CustomTypeKind::NamedStruct(NamedStruct(
typedef.name.clone(),
fields
.iter()
// TODO: Reorder custom-type definitions such that
// inner types get evaluated first. Otherwise this
// will cause a panic!
.map(|StructField(_, t, _)| t.get_type(&type_values, &types))
.collect(),
)))
}
};
types.insert(type_value, typedef.clone());
@ -316,120 +314,128 @@ impl mir::Module {
for mir_function in &self.functions {
let function = functions.get(&mir_function.name).unwrap();
let mut entry = function.ir.block("entry");
// Insert debug information
let debug_scope = if let Some(location) =
mir_function.signature().into_debug(tokens, compile_unit)
{
// let debug_scope = debug.inner_scope(&outer_scope, location);
let fn_param_ty = &mir_function.return_type.get_debug_type_hard(
compile_unit,
&debug,
&debug_types,
&type_values,
&types,
tokens,
);
let debug_ty = debug.debug_type(DebugTypeData::Subprogram(DebugSubprogramType {
parameters: vec![*fn_param_ty],
flags: DwarfFlags,
}));
let subprogram = debug.subprogram(DebugSubprogramData {
name: mir_function.name.clone(),
outer_scope: compile_unit.clone(),
location,
ty: debug_ty,
opts: DebugSubprogramOptionals {
is_local: !mir_function.is_pub,
is_definition: true,
..DebugSubprogramOptionals::default()
},
});
function.ir.set_debug(subprogram);
Some(subprogram)
} else {
None
};
// Compile actual IR part
let mut stack_values = HashMap::new();
for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() {
// Codegen actual parameters
let arg_name = format!("arg.{}", p_name);
let param = entry
.build_named(format!("{}.get", arg_name), Instr::Param(i))
.unwrap();
let alloca = entry
.build_named(
&arg_name,
Instr::Alloca(p_ty.get_type(&type_values, &types)),
)
.unwrap();
entry
.build_named(format!("{}.store", arg_name), Instr::Store(alloca, param))
.unwrap();
stack_values.insert(
p_name.clone(),
StackValue(
StackValueKind::mutable(p_ty.is_mutable(), alloca),
TypeKind::CodegenPtr(Box::new(p_ty.clone())),
),
);
// Generate debug info
if let (Some(debug_scope), Some(location)) = (
&debug_scope,
mir_function.signature().into_debug(tokens, compile_unit),
) {
debug.metadata(
&location,
DebugMetadata::ParamVar(DebugParamVariable {
name: p_name.clone(),
arg_idx: i as u32,
ty: p_ty.get_debug_type_hard(
*debug_scope,
&debug,
&debug_types,
&type_values,
&types,
tokens,
),
always_preserve: true,
flags: DwarfFlags,
}),
);
}
}
let mut scope = Scope {
context,
modules: &modules,
tokens,
module: &module,
module_id: self.module_id,
function,
block: entry,
functions: &functions,
types: &types,
type_values: &type_values,
stack_values,
debug: debug_scope.and_then(|scope| {
Some(Debug {
info: &debug,
scope,
types: &debug_types,
})
}),
};
match &mir_function.kind {
mir::FunctionDefinitionKind::Local(block, _) => {
let mut entry = function.ir.block("entry");
// Insert debug information
let debug_scope = if let Some(location) =
mir_function.signature().into_debug(tokens, compile_unit)
{
// let debug_scope = debug.inner_scope(&outer_scope, location);
let fn_param_ty = &mir_function.return_type.get_debug_type_hard(
compile_unit,
&debug,
&debug_types,
&type_values,
&types,
self.module_id,
&self.tokens,
&modules,
);
let debug_ty =
debug.debug_type(DebugTypeData::Subprogram(DebugSubprogramType {
parameters: vec![*fn_param_ty],
flags: DwarfFlags,
}));
let subprogram = debug.subprogram(DebugSubprogramData {
name: mir_function.name.clone(),
outer_scope: compile_unit.clone(),
location,
ty: debug_ty,
opts: DebugSubprogramOptionals {
is_local: !mir_function.is_pub,
is_definition: true,
..DebugSubprogramOptionals::default()
},
});
function.ir.set_debug(subprogram);
Some(subprogram)
} else {
None
};
// Compile actual IR part
let mut stack_values = HashMap::new();
for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() {
// Codegen actual parameters
let arg_name = format!("arg.{}", p_name);
let param = entry
.build_named(format!("{}.get", arg_name), Instr::Param(i))
.unwrap();
let alloca = entry
.build_named(
&arg_name,
Instr::Alloca(p_ty.get_type(&type_values, &types)),
)
.unwrap();
entry
.build_named(format!("{}.store", arg_name), Instr::Store(alloca, param))
.unwrap();
stack_values.insert(
p_name.clone(),
StackValue(
StackValueKind::mutable(p_ty.is_mutable(), alloca),
TypeKind::CodegenPtr(Box::new(p_ty.clone())),
),
);
// Generate debug info
if let (Some(debug_scope), Some(location)) = (
&debug_scope,
mir_function.signature().into_debug(tokens, compile_unit),
) {
dbg!(mir_function.name.clone());
dbg!(p_name.clone());
// debug.metadata(
// &location,
// DebugMetadata::ParamVar(DebugParamVariable {
// name: p_name.clone(),
// arg_idx: i as u32,
// ty: p_ty.get_debug_type_hard(
// *debug_scope,
// &debug,
// &debug_types,
// &type_values,
// &types,
// self.module_id,
// &self.tokens,
// &modules,
// ),
// always_preserve: true,
// flags: DwarfFlags,
// }),
// );
}
}
let mut scope = Scope {
context,
modules: &modules,
tokens,
module: &module,
module_id: self.module_id,
function,
block: entry,
functions: &functions,
types: &types,
type_values: &type_values,
stack_values,
debug: debug_scope.and_then(|scope| {
Some(Debug {
info: &debug,
scope,
types: &debug_types,
})
}),
};
let state = State::default();
if let Some(ret) = block.codegen(&mut scope, &state) {
scope.block.terminate(Term::Ret(ret.instr())).unwrap();
@ -454,7 +460,9 @@ impl mir::Module {
ModuleCodegen {
module,
debug_types: Some(debug_types),
type_values,
tokens: &self.tokens,
}
}
}
@ -680,8 +688,9 @@ impl mir::Expression {
let params = call
.parameters
.iter()
.map(|e| e.codegen(scope, &mut state.load(true)).unwrap().instr())
.collect();
.map(|e| e.codegen(scope, state).unwrap())
.collect::<Vec<_>>();
let param_instrs = params.iter().map(|e| e.instr()).collect();
let callee = scope
.functions
.get(&call.name)
@ -691,7 +700,7 @@ impl mir::Expression {
.block
.build_named(
call.name.clone(),
Instr::FunctionCall(callee.ir.value(), params),
Instr::FunctionCall(callee.ir.value(), param_instrs),
)
.unwrap();
@ -769,7 +778,6 @@ impl mir::Expression {
};
let (ptr, contained_ty) = if let TypeKind::UserPtr(further_inner) = *inner.clone() {
dbg!(&further_inner, &val_t);
let loaded = scope
.block
.build_named(
@ -806,7 +814,6 @@ impl mir::Expression {
};
if state.should_load {
dbg!(&contained_ty);
Some(StackValue(
kind.derive(
scope
@ -900,7 +907,6 @@ impl mir::Expression {
mir::ExprKind::Accessed(expression, type_kind, field) => {
let struct_val = expression.codegen(scope, &state.load(false)).unwrap();
dbg!(&expression, &struct_val);
let TypeKind::CodegenPtr(inner) = &struct_val.1 else {
panic!("tried accessing non-pointer");
};
@ -1049,7 +1055,7 @@ impl mir::Expression {
};
StackValue(
StackValueKind::mutable(mutable, var_ptr_instr),
*borrow_inner.clone(),
TypeKind::CodegenPtr(borrow_inner.clone()),
)
}
})
@ -1059,7 +1065,18 @@ impl mir::Expression {
if val.1 == *type_kind {
Some(val)
} else if let (TypeKind::UserPtr(_), TypeKind::UserPtr(_)) = (&val.1, type_kind) {
Some(val)
Some(StackValue(
val.0.derive(
scope
.block
.build(Instr::BitCast(
val.instr(),
type_kind.get_type(scope.type_values, scope.types),
))
.unwrap(),
),
type_kind.clone(),
))
} else {
let cast_instr = val
.1
@ -1262,7 +1279,7 @@ impl TypeKind {
TypeKind::F128 => Type::F128,
TypeKind::F80 => Type::F80,
TypeKind::F128PPC => Type::F128PPC,
TypeKind::Char => Type::I8,
TypeKind::Char => Type::U8,
TypeKind::Array(elem_t, len) => {
Type::Array(Box::new(elem_t.get_type(type_vals, typedefs)), *len)
}
@ -1293,7 +1310,9 @@ impl TypeKind {
debug.types,
scope.type_values,
scope.types,
scope.module_id,
scope.tokens,
scope.modules,
)
}
@ -1304,7 +1323,9 @@ impl TypeKind {
debug_types: &HashMap<TypeKind, DebugTypeValue>,
type_values: &HashMap<TypeKey, TypeValue>,
types: &HashMap<TypeValue, TypeDefinition>,
local_mod: SourceModuleId,
tokens: &Vec<FullToken>,
modules: &HashMap<SourceModuleId, ModuleCodegen>,
) -> DebugTypeValue {
if let Some(ty) = debug_types.get(self) {
return *ty;
@ -1322,7 +1343,9 @@ impl TypeKind {
debug_types,
type_values,
types,
local_mod,
tokens,
modules,
),
size_bits: self.size_of(),
})
@ -1334,7 +1357,9 @@ impl TypeKind {
debug_types,
type_values,
types,
local_mod,
tokens,
modules,
);
DebugTypeData::Array(DebugArrayType {
size_bits: self.size_of(),
@ -1345,15 +1370,21 @@ impl TypeKind {
}
TypeKind::CustomType(key) => {
let typedef = types.get(type_values.get(key).unwrap()).unwrap();
match &typedef.kind {
TypeDefinitionKind::Struct(struct_type) => {
let mut fields = Vec::new();
let mut size_bits = 0;
for field in &struct_type.0 {
let location = if typedef.source_module != local_mod {
None
} else {
field.2.into_debug(&tokens, scope)
};
fields.push(DebugFieldType {
name: field.0.clone(),
location: field.2.into_debug(tokens, scope).unwrap(),
scope,
pos: location.map(|l| l.pos),
size_bits: field.1.size_of(),
offset: size_bits,
flags: DwarfFlags,
@ -1363,15 +1394,23 @@ impl TypeKind {
debug_types,
type_values,
types,
local_mod,
tokens,
modules,
),
});
size_bits += field.1.size_of();
}
{
let location = if typedef.source_module != local_mod {
None
} else {
typedef.meta.into_debug(&tokens, scope)
};
DebugTypeData::Struct(DebugStructType {
name: key.0.clone(),
location: typedef.meta.into_debug(tokens, scope).unwrap(),
scope,
pos: location.map(|l| l.pos),
size_bits,
flags: DwarfFlags,
fields,
@ -1422,7 +1461,7 @@ impl Metadata {
if let Some((start, _)) = self.into_positions(tokens) {
Some(start.debug(scope))
} else {
Some(Position(0, 0).debug(scope))
None
}
}
}
@ -1430,8 +1469,10 @@ impl Metadata {
impl Position {
fn debug(self, scope: DebugProgramValue) -> DebugLocation {
DebugLocation {
line: self.1,
column: self.0,
pos: DebugPosition {
line: self.1,
column: self.0,
},
scope,
}
}