Compare commits

..

9 Commits

17 changed files with 927 additions and 487 deletions

52
Cargo.lock generated
View File

@ -3,13 +3,10 @@
version = 4 version = 4
[[package]] [[package]]
name = "aho-corasick" name = "anyhow"
version = "1.1.3" version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "cc" name = "cc"
@ -43,23 +40,18 @@ checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]] [[package]]
name = "llvm-sys" name = "llvm-sys"
version = "160.2.1" version = "201.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e73861901245d32e1c3d8b35b639cf100859b4cd0c9da56fe0273040acbb3ea4" checksum = "9bb947e8b79254ca10d496d0798a9ba1287dcf68e50a92b016fec1cc45bef447"
dependencies = [ dependencies = [
"anyhow",
"cc", "cc",
"lazy_static", "lazy_static",
"libc", "libc",
"regex", "regex-lite",
"semver", "semver",
] ]
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.95" version = "1.0.95"
@ -79,40 +71,16 @@ dependencies = [
] ]
[[package]] [[package]]
name = "regex" name = "regex-lite"
version = "1.11.1" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]] [[package]]
name = "reid" name = "reid"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"colored", "colored",
"llvm-sys",
"reid-lib", "reid-lib",
"thiserror", "thiserror",
] ]

View File

@ -77,42 +77,42 @@ change erratically.
This is what worked for me, might not (probably) work for you, depending on This is what worked for me, might not (probably) work for you, depending on
various versions of various libraries. various versions of various libraries.
### Compiling LLVM 16.0.0 ### Compiling LLVM 20.1.8
#### Context #### Context
Context for my computer. I am on ArchLinux, and here are some libraries and Context for my computer. I am on ArchLinux, and here are some libraries and
their current versions that I have installed as of compiling, I'm not sure what their current versions that I have installed as of compiling, I'm not sure what
of them are relevant, if any, but saving them here still feels like a good idea of them are relevant, if any, but saving them here still feels like a good idea
for the future: for the future:
- `cmake 3.27.0-1` - `clang 19.1.7-2`
- `lib32-llvm-libs 15.0.7-1` - `cmake 4.0.2-1`
- `llvm 15.0.7-3` - `extra-cmake-modules 6.14.0-1`
- `llvm-libs 15.0.7-3` - `gcc 15.1.1+r7+gf36ec88aa85a-1`
- `gcc 13.1.1-2` - `gcc-libs 15.1.1+r7+gf36ec88aa85a-1`
- `gcc-libs 13.1.1-2` - `lib32-gcc-libs 15.1.1+r7+gf36ec88aa85a-1`
- `lib32-gcc-libs 13.1.1-2` - `lib32-llvm-libs 1:19.1.7-2`
- `lld 15.0.7-2` - `libgccjit 15.1.1+r7+gf36ec88aa85a-1`
- `lldb 15.0.7-3` - `lld 19.1.7-1`
- `clang 15.0.7-9` - `lldb 19.1.7-2`
- `llvm 19.1.7-2`
- `llvm-libs 19.1.7-2`
- `llvm14 14.0.6-5`
- `llvm14-libs 14.0.6-5`
- `llvm15 15.0.7-3`
- `llvm15-libs 15.0.7-3`
- `make 4.4.1-2` - `make 4.4.1-2`
- `automake 1.16.5-2`
#### Commands #### Commands
```sh ```sh
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.0/llvm-16.0.0.src.tar.xz git clone https://github.com/llvm/llvm-project.git --depth=1 --branch=llvmorg-20.1.8
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.0/cmake-16.0.0.src.tar.xz
tar xvf llvm-16.0.0.src.tar.xz cd llvm_project
tar xvf cmake-16.0.0.src.tar.xz
mv cmake-16.0.0.src cmake cmake llvm -B build -DCMAKE_BUILD_TYPE=MinSizeRel -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INCLUDE_TESTS=OFF -DLLVM_BUILD_BENCHMARKS=OFF -G Ninja -DLLVM_USE_LINKER="ld.lld" -DLLVM_PARALLEL_LINK_JOBS=8
cd llvm-16.0.0.src ninja -j23
cmake -B build -DCMAKE_INSTALL_PREFIX=$HOME/llvm-16 -DCMAKE_BUILD_TYPE=MinSizeRel -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INCLUDE_TESTS=OFF
make -j8
``` ```
*Also Note:* Building LLVM with `Ninja` was not successful for me, but this *Also Note:* Building LLVM with `Ninja` was not successful for me, but this
@ -121,11 +121,11 @@ method was. Ninja may be successful with you, to try it, add `-G Ninja` to the
### Building this crate itself ### Building this crate itself
Assuming `llvm-16.0.0.src` from the previous step was at Assuming `llvm-project` from the previous step was at
`/path/llvm-16.0.0.src`, building this crate can be done via the following command: `/path/llvm-project`, building this crate can be done via the following command:
```sh ```sh
LLVM_SYS_160_PREFIX=/path/llvm-16.0.0.src/build cargo build LLVM_SYS_201_PREFIX=/path/llvm-project/build cargo build
``` ```
## In conclusion ## In conclusion

View File

@ -7,6 +7,6 @@ edition = "2024"
[dependencies] [dependencies]
## LLVM Bindings ## LLVM Bindings
llvm-sys = "160" llvm-sys = {version ="201.0.1", features=["force-static"] }
## Make it easier to generate errors ## Make it easier to generate errors
thiserror = "1.0.44" thiserror = "1.0.44"

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

@ -7,7 +7,7 @@ use crate::{
BlockData, CustomTypeKind, FunctionData, Instr, InstructionData, ModuleData, NamedStruct, BlockData, CustomTypeKind, FunctionData, Instr, InstructionData, ModuleData, NamedStruct,
TerminatorKind, Type, TypeData, TerminatorKind, Type, TypeData,
debug_information::{ debug_information::{
DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue, DebugInformation, DebugLocationValue, DebugMetadataValue, DebugProgramValue,
}, },
util::match_types, util::match_types,
}; };
@ -65,12 +65,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 +195,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: DebugProgramValue,
) { ) {
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)
} }
} }
@ -225,6 +227,25 @@ impl Builder {
} }
} }
pub(crate) unsafe fn set_terminator_location(
&self,
block: &BlockValue,
location: DebugLocationValue,
) -> Result<(), ()> {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(block.0.0.0);
let function = module.functions.get_unchecked_mut(block.0.1);
let block = function.blocks.get_unchecked_mut(block.1);
if let Some(_) = &block.data.terminator_location {
Err(())
} else {
block.data.terminator_location = Some(location);
Ok(())
}
}
}
pub(crate) unsafe fn delete_block(&self, block: &BlockValue) -> Result<(), ()> { pub(crate) unsafe fn delete_block(&self, block: &BlockValue) -> Result<(), ()> {
unsafe { unsafe {
let mut modules = self.modules.borrow_mut(); let mut modules = self.modules.borrow_mut();

View File

@ -5,9 +5,10 @@
use std::{collections::HashMap, ptr::null_mut}; use std::{collections::HashMap, ptr::null_mut};
use llvm_sys::{ use llvm_sys::{
LLVMIntPredicate, LLVMLinkage, LLVMIntPredicate, LLVMLinkage, LLVMValueKind,
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},
}; };
@ -90,14 +92,6 @@ impl CompiledModule {
LLVMSetTarget(self.module_ref, triple); LLVMSetTarget(self.module_ref, triple);
LLVMSetModuleDataLayout(self.module_ref, data_layout); LLVMSetModuleDataLayout(self.module_ref, data_layout);
let mut err = ErrorMessageHolder::null();
LLVMVerifyModule(
self.module_ref,
llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction,
err.borrow_mut(),
);
err.into_result().unwrap();
let mut asm_buffer = MemoryBufferHolder::empty("asm"); let mut asm_buffer = MemoryBufferHolder::empty("asm");
let mut err = ErrorMessageHolder::null(); let mut err = ErrorMessageHolder::null();
LLVMTargetMachineEmitToMemoryBuffer( LLVMTargetMachineEmitToMemoryBuffer(
@ -120,14 +114,28 @@ impl CompiledModule {
); );
err.into_result().unwrap(); err.into_result().unwrap();
let llvm_ir = from_cstring(LLVMPrintModuleToString(self.module_ref))
.expect("Unable to print LLVM IR to string");
let mut err = ErrorMessageHolder::null();
LLVMVerifyModule(
self.module_ref,
llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction,
err.borrow_mut(),
);
if let Err(e) = err.into_result() {
println!("{}", llvm_ir);
panic!("{}", e);
}
CompileOutput { CompileOutput {
triple: from_cstring(triple).expect("Unable to convert triple from cstring"), triple: from_cstring(triple).expect("Unable to convert triple from cstring"),
assembly: asm_buffer assembly: asm_buffer
.as_string() .as_string()
.expect("Error while converting assembly-buffer to string"), .expect("Error while converting assembly-buffer to string"),
obj_buffer: obj_buffer.as_buffer(), obj_buffer: obj_buffer.as_buffer(),
llvm_ir: from_cstring(LLVMPrintModuleToString(self.module_ref)) llvm_ir,
.expect("Unable to print LLVM IR to string"),
} }
} }
} }
@ -180,12 +188,35 @@ 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>,
programs: &'a mut HashMap<DebugProgramValue, LLVMMetadataRef>,
metadata: &'a mut HashMap<DebugMetadataValue, LLVMMetadataRef>,
locations: &'a mut HashMap<DebugLocationValue, 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 +234,85 @@ impl ModuleHolder {
// Compile the contents // Compile the contents
let mut types = HashMap::new();
let mut metadata = HashMap::new();
let mut programs = HashMap::new();
let mut locations = 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();
// scopes.insert(scope.borrow().value.clone(), compile_unit);
// for scope in &scope.borrow().inner_scopes {
// dbg!("hello");
// scope.compile_scope(compile_unit, file_ref, &mut scopes, di_builder);
// }
// dbg!("after!");
programs.insert(DebugProgramValue(0), compile_unit);
let debug = LLVMDebugInformation {
builder: di_builder,
debug: debug,
file_ref,
types: &mut types,
metadata: &mut metadata,
programs: &mut programs,
locations: &mut locations,
};
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));
@ -210,10 +320,26 @@ impl ModuleHolder {
let mut functions = HashMap::new(); let mut functions = HashMap::new();
for function in &self.functions { for function in &self.functions {
functions.insert( let func = function.compile_signature(context, module_ref, &types, &debug);
function.value, functions.insert(function.value, func);
function.compile_signature(context, module_ref, &types),
); if let Some(debug) = &mut debug {
if let Some(program_value) = function.data.debug {
debug.programs.insert(program_value, func.metadata.unwrap());
}
}
}
if let Some(debug) = &mut debug {
for location in debug.debug.get_locations().borrow().iter() {
let location_ref = location.compile(context, &debug);
debug.locations.insert(location.value, location_ref);
}
for meta in debug.debug.get_metadata().borrow().iter() {
let meta_ref = meta.compile(&debug);
debug.metadata.insert(meta.value.clone(), meta_ref);
}
} }
let mut module = LLVMModule { let mut module = LLVMModule {
@ -225,17 +351,130 @@ 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 DebugLocationHolder {
unsafe fn compile(
&self,
context: &LLVMContext,
debug: &LLVMDebugInformation,
) -> LLVMMetadataRef {
unsafe {
LLVMDIBuilderCreateDebugLocation(
context.context_ref,
self.location.line,
self.location.column,
*debug.programs.get(&self.program).unwrap(),
null_mut(),
)
}
}
}
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(&self, debug: &LLVMDebugInformation) -> LLVMMetadataRef {
dbg!(&self.program);
unsafe {
match &self.data {
DebugMetadata::ParamVar(param) => LLVMDIBuilderCreateParameterVariable(
debug.builder,
*debug.programs.get(&self.program).unwrap(),
into_cstring(param.name.clone()).as_ptr(),
param.name.len(),
param.arg_idx + 1,
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 +507,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 +525,43 @@ 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;
let subprogram = LLVMDIBuilderCreateFunction(
debug.builder,
*debug.programs.get(&subprogram.outer_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,
);
LLVMSetSubprogram(function_ref, subprogram);
Some(subprogram)
} else {
None
}
} else {
None
};
LLVMFunction { LLVMFunction {
type_ref: fn_type, type_ref: fn_type,
value_ref: function_ref, value_ref: function_ref,
metadata,
} }
} }
} }
@ -355,7 +629,8 @@ impl BlockHolder {
module.values.insert(key, ret); module.values.insert(key, ret);
} }
self.data let term_instr = self
.data
.terminator .terminator
.clone() .clone()
.expect(&format!( .expect(&format!(
@ -363,6 +638,20 @@ impl BlockHolder {
self.data.name self.data.name
)) ))
.compile(module, function, block_ref); .compile(module, function, block_ref);
dbg!(&self.value, &self.data.terminator_location);
if let Some(location) = &self.data.terminator_location {
LLVMInstructionSetDebugLoc(
term_instr.value_ref,
*module
.debug
.as_ref()
.unwrap()
.locations
.get(&location)
.unwrap(),
);
}
} }
} }
} }
@ -519,6 +808,28 @@ impl InstructionHolder {
} }
} }
}; };
if let Some(location) = &self.data.location {
unsafe {
match LLVMGetValueKind(val) {
LLVMValueKind::LLVMInstructionValueKind
| LLVMValueKind::LLVMMemoryDefValueKind
| LLVMValueKind::LLVMMemoryUseValueKind
| LLVMValueKind::LLVMMemoryPhiValueKind => {
LLVMInstructionSetDebugLoc(
val,
*module
.debug
.as_ref()
.unwrap()
.locations
.get(&location)
.unwrap(),
);
}
_ => {}
}
}
}
LLVMValue { LLVMValue {
_ty, _ty,
value_ref: val, value_ref: val,

View File

@ -5,7 +5,10 @@ use std::{
marker::PhantomData, marker::PhantomData,
}; };
use crate::{CmpPredicate, Instr, InstructionData, TerminatorKind, builder::*}; use crate::{
CmpPredicate, Instr, InstructionData, TerminatorKind, builder::*,
debug_information::DebugLocationValue,
};
impl Debug for Builder { impl Debug for Builder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -29,6 +32,7 @@ impl Debug for ModuleHolder {
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(&format!("{}({:#?}) ", self.data.name, self.value)) f.debug_tuple(&format!("{}({:#?}) ", self.data.name, self.value))
.field(&self.functions) .field(&self.functions)
.field(&self.debug_information)
.finish() .finish()
} }
} }
@ -53,6 +57,7 @@ impl Debug for BlockHolder {
)) ))
.field(&self.instructions) .field(&self.instructions)
.field(&self.data.terminator) .field(&self.data.terminator)
.field(&self.data.terminator_location)
.finish() .finish()
} }
} }
@ -67,7 +72,20 @@ impl Debug for InstructionHolder {
impl Debug for InstructionData { impl Debug for InstructionData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.kind.fmt(f) self.kind.fmt(f)?;
if let Some(location) = self.location {
write!(f, " ({:?})", location)?;
}
Ok(())
}
}
impl Debug for DebugLocationValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("DebugLocationValue")
.field(&self.0)
.field(&self.1)
.finish()
} }
} }

View File

@ -1,17 +1,21 @@
use std::{ use std::{cell::RefCell, rc::Rc};
cell::{RefCell, RefMut},
rc::Rc,
};
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct DebugScopeValue(pub Vec<usize>); pub struct DebugScopeValue(pub Vec<usize>);
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct DebugLocationValue(pub DebugScopeValue, pub usize); pub struct DebugLocationValue(pub DebugProgramValue, 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);
/// Represents either a subprogram, or the compilation context
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct DebugProgramValue(pub usize);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DebugFileData { pub struct DebugFileData {
pub name: String, pub name: String,
@ -20,135 +24,261 @@ 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) program: DebugProgramValue,
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: DebugProgramValue,
pub(crate) data: DebugSubprogramData,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct DebugLocationHolder { pub(crate) struct DebugLocationHolder {
value: DebugLocationValue, pub(crate) program: DebugProgramValue,
location: DebugLocation, pub(crate) value: DebugLocationValue,
pub(crate) location: DebugLocation,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DebugInformation {
pub file: DebugFileData,
// scope: Rc<RefCell<DebugScopeHolder>>,
locations: Rc<RefCell<Vec<DebugLocationHolder>>>,
programs: Rc<RefCell<Vec<DebugSubprogramHolder>>>,
metadata: Rc<RefCell<Vec<DebugMetadataHolder>>>,
types: Rc<RefCell<Vec<DebugTypeHolder>>>,
}
impl DebugInformation {
pub fn from_file(file: DebugFileData) -> (DebugInformation, DebugProgramValue) {
(
DebugInformation {
file,
// scope: Rc::new(RefCell::new(DebugScopeHolder {
// value: scope_value.clone(),
// inner_scopes: Vec::new(),
// locations: Vec::new(),
// location: None,
// })),
locations: Rc::new(RefCell::new(Vec::new())),
metadata: Rc::new(RefCell::new(Vec::new())),
programs: Rc::new(RefCell::new(Vec::new())),
types: Rc::new(RefCell::new(Vec::new())),
},
DebugProgramValue(0),
)
}
// pub fn inner_scope(
// &self,
// parent: &DebugScopeValue,
// location: DebugLocation,
// ) -> DebugScopeValue {
// unsafe {
// let mut outer_scope = RefMut::map(self.scope.borrow_mut(), |mut v| {
// for i in &parent.0 {
// v = v.inner_scopes.get_unchecked_mut(*i);
// }
// v
// });
// let mut arr = parent.0.clone();
// arr.push(parent.0.len());
// let value = DebugScopeValue(arr);
// outer_scope.inner_scopes.push(DebugScopeHolder {
// value: value.clone(),
// inner_scopes: Vec::new(),
// locations: Vec::new(),
// location: Some(location),
// });
// value
// }
// }
pub fn location(
&self,
program_value: &DebugProgramValue,
location: DebugLocation,
) -> DebugLocationValue {
let value = DebugLocationValue(program_value.clone(), self.locations.borrow().len());
let location = DebugLocationHolder {
program: *program_value,
value: value.clone(),
location,
};
self.locations.borrow_mut().push(location);
value
}
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, program: &DebugProgramValue, kind: DebugMetadata) -> DebugMetadataValue {
let mut metadata = self.metadata.borrow_mut();
let value = DebugMetadataValue(metadata.len());
metadata.push(DebugMetadataHolder {
program: *program,
value: value.clone(),
data: kind,
});
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) -> DebugProgramValue {
let mut subprogram = self.programs.borrow_mut();
let value = DebugProgramValue(subprogram.len() + 1);
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.programs.clone()
}
pub fn get_types(&self) -> Rc<RefCell<Vec<DebugTypeHolder>>> {
self.types.clone()
}
pub fn get_locations(&self) -> Rc<RefCell<Vec<DebugLocationHolder>>> {
self.locations.clone()
}
pub fn get_subprogram_data(&self, value: &DebugProgramValue) -> DebugSubprogramData {
unsafe {
self.programs
.borrow()
.get_unchecked(value.0 - 1)
.data
.clone()
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct DebugLocation { pub struct DebugLocation {
pub line: u32, pub line: u32,
pub column: u32, pub column: u32,
} }
#[derive(Debug, Clone)]
pub struct DebugInformation {
file: DebugFileData,
scope: Rc<RefCell<DebugScopeHolder>>,
metadata: Rc<RefCell<Vec<DebugMetadataHolder>>>,
}
impl DebugInformation {
pub fn from_file(file: DebugFileData) -> (DebugInformation, DebugScopeValue) {
let scope_value = DebugScopeValue(Vec::new());
(
DebugInformation {
file,
scope: Rc::new(RefCell::new(DebugScopeHolder {
value: scope_value.clone(),
inner_scopes: Vec::new(),
locations: Vec::new(),
location: None,
})),
metadata: Rc::new(RefCell::new(Vec::new())),
},
scope_value,
)
}
pub fn inner_scope(
&self,
parent: &DebugScopeValue,
location: DebugLocation,
) -> DebugScopeValue {
unsafe {
let mut outer_scope = RefMut::map(self.scope.borrow_mut(), |mut v| {
for i in &parent.0 {
v = v.inner_scopes.get_unchecked_mut(*i);
}
v
});
let mut arr = parent.0.clone();
arr.push(parent.0.len());
let value = DebugScopeValue(arr);
outer_scope.inner_scopes.push(DebugScopeHolder {
value: value.clone(),
inner_scopes: Vec::new(),
locations: Vec::new(),
location: Some(location),
});
value
}
}
pub fn location(
&self,
scope_value: &DebugScopeValue,
line: u32,
column: u32,
) -> DebugLocationValue {
unsafe {
let mut scope = RefMut::map(self.scope.borrow_mut(), |mut v| {
for i in &scope_value.0 {
v = v.inner_scopes.get_unchecked_mut(*i);
}
v
});
let value = DebugLocationValue(scope_value.clone(), scope.locations.len());
let location = DebugLocationHolder {
value: value.clone(),
location: DebugLocation { line, column },
};
scope.locations.push(location);
value
}
}
pub fn metadata(&self, scope: &DebugScopeValue, kind: DebugMetadata) -> DebugMetadataValue {
let mut metadata = self.metadata.borrow_mut();
let value = DebugMetadataValue(metadata.len());
metadata.push(DebugMetadataHolder {
scope: scope.clone(),
value: value.clone(),
data: kind,
});
value
}
}
#[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<DebugProgramValue>,
pub flags: DwarfFlags,
}
#[derive(Debug, Clone, Copy)]
pub enum DwarfEncoding {
Address = 1, Address = 1,
Boolean = 2, Boolean = 2,
Float = 4, Float = 4,
@ -159,34 +289,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 outer_scope: DebugProgramValue,
/// 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

@ -7,8 +7,7 @@ use std::{fmt::Debug, marker::PhantomData};
use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue, TypeValue}; use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue, TypeValue};
use debug::PrintableModule; use debug::PrintableModule;
use debug_information::{ use debug_information::{
DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue, DebugFileData, DebugInformation, DebugLocationValue, DebugMetadataValue, DebugProgramValue,
DebugScopeValue,
}; };
use util::match_types; use util::match_types;
@ -24,9 +23,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 +75,7 @@ impl<'ctx> Module<'ctx> {
ret, ret,
params, params,
flags, flags,
meta: None, debug: None,
}, },
), ),
} }
@ -106,10 +105,10 @@ impl<'ctx> Module<'ctx> {
pub fn create_debug_info( pub fn create_debug_info(
&mut self, &mut self,
file: DebugFileData, file: DebugFileData,
) -> (DebugInformation, DebugScopeValue) { ) -> (DebugInformation, DebugProgramValue) {
let (debug_info, scope) = DebugInformation::from_file(file); let (debug_info, program_value) = DebugInformation::from_file(file);
self.debug_info = Some(debug_info.clone()); self.debug_info = Some(debug_info.clone());
(debug_info, scope) (debug_info, program_value)
} }
pub fn get_debug_info(&self) -> &Option<DebugInformation> { pub fn get_debug_info(&self) -> &Option<DebugInformation> {
@ -131,7 +130,7 @@ pub struct FunctionData {
ret: Type, ret: Type,
params: Vec<Type>, params: Vec<Type>,
flags: FunctionFlags, flags: FunctionFlags,
meta: Option<DebugMetadataValue>, debug: Option<DebugProgramValue>,
} }
#[derive(Debug, Clone, Copy, Hash)] #[derive(Debug, Clone, Copy, Hash)]
@ -170,6 +169,7 @@ impl<'ctx> Function<'ctx> {
BlockData { BlockData {
name: name.to_owned(), name: name.to_owned(),
terminator: None, terminator: None,
terminator_location: None,
deleted: false, deleted: false,
}, },
), ),
@ -177,9 +177,9 @@ impl<'ctx> Function<'ctx> {
} }
} }
pub fn set_metadata(&self, metadata: DebugMetadataValue) { pub fn set_debug(&self, subprogram: DebugProgramValue) {
unsafe { unsafe {
self.builder.add_function_metadata(&self.value, metadata); self.builder.set_debug_subprogram(&self.value, subprogram);
} }
} }
@ -192,6 +192,7 @@ impl<'ctx> Function<'ctx> {
pub struct BlockData { pub struct BlockData {
name: String, name: String,
terminator: Option<TerminatorKind>, terminator: Option<TerminatorKind>,
terminator_location: Option<DebugLocationValue>,
deleted: bool, deleted: bool,
} }
@ -233,6 +234,10 @@ impl<'builder> Block<'builder> {
unsafe { self.builder.terminate(&self.value, instruction) } unsafe { self.builder.terminate(&self.value, instruction) }
} }
pub fn set_terminator_location(&mut self, location: DebugLocationValue) -> Result<(), ()> {
unsafe { self.builder.set_terminator_location(&self.value, location) }
}
/// Delete block if it is unused. Return true if deleted, false if not. /// Delete block if it is unused. Return true if deleted, false if not.
pub fn delete_if_unused(&mut self) -> Result<bool, ()> { pub fn delete_if_unused(&mut self) -> Result<bool, ()> {
unsafe { unsafe {
@ -250,6 +255,28 @@ impl<'builder> Block<'builder> {
} }
} }
impl InstructionValue {
pub fn with_location(self, block: &Block, location: DebugLocationValue) -> InstructionValue {
unsafe {
block.builder.add_instruction_location(&self, location);
}
self
}
pub fn maybe_location(
self,
block: &mut Block,
location: Option<DebugLocationValue>,
) -> InstructionValue {
unsafe {
if let Some(location) = location {
block.builder.add_instruction_location(&self, location);
}
}
self
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct InstructionData { pub struct InstructionData {
kind: Instr, kind: Instr,

View File

@ -12,8 +12,6 @@ default = ["color"]
color = ["colored"] color = ["colored"]
[dependencies] [dependencies]
## LLVM Bindings
llvm-sys = "160"
## Make it easier to generate errors ## Make it easier to generate errors
thiserror = "1.0.44" thiserror = "1.0.44"
reid-lib = { path = "../reid-llvm-lib" } reid-lib = { path = "../reid-llvm-lib" }

View File

@ -1,186 +0,0 @@
use std::path::PathBuf;
use reid::mir::{self, *};
use reid_lib::Context;
fn main() {
let fibonacci_name = "fibonacci".to_owned();
let fibonacci_n = "N".to_owned();
let fibonacci = FunctionDefinition {
name: fibonacci_name.clone(),
is_pub: false,
is_imported: false,
return_type: TypeKind::I32,
parameters: vec![(fibonacci_n.clone(), TypeKind::I32)],
kind: FunctionDefinitionKind::Local(
Block {
statements: vec![Statement(
StmtKind::Expression(Expression(
ExprKind::If(IfExpression(
// If N < 3
Box::new(Expression(
ExprKind::BinOp(
BinaryOperator::Cmp(CmpOperator::GT),
Box::new(Expression(
ExprKind::Variable(NamedVariableRef(
TypeKind::I32,
"N".to_string(),
Default::default(),
)),
Default::default(),
)),
Box::new(Expression(
ExprKind::Literal(Literal::I32(2)),
Default::default(),
)),
),
Default::default(),
)),
// Then
Block {
statements: vec![],
return_expression: Some((
ReturnKind::Hard,
// return fibonacci(n-1) + fibonacci(n-2)
Box::new(Expression(
ExprKind::BinOp(
BinaryOperator::Add,
// fibonacci(n-1)
Box::new(Expression(
ExprKind::FunctionCall(FunctionCall {
name: fibonacci_name.clone(),
return_type: TypeKind::I32,
parameters: vec![Expression(
ExprKind::BinOp(
BinaryOperator::Minus,
Box::new(Expression(
ExprKind::Variable(
NamedVariableRef(
TypeKind::I32,
fibonacci_n.clone(),
Default::default(),
),
),
Default::default(),
)),
Box::new(Expression(
ExprKind::Literal(Literal::I32(1)),
Default::default(),
)),
),
Default::default(),
)],
}),
Default::default(),
)),
// fibonacci(n-2)
Box::new(Expression(
ExprKind::FunctionCall(FunctionCall {
name: fibonacci_name.clone(),
return_type: TypeKind::I32,
parameters: vec![Expression(
ExprKind::BinOp(
BinaryOperator::Minus,
Box::new(Expression(
ExprKind::Variable(
NamedVariableRef(
TypeKind::I32,
fibonacci_n.clone(),
Default::default(),
),
),
Default::default(),
)),
Box::new(Expression(
ExprKind::Literal(Literal::I32(2)),
Default::default(),
)),
),
Default::default(),
)],
}),
Default::default(),
)),
),
Default::default(),
)),
)),
meta: Default::default(),
},
// No else-block
None,
)),
Default::default(),
)),
Default::default(),
)],
// return 1
return_expression: Some((
ReturnKind::Soft,
Box::new(Expression(
ExprKind::Literal(Literal::I32(1)),
Default::default(),
)),
)),
meta: Default::default(),
},
Default::default(),
),
};
let main = FunctionDefinition {
name: "main".to_owned(),
is_pub: false,
is_imported: false,
return_type: TypeKind::I32,
parameters: vec![],
kind: FunctionDefinitionKind::Local(
Block {
statements: vec![],
return_expression: Some((
ReturnKind::Soft,
Box::new(Expression(
ExprKind::FunctionCall(FunctionCall {
name: fibonacci_name.clone(),
return_type: TypeKind::I32,
parameters: vec![Expression(
ExprKind::Literal(Literal::I32(5)),
Default::default(),
)],
}),
Default::default(),
)),
)),
meta: Default::default(),
},
Default::default(),
),
};
let mir_context = mir::Context {
modules: vec![Module {
name: "test module".to_owned(),
module_id: SourceModuleId::default(),
imports: vec![],
functions: vec![fibonacci, main],
typedefs: Vec::new(),
path: None,
is_main: true,
}],
base: PathBuf::new(),
};
println!("test1");
let context = Context::new();
let codegen = mir_context.codegen(&context);
println!("test2");
codegen.compile();
println!("test3");
// match codegen_module.module.print_to_string() {
// Ok(v) => println!("{}", v),
// Err(e) => println!("Err: {:?}", e),
// }
}

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, DebugProgramValue, DebugScopeValue,
DebugSubprogramData, DebugSubprogramOptionals, DebugSubprogramTypeData, 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,26 @@ 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: Option<Debug<'ctx>>,
debug_scope: DebugScopeValue, debug_const_tys: &'a HashMap<TypeKind, DebugTypeValue>,
debug_const_tys: &'a HashMap<TypeKind, DebugMetadataValue>, }
#[derive(Debug, Clone)]
pub struct Debug<'ctx> {
info: &'ctx DebugInformation,
scope: DebugProgramValue,
}
pub struct StackFunction<'ctx> {
ir: Function<'ctx>,
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -79,6 +110,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,
@ -86,8 +118,7 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
types: self.types, types: self.types,
type_values: self.type_values, type_values: self.type_values,
stack_values: self.stack_values.clone(), stack_values: self.stack_values.clone(),
debug: self.debug, debug: self.debug.clone(),
debug_scope: self.debug_scope.clone(),
debug_const_tys: self.debug_const_tys, debug_const_tys: self.debug_const_tys,
} }
} }
@ -126,10 +157,14 @@ 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, compile_unit) = if let Some(path) = &self.path {
module.create_debug_info(DebugFileData { module.create_debug_info(DebugFileData {
name: path.file_name().unwrap().to_str().unwrap().to_owned(), name: path.file_name().unwrap().to_str().unwrap().to_owned(),
directory: path.parent().unwrap().to_str().unwrap().to_owned(), directory: path.parent().unwrap().to_str().unwrap().to_owned(),
@ -147,14 +182,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 +242,49 @@ impl mir::Module {
}, },
), ),
}; };
functions.insert(function.name.clone(), func);
functions.insert(function.name.clone(), StackFunction { ir: func });
} }
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");
// Insert debug information
let debug_scope = if let Some(location) = mir_function.signature().into_debug(tokens) {
// let debug_scope = debug.inner_scope(&outer_scope, location);
let fn_param_ty = debug_const_types.get(&TypeKind::U32).unwrap();
let debug_ty =
debug.debug_type(DebugTypeData::Subprogram(DebugSubprogramTypeData {
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(); 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() {
// Codegen actual parameters
stack_values.insert( stack_values.insert(
p_name.clone(), p_name.clone(),
StackValue( StackValue(
@ -225,10 +292,28 @@ impl mir::Module {
p_ty.get_type(&type_values, &types), p_ty.get_type(&type_values, &types),
), ),
); );
// Generate debug info
if let (Some(debug_scope), Some(location)) =
(&debug_scope, mir_function.signature().into_debug(tokens))
{
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,
}),
);
}
} }
let mut scope = Scope { let mut scope = Scope {
context, context,
tokens,
module: &module, module: &module,
function, function,
block: entry, block: entry,
@ -236,10 +321,15 @@ impl mir::Module {
types: &types, types: &types,
type_values: &type_values, type_values: &type_values,
stack_values, stack_values,
debug: &debug, debug: debug_scope.and_then(|scope| {
debug_scope: debug_scope.clone(), Some(Debug {
info: &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();
@ -253,22 +343,11 @@ impl mir::Module {
} }
} }
let fn_return_ty = debug_const_types.get(&TypeKind::U32).unwrap(); if let Some(debug) = scope.debug {
let location = &block.return_meta().into_debug(tokens).unwrap();
scope.function.set_metadata(scope.debug.metadata( let location = debug.info.location(&debug.scope, *location);
&scope.debug_scope, scope.block.set_terminator_location(location).unwrap();
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(_) => {}
} }
@ -285,7 +364,13 @@ impl mir::Block {
state: &State, state: &State,
) -> Option<InstructionValue> { ) -> Option<InstructionValue> {
for stmt in &self.statements { for stmt in &self.statements {
stmt.codegen(&mut scope, state); stmt.codegen(&mut scope, state).map(|s| {
if let Some(debug) = &scope.debug {
let location = stmt.1.into_debug(scope.tokens).unwrap();
let loc_val = debug.info.location(&debug.scope, location);
s.with_location(&mut scope.block, loc_val);
}
});
} }
if let Some((kind, expr)) = &self.return_expression { if let Some((kind, expr)) = &self.return_expression {
@ -372,6 +457,16 @@ impl mir::Expression {
scope: &mut Scope<'ctx, 'a>, scope: &mut Scope<'ctx, 'a>,
state: &State, state: &State,
) -> Option<InstructionValue> { ) -> Option<InstructionValue> {
let location = if let Some(debug) = &scope.debug {
Some(
debug
.info
.location(&debug.scope, self.1.into_debug(scope.tokens).unwrap()),
)
} else {
None
};
match &self.0 { match &self.0 {
mir::ExprKind::Variable(varref) => { mir::ExprKind::Variable(varref) => {
varref.0.known().expect("variable type unknown"); varref.0.known().expect("variable type unknown");
@ -444,13 +539,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
@ -575,6 +670,7 @@ impl mir::Expression {
Some(struct_ptr) Some(struct_ptr)
} }
} }
.map(|i| i.maybe_location(&mut scope.block, location))
} }
} }
@ -587,9 +683,27 @@ 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 mut 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");
if let Some(debug) = &scope.debug {
let before_location = self.0 .1.into_debug(scope.tokens).unwrap();
let before_v = debug.info.location(&debug.scope, before_location);
scope.block.set_terminator_location(before_v).unwrap();
let then_location = self.1.return_meta().into_debug(scope.tokens).unwrap();
let then_v = debug.info.location(&debug.scope, then_location);
then_b.set_terminator_location(then_v).unwrap();
let else_location = if let Some(else_block) = &self.2 {
else_block.return_meta().into_debug(scope.tokens).unwrap()
} else {
then_location
};
let else_v = debug.info.location(&debug.scope, else_location);
else_b.set_terminator_location(else_v).unwrap();
}
// Store for convenience // Store for convenience
let then_bb = then_b.value(); let then_bb = then_b.value();
@ -603,6 +717,7 @@ impl mir::IfExpression {
let else_res = if let Some(else_block) = &self.2 { let else_res = if let Some(else_block) = &self.2 {
let mut else_scope = scope.with_block(else_b); let mut else_scope = scope.with_block(else_b);
scope scope
.block .block
.terminate(Term::CondBr(condition, then_bb, else_bb)) .terminate(Term::CondBr(condition, then_bb, else_bb))
@ -709,3 +824,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

@ -1,3 +1,5 @@
use reid_lib::debug_information::DebugLocation;
use super::{typecheck::ErrorKind, typerefs::TypeRefs, VagueType as Vague, *}; use super::{typecheck::ErrorKind, typerefs::TypeRefs, VagueType as Vague, *};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -69,6 +71,14 @@ impl Block {
.ok_or(ReturnTypeOther::NoBlockReturn(self.meta)) .ok_or(ReturnTypeOther::NoBlockReturn(self.meta))
} }
pub fn return_meta(&self) -> Metadata {
self.return_expression
.as_ref()
.map(|e| e.1 .1)
.or(self.statements.last().map(|s| s.1))
.unwrap_or(self.meta)
}
pub fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> { pub fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
let mut early_return = None; let mut early_return = None;

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_or(first);
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)>,
@ -264,14 +282,14 @@ pub enum FunctionDefinitionKind {
} }
impl FunctionDefinition { impl FunctionDefinition {
fn block_meta(&self) -> Metadata { pub fn block_meta(&self) -> Metadata {
match &self.kind { match &self.kind {
FunctionDefinitionKind::Local(block, _) => block.meta.clone(), FunctionDefinitionKind::Local(block, _) => block.meta.clone(),
FunctionDefinitionKind::Extern(_) => Metadata::default(), FunctionDefinitionKind::Extern(_) => Metadata::default(),
} }
} }
fn signature(&self) -> Metadata { pub fn signature(&self) -> Metadata {
match &self.kind { match &self.kind {
FunctionDefinitionKind::Local(_, metadata) => metadata.clone(), FunctionDefinitionKind::Local(_, metadata) => metadata.clone(),
FunctionDefinitionKind::Extern(_) => Metadata::default(), FunctionDefinitionKind::Extern(_) => Metadata::default(),