Add debug information compilation for subprograms and their parameters
This commit is contained in:
parent
9bb4f97e6b
commit
0c6d9885ec
@ -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");
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(¶m.ty).unwrap(),
|
||||
param.always_preserve as i32,
|
||||
param.flags.as_llvm(),
|
||||
),
|
||||
DebugMetadata::LocalVar(debug_local_variable) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DebugTypeHolder {
|
||||
unsafe fn compile_debug(&self, debug: &LLVMDebugInformation) -> LLVMMetadataRef {
|
||||
unsafe {
|
||||
match &self.data {
|
||||
DebugTypeData::Basic(ty) => LLVMDIBuilderCreateBasicType(
|
||||
debug.builder,
|
||||
into_cstring(ty.name.clone()).as_ptr(),
|
||||
ty.name.len(),
|
||||
ty.size_bits as u64,
|
||||
ty.encoding as u32,
|
||||
ty.flags.as_llvm(),
|
||||
),
|
||||
DebugTypeData::Subprogram(subprogram) => {
|
||||
let mut params = subprogram
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|p| *debug.types.get(p).unwrap())
|
||||
.collect::<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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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 {
|
||||
debug.debug_type(DebugTypeData::Basic(DebugBasicType {
|
||||
name: String::from("u32"),
|
||||
size_bits: 32,
|
||||
encoding: AteEncoding::Unsigned,
|
||||
}),
|
||||
),
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
@ -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)>,
|
||||
|
Loading…
Reference in New Issue
Block a user