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 ConstValue::*;
use Instr::*; 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 main = module.function("main", Type::I32, Vec::new(), FunctionFlags::default());
let mut m_entry = main.block("entry"); let mut m_entry = main.block("entry");

View File

@ -8,6 +8,7 @@ use crate::{
TerminatorKind, Type, TypeData, TerminatorKind, Type, TypeData,
debug_information::{ debug_information::{
DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue, DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue,
DebugSubprogramValue,
}, },
util::match_types, util::match_types,
}; };
@ -65,12 +66,14 @@ pub struct InstructionHolder {
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct Builder { pub(crate) struct Builder {
modules: Rc<RefCell<Vec<ModuleHolder>>>, modules: Rc<RefCell<Vec<ModuleHolder>>>,
pub(crate) producer: String,
} }
impl Builder { impl Builder {
pub fn new() -> Builder { pub fn new(producer: String) -> Builder {
Builder { Builder {
modules: Rc::new(RefCell::new(Vec::new())), 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, &self,
value: &FunctionValue, value: &FunctionValue,
metadata: DebugMetadataValue, subprogram: DebugSubprogramValue,
) { ) {
unsafe { unsafe {
let mut modules = self.modules.borrow_mut(); let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(value.0.0); let module = modules.get_unchecked_mut(value.0.0);
let function = module.functions.get_unchecked_mut(value.1); 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, LLVMIntPredicate, LLVMLinkage,
analysis::LLVMVerifyModule, analysis::LLVMVerifyModule,
core::*, core::*,
debuginfo::*,
linker::LLVMLinkModules2, linker::LLVMLinkModules2,
prelude::*, prelude::*,
target::{ target::{
@ -23,6 +24,7 @@ use llvm_sys::{
use crate::{ use crate::{
CustomTypeKind, CustomTypeKind,
builder::{TypeHolder, TypeValue}, builder::{TypeHolder, TypeValue},
debug_information::*,
util::{ErrorMessageHolder, MemoryBufferHolder, from_cstring, into_cstring}, util::{ErrorMessageHolder, MemoryBufferHolder, from_cstring, into_cstring},
}; };
@ -180,12 +182,34 @@ pub struct LLVMModule<'a> {
blocks: HashMap<BlockValue, LLVMBasicBlockRef>, blocks: HashMap<BlockValue, LLVMBasicBlockRef>,
values: HashMap<InstructionValue, LLVMValue>, values: HashMap<InstructionValue, LLVMValue>,
types: HashMap<TypeValue, LLVMTypeRef>, 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)] #[derive(Clone, Copy)]
pub struct LLVMFunction { pub struct LLVMFunction {
type_ref: LLVMTypeRef, type_ref: LLVMTypeRef,
value_ref: LLVMValueRef, value_ref: LLVMValueRef,
metadata: Option<LLVMMetadataRef>,
} }
pub struct LLVMValue { pub struct LLVMValue {
@ -203,6 +227,80 @@ impl ModuleHolder {
// Compile the contents // 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(); let mut types = HashMap::new();
for ty in &self.types { for ty in &self.types {
types.insert(ty.value, ty.compile_type(context, &types)); types.insert(ty.value, ty.compile_type(context, &types));
@ -212,10 +310,17 @@ impl ModuleHolder {
for function in &self.functions { for function in &self.functions {
functions.insert( functions.insert(
function.value, 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 { let mut module = LLVMModule {
builder, builder,
context_ref: context.context_ref, context_ref: context.context_ref,
@ -225,17 +330,111 @@ impl ModuleHolder {
types, types,
blocks: HashMap::new(), blocks: HashMap::new(),
values: HashMap::new(), values: HashMap::new(),
debug,
}; };
for function in &self.functions { for function in &self.functions {
function.compile(&mut module, self.data.is_main); function.compile(&mut module, self.data.is_main);
} }
if let Some(debug) = &module.debug {
LLVMDIBuilderFinalize(debug.builder);
}
module_ref 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 { impl TypeHolder {
unsafe fn compile_type( unsafe fn compile_type(
&self, &self,
@ -268,6 +467,7 @@ impl FunctionHolder {
context: &LLVMContext, context: &LLVMContext,
module_ref: LLVMModuleRef, module_ref: LLVMModuleRef,
types: &HashMap<TypeValue, LLVMTypeRef>, types: &HashMap<TypeValue, LLVMTypeRef>,
debug: &Option<LLVMDebugInformation>,
) -> LLVMFunction { ) -> LLVMFunction {
unsafe { unsafe {
let ret_type = self.data.ret.as_llvm(context.context_ref, types); let ret_type = self.data.ret.as_llvm(context.context_ref, types);
@ -285,9 +485,41 @@ impl FunctionHolder {
let function_ref = let function_ref =
LLVMAddFunction(module_ref, into_cstring(&self.data.name).as_ptr(), fn_type); 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 { LLVMFunction {
type_ref: fn_type, type_ref: fn_type,
value_ref: function_ref, value_ref: function_ref,
metadata,
} }
} }
} }

View File

@ -9,9 +9,15 @@ pub struct DebugScopeValue(pub Vec<usize>);
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct DebugLocationValue(pub DebugScopeValue, pub usize); 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); pub struct DebugMetadataValue(pub usize);
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct DebugSubprogramValue(pub usize);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DebugFileData { pub struct DebugFileData {
pub name: String, pub name: String,
@ -20,17 +26,29 @@ pub struct DebugFileData {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct DebugScopeHolder { pub(crate) struct DebugScopeHolder {
value: DebugScopeValue, pub(crate) value: DebugScopeValue,
location: Option<DebugLocation>, pub(crate) location: Option<DebugLocation>,
inner_scopes: Vec<DebugScopeHolder>, pub(crate) inner_scopes: Vec<DebugScopeHolder>,
locations: Vec<DebugLocationHolder>, pub(crate) locations: Vec<DebugLocationHolder>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DebugMetadataHolder { pub struct DebugMetadataHolder {
scope: DebugScopeValue, pub(crate) scope: DebugScopeValue,
value: DebugMetadataValue, pub(crate) value: DebugMetadataValue,
data: DebugMetadata, 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)] #[derive(Debug, Clone)]
@ -39,17 +57,13 @@ pub(crate) struct DebugLocationHolder {
location: DebugLocation, location: DebugLocation,
} }
#[derive(Debug, Clone)]
pub struct DebugLocation {
pub line: u32,
pub column: u32,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DebugInformation { pub struct DebugInformation {
file: DebugFileData, pub file: DebugFileData,
scope: Rc<RefCell<DebugScopeHolder>>, scope: Rc<RefCell<DebugScopeHolder>>,
subprograms: Rc<RefCell<Vec<DebugSubprogramHolder>>>,
metadata: Rc<RefCell<Vec<DebugMetadataHolder>>>, metadata: Rc<RefCell<Vec<DebugMetadataHolder>>>,
types: Rc<RefCell<Vec<DebugTypeHolder>>>,
} }
impl DebugInformation { impl DebugInformation {
@ -65,6 +79,8 @@ impl DebugInformation {
location: None, location: None,
})), })),
metadata: Rc::new(RefCell::new(Vec::new())), metadata: Rc::new(RefCell::new(Vec::new())),
subprograms: Rc::new(RefCell::new(Vec::new())),
types: Rc::new(RefCell::new(Vec::new())),
}, },
scope_value, 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 { pub fn metadata(&self, scope: &DebugScopeValue, kind: DebugMetadata) -> DebugMetadataValue {
let mut metadata = self.metadata.borrow_mut(); let mut metadata = self.metadata.borrow_mut();
let value = DebugMetadataValue(metadata.len()); let value = DebugMetadataValue(metadata.len());
@ -130,25 +156,133 @@ impl DebugInformation {
}); });
value 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)] #[derive(Debug, Clone)]
pub enum DebugMetadata { pub enum DebugMetadata {
Function(DebugFunction),
BasicType(DebugBasicType),
ParamVar(DebugParamVariable), ParamVar(DebugParamVariable),
LocalVar(DebugLocalVariable), LocalVar(DebugLocalVariable),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DebugBasicType { pub struct DebugParamVariable {
pub name: String, pub name: String,
pub size_bits: u32, /// the index (starting from 1) of this variable in the subprogram
pub encoding: AteEncoding, /// 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)] #[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, Address = 1,
Boolean = 2, Boolean = 2,
Float = 4, Float = 4,
@ -159,34 +293,25 @@ pub enum AteEncoding {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DebugFunction { pub struct DebugSubprogramData {
pub scope: DebugScopeValue, /// Function name.
pub name: String, pub name: String,
pub linkage_name: String, pub scope: DebugScopeValue,
/// Used for line number.
pub location: DebugLocation, 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_local: bool,
pub is_definition: bool, pub is_definition: bool,
pub is_optimized: bool, pub is_optimized: bool,
pub scope_line: u32, /// These flags are used to emit dwarf attributes. e.g. is this function
} /// prototyped or not.
pub flags: DwarfFlags,
#[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,
} }

View File

@ -8,7 +8,7 @@ use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue,
use debug::PrintableModule; use debug::PrintableModule;
use debug_information::{ use debug_information::{
DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue, DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue,
DebugScopeValue, DebugScopeValue, DebugSubprogramValue,
}; };
use util::match_types; use util::match_types;
@ -24,9 +24,9 @@ pub struct Context {
} }
impl Context { impl Context {
pub fn new() -> Context { pub fn new<T: Into<String>>(producer: T) -> Context {
Context { Context {
builder: Builder::new(), builder: Builder::new(producer.into()),
} }
} }
@ -76,7 +76,7 @@ impl<'ctx> Module<'ctx> {
ret, ret,
params, params,
flags, flags,
meta: None, debug: None,
}, },
), ),
} }
@ -131,7 +131,7 @@ pub struct FunctionData {
ret: Type, ret: Type,
params: Vec<Type>, params: Vec<Type>,
flags: FunctionFlags, flags: FunctionFlags,
meta: Option<DebugMetadataValue>, debug: Option<DebugSubprogramValue>,
} }
#[derive(Debug, Clone, Copy, Hash)] #[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 { 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"); println!("test1");
let context = Context::new(); let context = Context::new("testcodegen");
let codegen = mir_context.codegen(&context); let codegen = mir_context.codegen(&context);
println!("test2"); println!("test2");

View File

@ -4,15 +4,22 @@ use reid_lib::{
builder::{InstructionValue, TypeValue}, builder::{InstructionValue, TypeValue},
compile::CompiledModule, compile::CompiledModule,
debug_information::{ debug_information::{
AteEncoding, DebugBasicType, DebugFileData, DebugFunction, DebugInformation, DebugLocation, DebugBasicType, DebugFileData, DebugInformation, DebugLocation, DebugMetadata,
DebugMetadata, DebugMetadataValue, DebugScopeValue, DebugMetadataValue, DebugParamVariable, DebugScopeValue, DebugSubprogramData,
DebugSubprogramOptionals, DebugSubprogramTypeData, DebugSubprogramValue, DebugTypeData,
DebugTypeValue, DwarfEncoding, DwarfFlags,
}, },
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,
}; };
use crate::mir::{ use crate::{
self, NamedVariableRef, StructField, StructType, TypeDefinitionKind, TypeKind, VagueLiteral, 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 /// Context that contains all of the given modules as complete codegenerated
@ -32,10 +39,24 @@ impl<'ctx> CodegenContext<'ctx> {
impl mir::Context { impl mir::Context {
/// Compile MIR [`Context`] into [`CodegenContext`] containing LLIR. /// 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(); let mut modules = Vec::new();
for module in &self.modules { 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 } CodegenContext { context }
} }
@ -53,16 +74,22 @@ impl<'ctx> std::fmt::Debug for ModuleCodegen<'ctx> {
pub struct Scope<'ctx, 'a> { pub struct Scope<'ctx, 'a> {
context: &'ctx Context, context: &'ctx Context,
tokens: &'ctx Vec<FullToken>,
module: &'ctx Module<'ctx>, module: &'ctx Module<'ctx>,
function: &'ctx Function<'ctx>, function: &'ctx StackFunction<'ctx>,
block: Block<'ctx>, block: Block<'ctx>,
types: &'a HashMap<TypeValue, TypeDefinitionKind>, types: &'a HashMap<TypeValue, TypeDefinitionKind>,
type_values: &'a HashMap<String, TypeValue>, type_values: &'a HashMap<String, TypeValue>,
functions: &'a HashMap<String, Function<'ctx>>, functions: &'a HashMap<String, StackFunction<'ctx>>,
stack_values: HashMap<String, StackValue>, stack_values: HashMap<String, StackValue>,
debug: &'ctx DebugInformation, debug: &'ctx DebugInformation,
debug_scope: DebugScopeValue, 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)] #[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> { fn with_block(&self, block: Block<'ctx>) -> Scope<'ctx, 'a> {
Scope { Scope {
block, block,
tokens: self.tokens,
function: self.function, function: self.function,
context: self.context, context: self.context,
module: self.module, module: self.module,
@ -126,7 +154,11 @@ impl Default for State {
} }
impl mir::Module { 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 mut module = context.module(&self.name, self.is_main);
let (debug, debug_scope) = if let Some(path) = &self.path { let (debug, debug_scope) = if let Some(path) = &self.path {
@ -147,14 +179,12 @@ impl mir::Module {
debug_const_types.insert( debug_const_types.insert(
TypeKind::U32, TypeKind::U32,
debug.metadata( debug.debug_type(DebugTypeData::Basic(DebugBasicType {
&debug_scope, name: String::from("u32"),
DebugMetadata::BasicType(DebugBasicType { size_bits: 32,
name: String::from("u32"), encoding: DwarfEncoding::Unsigned,
size_bits: 32, flags: DwarfFlags,
encoding: AteEncoding::Unsigned, })),
}),
),
); );
for typedef in &self.typedefs { 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 { for mir_function in &self.functions {
let function = functions.get(&mir_function.name).unwrap(); 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(); let mut stack_values = HashMap::new();
for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() { 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( stack_values.insert(
p_name.clone(), p_name.clone(),
StackValue( StackValue(
@ -229,6 +313,7 @@ impl mir::Module {
let mut scope = Scope { let mut scope = Scope {
context, context,
tokens,
module: &module, module: &module,
function, function,
block: entry, block: entry,
@ -237,9 +322,10 @@ impl mir::Module {
type_values: &type_values, type_values: &type_values,
stack_values, stack_values,
debug: &debug, debug: &debug,
debug_scope: debug_scope.clone(), debug_scope: debug_scope,
debug_const_tys: &debug_const_types, debug_const_tys: &debug_const_types,
}; };
match &mir_function.kind { match &mir_function.kind {
mir::FunctionDefinitionKind::Local(block, _) => { mir::FunctionDefinitionKind::Local(block, _) => {
let state = State::default(); let state = State::default();
@ -252,23 +338,6 @@ impl mir::Module {
scope.block.terminate(Term::RetVoid).ok(); 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(_) => {} mir::FunctionDefinitionKind::Extern(_) => {}
} }
@ -444,13 +513,13 @@ impl mir::Expression {
Some( Some(
scope scope
.block .block
.build(Instr::FunctionCall(callee.value(), params)) .build(Instr::FunctionCall(callee.ir.value(), params))
.unwrap(), .unwrap(),
) )
} }
mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state), mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state),
mir::ExprKind::Block(block) => { 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) { if let Some(ret) = block.codegen(&mut inner_scope, state) {
inner_scope inner_scope
.block .block
@ -587,9 +656,9 @@ impl mir::IfExpression {
let condition = self.0.codegen(scope, state).unwrap(); let condition = self.0.codegen(scope, state).unwrap();
// Create blocks // Create blocks
let then_b = scope.function.block("then"); let then_b = scope.function.ir.block("then");
let mut else_b = scope.function.block("else"); let mut else_b = scope.function.ir.block("else");
let after_b = scope.function.block("after"); let after_b = scope.function.ir.block("after");
// Store for convenience // Store for convenience
let then_bb = then_b.value(); 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)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct ErrModule { pub struct Module {
pub name: String, pub name: String,
pub tokens: Option<Vec<FullToken>>, pub tokens: Option<Vec<FullToken>>,
pub source: Option<String>, pub source: Option<String>,
@ -77,7 +77,7 @@ pub struct ErrModule {
#[derive(Debug, Clone, PartialEq, Eq, Default)] #[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ModuleMap { pub struct ModuleMap {
module_map: HashMap<mir::SourceModuleId, ErrModule>, module_map: HashMap<mir::SourceModuleId, Module>,
module_counter: mir::SourceModuleId, module_counter: mir::SourceModuleId,
} }
@ -86,7 +86,7 @@ impl ModuleMap {
let id = self.module_counter.increment(); let id = self.module_counter.increment();
self.module_map.insert( self.module_map.insert(
id, id,
ErrModule { Module {
name: name.into(), name: name.into(),
tokens: None, tokens: None,
source: 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) self.module_map.get(id)
} }
} }
@ -177,7 +177,7 @@ impl std::fmt::Display for ReidError {
let mut curr_module = None; let mut curr_module = None;
for error in sorted_errors { for error in sorted_errors {
let meta = error.get_meta(); 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 position = if let Some(tokens) = &module.tokens {
let range_tokens = meta.range.into_tokens(&tokens); let range_tokens = meta.range.into_tokens(&tokens);

View File

@ -86,7 +86,7 @@ pub fn compile_module<'map>(
path: Option<PathBuf>, path: Option<PathBuf>,
is_main: bool, is_main: bool,
) -> Result<mir::Module, ReidError> { ) -> 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); 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)?; perform_all_passes(&mut mir_context, module_map)?;
let mut context = Context::new(); let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
let codegen_modules = mir_context.codegen(&mut context); let codegen_modules = mir_context.codegen(&mut context, &module_map);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
dbg!(&codegen_modules); dbg!(&codegen_modules);

View File

@ -87,7 +87,7 @@ impl<'map> Pass for LinkerPass<'map> {
for module in context.modules.drain(..) { for module in context.modules.drain(..) {
let tokens = self let tokens = self
.module_map .module_map
.get_module(&module.module_id) .module(&module.module_id)
.unwrap() .unwrap()
.tokens .tokens
.clone() .clone()

View File

@ -4,7 +4,10 @@
use std::{collections::HashMap, path::PathBuf}; use std::{collections::HashMap, path::PathBuf};
use crate::{lexer::Position, token_stream::TokenRange}; use crate::{
lexer::{FullToken, Position},
token_stream::TokenRange,
};
mod display; mod display;
pub mod r#impl; pub mod r#impl;
@ -36,6 +39,19 @@ impl Metadata {
(self.range.start >= other.range.start && self.range.end <= other.range.end) (self.range.start >= other.range.start && self.range.end <= other.range.end)
|| (other.range.start >= self.range.start && other.range.end <= self.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 { impl std::ops::Add for Metadata {
@ -248,7 +264,9 @@ pub struct FunctionCall {
#[derive(Debug)] #[derive(Debug)]
pub struct FunctionDefinition { pub struct FunctionDefinition {
pub name: String, pub name: String,
/// Whether this function is visible to outside modules
pub is_pub: bool, pub is_pub: bool,
/// Whether this module is from an external module, and has been imported
pub is_imported: bool, pub is_imported: bool,
pub return_type: TypeKind, pub return_type: TypeKind,
pub parameters: Vec<(String, TypeKind)>, pub parameters: Vec<(String, TypeKind)>,