mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 23:31:12 +00:00
add --debug mode that annotates LLVM IR with debug info
This commit is contained in:
parent
1022b4ef42
commit
5569e328f6
6 changed files with 62 additions and 22 deletions
|
@ -16,6 +16,8 @@ To run the test suite (via `cargo test`), you additionally need to install:
|
||||||
* [`valgrind`](https://www.valgrind.org/) (needs special treatment to [install on macOS](https://stackoverflow.com/a/61359781)
|
* [`valgrind`](https://www.valgrind.org/) (needs special treatment to [install on macOS](https://stackoverflow.com/a/61359781)
|
||||||
Alternatively, you can use `cargo test --no-fail-fast` or `cargo test -p specific_tests` to skip over the valgrind failures & tests.
|
Alternatively, you can use `cargo test --no-fail-fast` or `cargo test -p specific_tests` to skip over the valgrind failures & tests.
|
||||||
|
|
||||||
|
For debugging LLVM IR, we use [DebugIR](https://github.com/vaivaswatha/debugir). This dependency is only required to build with the `--debug` flag, and for normal developtment you should be fine without it.
|
||||||
|
|
||||||
### libunwind & libc++-dev
|
### libunwind & libc++-dev
|
||||||
|
|
||||||
MacOS systems should already have `libunwind`, but other systems will need to install it (On Ubuntu, this can be donw with `sudo apt-get install libunwind-dev`).
|
MacOS systems should already have `libunwind`, but other systems will need to install it (On Ubuntu, this can be donw with `sudo apt-get install libunwind-dev`).
|
||||||
|
|
|
@ -24,6 +24,7 @@ pub fn build_file(
|
||||||
src_dir: PathBuf,
|
src_dir: PathBuf,
|
||||||
roc_file_path: PathBuf,
|
roc_file_path: PathBuf,
|
||||||
opt_level: OptLevel,
|
opt_level: OptLevel,
|
||||||
|
emit_debug_info: bool,
|
||||||
link_type: LinkType,
|
link_type: LinkType,
|
||||||
) -> Result<PathBuf, LoadingProblem> {
|
) -> Result<PathBuf, LoadingProblem> {
|
||||||
let compilation_start = SystemTime::now();
|
let compilation_start = SystemTime::now();
|
||||||
|
@ -95,6 +96,7 @@ pub fn build_file(
|
||||||
Triple::host(),
|
Triple::host(),
|
||||||
&app_o_file,
|
&app_o_file,
|
||||||
opt_level,
|
opt_level,
|
||||||
|
emit_debug_info,
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("\nSuccess! 🎉\n\n\t➡ {}\n", app_o_file.display());
|
println!("\nSuccess! 🎉\n\n\t➡ {}\n", app_o_file.display());
|
||||||
|
|
|
@ -14,6 +14,7 @@ use target_lexicon::Triple;
|
||||||
pub mod build;
|
pub mod build;
|
||||||
pub mod repl;
|
pub mod repl;
|
||||||
|
|
||||||
|
pub static FLAG_DEBUG: &str = "debug";
|
||||||
pub static FLAG_OPTIMIZE: &str = "optimize";
|
pub static FLAG_OPTIMIZE: &str = "optimize";
|
||||||
pub static FLAG_ROC_FILE: &str = "ROC_FILE";
|
pub static FLAG_ROC_FILE: &str = "ROC_FILE";
|
||||||
pub static DIRECTORY_OR_FILES: &str = "DIRECTORY_OR_FILES";
|
pub static DIRECTORY_OR_FILES: &str = "DIRECTORY_OR_FILES";
|
||||||
|
@ -34,6 +35,12 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
.help("Optimize the compiled program to run faster. (Optimization takes time to complete.)")
|
.help("Optimize the compiled program to run faster. (Optimization takes time to complete.)")
|
||||||
.required(false),
|
.required(false),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(FLAG_DEBUG)
|
||||||
|
.long(FLAG_DEBUG)
|
||||||
|
.help("Store LLVM debug information in the generated program")
|
||||||
|
.required(false),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.subcommand(App::new("run")
|
.subcommand(App::new("run")
|
||||||
.about("Build and run a program")
|
.about("Build and run a program")
|
||||||
|
@ -48,6 +55,12 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
.help("Optimize the compiled program to run faster. (Optimization takes time to complete.)")
|
.help("Optimize the compiled program to run faster. (Optimization takes time to complete.)")
|
||||||
.required(false),
|
.required(false),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(FLAG_DEBUG)
|
||||||
|
.long(FLAG_DEBUG)
|
||||||
|
.help("Store LLVM debug information in the generated program")
|
||||||
|
.required(false),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.subcommand(App::new("repl")
|
.subcommand(App::new("repl")
|
||||||
.about("Launch the interactive Read Eval Print Loop (REPL)")
|
.about("Launch the interactive Read Eval Print Loop (REPL)")
|
||||||
|
@ -70,6 +83,8 @@ pub fn build(target: &Triple, matches: &ArgMatches, run_after_build: bool) -> io
|
||||||
} else {
|
} else {
|
||||||
OptLevel::Normal
|
OptLevel::Normal
|
||||||
};
|
};
|
||||||
|
let emit_debug_info = matches.is_present(FLAG_DEBUG);
|
||||||
|
|
||||||
let path = Path::new(filename).canonicalize().unwrap();
|
let path = Path::new(filename).canonicalize().unwrap();
|
||||||
let src_dir = path.parent().unwrap().canonicalize().unwrap();
|
let src_dir = path.parent().unwrap().canonicalize().unwrap();
|
||||||
|
|
||||||
|
@ -92,7 +107,14 @@ pub fn build(target: &Triple, matches: &ArgMatches, run_after_build: bool) -> io
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let binary_path = build::build_file(target, src_dir, path, opt_level, LinkType::Executable)
|
let binary_path = build::build_file(
|
||||||
|
target,
|
||||||
|
src_dir,
|
||||||
|
path,
|
||||||
|
opt_level,
|
||||||
|
emit_debug_info,
|
||||||
|
LinkType::Executable,
|
||||||
|
)
|
||||||
.expect("TODO gracefully handle build_file failing");
|
.expect("TODO gracefully handle build_file failing");
|
||||||
|
|
||||||
if run_after_build {
|
if run_after_build {
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub fn gen_from_mono_module(
|
||||||
target: Triple,
|
target: Triple,
|
||||||
app_o_file: &Path,
|
app_o_file: &Path,
|
||||||
opt_level: OptLevel,
|
opt_level: OptLevel,
|
||||||
|
emit_debug_info: bool,
|
||||||
) {
|
) {
|
||||||
use roc_reporting::report::{
|
use roc_reporting::report::{
|
||||||
can_problem, mono_problem, type_problem, RocDocAllocator, DEFAULT_PALETTE,
|
can_problem, mono_problem, type_problem, RocDocAllocator, DEFAULT_PALETTE,
|
||||||
|
@ -161,7 +162,9 @@ pub fn gen_from_mono_module(
|
||||||
|
|
||||||
// annotate the LLVM IR output with debug info
|
// annotate the LLVM IR output with debug info
|
||||||
// so errors are reported with the line number of the LLVM source
|
// so errors are reported with the line number of the LLVM source
|
||||||
if true {
|
if emit_debug_info {
|
||||||
|
module.strip_debug_info();
|
||||||
|
|
||||||
let mut app_ll_file = std::path::PathBuf::from(app_o_file);
|
let mut app_ll_file = std::path::PathBuf::from(app_o_file);
|
||||||
app_ll_file.set_extension("ll");
|
app_ll_file.set_extension("ll");
|
||||||
|
|
||||||
|
@ -217,20 +220,19 @@ pub fn gen_from_mono_module(
|
||||||
])
|
])
|
||||||
.output()
|
.output()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
} else {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit the .o file
|
// Emit the .o file
|
||||||
|
|
||||||
let reloc = RelocMode::Default;
|
let reloc = RelocMode::Default;
|
||||||
let model = CodeModel::Default;
|
let model = CodeModel::Default;
|
||||||
let target_machine = target::target_machine(&target, opt_level.into(), reloc, model).unwrap();
|
let target_machine =
|
||||||
|
target::target_machine(&target, opt_level.into(), reloc, model).unwrap();
|
||||||
|
|
||||||
target_machine
|
target_machine
|
||||||
.write_to_file(&env.module, FileType::Object, &app_o_file)
|
.write_to_file(&env.module, FileType::Object, &app_o_file)
|
||||||
.expect("Writing .o file failed");
|
.expect("Writing .o file failed");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FunctionIterator<'ctx> {
|
pub struct FunctionIterator<'ctx> {
|
||||||
next: Option<FunctionValue<'ctx>>,
|
next: Option<FunctionValue<'ctx>>,
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
app "effect-example" imports [ Effect, RBTree ] provides [ main ] to "./platform"
|
app "effect-example" imports [ Effect ] provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
|
||||||
main : Effect.Effect {} as Fx
|
main : Effect.Effect {} as Fx
|
||||||
main =
|
main =
|
||||||
if RBTree.isEmpty (RBTree.insert 1 2 Empty) then
|
when if 1 == 1 then True 3 else False 3.14 is
|
||||||
Effect.putLine "Yay"
|
True 3 -> Effect.putLine "Yay"
|
||||||
|> Effect.after (\{} -> Effect.getLine)
|
_ -> Effect.putLine "Yay"
|
||||||
|> Effect.after (\line -> Effect.putLine line)
|
|
||||||
else
|
|
||||||
Effect.putLine "Nay"
|
|
||||||
|
|
||||||
|
# main : Effect.Effect {} as Fx
|
||||||
|
# main =
|
||||||
|
# if RBTree.isEmpty (RBTree.insert 1 2 Empty) then
|
||||||
|
# Effect.putLine "Yay"
|
||||||
|
# |> Effect.after (\{} -> Effect.getLine)
|
||||||
|
# |> Effect.after (\line -> Effect.putLine line)
|
||||||
|
# else
|
||||||
|
# Effect.putLine "Nay"
|
||||||
|
#
|
||||||
|
|
|
@ -95,7 +95,12 @@ pub fn rust_main() -> isize {
|
||||||
|
|
||||||
let closure_data_ptr = buffer.offset(16);
|
let closure_data_ptr = buffer.offset(16);
|
||||||
|
|
||||||
call_the_closure(function_pointer as *const u8, closure_data_ptr as *const u8)
|
let result =
|
||||||
|
call_the_closure(function_pointer as *const u8, closure_data_ptr as *const u8);
|
||||||
|
|
||||||
|
std::alloc::dealloc(buffer, layout);
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
std::alloc::dealloc(buffer, layout);
|
std::alloc::dealloc(buffer, layout);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue