Skip to content

Commit

Permalink
Merge pull request lcompilers#1240 from certik/debug
Browse files Browse the repository at this point in the history
Initial debugging info implementation
  • Loading branch information
certik committed Oct 31, 2022
2 parents b2b74ca + 433d7e2 commit 6241a98
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 12 deletions.
17 changes: 13 additions & 4 deletions run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def is_included(backend):
ast_new = is_included("ast_new")
asr = is_included("asr")
llvm = is_included("llvm")
llvm_dbg = is_included("llvm_dbg")
cpp = is_included("cpp")
c = is_included("c")
wat = is_included("wat")
Expand Down Expand Up @@ -80,17 +81,25 @@ def is_included(backend):
run_test(filename, "pass_{}".format(pass_), cmd,
filename, update_reference, extra_args)

if llvm:
if no_llvm:
log.info(f"{filename} * llvm SKIPPED as requested")
else:
if no_llvm:
log.info(f"{filename} * llvm SKIPPED as requested")
else:
if llvm:
run_test(
filename,
"llvm",
"lpython --no-color --show-llvm {infile} -o {outfile}",
filename,
update_reference,
extra_args)
if llvm_dbg:
run_test(
filename,
"llvm_dbg",
"lpython --no-color --show-llvm -g {infile} -o {outfile}",
filename,
update_reference,
extra_args)

if cpp:
run_test(filename, "cpp", "lpython --no-color --show-cpp {infile}",
Expand Down
3 changes: 1 addition & 2 deletions src/bin/lpython.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,6 @@ int main(int argc, char *argv[])
bool arg_c = false;
bool arg_v = false;
// bool arg_E = false;
// bool arg_g = false;
// std::string arg_J;
// std::vector<std::string> arg_I;
// std::vector<std::string> arg_l;
Expand Down Expand Up @@ -1135,7 +1134,7 @@ int main(int argc, char *argv[])
app.add_option("-I", compiler_options.import_path, "Specify the path"
"to look for the module")->allow_extra_args(false);
// app.add_option("-J", arg_J, "Where to save mod files");
// app.add_flag("-g", arg_g, "Compile with debugging information");
app.add_flag("-g", compiler_options.arg_g, "Compile with debugging information");
// app.add_option("-D", compiler_options.c_preprocessor_defines, "Define <macro>=<value> (or 1 if <value> omitted)")->allow_extra_args(false);
app.add_flag("--version", arg_version, "Display compiler version information");

Expand Down
136 changes: 132 additions & 4 deletions src/libasr/codegen/asr_to_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <llvm/ExecutionEngine/ObjectCache.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Path.h>
#include <llvm/IR/DIBuilder.h>

#include <libasr/asr.h>
#include <libasr/containers.h>
Expand Down Expand Up @@ -160,6 +161,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
std::unique_ptr<llvm::Module> module;
std::unique_ptr<llvm::IRBuilder<>> builder;
Platform platform;
bool enable_debug_info;
Allocator &al;

llvm::Value *tmp;
Expand Down Expand Up @@ -229,12 +231,19 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
bool lookup_enum_value_for_nonints;
bool is_assignment_target;

// For handling debug information
std::unique_ptr<llvm::DIBuilder> DBuilder;
llvm::DICompileUnit *debug_CU;
llvm::DIScope *debug_current_scope;
std::map<uint64_t, llvm::DIScope*> llvm_symtab_fn_discope;
llvm::DIFile *debug_Unit;

ASRToLLVMVisitor(Allocator &al, llvm::LLVMContext &context, Platform platform,
diag::Diagnostics &diagnostics) :
bool enable_debug_info, diag::Diagnostics &diagnostics) :
diag{diagnostics},
context(context),
builder(std::make_unique<llvm::IRBuilder<>>(context)),
platform{platform},
platform{platform}, enable_debug_info{enable_debug_info},
al{al},
prototype_only(false),
llvm_utils(std::make_unique<LLVMUtils>(context, builder.get())),
Expand Down Expand Up @@ -332,6 +341,76 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
dict_api_sc->reset_iterators();
}

void get_type_debug_info(ASR::ttype_t* t, std::string &type_name,
uint32_t &type_size, uint32_t &type_encoding) {
type_size = ASRUtils::extract_kind_from_ttype_t(t)*8;
switch( t->type ) {
case ASR::ttypeType::Integer: {
type_name = "integer";
type_encoding = llvm::dwarf::DW_ATE_signed;
break;
}
case ASR::ttypeType::Logical: {
type_name = "boolean";
type_encoding = llvm::dwarf::DW_ATE_boolean;
break;
}
case ASR::ttypeType::Real: {
if( type_size == 32 ) {
type_name = "float";
} else if( type_size == 64 ) {
type_name = "double";
}
type_encoding = llvm::dwarf::DW_ATE_float;
break;
}
default : throw LCompilersException("Debug information for the type: `"
+ ASRUtils::type_to_str_python(t) + "` is not yet implemented");
}
}

template <typename T>
void debug_emit_loc(const T &x) {
Location loc = x.base.base.loc;
uint64_t line = loc.first;
uint64_t column = 0;
builder->SetCurrentDebugLocation(
llvm::DILocation::get(debug_current_scope->getContext(),
line, column, debug_current_scope));
}

template <typename T>
void debug_emit_function(const T &x, llvm::DISubprogram *&SP) {
debug_Unit = DBuilder->createFile(
debug_CU->getFilename(),
debug_CU->getDirectory());
llvm::DIScope *FContext = debug_Unit;
uint64_t LineNo, ScopeLine;
LineNo = ScopeLine = 0;
std::string fn_debug_name = x.m_name;
llvm::DIBasicType *return_type_info = nullptr;
if constexpr (std::is_same_v<T, ASR::Function_t>){
if(x.m_return_var != nullptr) {
std::string type_name; uint32_t type_size, type_encoding;
get_type_debug_info(ASRUtils::expr_type(x.m_return_var),
type_name, type_size, type_encoding);
return_type_info = DBuilder->createBasicType(type_name,
type_size, type_encoding);
}
} else if constexpr (std::is_same_v<T, ASR::Program_t>) {
return_type_info = DBuilder->createBasicType("integer", 32,
llvm::dwarf::DW_ATE_signed);
}
llvm::DISubroutineType *return_type = DBuilder->createSubroutineType(
DBuilder->getOrCreateTypeArray(return_type_info));
SP = DBuilder->createFunction(
FContext, fn_debug_name, llvm::StringRef(), debug_Unit,
LineNo, return_type, ScopeLine,
llvm::DINode::FlagPrototyped,
llvm::DISubprogram::SPFlagDefinition);
debug_current_scope = SP;
}

inline bool verify_dimensions_t(ASR::dimension_t* m_dims, int n_dims) {
if( n_dims <= 0 ) {
return false;
Expand Down Expand Up @@ -1068,6 +1147,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
module = std::make_unique<llvm::Module>("LFortran", context);
module->setDataLayout("");

if (enable_debug_info) {
DBuilder = std::make_unique<llvm::DIBuilder>(*module);
debug_CU = DBuilder->createCompileUnit(
llvm::dwarf::DW_LANG_C, DBuilder->createFile("xxexpr.py", "/yy/"),
"LPython Compiler", false, "", 0);
}

// All loose statements must be converted to a function, so the items
// must be empty:
Expand Down Expand Up @@ -2164,6 +2249,11 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
llvm::Function::ExternalLinkage, "main", module.get());
llvm::BasicBlock *BB = llvm::BasicBlock::Create(context,
".entry", F);
if (enable_debug_info) {
llvm::DISubprogram *SP;
debug_emit_function(x, SP);
F->setSubprogram(SP);
}
builder->SetInsertPoint(BB);
declare_vars(x);
for (size_t i=0; i<x.n_body; i++) {
Expand All @@ -2174,6 +2264,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
builder->CreateRet(ret_val2);
dict_api_lp->set_is_dict_present(is_dict_present_copy_lp);
dict_api_sc->set_is_dict_present(is_dict_present_copy_sc);

// Finalize the debug info.
if (enable_debug_info) DBuilder->finalize();
}

/*
Expand Down Expand Up @@ -2454,6 +2547,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
template<typename T>
void declare_vars(const T &x) {
llvm::Value *target_var;
uint32_t debug_arg_count = 0;
for (auto &item : x.m_symtab->get_scope()) {
if (is_a<ASR::Variable_t>(*item.second)) {
ASR::Variable_t *v = down_cast<ASR::Variable_t>(item.second);
Expand Down Expand Up @@ -2505,6 +2599,22 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
}
}
llvm::AllocaInst *ptr = builder->CreateAlloca(type, nullptr, v->m_name);
if (enable_debug_info) {
// Reset the debug location
builder->SetCurrentDebugLocation(nullptr);
uint64_t LineNo = v->base.base.loc.first;
std::string type_name;
uint32_t type_size, type_encoding;
get_type_debug_info(v->m_type, type_name, type_size,
type_encoding);
llvm::DILocalVariable *debug_var = DBuilder->createParameterVariable(
debug_current_scope, v->m_name, ++debug_arg_count, debug_Unit, LineNo,
DBuilder->createBasicType(type_name, type_size, type_encoding), true);
DBuilder->insertDeclare(ptr, debug_var, DBuilder->createExpression(),
llvm::DILocation::get(debug_current_scope->getContext(),
LineNo, 0, debug_current_scope), builder->GetInsertBlock());
}

if( ASR::is_a<ASR::Struct_t>(*v->m_type) ) {
ASR::Struct_t* struct_t = ASR::down_cast<ASR::Struct_t>(v->m_type);
ASR::StructType_t* struct_type = ASR::down_cast<ASR::StructType_t>(
Expand Down Expand Up @@ -3071,11 +3181,15 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
parent_function = nullptr;
dict_api_lp->set_is_dict_present(is_dict_present_copy_lp);
dict_api_sc->set_is_dict_present(is_dict_present_copy_sc);

// Finalize the debug info.
if (enable_debug_info) DBuilder->finalize();
}

void instantiate_function(const ASR::Function_t &x){
uint32_t h = get_hash((ASR::asr_t*)&x);
llvm::Function *F = nullptr;
llvm::DISubprogram *SP;
std::string sym_name = x.m_name;
if (sym_name == "main") {
sym_name = "_xx_lcompilers_changed_main_xx";
Expand All @@ -3102,11 +3216,21 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
llvm_symtab_fn_names[fn_name] = h;
F = llvm::Function::Create(function_type,
llvm::Function::ExternalLinkage, fn_name, module.get());

// Add Debugging information to the LLVM function F
if (enable_debug_info) {
debug_emit_function(x, SP);
F->setSubprogram(SP);
}
} else {
uint32_t old_h = llvm_symtab_fn_names[fn_name];
F = llvm_symtab_fn[old_h];
if (enable_debug_info) {
SP = (llvm::DISubprogram*) llvm_symtab_fn_discope[old_h];
}
}
llvm_symtab_fn[h] = F;
if (enable_debug_info) llvm_symtab_fn_discope[h] = SP;

// Instantiate (pre-declare) all nested interfaces
for (auto &item : x.m_symtab->get_scope()) {
Expand Down Expand Up @@ -3303,10 +3427,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
parent_function = &x;
parent_function_hash = h;
llvm::Function* F = llvm_symtab_fn[h];
if (enable_debug_info) debug_current_scope = llvm_symtab_fn_discope[h];
proc_return = llvm::BasicBlock::Create(context, "return");
llvm::BasicBlock *BB = llvm::BasicBlock::Create(context,
".entry", F);
builder->SetInsertPoint(BB);
if (enable_debug_info) debug_emit_loc(x);
declare_args(x, *F);
declare_local_vars(x);
}
Expand Down Expand Up @@ -3587,6 +3713,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
}

void visit_Assignment(const ASR::Assignment_t &x) {
if (enable_debug_info) debug_emit_loc(x);
if( x.m_overloaded ) {
this->visit_stmt(*x.m_overloaded);
return ;
Expand Down Expand Up @@ -5872,6 +5999,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
}

void visit_SubroutineCall(const ASR::SubroutineCall_t &x) {
if (enable_debug_info) debug_emit_loc(x);
if( ASRUtils::is_intrinsic_optimization(x.m_name) ) {
ASR::Function_t* routine = ASR::down_cast<ASR::Function_t>(
ASRUtils::symbol_get_past_external(x.m_name));
Expand Down Expand Up @@ -6213,12 +6341,12 @@ Result<std::unique_ptr<LLVMModule>> asr_to_llvm(ASR::TranslationUnit_t &asr,
diag::Diagnostics &diagnostics,
llvm::LLVMContext &context, Allocator &al,
LCompilers::PassManager& pass_manager,
Platform platform, const std::string &run_fn)
CompilerOptions &co, const std::string &run_fn)
{
#if LLVM_VERSION_MAJOR >= 15
context.setOpaquePointers(false);
#endif
ASRToLLVMVisitor v(al, context, platform, diagnostics);
ASRToLLVMVisitor v(al, context, co.platform, co.arg_g, diagnostics);
LCompilers::PassOptions pass_options;
pass_options.run_fun = run_fn;
pass_options.always_run = false;
Expand Down
2 changes: 1 addition & 1 deletion src/libasr/codegen/asr_to_llvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace LFortran {
diag::Diagnostics &diagnostics,
llvm::LLVMContext &context, Allocator &al,
LCompilers::PassManager& pass_manager,
Platform platform,
CompilerOptions &co,
const std::string &run_fn);

} // namespace LFortran
Expand Down
1 change: 1 addition & 0 deletions src/libasr/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct CompilerOptions {
bool implicit_interface = false;
std::string target = "";
std::string arg_o = "";
bool arg_g = false;
std::string import_path = "";
Platform platform;

Expand Down
2 changes: 1 addition & 1 deletion src/lpython/python_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Result<std::unique_ptr<LLVMModule>> PythonCompiler::get_llvm3(
std::unique_ptr<LFortran::LLVMModule> m;
Result<std::unique_ptr<LFortran::LLVMModule>> res
= asr_to_llvm(asr, diagnostics,
e->get_context(), al, lpm, compiler_options.platform,
e->get_context(), al, lpm, compiler_options,
run_fn);
if (res.ok) {
m = std::move(res.result);
Expand Down
13 changes: 13 additions & 0 deletions tests/reference/llvm_dbg-expr_01-bc258d6.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"basename": "llvm_dbg-expr_01-bc258d6",
"cmd": "lpython --no-color --show-llvm -g {infile} -o {outfile}",
"infile": "tests/expr_01.py",
"infile_hash": "4284fe3a1b4dd3e5d1de1357a79e9a25b426ca245b4cc91cf99e8547",
"outfile": null,
"outfile_hash": null,
"stdout": "llvm_dbg-expr_01-bc258d6.stdout",
"stdout_hash": "81125732049c71a6e7061cb752e3d50b5ab879c8ee939a454b326ac7",
"stderr": null,
"stderr_hash": null,
"returncode": 0
}
Loading

0 comments on commit 6241a98

Please sign in to comment.