Compare commits
9 Commits
9bb4f97e6b
...
e1d014bcc2
Author | SHA1 | Date | |
---|---|---|---|
e1d014bcc2 | |||
f81fc7e925 | |||
9749a29680 | |||
92f12e90eb | |||
b169e67ca4 | |||
1967cadbc0 | |||
287ab69d32 | |||
990d8cb448 | |||
0c6d9885ec |
52
Cargo.lock
generated
52
Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
50
README.md
50
README.md
@ -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
|
||||
|
@ -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"
|
@ -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");
|
||||
|
@ -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();
|
||||
|
@ -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(¶m.ty).unwrap(),
|
||||
param.always_preserve as i32,
|
||||
param.flags.as_llvm(),
|
||||
),
|
||||
DebugMetadata::LocalVar(debug_local_variable) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DebugTypeHolder {
|
||||
unsafe fn compile_debug(&self, debug: &LLVMDebugInformation) -> LLVMMetadataRef {
|
||||
unsafe {
|
||||
match &self.data {
|
||||
DebugTypeData::Basic(ty) => LLVMDIBuilderCreateBasicType(
|
||||
debug.builder,
|
||||
into_cstring(ty.name.clone()).as_ptr(),
|
||||
ty.name.len(),
|
||||
ty.size_bits as u64,
|
||||
ty.encoding as u32,
|
||||
ty.flags.as_llvm(),
|
||||
),
|
||||
DebugTypeData::Subprogram(subprogram) => {
|
||||
let mut params = subprogram
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|p| *debug.types.get(p).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
LLVMDIBuilderCreateSubroutineType(
|
||||
debug.builder,
|
||||
debug.file_ref,
|
||||
params.as_mut_ptr(),
|
||||
params.len() as u32,
|
||||
subprogram.flags.as_llvm(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DwarfFlags {
|
||||
pub fn as_llvm(&self) -> i32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeHolder {
|
||||
unsafe fn compile_type(
|
||||
&self,
|
||||
@ -268,6 +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,
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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" }
|
||||
|
@ -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),
|
||||
// }
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ impl Ord for ErrorKind {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ErrModule {
|
||||
pub struct Module {
|
||||
pub name: String,
|
||||
pub tokens: Option<Vec<FullToken>>,
|
||||
pub source: Option<String>,
|
||||
@ -77,7 +77,7 @@ pub struct ErrModule {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct ModuleMap {
|
||||
module_map: HashMap<mir::SourceModuleId, ErrModule>,
|
||||
module_map: HashMap<mir::SourceModuleId, Module>,
|
||||
module_counter: mir::SourceModuleId,
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ impl ModuleMap {
|
||||
let id = self.module_counter.increment();
|
||||
self.module_map.insert(
|
||||
id,
|
||||
ErrModule {
|
||||
Module {
|
||||
name: name.into(),
|
||||
tokens: None,
|
||||
source: None,
|
||||
@ -107,7 +107,7 @@ impl ModuleMap {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_module(&self, id: &mir::SourceModuleId) -> Option<&ErrModule> {
|
||||
pub fn module(&self, id: &mir::SourceModuleId) -> Option<&Module> {
|
||||
self.module_map.get(id)
|
||||
}
|
||||
}
|
||||
@ -177,7 +177,7 @@ impl std::fmt::Display for ReidError {
|
||||
let mut curr_module = None;
|
||||
for error in sorted_errors {
|
||||
let meta = error.get_meta();
|
||||
let module = self.map.get_module(&meta.source_module_id).unwrap();
|
||||
let module = self.map.module(&meta.source_module_id).unwrap();
|
||||
let position = if let Some(tokens) = &module.tokens {
|
||||
let range_tokens = meta.range.into_tokens(&tokens);
|
||||
|
||||
|
@ -86,7 +86,7 @@ pub fn compile_module<'map>(
|
||||
path: Option<PathBuf>,
|
||||
is_main: bool,
|
||||
) -> Result<mir::Module, ReidError> {
|
||||
let module = map.get_module(&module_id).cloned().unwrap();
|
||||
let module = map.module(&module_id).cloned().unwrap();
|
||||
|
||||
let mut token_stream = TokenStream::from(&tokens);
|
||||
|
||||
@ -196,8 +196,8 @@ pub fn compile_and_pass<'map>(
|
||||
|
||||
perform_all_passes(&mut mir_context, module_map)?;
|
||||
|
||||
let mut context = Context::new();
|
||||
let codegen_modules = mir_context.codegen(&mut context);
|
||||
let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
|
||||
let codegen_modules = mir_context.codegen(&mut context, &module_map);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(&codegen_modules);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -87,7 +87,7 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
for module in context.modules.drain(..) {
|
||||
let tokens = self
|
||||
.module_map
|
||||
.get_module(&module.module_id)
|
||||
.module(&module.module_id)
|
||||
.unwrap()
|
||||
.tokens
|
||||
.clone()
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use crate::{lexer::Position, token_stream::TokenRange};
|
||||
use crate::{
|
||||
lexer::{FullToken, Position},
|
||||
token_stream::TokenRange,
|
||||
};
|
||||
|
||||
mod display;
|
||||
pub mod r#impl;
|
||||
@ -36,6 +39,19 @@ impl Metadata {
|
||||
(self.range.start >= other.range.start && self.range.end <= other.range.end)
|
||||
|| (other.range.start >= self.range.start && other.range.end <= self.range.end)
|
||||
}
|
||||
|
||||
pub fn into_positions(&self, tokens: &Vec<FullToken>) -> Option<(Position, Position)> {
|
||||
let mut iter = tokens
|
||||
.iter()
|
||||
.skip(self.range.start)
|
||||
.take(self.range.end - self.range.start);
|
||||
if let Some(first) = iter.next() {
|
||||
let last = iter.last().unwrap_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(),
|
||||
|
Loading…
Reference in New Issue
Block a user