Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add debug info for labels to Odin #4385

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions src/llvm_backend_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1301,3 +1301,88 @@ gb_internal void add_debug_info_for_global_constant_from_entity(lbGenerator *gen
}
}
}

// TODO(tf2spi) ... *sigh* I'm sad
// LLVM-C doesn't have an API to emit DILabel yet, so this is not exported in the dll.
// For POSIX, we can temporarily use the C++ APIs, but we're out of luck for Windows
// until the DLL gets updated with definitions like LLVMDIBuilderCreateLabel.
// These might be the ~80 most disgusting lines in this entire compiler.
#ifndef _WIN32
// Don't you just love a good ol' mangled name? I know I do.
// Mangled name of "llvm::DIBuilder::createLabel(DIScope, StringRef, DIFile, unsigned, bool)"
extern "C" LLVMMetadataRef _ZN4llvm9DIBuilder11createLabelEPNS_7DIScopeENS_9StringRefEPNS_6DIFileEjb(
LLVMDIBuilderRef Builder,
LLVMMetadataRef Scope,
String Name, // Not technically proper to do, but it's ABI compatible for now...
LLVMMetadataRef File,
unsigned int LineNo,
bool AlwaysPreserve);
// Mangled name of "llvm::DIBuilder::insertLabel(DILabel, DILocation, BasicBlock)"
extern "C" LLVMMetadataRef _ZN4llvm9DIBuilder11insertLabelEPNS_7DILabelEPKNS_10DILocationEPNS_10BasicBlockE(
LLVMDIBuilderRef Builder,
LLVMMetadataRef Label,
LLVMMetadataRef Location,
LLVMBasicBlockRef Block);
#endif
gb_internal void lb_add_debug_label(lbProcedure *p, Ast *label, lbBlock *target) {
// TODO(tf2spi): Not implemented on Windows because LLVM-C does not have
// an official API for DILabel yet, so DLL does not export it.
// When there is one, implement this function for Windows.
#ifdef _WIN32
if ((volatile int)0 == 0) return;
#endif

if (p == nullptr || p->debug_info == nullptr) {
return;
}
if (target == nullptr || label == nullptr || label->kind != Ast_Label) {
return;
}
Token label_token = label->Label.token;
if (is_blank_ident(label_token.string)) {
return;
}
lbModule *m = p->module;
if (m == nullptr) {
return;
}

AstFile *file = label->file();
LLVMMetadataRef llvm_file = lb_get_llvm_metadata(m, file);
if (llvm_file == nullptr) {
debugf("llvm file not found for label\n");
return;
}
LLVMMetadataRef llvm_scope = p->debug_info;
if(llvm_scope == nullptr) {
debugf("llvm scope not found for label\n");
return;
}
LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, label_token.pos);
LLVMBasicBlockRef llvm_block = target->block;
if (llvm_block == nullptr || llvm_debug_loc == nullptr) {
return;
}

// TODO(tf2spi): Generate and insert DILabel for Windows when feasible
#ifndef _WIN32
LLVMMetadataRef llvm_label = _ZN4llvm9DIBuilder11createLabelEPNS_7DIScopeENS_9StringRefEPNS_6DIFileEjb(
m->debug_builder,
llvm_scope,
label_token.string,
llvm_file,
label_token.pos.line,

// NOTE(tf2spi): Defaults to false in LLVM API, but I'd rather not take chances
// Always preserve the label no matter what when debugging
true
);
GB_ASSERT(llvm_label != nullptr);
_ZN4llvm9DIBuilder11insertLabelEPNS_7DILabelEPKNS_10DILocationEPNS_10BasicBlockE(
m->debug_builder,
llvm_label,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: llvm_label could be nullptr here? Although IIRC, LLVM uses new in a bunch of places and doesn't specify std::nothrow, even in the C API, so I think exceptions would kill odin before it returns nullptr anyways.

llvm_debug_loc,
llvm_block
);
#endif
}
72 changes: 67 additions & 5 deletions src/llvm_backend_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ gb_internal lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) {
return empty;
}


gb_internal lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, lbBlock *continue_, lbBlock *fallthrough_) {
lbTargetList *tl = gb_alloc_item(permanent_allocator(), lbTargetList);
tl->prev = p->target_list;
Expand Down Expand Up @@ -683,6 +682,18 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
lbBlock *body = lb_create_block(p, "for.interval.body");
lbBlock *done = lb_create_block(p, "for.interval.done");

// TODO(tf2spi): This is inlined in more than several places.
// Putting this in a function might be preferred.
// LLVMSetCurrentDebugLocation2 has side effects,
// so I didn't want to hide that before it got reviewed.
if (rs->label != nullptr && p->debug_info != nullptr) {
lbBlock *label = lb_create_block(p, "for.interval.label");
lb_emit_jump(p, label);
lb_start_block(p, label);

LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, rs->label));
lb_add_debug_label(p, rs->label, label);
}
lb_emit_jump(p, loop);
lb_start_block(p, loop);

Expand Down Expand Up @@ -888,6 +899,14 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs

lbAddr index = lb_add_local_generated(p, t_int, false);

if (rs->label != nullptr && p->debug_info != nullptr) {
lbBlock *label = lb_create_block(p, "for.soa.label");
lb_emit_jump(p, label);
lb_start_block(p, label);

LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, rs->label));
lb_add_debug_label(p, rs->label, label);
}
if (!is_reverse) {
/*
for x, i in array {
Expand Down Expand Up @@ -965,7 +984,6 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs
lb_store_range_stmt_val(p, val1, lb_addr_load(p, index));
}


lb_push_target_list(p, rs->label, done, loop, nullptr);

lb_build_stmt(p, rs->body);
Expand Down Expand Up @@ -1024,6 +1042,15 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
lbBlock *done = nullptr;
bool is_map = false;

if (rs->label != nullptr && p->debug_info != nullptr) {
lbBlock *label = lb_create_block(p, "for.range.label");
lb_emit_jump(p, label);
lb_start_block(p, label);

LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, rs->label));
lb_add_debug_label(p, rs->label, label);
}

if (tav.mode == Addressing_Type) {
lb_build_range_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done);
} else {
Expand Down Expand Up @@ -1415,6 +1442,14 @@ gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, boo
gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
lb_open_scope(p, scope);

if (ss->label != nullptr && p->debug_info != nullptr) {
lbBlock *label = lb_create_block(p, "switch.label");
lb_emit_jump(p, label);
lb_start_block(p, label);

LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, ss->label));
lb_add_debug_label(p, ss->label, label);
}
if (ss->init != nullptr) {
lb_build_stmt(p, ss->init);
}
Expand Down Expand Up @@ -1619,6 +1654,7 @@ gb_internal lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValu
gb_internal void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, lbBlock *done) {
ast_node(cc, CaseClause, clause);

// NOTE(tf2spi): Debug info for label not generated here on purpose
lb_push_target_list(p, label, done, nullptr, nullptr);
lb_build_stmt_list(p, cc->stmts);
lb_close_scope(p, lbDeferExit_Default, body);
Expand Down Expand Up @@ -2183,6 +2219,14 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
else_ = lb_create_block(p, "if.else");
}
if (is->label != nullptr) {
if (p->debug_info != nullptr) {
lbBlock *label = lb_create_block(p, "if.label");
lb_emit_jump(p, label);
lb_start_block(p, label);

LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, is->label));
lb_add_debug_label(p, is->label, label);
}
lbTargetList *tl = lb_push_target_list(p, is->label, done, nullptr, nullptr);
tl->is_block = true;
}
Expand Down Expand Up @@ -2275,12 +2319,19 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) {

lb_push_target_list(p, fs->label, done, post, nullptr);

if (fs->label != nullptr && p->debug_info != nullptr) {
lbBlock *label = lb_create_block(p, "for.label");
lb_emit_jump(p, label);
lb_start_block(p, label);

LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, fs->label));
lb_add_debug_label(p, fs->label, label);
}
if (fs->init != nullptr) {
#if 1
lbBlock *init = lb_create_block(p, "for.init");
lb_emit_jump(p, init);
lb_start_block(p, init);
#endif

lb_build_stmt(p, fs->init);
}

Expand All @@ -2296,7 +2347,6 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) {
lb_start_block(p, body);
}


lb_build_stmt(p, fs->body);

lb_pop_target_list(p);
Expand Down Expand Up @@ -2570,9 +2620,21 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {


case_ast_node(bs, BlockStmt, node);
lbBlock *body = nullptr;
lbBlock *done = nullptr;
if (bs->label != nullptr) {
if (p->debug_info != nullptr) {
lbBlock *label = lb_create_block(p, "block.label");
lb_emit_jump(p, label);
lb_start_block(p, label);

LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, bs->label));
lb_add_debug_label(p, bs->label, label);
}
body = lb_create_block(p, "block.body");
done = lb_create_block(p, "block.done");
lb_emit_jump(p, body);
lb_start_block(p, body);
lbTargetList *tl = lb_push_target_list(p, bs->label, done, nullptr, nullptr);
tl->is_block = true;
}
Expand Down