From ecce1d9974d63a6cb41d24f230b8201fa07f0e63 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Sun, 30 Sep 2018 04:24:24 +1000 Subject: [PATCH] Add debug location stack. --- src/ir.cpp | 93 +++++++++++++++++++++++++++++++++++++----------- src/ir_print.cpp | 49 ++++++++++++++----------- 2 files changed, 101 insertions(+), 41 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 7219bead2..b9803aeb7 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26,9 +26,9 @@ struct irModule { Map anonymous_proc_lits; // Key: Ast * irDebugInfo * debug_compile_unit; - irDebugInfo * debug_all_enums; // irDebugInfoArray - irDebugInfo * debug_all_globals; // irDebugInfoArray - + irDebugInfo * debug_all_enums; // TODO(lachsinc): Move into irDebugInfo_CompileUnit + irDebugInfo * debug_all_globals; // TODO(lachsinc): Move into irDebugInfo_CompileUnit + Array debug_location_stack; i32 global_string_index; @@ -112,11 +112,6 @@ struct irBranchBlocks { }; -struct irDebugLocation { - TokenPos pos; - irDebugInfo *debug_scope; -}; - struct irContextData { irValue *value; isize scope_index; @@ -257,7 +252,6 @@ gbAllocator ir_allocator(void) { }) \ IR_INSTR_KIND(StartupRuntime, i32) \ IR_INSTR_KIND(DebugDeclare, struct { \ - irDebugInfo *scope; \ Ast * expr; \ Entity * entity; \ bool is_addr; \ @@ -424,7 +418,7 @@ struct irValue { irValueKind kind; i32 index; bool index_set; - irDebugLocation loc; + irDebugInfo * loc; union { irValueConstant Constant; irValueConstantSlice ConstantSlice; @@ -528,6 +522,7 @@ enum irDebugInfoKind { irDebugInfo_File, irDebugInfo_Scope, irDebugInfo_Proc, + irDebugInfo_Location, irDebugInfo_AllProcs, irDebugInfo_BasicType, // basic types @@ -575,6 +570,10 @@ struct irDebugInfo { irDebugInfo * types; // !{return, return, param, param, param.. etc.} // TODO(lachsinc): variables / retainedNodes ? } Proc; + struct { + TokenPos pos; + irDebugInfo *scope; + } Location; struct { Array procs; } AllProcs; // TODO(lachsinc): Redundant w/ DebugInfoArray. Merge. @@ -641,7 +640,7 @@ struct irDebugInfo { irDebugInfo *type; } LocalVariable; struct { - Array elements; + Array elements; // TODO(lachsinc): Never cleaned up? } DebugInfoArray; }; }; @@ -824,7 +823,8 @@ irAddr ir_build_addr (irProcedure *proc, Ast *expr); void ir_build_proc (irValue *value, irProcedure *parent); void ir_gen_global_type_name(irModule *m, Entity *e, String name); irValue *ir_get_type_info_ptr (irProcedure *proc, Type *type); - +void ir_value_set_debug_location(irProcedure *proc, irValue *v); +irDebugInfo *ir_add_debug_info_local(irModule *module, Entity *e, i32 arg_id, irDebugInfo *scope, irDebugInfo *file); @@ -1134,7 +1134,7 @@ irValue *ir_instr_comment(irProcedure *p, String text) { irValue *ir_instr_debug_declare(irProcedure *p, irDebugInfo *scope, Ast *expr, Entity *entity, bool is_addr, irValue *value) { irValue *v = ir_alloc_instr(p, irInstr_DebugDeclare); - v->Instr.DebugDeclare.scope = scope; + // TODO(lachsinc): Set v->loc ?? v->Instr.DebugDeclare.expr = expr; v->Instr.DebugDeclare.entity = entity; v->Instr.DebugDeclare.is_addr = is_addr; @@ -1163,6 +1163,7 @@ irValue *ir_value_constant_slice(Type *type, irValue *backing_array, i64 count) irValue *ir_emit(irProcedure *proc, irValue *instr) { GB_ASSERT(instr->kind == irValue_Instr); + irModule *m = proc->module; irBlock *b = proc->curr_block; instr->Instr.block = b; if (b != nullptr) { @@ -1173,6 +1174,9 @@ irValue *ir_emit(irProcedure *proc, irValue *instr) { } else if (instr->Instr.kind != irInstr_Unreachable) { GB_PANIC("ir_emit: Instruction missing parent block"); } + if (m->generate_debug_info) { + ir_value_set_debug_location(proc, instr); + } return instr; } @@ -1426,6 +1430,8 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial } if (expr != nullptr && proc->entity != nullptr) { + // TODO(lachsinc): push location ?? or just check current stack top is == expr loc info. + irDebugInfo *di = *map_get(&proc->module->debug_info, hash_entity(proc->entity)); ir_emit(proc, ir_instr_debug_declare(proc, di, expr, e, true, instr)); @@ -2229,6 +2235,21 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na return di; } +irDebugInfo *ir_add_debug_info_location(irModule *m, Ast *node, irDebugInfo *scope) { + GB_ASSERT_NOT_NULL(node); + // TODO(lachsinc): Should we traverse the node/children until we find one with + // valid token/pos and use that instead?? + // OR, check that the node already contains valid location data. + irDebugInfo **existing = map_get(&m->debug_info, hash_node(node)); + if (existing != nullptr) { + return *existing; + } + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_Location); + di->Location.pos = ast_token(node).pos; + di->Location.scope = scope; + map_set(&m->debug_info, hash_node(node), di); + return di; +} //////////////////////////////////////////////////////////////// // @@ -2266,11 +2287,31 @@ irValue *ir_emit_select(irProcedure *p, irValue *cond, irValue *t, irValue *f) { return ir_emit(p, ir_instr_select(p, cond, t, f)); } -void ir_add_debug_location_to_value(irProcedure *proc, irValue *v, Ast *e) { - if (v != nullptr && e != nullptr) { - v->loc.debug_scope = proc->debug_scope; - v->loc.pos = ast_token(e).pos; +void ir_value_set_debug_location(irProcedure *proc, irValue *v) { + GB_ASSERT_NOT_NULL(proc); + GB_ASSERT_NOT_NULL(v); + if (v->loc != nullptr) { + return; // Already set } + + // TODO(lachsinc): Read from debug_location_stack. + irModule *m = proc->module; + GB_ASSERT(m->debug_location_stack.count > 0); + // TODO(lachsinc): Assert scope info contained in stack top is appropriate against proc. + v->loc = *array_end_ptr(&m->debug_location_stack); + + // TODO(lachsinc): HACK; This shouldn't be done here. Proc's debug info should be created prior + // to adding proc-values. + // TODO(lachsinc): Handle arbitrary files/proc/scope irDebugInfo's so this function works on globals etc. ? + /* + if (proc->debug_scope == nullptr) { + irDebugInfo *di_file = ir_add_debug_info_file(proc->module, expr->file); + ir_add_debug_info_proc(proc, proc->entity, proc->name, di_file, di_file); + } + GB_ASSERT_NOT_NULL(proc->debug_scope); + v->loc = ir_add_debug_info_location(proc->module, expr, proc->debug_scope); + GB_ASSERT_MSG(v->loc != nullptr, "Unable to set debug location for irValue."); + */ } void ir_emit_zero_init(irProcedure *p, irValue *address, Ast *expr) { @@ -2434,7 +2475,6 @@ irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array args, Ast *expr) { @@ -2447,7 +2487,6 @@ irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char GB_ASSERT_MSG(found != nullptr, "%.*s", LIT(name)); irValue *gp = *found; irValue *call = ir_emit_call(proc, gp, args); - ir_add_debug_location_to_value(proc, call, expr); return call; } @@ -5380,7 +5419,6 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr); irValue *ir_build_expr(irProcedure *proc, Ast *expr) { irValue *v = ir_build_expr_internal(proc, expr); - ir_add_debug_location_to_value(proc, v, expr); return v; } @@ -8286,6 +8324,18 @@ void ir_module_add_value(irModule *m, Entity *e, irValue *v) { } } +void ir_module_push_debug_location(irModule *m, Ast *node, irDebugInfo *scope) { + // TODO(lachsinc): Assert the stack is empty when we finish ir gen process ?? + GB_ASSERT_NOT_NULL(node); + irDebugInfo *debug_location = ir_add_debug_info_location(m, node, scope); + array_add(&m->debug_location_stack, debug_location); +} + +void ir_module_pop_debug_location(irModule *m) { + GB_ASSERT_MSG(m->debug_location_stack.count > 0, "Attempt to pop debug location stack too many times"); + array_pop(&m->debug_location_stack); +} + void ir_init_module(irModule *m, Checker *c) { // TODO(bill): Determine a decent size for the arena isize token_count = c->parser->total_token_count; @@ -8414,6 +8464,8 @@ void ir_init_module(irModule *m, Checker *c) { array_init(&globals_di->DebugInfoArray.elements, heap_allocator()); // TODO(lachsinc): ir_allocator() ?? map_set(&m->debug_info, hash_pointer(globals_di), globals_di); // TODO(lachsinc): Safe to hash this pointer for key? m->debug_all_globals = globals_di; + + array_init(&m->debug_location_stack, heap_allocator()); // TODO(lachsinc): ir_allocator() ?? } } @@ -8427,6 +8479,7 @@ void ir_destroy_module(irModule *m) { array_free(&m->procs); array_free(&m->procs_to_generate); array_free(&m->foreign_library_paths); + array_free(&m->debug_location_stack); gb_arena_free(&m->tmp_arena); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 7aa08a1fb..70f5e9f0a 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -212,32 +212,39 @@ void ir_print_encoded_global(irFileBuffer *f, String name, bool remove_prefix) { } -bool ir_print_debug_location(irFileBuffer *f, irModule *m, irValue *v, irProcedure *proc = nullptr) { -#if 1 - if (m->generate_debug_info && v != nullptr) { - TokenPos pos = v->loc.pos; - irDebugInfo *scope = v->loc.debug_scope; - i32 id = 0; - if (scope != nullptr) { - id = scope->id; - } else if (proc != nullptr) { - if (proc->debug_scope != nullptr) { - id = proc->debug_scope->id; - pos = proc->entity->token.pos; +bool ir_print_debug_location(irFileBuffer *f, irModule *m, irValue *v) { + if (!m->generate_debug_info) { + return false; + } + + GB_ASSERT_NOT_NULL(v); + + if (v->loc) { + // Update curr_debug_loc + m->curr_debug_loc = v->loc; + } + if (m->curr_debug_loc != nullptr) { + GB_ASSERT(m->curr_debug_loc->kind == irDebugInfo_Location); + ir_fprintf(f, ", !dbg !%d", m->curr_debug_loc->id); + return true; + } + // TODO(lachsinc): HACK HACK HACK + // For now, since inlinable call instructions _require_ a valid !dbg attachment. If there is no valid + // we just set to first line of the containing procedure (like before). This is not great, + // and continues to exhibit bad stepping behabiour, but now should occur much less often + // thanks to above. The proper fix is to, in ir.cpp, set valid loc for all irValues that require + // it. + if (v->kind == irValue_Instr) { + if (v->Instr.kind == irInstr_Call) { + if (v->Instr.Call.inlining == ProcInlining_no_inline) { + return false; } - } - if (id > 0 && pos.line > 0) { - ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, id); - return true; + GB_PANIC("Inlinable 'call' instructions in a debuggable proc must have !dbg metadata attachment"); } } return false; -#else - return true; -#endif } - void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct = false); void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hint); @@ -1516,7 +1523,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { case ProcInlining_inline: ir_write_str_lit(f, " alwaysinline"); break; case ProcInlining_no_inline: ir_write_str_lit(f, " noinline"); break; } - ir_print_debug_location(f, m, value, instr->block->proc); + ir_print_debug_location(f, m, value); break; }