diff options
| author | lachsinc <lachlansinclair@gmail.com> | 2018-09-26 02:01:03 +1000 |
|---|---|---|
| committer | lachsinc <lachlansinclair@gmail.com> | 2018-09-26 02:01:03 +1000 |
| commit | 0f6c1f3482c1ec0ccce2d41799ce0281a12f637e (patch) | |
| tree | 60397451b1232b6a45e8312ae315b58899d1029c /src | |
| parent | 1ee0fe74573fa167c55c78acc372514edb149be1 (diff) | |
Add debug info for globals. Misc debug info cleanup.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ir.cpp | 100 | ||||
| -rw-r--r-- | src/ir_print.cpp | 62 |
2 files changed, 130 insertions, 32 deletions
diff --git a/src/ir.cpp b/src/ir.cpp index 6583c0198..878dfc03c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26,6 +26,8 @@ struct irModule { Map<irValue *> anonymous_proc_lits; // Key: Ast * irDebugInfo * debug_compile_unit; + irDebugInfo * debug_all_enums; // irDebugInfoArray + irDebugInfo * debug_all_globals; // irDebugInfoArray @@ -517,7 +519,6 @@ enum irDebugEncoding { irDebugBasicEncoding_enumeration_type = 4, irDebugBasicEncoding_structure_type = 19, irDebugBasicEncoding_union_type = 23, - }; enum irDebugInfoKind { @@ -534,6 +535,7 @@ enum irDebugInfoKind { irDebugInfo_DerivedType, // pointer, typedef irDebugInfo_CompositeType, // array, struct, enum, (raw_)union irDebugInfo_Enumerator, // For irDebugInfo_CompositeType if enum + irDebugInfo_GlobalVariableExpression, // for describe if global is const or not irDebugInfo_GlobalVariable, irDebugInfo_LocalVariable, @@ -618,13 +620,17 @@ struct irDebugInfo { i64 value; } Enumerator; struct { + irDebugInfo *var; + } GlobalVariableExpression; + struct { String name; String linkage_name; irDebugInfo *scope; irDebugInfo *file; TokenPos pos; + irDebugInfo *type; irValue *variable; - irDebugInfo *declaration; + // irDebugInfo *declaration; } GlobalVariable; struct { String name; @@ -1543,11 +1549,17 @@ irDebugInfo *ir_add_debug_info_array(irModule *module, isize count, isize capaci return di; } -irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) { +irDebugInfo *ir_add_debug_info_file(irModule *module, AstFile *file) { // if (!proc->module->generate_debug_info) { // return nullptr; // } + irDebugInfo **existing = map_get(&module->debug_info, hash_ast_file(file)); + if (existing != nullptr) { + GB_ASSERT((*existing)->kind == irDebugInfo_File); + return *existing; + } + GB_ASSERT(file != nullptr); irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_File); di->File.file = file; @@ -1570,7 +1582,7 @@ irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) { di->File.filename = filename; di->File.directory = directory; - map_set(&proc->module->debug_info, hash_ast_file(file), di); + map_set(&module->debug_info, hash_ast_file(file), di); return di; } @@ -1612,12 +1624,12 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { case Basic_any: case Basic_rawptr: - case Basic_cstring: // TODO(lachsinc) return irDebugBasicEncoding_address; // case Basic_complex32: case Basic_complex64: case Basic_complex128: + case Basic_cstring: case Basic_string: break; // not a "DIBasicType" } @@ -1692,9 +1704,9 @@ irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scop // TODO(lachsinc): Necessary ? di->CompositeType.size = 8*cast(i32)(type_size_of(t_rawptr) + - type_size_of(t_int) + - type_size_of(t_int) + - type_size_of(t_allocator)); // TODO(lachsinc): Allocator is correct size?? + type_size_of(t_int) + + type_size_of(t_int) + + type_size_of(t_allocator)); // TODO(lachsinc): Allocator is correct size?? di->CompositeType.align = 8*cast(i32)type_align_of(t_rawptr); di->CompositeType.elements = ir_add_debug_info_array(module, 0, 4); @@ -1847,7 +1859,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity for_array(field_index, base->Struct.fields) { array_add(&di->CompositeType.elements->DebugInfoArray.elements, ir_add_debug_info_field(module, di, base->Struct.fields[field_index], cast(i32)field_index, - base->Struct.fields[field_index]->type, file)); + base->Struct.fields[field_index]->type, file)); } di->CompositeType.tag = irDebugBasicEncoding_structure_type; } else if (is_type_union(type)) { @@ -1865,6 +1877,10 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity ir_add_debug_info_enumerator(module, base->Enum.fields[field_index])); } di->CompositeType.tag = irDebugBasicEncoding_enumeration_type; + + // TODO(lachsinc): Do we want to ensure this is an enum in the global scope before + // adding it into the modules enum array ?? + array_add(&module->debug_all_enums->DebugInfoArray.elements, di); } return di; @@ -1902,10 +1918,6 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity return di; } - // TODO(lachsinc): Not sure if correct.. Also cleanup - // NOTE(lachsinc): For now dynamic arrays are just a pointer to their data. - // We could get fancy and use a composite type along with - // DW_TAG_class_type / template debug stuff eventually. if (is_type_dynamic_array(type)) { return ir_add_debug_info_dynamic_array(module, scope, e, type, file); } @@ -1960,6 +1972,36 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity } } +irDebugInfo *ir_add_debug_info_global(irModule *module, irDebugInfo *scope, irValue *v) { + // if (!proc->module->generate_debug_info) { + // return nullptr; + // } + + Entity *e = v->Global.entity; + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_GlobalVariableExpression); + + irDebugInfo *var_di = ir_alloc_debug_info(irDebugInfo_GlobalVariable); + var_di->GlobalVariable.name = e->token.string; + var_di->GlobalVariable.scope = scope; + var_di->GlobalVariable.file = scope; + var_di->GlobalVariable.pos = e->token.pos; + var_di->GlobalVariable.type = ir_add_debug_info_type(module, scope, e, e->type, scope); + var_di->GlobalVariable.variable = v; + + // NOTE(lachsinc): The "DIGlobalVariableExpression" owns us, and is what we refer to from other + // locations in the ir source, so we will reserve the "e" hash for it, and use something else + // unique for the DIGlobalVariable's hash. + map_set(&module->debug_info, hash_pointer(var_di), var_di); + + di->GlobalVariableExpression.var = var_di; + map_set(&module->debug_info, hash_entity(e), di); + + array_add(&module->debug_all_globals->DebugInfoArray.elements, di); + + return di; +} + irDebugInfo *ir_add_debug_info_local(irProcedure *proc, irDebugInfo *scope, Entity *e, i32 arg_id) { // if (!proc->module->generate_debug_info) { // return nullptr; @@ -7997,16 +8039,7 @@ void ir_build_proc(irValue *value, irProcedure *parent) { proc->is_export = e->Procedure.is_export; proc->is_foreign = e->Procedure.is_foreign; - irDebugInfo *di_file = nullptr; - - irDebugInfo **di_file_found = map_get(&m->debug_info, hash_ast_file(f)); - if (di_file_found) { - di_file = *di_file_found; - GB_ASSERT(di_file->kind == irDebugInfo_File); - } else { - di_file = ir_add_debug_info_file(proc, f); - } - + irDebugInfo *di_file = ir_add_debug_info_file(m, f); ir_add_debug_info_proc(proc, e, proc->name, di_file); } @@ -8083,6 +8116,17 @@ void ir_build_proc(irValue *value, irProcedure *parent) { void ir_module_add_value(irModule *m, Entity *e, irValue *v) { map_set(&m->values, hash_entity(e), v); + // TODO(lachsinc): This may not be the most sensible place to do this! + // it may be more sensible to look for more specific locations that call ir_value_global and assign it a value? maybe? + // ir_value_global itself doesn't have access to module and I'm trying to minimise changes to non-debug ir stuff. + if (v->kind == irValue_Global && v->Global.value != nullptr && e->state == EntityState_Resolved) { + CheckerInfo *info = m->info; + String filename = e->token.pos.file; + AstFile *f = ast_file_of_filename(info, filename); + GB_ASSERT(f); + irDebugInfo *di_file = ir_add_debug_info_file(m, f); + ir_add_debug_info_global(m, di_file, v); + } } void ir_init_module(irModule *m, Checker *c) { @@ -8203,6 +8247,16 @@ void ir_init_module(irModule *m, Checker *c) { map_set(&m->debug_info, hash_pointer(m), di); m->debug_compile_unit = di; + + irDebugInfo *enums_di = ir_alloc_debug_info(irDebugInfo_DebugInfoArray); + array_init(&enums_di->DebugInfoArray.elements, heap_allocator()); // TODO(lachsinc): ir_allocator() ?? + map_set(&m->debug_info, hash_pointer(enums_di), enums_di); // TODO(lachsinc): Safe to hash this pointer for key? + m->debug_all_enums = enums_di; + + irDebugInfo *globals_di = ir_alloc_debug_info(irDebugInfo_DebugInfoArray); + 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; } } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index bf002b68e..3ec17d09b 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1902,6 +1902,15 @@ void print_llvm_ir(irGen *ir) { } else { ir_write_string(f, str_lit("zeroinitializer")); } + if (m->generate_debug_info) { + irDebugInfo **di_lookup = map_get(&m->debug_info, hash_entity(g->entity)); + if (di_lookup != nullptr) { + irDebugInfo *di = *di_lookup; + GB_ASSERT(di); + GB_ASSERT(di->kind == irDebugInfo_GlobalVariableExpression); + ir_fprintf(f, ", !dbg !%d", di->id); + } + } } ir_write_byte(f, '\n'); } @@ -1946,11 +1955,14 @@ void print_llvm_ir(irGen *ir) { ", runtimeVersion: 0" ", isOptimized: false" ", emissionKind: FullDebug" - ", retainedTypes: !0" - ", enums: !0" - ", globals: !0" + ", retainedTypes: !0" // TODO(lachsinc) + ", enums: !%d" + ", globals: !%d" ")", - file->id, LIT(build_context.ODIN_VERSION)); + file->id, + LIT(build_context.ODIN_VERSION), + m->debug_all_enums->id, + m->debug_all_globals->id); break; } case irDebugInfo_File: @@ -1961,7 +1973,7 @@ void print_llvm_ir(irGen *ir) { ir_fprintf(f, ")"); break; case irDebugInfo_Proc: - // TODO(lach): We need to store scope info inside di, not just file info, for procs. + // TODO(lachsinc): We need to store scope info inside di, not just file info, for procs. ir_fprintf(f, "distinct !DISubprogram(" "name: \"%.*s\"" ", linkageName: \"%.*s\"" @@ -1970,7 +1982,7 @@ void print_llvm_ir(irGen *ir) { ", line: %td" ", scopeLine: %td" ", isDefinition: true" - ", isLocal: false" // TODO(lach): This used to be always set to true, pretend no local for now. We need to check if scope == file. + ", isLocal: false" // TODO(lachsinc): This used to be always set to true, pretend no local for now. We need to check if scope == file. ", flags: DIFlagPrototyped" ", isOptimized: false" ", unit: !%d" @@ -1985,6 +1997,39 @@ void print_llvm_ir(irGen *ir) { di->Proc.types->id); ir_write_byte(f, ')'); // !DISubprogram( break; + case irDebugInfo_GlobalVariableExpression: { + ir_fprintf(f, "!DIGlobalVariableExpression(" + "var: !%d" + ", expr: !DIExpression(", + di->GlobalVariableExpression.var->id); + if (di->GlobalVariableExpression.var->GlobalVariable.variable->Global.is_constant) { + ir_write_str_lit(f, "DW_OP_constu, "); + // TODO(lachsinc): Confirm this prints the type as llvm expects eg. hex representation for float is safe etc. + ir_print_value(f, m, di->GlobalVariable.variable, ir_type(di->GlobalVariable.variable)); + ir_write_str_lit(f, ", DW_OP_stack_value"); + } else { + // NOTE(lachsinc): non-const globals expect empty "!DIExpression()" + } + ir_write_byte(f, ')'); // !DIExpression( + ir_write_byte(f, ')'); // !DIGlobalVariableExpression( + break; + } + case irDebugInfo_GlobalVariable: { + ir_fprintf(f, "distinct !DIGlobalVariable(" + "name: \"%.*s\"" + ", scope: !%d" + ", file: !%d" + ", line: %d" + ", type: !%d" + ", isLocal: true" // TODO(lachsinc): Check is_foreign ?? + ", isDefinition: true)", // TODO(lachsinc): Check is_foreign ?? + LIT(di->GlobalVariable.name), + di->GlobalVariable.scope->id, + di->GlobalVariable.file->id, + di->GlobalVariable.pos.line, + di->GlobalVariable.type->id); + break; + } case irDebugInfo_LocalVariable: { ir_fprintf(f, "!DILocalVariable(" "name: \"%.*s\"" @@ -2082,13 +2127,12 @@ void print_llvm_ir(irGen *ir) { case irDebugInfo_Enumerator: { ir_fprintf(f, "!DIEnumerator(" "name: \"%.*s\"" - ", value: %d", // TODO(lachsinc): PRId64 equiv? + ", value: %d)", // TODO(lachsinc): PRId64 equiv? LIT(di->Enumerator.name), di->Enumerator.value); - ir_write_byte(f, ')'); break; } - // TODO(lach): Merge w/ DebugInfoArray + // TODO(lachsinc): Merge w/ DebugInfoArray case irDebugInfo_AllProcs: ir_fprintf(f, "!{"); for_array(proc_index, di->AllProcs.procs) { |