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
[[package]]
name = "aho-corasick"
version = "1.1.3"
name = "anyhow"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "cc"
@ -43,23 +40,18 @@ checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "llvm-sys"
version = "160.2.1"
version = "201.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e73861901245d32e1c3d8b35b639cf100859b4cd0c9da56fe0273040acbb3ea4"
checksum = "9bb947e8b79254ca10d496d0798a9ba1287dcf68e50a92b016fec1cc45bef447"
dependencies = [
"anyhow",
"cc",
"lazy_static",
"libc",
"regex",
"regex-lite",
"semver",
]
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "proc-macro2"
version = "1.0.95"
@ -79,40 +71,16 @@ dependencies = [
]
[[package]]
name = "regex"
version = "1.11.1"
name = "regex-lite"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
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"
checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
[[package]]
name = "reid"
version = "0.1.0"
dependencies = [
"colored",
"llvm-sys",
"reid-lib",
"thiserror",
]

View File

@ -77,42 +77,42 @@ change erratically.
This is what worked for me, might not (probably) work for you, depending on
various versions of various libraries.
### Compiling LLVM 16.0.0
### Compiling LLVM 20.1.8
#### Context
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
of them are relevant, if any, but saving them here still feels like a good idea
for the future:
- `cmake 3.27.0-1`
- `lib32-llvm-libs 15.0.7-1`
- `llvm 15.0.7-3`
- `llvm-libs 15.0.7-3`
- `gcc 13.1.1-2`
- `gcc-libs 13.1.1-2`
- `lib32-gcc-libs 13.1.1-2`
- `lld 15.0.7-2`
- `lldb 15.0.7-3`
- `clang 15.0.7-9`
- `clang 19.1.7-2`
- `cmake 4.0.2-1`
- `extra-cmake-modules 6.14.0-1`
- `gcc 15.1.1+r7+gf36ec88aa85a-1`
- `gcc-libs 15.1.1+r7+gf36ec88aa85a-1`
- `lib32-gcc-libs 15.1.1+r7+gf36ec88aa85a-1`
- `lib32-llvm-libs 1:19.1.7-2`
- `libgccjit 15.1.1+r7+gf36ec88aa85a-1`
- `lld 19.1.7-1`
- `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`
- `automake 1.16.5-2`
#### Commands
```sh
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.0/llvm-16.0.0.src.tar.xz
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.0/cmake-16.0.0.src.tar.xz
git clone https://github.com/llvm/llvm-project.git --depth=1 --branch=llvmorg-20.1.8
tar xvf llvm-16.0.0.src.tar.xz
tar xvf cmake-16.0.0.src.tar.xz
cd llvm_project
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
cmake -B build -DCMAKE_INSTALL_PREFIX=$HOME/llvm-16 -DCMAKE_BUILD_TYPE=MinSizeRel -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INCLUDE_TESTS=OFF
make -j8
ninja -j23
```
*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
Assuming `llvm-16.0.0.src` from the previous step was at
`/path/llvm-16.0.0.src`, building this crate can be done via the following command:
Assuming `llvm-project` from the previous step was at
`/path/llvm-project`, building this crate can be done via the following command:
```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

View File

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

View File

@ -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");

View File

@ -7,7 +7,7 @@ use crate::{
BlockData, CustomTypeKind, FunctionData, Instr, InstructionData, ModuleData, NamedStruct,
TerminatorKind, Type, TypeData,
debug_information::{
DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue,
DebugInformation, DebugLocationValue, DebugMetadataValue, DebugProgramValue,
},
util::match_types,
};
@ -65,12 +65,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 +195,16 @@ impl Builder {
}
}
pub(crate) unsafe fn add_function_metadata(
pub(crate) unsafe fn set_debug_subprogram(
&self,
value: &FunctionValue,
metadata: DebugMetadataValue,
subprogram: DebugProgramValue,
) {
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)
}
}
@ -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<(), ()> {
unsafe {
let mut modules = self.modules.borrow_mut();

View File

@ -5,9 +5,10 @@
use std::{collections::HashMap, ptr::null_mut};
use llvm_sys::{
LLVMIntPredicate, LLVMLinkage,
LLVMIntPredicate, LLVMLinkage, LLVMValueKind,
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},
};
@ -90,14 +92,6 @@ impl CompiledModule {
LLVMSetTarget(self.module_ref, triple);
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 err = ErrorMessageHolder::null();
LLVMTargetMachineEmitToMemoryBuffer(
@ -120,14 +114,28 @@ impl CompiledModule {
);
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 {
triple: from_cstring(triple).expect("Unable to convert triple from cstring"),
assembly: asm_buffer
.as_string()
.expect("Error while converting assembly-buffer to string"),
obj_buffer: obj_buffer.as_buffer(),
llvm_ir: from_cstring(LLVMPrintModuleToString(self.module_ref))
.expect("Unable to print LLVM IR to string"),
llvm_ir,
}
}
}
@ -180,12 +188,35 @@ 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>,
programs: &'a mut HashMap<DebugProgramValue, LLVMMetadataRef>,
metadata: &'a mut HashMap<DebugMetadataValue, LLVMMetadataRef>,
locations: &'a mut HashMap<DebugLocationValue, LLVMMetadataRef>,
}
#[derive(Clone, Copy)]
pub struct LLVMFunction {
type_ref: LLVMTypeRef,
value_ref: LLVMValueRef,
metadata: Option<LLVMMetadataRef>,
}
pub struct LLVMValue {
@ -203,6 +234,85 @@ impl ModuleHolder {
// 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();
for ty in &self.types {
types.insert(ty.value, ty.compile_type(context, &types));
@ -210,10 +320,26 @@ impl ModuleHolder {
let mut functions = HashMap::new();
for function in &self.functions {
functions.insert(
function.value,
function.compile_signature(context, module_ref, &types),
);
let func = function.compile_signature(context, module_ref, &types, &debug);
functions.insert(function.value, func);
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 {
@ -225,17 +351,130 @@ 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 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 {
unsafe fn compile_type(
&self,
@ -268,6 +507,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 +525,43 @@ 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;
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 {
type_ref: fn_type,
value_ref: function_ref,
metadata,
}
}
}
@ -355,7 +629,8 @@ impl BlockHolder {
module.values.insert(key, ret);
}
self.data
let term_instr = self
.data
.terminator
.clone()
.expect(&format!(
@ -363,6 +638,20 @@ impl BlockHolder {
self.data.name
))
.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 {
_ty,
value_ref: val,

View File

@ -5,7 +5,10 @@ use std::{
marker::PhantomData,
};
use crate::{CmpPredicate, Instr, InstructionData, TerminatorKind, builder::*};
use crate::{
CmpPredicate, Instr, InstructionData, TerminatorKind, builder::*,
debug_information::DebugLocationValue,
};
impl Debug for Builder {
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 {
f.debug_tuple(&format!("{}({:#?}) ", self.data.name, self.value))
.field(&self.functions)
.field(&self.debug_information)
.finish()
}
}
@ -53,6 +57,7 @@ impl Debug for BlockHolder {
))
.field(&self.instructions)
.field(&self.data.terminator)
.field(&self.data.terminator_location)
.finish()
}
}
@ -67,7 +72,20 @@ impl Debug for InstructionHolder {
impl Debug for InstructionData {
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::{
cell::{RefCell, RefMut},
rc::Rc,
};
use std::{cell::RefCell, rc::Rc};
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct DebugScopeValue(pub Vec<usize>);
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct DebugLocationValue(pub DebugScopeValue, pub usize);
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
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);
/// Represents either a subprogram, or the compilation context
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct DebugProgramValue(pub usize);
#[derive(Debug, Clone)]
pub struct DebugFileData {
pub name: String,
@ -20,135 +24,261 @@ 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) program: DebugProgramValue,
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: DebugProgramValue,
pub(crate) data: DebugSubprogramData,
}
#[derive(Debug, Clone)]
pub(crate) struct DebugLocationHolder {
value: DebugLocationValue,
location: DebugLocation,
pub(crate) program: DebugProgramValue,
pub(crate) value: DebugLocationValue,
pub(crate) location: DebugLocation,
}
#[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 line: 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)]
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<DebugProgramValue>,
pub flags: DwarfFlags,
}
#[derive(Debug, Clone, Copy)]
pub enum DwarfEncoding {
Address = 1,
Boolean = 2,
Float = 4,
@ -159,34 +289,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 outer_scope: DebugProgramValue,
/// 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,
}

View File

@ -7,8 +7,7 @@ use std::{fmt::Debug, marker::PhantomData};
use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue, TypeValue};
use debug::PrintableModule;
use debug_information::{
DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue,
DebugScopeValue,
DebugFileData, DebugInformation, DebugLocationValue, DebugMetadataValue, DebugProgramValue,
};
use util::match_types;
@ -24,9 +23,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 +75,7 @@ impl<'ctx> Module<'ctx> {
ret,
params,
flags,
meta: None,
debug: None,
},
),
}
@ -106,10 +105,10 @@ impl<'ctx> Module<'ctx> {
pub fn create_debug_info(
&mut self,
file: DebugFileData,
) -> (DebugInformation, DebugScopeValue) {
let (debug_info, scope) = DebugInformation::from_file(file);
) -> (DebugInformation, DebugProgramValue) {
let (debug_info, program_value) = DebugInformation::from_file(file);
self.debug_info = Some(debug_info.clone());
(debug_info, scope)
(debug_info, program_value)
}
pub fn get_debug_info(&self) -> &Option<DebugInformation> {
@ -131,7 +130,7 @@ pub struct FunctionData {
ret: Type,
params: Vec<Type>,
flags: FunctionFlags,
meta: Option<DebugMetadataValue>,
debug: Option<DebugProgramValue>,
}
#[derive(Debug, Clone, Copy, Hash)]
@ -170,6 +169,7 @@ impl<'ctx> Function<'ctx> {
BlockData {
name: name.to_owned(),
terminator: None,
terminator_location: None,
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 {
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 {
name: String,
terminator: Option<TerminatorKind>,
terminator_location: Option<DebugLocationValue>,
deleted: bool,
}
@ -233,6 +234,10 @@ impl<'builder> Block<'builder> {
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.
pub fn delete_if_unused(&mut self) -> Result<bool, ()> {
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)]
pub struct InstructionData {
kind: Instr,

View File

@ -12,8 +12,6 @@ default = ["color"]
color = ["colored"]
[dependencies]
## LLVM Bindings
llvm-sys = "160"
## Make it easier to generate errors
thiserror = "1.0.44"
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},
compile::CompiledModule,
debug_information::{
AteEncoding, DebugBasicType, DebugFileData, DebugFunction, DebugInformation, DebugLocation,
DebugMetadata, DebugMetadataValue, DebugScopeValue,
DebugBasicType, DebugFileData, DebugInformation, DebugLocation, DebugMetadata,
DebugMetadataValue, DebugParamVariable, DebugProgramValue, DebugScopeValue,
DebugSubprogramData, DebugSubprogramOptionals, DebugSubprogramTypeData, 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,26 @@ 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: Option<Debug<'ctx>>,
debug_const_tys: &'a HashMap<TypeKind, DebugTypeValue>,
}
#[derive(Debug, Clone)]
pub struct Debug<'ctx> {
info: &'ctx DebugInformation,
scope: DebugProgramValue,
}
pub struct StackFunction<'ctx> {
ir: Function<'ctx>,
}
#[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> {
Scope {
block,
tokens: self.tokens,
function: self.function,
context: self.context,
module: self.module,
@ -86,8 +118,7 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
types: self.types,
type_values: self.type_values,
stack_values: self.stack_values.clone(),
debug: self.debug,
debug_scope: self.debug_scope.clone(),
debug: self.debug.clone(),
debug_const_tys: self.debug_const_tys,
}
}
@ -126,10 +157,14 @@ 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 {
let (debug, compile_unit) = if let Some(path) = &self.path {
module.create_debug_info(DebugFileData {
name: path.file_name().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(
TypeKind::U32,
debug.metadata(
&debug_scope,
DebugMetadata::BasicType(DebugBasicType {
name: String::from("u32"),
size_bits: 32,
encoding: AteEncoding::Unsigned,
}),
),
debug.debug_type(DebugTypeData::Basic(DebugBasicType {
name: String::from("u32"),
size_bits: 32,
encoding: DwarfEncoding::Unsigned,
flags: DwarfFlags,
})),
);
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 {
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();
for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() {
// Codegen actual parameters
stack_values.insert(
p_name.clone(),
StackValue(
@ -225,10 +292,28 @@ impl mir::Module {
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 {
context,
tokens,
module: &module,
function,
block: entry,
@ -236,10 +321,15 @@ impl mir::Module {
types: &types,
type_values: &type_values,
stack_values,
debug: &debug,
debug_scope: debug_scope.clone(),
debug: debug_scope.and_then(|scope| {
Some(Debug {
info: &debug,
scope,
})
}),
debug_const_tys: &debug_const_types,
};
match &mir_function.kind {
mir::FunctionDefinitionKind::Local(block, _) => {
let state = State::default();
@ -253,22 +343,11 @@ impl mir::Module {
}
}
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,
}),
));
if let Some(debug) = scope.debug {
let location = &block.return_meta().into_debug(tokens).unwrap();
let location = debug.info.location(&debug.scope, *location);
scope.block.set_terminator_location(location).unwrap();
}
}
mir::FunctionDefinitionKind::Extern(_) => {}
}
@ -285,7 +364,13 @@ impl mir::Block {
state: &State,
) -> Option<InstructionValue> {
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 {
@ -372,6 +457,16 @@ impl mir::Expression {
scope: &mut Scope<'ctx, 'a>,
state: &State,
) -> 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 {
mir::ExprKind::Variable(varref) => {
varref.0.known().expect("variable type unknown");
@ -444,13 +539,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
@ -575,6 +670,7 @@ impl mir::Expression {
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();
// 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 mut then_b = scope.function.ir.block("then");
let mut else_b = scope.function.ir.block("else");
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
let then_bb = then_b.value();
@ -603,6 +717,7 @@ impl mir::IfExpression {
let else_res = if let Some(else_block) = &self.2 {
let mut else_scope = scope.with_block(else_b);
scope
.block
.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)]
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);

View File

@ -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);

View File

@ -1,3 +1,5 @@
use reid_lib::debug_information::DebugLocation;
use super::{typecheck::ErrorKind, typerefs::TypeRefs, VagueType as Vague, *};
#[derive(Debug, Clone)]
@ -69,6 +71,14 @@ impl Block {
.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> {
let mut early_return = None;

View File

@ -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()

View File

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