add --debug mode that annotates LLVM IR with debug info

This commit is contained in:
Folkert 2020-11-26 21:31:52 +01:00
parent 1022b4ef42
commit 5569e328f6
6 changed files with 62 additions and 22 deletions

View file

@ -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`).

View file

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

View file

@ -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 {

View file

@ -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,19 +220,18 @@ 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> {

View file

@ -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"
#

View file

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