From 2f86f8f8e0618a88c2794362e5f99db29876ef9d Mon Sep 17 00:00:00 2001 From: lachsinc Date: Wed, 5 Sep 2018 21:11:51 +1000 Subject: [PATCH 01/39] Provide llvm ir with more debug info (for Visual Studio debugger support). --- src/ir.cpp | 259 +++++++++++++++++++++++++++++++++++++++++++++-- src/ir_print.cpp | 144 ++++++++++++++++++++++++-- src/main.cpp | 14 ++- 3 files changed, 394 insertions(+), 23 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 8aca9fbfa..0b114ed9b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -505,6 +505,9 @@ enum irDebugEncoding { irDebugBasicEncoding_unsigned = 6, irDebugBasicEncoding_unsigned_char = 7, + // NOTE(lachsinc): Should the following be renamed from basic -> tag to mirror their DW_TAG_* + // counterparts? Perhaps separate out if they truly have different meaning. + irDebugBasicEncoding_member = 13, irDebugBasicEncoding_pointer_type = 15, irDebugBasicEncoding_typedef = 22, @@ -559,15 +562,18 @@ struct irDebugInfo { Scope * scope; // Actual scope } Scope; struct { - Entity * entity; - String name; - irDebugInfo *file; - TokenPos pos; + Entity * entity; + String name; + irDebugInfo * file; + TokenPos pos; + Array return_types; + // TODO(lachsinc): variables / retainedNodes ? } Proc; struct { Array procs; } AllProcs; + // NOTE(lachsinc): Many of the following fields could be removed/resolved as we print it? struct { String name; i32 size; @@ -577,17 +583,26 @@ struct irDebugInfo { struct { irDebugInfo * return_type; Array param_types; - } ProcType; + } ProcType; // TODO(lachsinc): Unused? struct { + irDebugEncoding tag; + String name; + irDebugInfo * scope; + irDebugInfo * file; + TokenPos pos; irDebugInfo * base_type; - irDebugEncoding encoding; + i32 size; + i32 align; + i32 offset; } DerivedType; struct { - irDebugEncoding encoding; + irDebugEncoding tag; String name; - String identifier; + String identifier; // TODO(lachsinc): Unused? + irDebugInfo * scope; irDebugInfo * file; TokenPos pos; + irDebugInfo * base_type; // optional, used for enumeration_type. i32 size; i32 align; Array elements; @@ -1110,7 +1125,6 @@ irValue *ir_instr_debug_declare(irProcedure *p, irDebugInfo *scope, Ast *expr, E v->Instr.DebugDeclare.is_addr = is_addr; v->Instr.DebugDeclare.value = value; return v; - } @@ -1382,6 +1396,8 @@ void ir_push_context_onto_stack(irProcedure *proc, irValue *ctx) { array_add(&proc->context_stack, cd); } +irDebugInfo *ir_add_debug_info_local(irProcedure *proc, irDebugInfo *scope, Entity *entity, i32 arg_id); + irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initialized) { irBlock *b = proc->decl_block; // all variables must be in the first block irValue *instr = ir_instr_local(proc, e, true); @@ -1397,6 +1413,12 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial if (expr != nullptr && proc->entity != nullptr) { 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)); + + // TODO(lachsinc): "Arg" is not used yet but should be eventually, if applicable, set to param index + // NOTE(lachsinc): The following call recurses through a type creating or finding the necessary debug info. + // This approach may be quite detrimental to perf esp. debug builds! + // This may not be the most appropriate place to place this? + ir_add_debug_info_local(proc, di, e, 0); } return instr; @@ -1503,6 +1525,8 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type) { // //////////////////////////////////////////////////////////////// +irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file); + irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) { // if (!proc->module->generate_debug_info) { // return nullptr; @@ -1534,32 +1558,245 @@ irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) { return di; } +irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { + switch (kind) { + case Basic_llvm_bool: + case Basic_bool: + case Basic_b8: + case Basic_b16: + case Basic_b32: + case Basic_b64: + return irDebugBasicEncoding_boolean; + + case Basic_i8: + return irDebugBasicEncoding_signed_char; + + case Basic_u8: + return irDebugBasicEncoding_unsigned_char; + + case Basic_i16: + case Basic_i32: + case Basic_i64: + case Basic_int: + case Basic_rune: // TODO(lachsinc) signed or unsigned? + return irDebugBasicEncoding_signed; + + case Basic_u16: + case Basic_u32: + case Basic_u64: + case Basic_uint: + case Basic_uintptr: // TODO(lachsinc) unsigned or address? + case Basic_typeid: // TODO(lachsinc) underlying type? + return irDebugBasicEncoding_unsigned; + + // case Basic_f16: + case Basic_f32: + case Basic_f64: + return irDebugBasicEncoding_float; + + 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_string: + break; // not a "DIBasicType" + } + + GB_PANIC("Unreachable"); + return irDebugBasicEncoding_Invalid; +} + +irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entity *e, i32 index, Type *type, irDebugInfo *file) { + Type *named = type; + type = base_type(type); + GB_ASSERT(type->kind != Type_Named); + + irDebugInfo **existing = map_get(&module->debug_info, hash_entity(e)); + if (existing != nullptr) { + return *existing; + } + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); + di->DerivedType.name = e->token.string; + di->DerivedType.scope = scope; + di->DerivedType.tag = irDebugBasicEncoding_member; + di->DerivedType.size = 8*cast(i32)type_size_of(type); + di->DerivedType.align = 8*cast(i32)type_align_of(type); + di->DerivedType.offset = 8*cast(i32)type_offset_of(type, index); // TODO(lachsinc): Confirm correct + di->DerivedType.file = file; + di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type, file); + GB_ASSERT_NOT_NULL(di->DerivedType.base_type); + + map_set(&module->debug_info, hash_entity(e), di); // TODO(lachsinc): Member type hashing to ensure unique?? + return di; +} + +irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { + // if (!proc->module->generate_debug_info) { + // return nullptr; + // } + + irDebugInfo **existing = map_get(&module->debug_info, hash_type(type)); + if (existing != nullptr) { + return *existing; + } + + if (type->kind == Type_Basic && !is_type_complex(type) && !is_type_string(type)) { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); + di->BasicType.encoding = ir_debug_encoding_for_basic(type->Basic.kind); + di->BasicType.name = type->Basic.name; + di->BasicType.size = 8*cast(i32)type_size_of(type); + di->BasicType.align = 8*cast(i32)type_align_of(type); + + map_set(&module->debug_info, hash_type(type), di); + return di; + } + + // NOTE(lachsinc): Types are into debug_info map as their named, not base_type()'d counterpart. + Type *base = base_type(type); + + if (is_type_struct(type) || is_type_union(type)) { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.scope = scope; + di->CompositeType.file = file; + di->CompositeType.pos = e->token.pos; + di->CompositeType.size = 8*cast(i32)type_size_of(type); + di->CompositeType.align = 8*cast(i32)type_align_of(type); + + // NOTE(lachsinc): Set map value before resolving field types to avoid circular dependencies. + map_set(&module->debug_info, hash_type(type), di); + + if (is_type_struct(type)) { + if (type->kind == Type_Named) { + di->CompositeType.name = type->Named.name; + } else { + di->CompositeType.name = str_lit("struct_name_todo"); + } + array_init(&di->CompositeType.elements, ir_allocator(), 0, base->Struct.fields.capacity); + for_array(field_index, base->Struct.fields) { + array_add(&di->CompositeType.elements, + ir_add_debug_info_field(module, di, base->Struct.fields[field_index], cast(i32)field_index, + base->Struct.fields[field_index]->type, file)); + } + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + } else if (is_type_union(type)) { + di->CompositeType.name = str_lit("union_todo"); + array_init(&di->CompositeType.elements, ir_allocator(), 0, 0); + // TODO(lachsinc): Add elements for union + di->CompositeType.tag = irDebugBasicEncoding_union_type; + } + + return di; + } + + if (is_type_pointer(type)) { + // TODO(lachsinc): Ensure this handles pointers to pointers of same type etc. correctly. + Type *deref_named = type_deref(base); + Type *deref = base_type(deref_named); + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); + // TODO(lachsinc): Is there a helper for getting a types name string? Also, should pointers + // include '^'? May be better to prepend '^' at ir print time rather than creating a new string here. + if (deref_named->kind == Type_Named) { + di->DerivedType.name = deref_named->Named.name; + } else if (deref->kind == Type_Basic) { + di->DerivedType.name = deref->Basic.name; + } else { + di->DerivedType.name = str_lit("derived_name_todo"); + } + di->DerivedType.tag = irDebugBasicEncoding_pointer_type; + di->DerivedType.scope = scope; + di->DerivedType.file = file; + di->DerivedType.pos = e->token.pos; + di->DerivedType.size = 8*cast(i32)type_size_of(type); + di->DerivedType.align = 8*cast(i32)type_align_of(type); + di->DerivedType.offset = 0; // TODO(lachsinc) + + GB_ASSERT(base->kind != Type_Named); + map_set(&module->debug_info, hash_type(type), di); + + di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, deref, file); + GB_ASSERT_NOT_NULL(di->DerivedType.base_type); + + return di; + } + + // + // TODO(lachsinc): HACK For now any remaining types interpreted as a rawptr. + // + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); + di->BasicType.align = 8*cast(i32)type_align_of(type); + di->BasicType.encoding = irDebugBasicEncoding_address; + di->BasicType.name = str_lit("type_todo"); + di->BasicType.size = 8*cast(i32)type_size_of(type); + + map_set(&module->debug_info, hash_type(type), 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; + // } + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_LocalVariable); + di->LocalVariable.name = e->token.string; + di->LocalVariable.scope = scope; + di->LocalVariable.file = scope->Proc.file; + di->LocalVariable.pos = e->token.pos; + di->LocalVariable.arg = arg_id; + di->LocalVariable.type = ir_add_debug_info_type(proc->module, scope, e, e->type, scope->Proc.file); + + map_set(&proc->module->debug_info, hash_entity(e), di); + return di; +} irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String name, irDebugInfo *file) { // if (!proc->module->generate_debug_info) { // return nullptr; // } - GB_ASSERT(entity != nullptr); irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_Proc); di->Proc.entity = entity; di->Proc.name = name; di->Proc.file = file; di->Proc.pos = entity->token.pos; + isize return_count = proc->type->Proc.result_count; + array_init(&di->Proc.return_types, ir_allocator(), 0, return_count); // TODO(lachsinc): ir_allocator() safe to use? + if (return_count >= 1) { + TypeTuple *tuple = &proc->type->Proc.results->Tuple; + for_array(i, tuple->variables) { + Entity *e = tuple->variables[i]; + if (e->kind != Entity_Variable) { + continue; // TODO(lachsinc): Confirm correct? + } + + irDebugInfo *type_di = ir_add_debug_info_type(proc->module, di, e, e->type, file); + GB_ASSERT_NOT_NULL(type_di); + array_add(&di->Proc.return_types, type_di); + } + } + proc->debug_scope = di; map_set(&proc->module->debug_info, hash_entity(entity), di); return di; } + //////////////////////////////////////////////////////////////// // // @Emit // //////////////////////////////////////////////////////////////// -irValue *ir_emit_runtime_call (irProcedure *proc, char const *name_, Array args, Ast *expr = nullptr); +irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array args, Ast *expr = nullptr); irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array args, Ast *expr = nullptr); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 5796845fb..d77657222 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -519,6 +519,36 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) { } } +void ir_print_debug_encoding(irFileBuffer *f, irDebugInfoKind kind, irDebugEncoding encoding) { + switch (kind) { + case irDebugInfo_BasicType: + switch (encoding) { + case irDebugBasicEncoding_address: ir_write_str_lit(f, "DW_ATE_address"); return; + case irDebugBasicEncoding_boolean: ir_write_str_lit(f, "DW_ATE_boolean"); return; + case irDebugBasicEncoding_float: ir_write_str_lit(f, "DW_ATE_float"); return; + case irDebugBasicEncoding_signed: ir_write_str_lit(f, "DW_ATE_signed"); return; + case irDebugBasicEncoding_signed_char: ir_write_str_lit(f, "DW_ATE_signed_char"); return; + case irDebugBasicEncoding_unsigned: ir_write_str_lit(f, "DW_ATE_unsigned"); return; + case irDebugBasicEncoding_unsigned_char: ir_write_str_lit(f, "DW_ATE_unsigned_char"); return; + } + case irDebugInfo_DerivedType: + switch (encoding) { + case irDebugBasicEncoding_member: ir_write_str_lit(f, "DW_TAG_member"); return; + case irDebugBasicEncoding_pointer_type: ir_write_str_lit(f, "DW_TAG_pointer_type"); return; + case irDebugBasicEncoding_typedef: ir_write_str_lit(f, "DW_TAG_typedef"); return; + } + case irDebugInfo_CompositeType: + switch (encoding) { + case irDebugBasicEncoding_array_type: ir_write_str_lit(f, "DW_TAG_array_type"); return; + case irDebugBasicEncoding_enumeration_type: ir_write_str_lit(f, "DW_TAG_enumeration_type"); return; + case irDebugBasicEncoding_structure_type: ir_write_str_lit(f, "DW_TAG_structure_type"); return; + case irDebugBasicEncoding_union_type: ir_write_str_lit(f, "DW_TAG_union_type"); return; + } + } + + GB_PANIC("Unreachable"); +} + void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type); void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type *elem_type) { @@ -1518,16 +1548,17 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { String name = e->token.string; TokenPos pos = e->token.pos; + irDebugInfo **lookup_di = map_get(&m->debug_info, hash_entity(e)); + GB_ASSERT_NOT_NULL(*lookup_di); + irDebugInfo* local_var_di = *lookup_di; + ir_write_str_lit(f, "call void @llvm.dbg.declare("); ir_write_str_lit(f, "metadata "); ir_print_type(f, m, vt); ir_write_byte(f, ' '); ir_print_value(f, m, dd->value, vt); - ir_write_str_lit(f, ", metadata !DILocalVariable(name: \""); - ir_print_escape_string(f, name, false, false); - ir_fprintf(f, "\", scope: !%d, line: %td)", di->id, pos.line); - ir_write_str_lit(f, ", metadata !DIExpression()"); - ir_write_byte(f, ')'); + ir_fprintf(f, ", metadata !%d", local_var_di->id); + ir_write_str_lit(f, ", metadata !DIExpression())"); ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, di->id); break; } @@ -1764,7 +1795,7 @@ void print_llvm_ir(irGen *ir) { ir_print_type(f, m, t_typeid); ir_write_str_lit(f, "} ; Basic_any\n"); - ir_write_str_lit(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone \n"); + ir_write_str_lit(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) #3 \n"); ir_write_byte(f, '\n'); @@ -1875,9 +1906,11 @@ void print_llvm_ir(irGen *ir) { ir_write_byte(f, '\n'); } + // TODO(lachsinc): Attribute map inside ir module? ir_fprintf(f, "attributes #0 = {nounwind uwtable}\n"); ir_fprintf(f, "attributes #1 = {nounwind alwaysinline uwtable}\n"); ir_fprintf(f, "attributes #2 = {nounwind noinline optnone uwtable}\n"); + ir_fprintf(f, "attributes #3 = {nounwind readnone}\n"); if (m->generate_debug_info) { ir_write_byte(f, '\n'); @@ -1909,7 +1942,7 @@ void print_llvm_ir(irGen *ir) { "language: DW_LANG_C_plus_plus" // Is this good enough? ", file: !%d" ", producer: \"Odin %.*s\"" - ", flags: \"\"" + // ", flags: \"\"" // TODO(lachsinc): Removed for now, check if correct ", runtimeVersion: 0" ", isOptimized: false" ", emissionKind: FullDebug" @@ -1938,13 +1971,104 @@ void print_llvm_ir(irGen *ir) { ", flags: DIFlagPrototyped" ", isOptimized: false" ", unit: !%d" - ")", + ", type: !DISubroutineType(types: !{", LIT(di->Proc.entity->token.string), LIT(di->Proc.name), - di->Proc.file->id, di->Proc.pos.line, + di->Proc.file->id, + di->Proc.pos.line, m->debug_compile_unit->id); + if (di->Proc.return_types.count == 0) { + ir_fprintf(f, "null})"); + } else { + for_array(return_type_index, di->Proc.return_types) { + ir_fprintf(f, "%s!%d", + return_type_index > 0 ? ", " : "", + di->Proc.return_types[return_type_index]->id); + } + ir_write_str_lit(f, "})"); + } + ir_write_byte(f, ')'); break; - + case irDebugInfo_LocalVariable: { + ir_fprintf(f, "!DILocalVariable(" + "name: \"%.*s\"" + ", scope: !%d" + ", file: !%d" + ", line: %d" + ", type: !%d", + LIT(di->LocalVariable.name), + di->LocalVariable.scope->id, + di->LocalVariable.file->id, + di->LocalVariable.pos.line, + di->LocalVariable.type->id); + if (di->LocalVariable.arg > 0) { + GB_ASSERT(false); // TODO(lachsinc): "Arg" debug info not implemented yet + ir_fprintf(f, ", arg: %d", di->LocalVariable.arg); + } + ir_write_byte(f, ')'); + break; + } + case irDebugInfo_BasicType: + ir_fprintf(f, "!DIBasicType(" + "name: \"%.*s\"" + ", size: %d" + ", encoding: ", + LIT(di->BasicType.name), + di->BasicType.size); + ir_print_debug_encoding(f, irDebugInfo_BasicType, di->BasicType.encoding); + ir_write_byte(f, ')'); + break; + case irDebugInfo_DerivedType: + GB_ASSERT(di->DerivedType.base_type); + ir_fprintf(f, "!DIDerivedType(" + "name: \"%.*s\"" + ", baseType: !%d" + ", size: %d" + ", align: %d" + ", tag: ", + LIT(di->DerivedType.name), + di->DerivedType.base_type->id, + di->DerivedType.size, + di->DerivedType.align); + ir_print_debug_encoding(f, irDebugInfo_DerivedType, di->DerivedType.tag); + if (di->DerivedType.offset > 0) { + ir_fprintf(f, ", offset: %d", + di->DerivedType.offset); + } + ir_write_byte(f, ')'); + break; + case irDebugInfo_CompositeType: { + ir_fprintf(f, "!DICompositeType(" + "name: \"%.*s\"" + ", scope: !%d" + ", file: !%d" + ", line: %td" + ", size: %d" + ", align: %d" + ", tag: ", + LIT(di->CompositeType.name), + di->CompositeType.scope->id, + di->CompositeType.file->id, + di->CompositeType.pos.line, + di->CompositeType.size, + di->CompositeType.align); + ir_print_debug_encoding(f, irDebugInfo_CompositeType, di->CompositeType.tag); + if (di->CompositeType.base_type) { + GB_ASSERT(di->CompositeType.tag == irDebugBasicEncoding_enumeration_type); + ir_fprintf(f, ", baseType: !%d", di->CompositeType.base_type->id); + } + if (di->CompositeType.elements.count > 0) { + ir_write_str_lit(f, ", elements: !{"); + for_array(element_index, di->CompositeType.elements) { + ir_fprintf(f, "%s!%d", + element_index > 0 ? ", " : "", + di->CompositeType.elements[element_index]->id); + } + ir_write_byte(f, '}'); + } + ir_write_byte(f, ')'); + break; + } case irDebugInfo_AllProcs: ir_fprintf(f, "!{"); for_array(proc_index, di->AllProcs.procs) { diff --git a/src/main.cpp b/src/main.cpp index 87c1ad511..8e250b799 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -661,6 +661,9 @@ void remove_temp_files(String output_base) { } i32 exec_llvm_opt(String output_base) { + // NOTE(lachsinc): See note below in exec_llvm_llc. + if (build_context.ODIN_DEBUG == true) return 0; + #if defined(GB_SYSTEM_WINDOWS) // For more passes arguments: http://llvm.org/docs/Passes.html return system_exec_command_line_app("llvm-opt", false, @@ -687,15 +690,21 @@ i32 exec_llvm_opt(String output_base) { } i32 exec_llvm_llc(String output_base) { + // NOTE(lachsinc): HACK!! opt.exe seems to strip away CodeView/PDB symbols regardless of + // To get around this we will use the non-optimized (.ll) version during debug build. + // There's probably better way to deal with this involving arguments or passing + // additional things (.ll file) into llc. + #if defined(GB_SYSTEM_WINDOWS) // For more arguments: http://llvm.org/docs/CommandGuide/llc.html return system_exec_command_line_app("llvm-llc", false, - "\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d " + "\"%.*sbin\\llc\" \"%.*s%s\" -filetype=obj -O%d " "-o \"%.*s.obj\" " "%.*s " "", LIT(build_context.ODIN_ROOT), LIT(output_base), + build_context.ODIN_DEBUG ? ".ll" : ".bc", build_context.optimization_level, LIT(output_base), LIT(build_context.llc_flags)); @@ -703,11 +712,12 @@ i32 exec_llvm_llc(String output_base) { // NOTE(zangent): Linux / Unix is unfinished and not tested very well. // For more arguments: http://llvm.org/docs/CommandGuide/llc.html return system_exec_command_line_app("llc", false, - "llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d " + "llc \"%.*s%s\" -filetype=obj -relocation-model=pic -O%d " "%.*s " "%s" "", LIT(output_base), + build_context.ODIN_DEBUG ? ".ll" : ".bc", build_context.optimization_level, LIT(build_context.llc_flags), str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : ""); From 8a789e33b03e7842f36205cbb5a41c3a87134c77 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Tue, 18 Sep 2018 14:17:43 +1000 Subject: [PATCH 02/39] Remove llc/opt hack. XX.bc now contains useful debug info thanks to removal of optimization flags in debug builds. --- src/build_settings.cpp | 17 +++++++++++++++-- src/main.cpp | 20 ++------------------ 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index cbf6fb689..50197202b 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -573,10 +573,23 @@ void init_build_context(void) { bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3); - gbString opt_flags = gb_string_make_reserve(heap_allocator(), 16); + gbString opt_flags = gb_string_make_reserve(heap_allocator(), 64); + opt_flags = gb_string_append_fmt(opt_flags, "-O%d ", bc->optimization_level); if (bc->optimization_level != 0) { - opt_flags = gb_string_append_fmt(opt_flags, "-O%d", bc->optimization_level); + // NOTE(lachsinc): The following options were previously passed during call + // to opt in main.cpp:exec_llvm_opt(). + // -die: Dead instruction elimination + // -memcpyopt: MemCpy optimization + opt_flags = gb_string_appendc(opt_flags, "-memcpyopt -die "); } + + // NOTE(lachsinc): This optimization option was previously required to get + // around an issue in fmt.odin. Thank bp for tracking it down! Leaving for now until the issue + // is resolved and confirmed by Bill. Maybe it should be readded in non-debug builds. + // if (bc->ODIN_DEBUG == false) { + // opt_flags = gb_string_appendc(opt_flags, "-mem2reg "); + // } + bc->opt_flags = make_string_c(opt_flags); diff --git a/src/main.cpp b/src/main.cpp index 8e250b799..ed72b5f0a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -661,16 +661,10 @@ void remove_temp_files(String output_base) { } i32 exec_llvm_opt(String output_base) { - // NOTE(lachsinc): See note below in exec_llvm_llc. - if (build_context.ODIN_DEBUG == true) return 0; - #if defined(GB_SYSTEM_WINDOWS) // For more passes arguments: http://llvm.org/docs/Passes.html return system_exec_command_line_app("llvm-opt", false, "\"%.*sbin/opt\" \"%.*s.ll\" -o \"%.*s.bc\" %.*s " - "-mem2reg " - "-memcpyopt " - "-die " "", LIT(build_context.ODIN_ROOT), LIT(output_base), LIT(output_base), @@ -680,9 +674,6 @@ i32 exec_llvm_opt(String output_base) { // with the Windows version, while they will be system-provided on MacOS and GNU/Linux return system_exec_command_line_app("llvm-opt", false, "opt \"%.*s.ll\" -o \"%.*s.bc\" %.*s " - "-mem2reg " - "-memcpyopt " - "-die " "", LIT(output_base), LIT(output_base), LIT(build_context.opt_flags)); @@ -690,21 +681,15 @@ i32 exec_llvm_opt(String output_base) { } i32 exec_llvm_llc(String output_base) { - // NOTE(lachsinc): HACK!! opt.exe seems to strip away CodeView/PDB symbols regardless of - // To get around this we will use the non-optimized (.ll) version during debug build. - // There's probably better way to deal with this involving arguments or passing - // additional things (.ll file) into llc. - #if defined(GB_SYSTEM_WINDOWS) // For more arguments: http://llvm.org/docs/CommandGuide/llc.html return system_exec_command_line_app("llvm-llc", false, - "\"%.*sbin\\llc\" \"%.*s%s\" -filetype=obj -O%d " + "\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d " "-o \"%.*s.obj\" " "%.*s " "", LIT(build_context.ODIN_ROOT), LIT(output_base), - build_context.ODIN_DEBUG ? ".ll" : ".bc", build_context.optimization_level, LIT(output_base), LIT(build_context.llc_flags)); @@ -712,12 +697,11 @@ i32 exec_llvm_llc(String output_base) { // NOTE(zangent): Linux / Unix is unfinished and not tested very well. // For more arguments: http://llvm.org/docs/CommandGuide/llc.html return system_exec_command_line_app("llc", false, - "llc \"%.*s%s\" -filetype=obj -relocation-model=pic -O%d " + "llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d " "%.*s " "%s" "", LIT(output_base), - build_context.ODIN_DEBUG ? ".ll" : ".bc", build_context.optimization_level, LIT(build_context.llc_flags), str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : ""); From 2cc2eb1ec095d3ec210d780566977b3966412c03 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Tue, 18 Sep 2018 18:10:03 +1000 Subject: [PATCH 03/39] Fix stepping/jumping between procedures/files. --- src/ir_print.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ir_print.cpp b/src/ir_print.cpp index d77657222..54b60e510 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1951,31 +1951,36 @@ void print_llvm_ir(irGen *ir) { ", globals: !0" ")", file->id, LIT(build_context.ODIN_VERSION)); - break; } case irDebugInfo_File: + // TODO(lachsinc): Does windows debug info expect '/' or '\5C' path separators ?? ir_fprintf(f, "!DIFile(filename: \""); ir_print_escape_path(f, di->File.filename); ir_fprintf(f, "\", directory: \""); ir_print_escape_path(f, di->File.directory); ir_fprintf(f, "\""); ir_fprintf(f, ")"); break; case irDebugInfo_Proc: + // TODO(lach): We need to store scope info inside di, not just file info, for procs. ir_fprintf(f, "distinct !DISubprogram(" "name: \"%.*s\"" ", linkageName: \"%.*s\"" + ", scope: !%d" ", file: !%d" ", line: %td" + ", scopeLine: %td" ", isDefinition: true" - ", isLocal: 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. ", flags: DIFlagPrototyped" ", isOptimized: false" ", unit: !%d" ", type: !DISubroutineType(types: !{", LIT(di->Proc.entity->token.string), LIT(di->Proc.name), + di->Proc.file->id, // TODO(lachsinc): HACK For now lets pretend all procs scope's == file. di->Proc.file->id, di->Proc.pos.line, + di->Proc.pos.line, // NOTE(lachsinc): Assume scopeLine always same as line. m->debug_compile_unit->id); if (di->Proc.return_types.count == 0) { ir_fprintf(f, "null})"); From 3772ea6ae145a17facc8007822a1d7eb97c4dd45 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Tue, 18 Sep 2018 20:10:33 +1000 Subject: [PATCH 04/39] Enum debug info support. --- src/ir.cpp | 31 +++++++++++++++++++++++++++++-- src/ir_print.cpp | 9 +++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 0b114ed9b..b1dca0325 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1635,6 +1635,22 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit return di; } +irDebugInfo *ir_add_debug_info_enumerator(irModule *module, Entity *e) { + irDebugInfo **existing = map_get(&module->debug_info, hash_entity(e)); + if (existing != nullptr) { + return *existing; + } + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_Enumerator); + di->Enumerator.name = e->token.string; + GB_ASSERT(e->kind == Entity_Constant); + GB_ASSERT(e->Constant.value.kind == ExactValue_Integer); + di->Enumerator.value = big_int_to_i64(&e->Constant.value.value_integer); + + map_set(&module->debug_info, hash_entity(e), di); + return di; +} + irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { // if (!proc->module->generate_debug_info) { // return nullptr; @@ -1656,16 +1672,17 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity return di; } - // NOTE(lachsinc): Types are into debug_info map as their named, not base_type()'d counterpart. + // NOTE(lachsinc): Types are inserted into debug_info map as their named, not base_type()'d counterpart. Type *base = base_type(type); - if (is_type_struct(type) || is_type_union(type)) { + if (is_type_struct(type) || is_type_union(type) || is_type_enum(type)) { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); di->CompositeType.scope = scope; di->CompositeType.file = file; di->CompositeType.pos = e->token.pos; di->CompositeType.size = 8*cast(i32)type_size_of(type); di->CompositeType.align = 8*cast(i32)type_align_of(type); + di->CompositeType.base_type = nullptr; // NOTE(lachsinc): Set map value before resolving field types to avoid circular dependencies. map_set(&module->debug_info, hash_type(type), di); @@ -1688,6 +1705,16 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity array_init(&di->CompositeType.elements, ir_allocator(), 0, 0); // TODO(lachsinc): Add elements for union di->CompositeType.tag = irDebugBasicEncoding_union_type; + } else if (is_type_enum(type)) { + GB_ASSERT(type->kind == Type_Named); + di->CompositeType.name = type->Named.name; + di->CompositeType.base_type = ir_add_debug_info_type(module, scope, e, type->Named.base->Enum.base_type, file); + array_init(&di->CompositeType.elements, ir_allocator(), 0, base->Enum.fields.capacity); + for_array(field_index, base->Enum.fields) { + array_add(&di->CompositeType.elements, + ir_add_debug_info_enumerator(module, base->Enum.fields[field_index])); + } + di->CompositeType.tag = irDebugBasicEncoding_enumeration_type; } return di; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 54b60e510..b7a4f9e65 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2074,6 +2074,15 @@ void print_llvm_ir(irGen *ir) { ir_write_byte(f, ')'); break; } + case irDebugInfo_Enumerator: { + ir_fprintf(f, "!DIEnumerator(" + "name: \"%.*s\"" + ", value: %d", // TODO(lachsinc): PRId64 equiv? + LIT(di->Enumerator.name), + di->Enumerator.value); + ir_write_byte(f, ')'); + break; + } case irDebugInfo_AllProcs: ir_fprintf(f, "!{"); for_array(proc_index, di->AllProcs.procs) { From 7dcad45e0d9b891dd17c7caf8de28d8345c41a37 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Tue, 18 Sep 2018 21:28:28 +1000 Subject: [PATCH 05/39] Add proper procedure type support (return types and param proc signature) --- src/ir.cpp | 38 ++++++++++++++++++++++++++++++-------- src/ir_print.cpp | 21 +++++++++++++-------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index b1dca0325..1a9a3c9cc 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -566,7 +566,7 @@ struct irDebugInfo { String name; irDebugInfo * file; TokenPos pos; - Array return_types; + Array types; // !{return, return, param, param, param.. etc.} // TODO(lachsinc): variables / retainedNodes ? } Proc; struct { @@ -1794,19 +1794,41 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na di->Proc.file = file; di->Proc.pos = entity->token.pos; - isize return_count = proc->type->Proc.result_count; - array_init(&di->Proc.return_types, ir_allocator(), 0, return_count); // TODO(lachsinc): ir_allocator() safe to use? - if (return_count >= 1) { - TypeTuple *tuple = &proc->type->Proc.results->Tuple; - for_array(i, tuple->variables) { - Entity *e = tuple->variables[i]; + isize result_count = proc->type->Proc.result_count; + isize param_count = proc->type->Proc.param_count; + array_init(&di->Proc.types, ir_allocator(), 0, gb_max(result_count, 1) + param_count); // TODO(lachsinc): ir_allocator() safe to use? + + // Result/return types + if (result_count >= 1) { + TypeTuple *results_tuple = &proc->type->Proc.results->Tuple; + for_array(i, results_tuple->variables) { + Entity *e = results_tuple->variables[i]; if (e->kind != Entity_Variable) { continue; // TODO(lachsinc): Confirm correct? } irDebugInfo *type_di = ir_add_debug_info_type(proc->module, di, e, e->type, file); GB_ASSERT_NOT_NULL(type_di); - array_add(&di->Proc.return_types, type_di); + array_add(&di->Proc.types, type_di); + } + } else { + // llvm expects "!{null}" for a function without return type, use nullptr to represent it. + // TODO(lachsinc): Is there a specific "void" type we should refer to? + array_add(&di->Proc.types, (irDebugInfo*)nullptr); + } + + // Param types + if (param_count >= 1) { + TypeTuple *params_tuple = &proc->type->Proc.params->Tuple; + for_array(i, params_tuple->variables) { + Entity *e = params_tuple->variables[i]; + if (e->kind != Entity_Variable) { + continue; // TODO(lachsinc): Confirm correct? + } + // TODO(lach): Could technically be a local? + irDebugInfo *type_di = ir_add_debug_info_type(proc->module, di, e, e->type, file); + GB_ASSERT_NOT_NULL(type_di); + array_add(&di->Proc.types, type_di); } } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index b7a4f9e65..cb635cab8 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1982,16 +1982,21 @@ void print_llvm_ir(irGen *ir) { di->Proc.pos.line, di->Proc.pos.line, // NOTE(lachsinc): Assume scopeLine always same as line. m->debug_compile_unit->id); - if (di->Proc.return_types.count == 0) { - ir_fprintf(f, "null})"); - } else { - for_array(return_type_index, di->Proc.return_types) { - ir_fprintf(f, "%s!%d", - return_type_index > 0 ? ", " : "", - di->Proc.return_types[return_type_index]->id); + if (di->Proc.types.count > 0) { + for_array(type_index, di->Proc.types) { + if (type_index > 0) { + ir_write_byte(f, ','); + } + if (di->Proc.types[type_index]) { + ir_fprintf(f, "!%d", di->Proc.types[type_index]->id); + } else { + ir_write_str_lit(f, "null"); + } } - ir_write_str_lit(f, "})"); + } else { + ir_write_str_lit(f, "null"); } + ir_write_str_lit(f, "})"); // !DISubroutineTypes close ir_write_byte(f, ')'); break; case irDebugInfo_LocalVariable: { From e7d72f684849b4446bd31ceeaef7c8f96620c48d Mon Sep 17 00:00:00 2001 From: lachsinc Date: Tue, 18 Sep 2018 23:21:44 +1000 Subject: [PATCH 06/39] Static array debug info. Temporary dynamic array debug info (pointer to data, no len/cap info provided yet). --- src/ir.cpp | 41 +++++++++++++++++++++++++++ src/ir_print.cpp | 74 ++++++++++++++++++++++++++++++------------------ 2 files changed, 87 insertions(+), 28 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 1a9a3c9cc..05445ebaf 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -585,6 +585,7 @@ struct irDebugInfo { Array param_types; } ProcType; // TODO(lachsinc): Unused? struct { + // TODO(lachsinc): Do derived types even need scope/file/line etc. info? irDebugEncoding tag; String name; irDebugInfo * scope; @@ -606,6 +607,7 @@ struct irDebugInfo { i32 size; i32 align; Array elements; + i32 array_count; // TODO(lach): We could define a new !DISubrange and place ptr to it inside above elements array instead. } CompositeType; struct { String name; @@ -1752,6 +1754,45 @@ 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)) { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); + + auto elem_type = type->DynamicArray.elem; + + di->DerivedType.name = str_lit("dynamic_array_todo"); + di->DerivedType.tag = irDebugBasicEncoding_pointer_type; + di->DerivedType.scope = scope; + di->DerivedType.file = file; + di->DerivedType.pos = e->token.pos; + di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, elem_type, file); + di->DerivedType.size = 64; // TODO(lachsinc): HACK + di->DerivedType.align = 0; // TODO(lachsinc): HACK + + GB_ASSERT(base->kind != Type_Named); + map_set(&module->debug_info, hash_type(type), di); + + return di; + } + + if (is_type_array(type)) { + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.size = 8*cast(i32)type_size_of(type); // TODO(lachsinc): Confirm correct array sizing. llvm expects size in bits! + di->CompositeType.align = 8*cast(i32)type_align_of(type); + di->CompositeType.base_type = ir_add_debug_info_type(module, scope, e, type->Array.elem, file); + di->CompositeType.tag = irDebugBasicEncoding_array_type; + di->CompositeType.array_count = (i32)type->Array.count; + + GB_ASSERT(base->kind != Type_Named); + map_set(&module->debug_info, hash_type(type), di); + + return di; + } + // // TODO(lachsinc): HACK For now any remaining types interpreted as a rawptr. // diff --git a/src/ir_print.cpp b/src/ir_print.cpp index cb635cab8..0e4a544f0 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2034,13 +2034,16 @@ void print_llvm_ir(irGen *ir) { "name: \"%.*s\"" ", baseType: !%d" ", size: %d" - ", align: %d" ", tag: ", LIT(di->DerivedType.name), di->DerivedType.base_type->id, di->DerivedType.size, di->DerivedType.align); ir_print_debug_encoding(f, irDebugInfo_DerivedType, di->DerivedType.tag); + if (di->DerivedType.align > 0) { + ir_fprintf(f, ", align: %d", + di->DerivedType.align); + } if (di->DerivedType.offset > 0) { ir_fprintf(f, ", offset: %d", di->DerivedType.offset); @@ -2048,35 +2051,50 @@ void print_llvm_ir(irGen *ir) { ir_write_byte(f, ')'); break; case irDebugInfo_CompositeType: { - ir_fprintf(f, "!DICompositeType(" - "name: \"%.*s\"" - ", scope: !%d" - ", file: !%d" - ", line: %td" - ", size: %d" - ", align: %d" - ", tag: ", - LIT(di->CompositeType.name), - di->CompositeType.scope->id, - di->CompositeType.file->id, - di->CompositeType.pos.line, - di->CompositeType.size, - di->CompositeType.align); - ir_print_debug_encoding(f, irDebugInfo_CompositeType, di->CompositeType.tag); - if (di->CompositeType.base_type) { - GB_ASSERT(di->CompositeType.tag == irDebugBasicEncoding_enumeration_type); - ir_fprintf(f, ", baseType: !%d", di->CompositeType.base_type->id); - } - if (di->CompositeType.elements.count > 0) { - ir_write_str_lit(f, ", elements: !{"); - for_array(element_index, di->CompositeType.elements) { - ir_fprintf(f, "%s!%d", - element_index > 0 ? ", " : "", - di->CompositeType.elements[element_index]->id); + if (di->CompositeType.tag == irDebugBasicEncoding_array_type) { + GB_ASSERT(di->CompositeType.base_type); + ir_fprintf(f, "!DICompositeType(" + "tag: DW_TAG_array_type" + ", size: %d" + ", align: %d" + ", baseType: !%d" + ", elements: !{!DISubrange(count: %d)}" + ")", + di->CompositeType.size, + di->CompositeType.align, + di->CompositeType.base_type->id, + di->CompositeType.array_count); + } else { + ir_fprintf(f, "!DICompositeType(" + "name: \"%.*s\"" + ", scope: !%d" + ", file: !%d" + ", line: %td" + ", size: %d" + ", align: %d" + ", tag: ", + LIT(di->CompositeType.name), + di->CompositeType.scope->id, + di->CompositeType.file->id, + di->CompositeType.pos.line, + di->CompositeType.size, + di->CompositeType.align); + ir_print_debug_encoding(f, irDebugInfo_CompositeType, di->CompositeType.tag); + if (di->CompositeType.base_type) { + GB_ASSERT(di->CompositeType.tag == irDebugBasicEncoding_enumeration_type); + ir_fprintf(f, ", baseType: !%d", di->CompositeType.base_type->id); } - ir_write_byte(f, '}'); + if (di->CompositeType.elements.count > 0) { + ir_write_str_lit(f, ", elements: !{"); + for_array(element_index, di->CompositeType.elements) { + ir_fprintf(f, "%s!%d", + element_index > 0 ? ", " : "", + di->CompositeType.elements[element_index]->id); + } + ir_write_byte(f, '}'); + } + ir_write_byte(f, ')'); } - ir_write_byte(f, ')'); break; } case irDebugInfo_Enumerator: { From cce5e595e53e124368ff36d59a128669c783c808 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Wed, 19 Sep 2018 01:52:08 +1000 Subject: [PATCH 07/39] String debug info. Minor cleanup of derived / composite debug info output. --- src/ir.cpp | 91 ++++++++++++++++++++++++++++++++++++++++-------- src/ir_print.cpp | 14 ++++---- 2 files changed, 85 insertions(+), 20 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 05445ebaf..c9a0ed5c0 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -588,13 +588,13 @@ struct irDebugInfo { // TODO(lachsinc): Do derived types even need scope/file/line etc. info? irDebugEncoding tag; String name; - irDebugInfo * scope; - irDebugInfo * file; - TokenPos pos; + irDebugInfo * scope; // Optional + irDebugInfo * file; // Optional + TokenPos pos; // Optional irDebugInfo * base_type; i32 size; - i32 align; - i32 offset; + i32 align; // Optional + i32 offset; // Optional } DerivedType; struct { irDebugEncoding tag; @@ -1623,13 +1623,13 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit } irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); - di->DerivedType.name = e->token.string; - di->DerivedType.scope = scope; + di->DerivedType.name = e ? e->token.string : str_lit("todo_member_type"); di->DerivedType.tag = irDebugBasicEncoding_member; + di->DerivedType.scope = scope; + di->DerivedType.file = file; di->DerivedType.size = 8*cast(i32)type_size_of(type); di->DerivedType.align = 8*cast(i32)type_align_of(type); di->DerivedType.offset = 8*cast(i32)type_offset_of(type, index); // TODO(lachsinc): Confirm correct - di->DerivedType.file = file; di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type, file); GB_ASSERT_NOT_NULL(di->DerivedType.base_type); @@ -1663,7 +1663,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity return *existing; } - if (type->kind == Type_Basic && !is_type_complex(type) && !is_type_string(type)) { + if (type->kind == Type_Basic && !is_type_complex(type) && !is_type_string(type) && !is_type_cstring(type)) { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); di->BasicType.encoding = ir_debug_encoding_for_basic(type->Basic.kind); di->BasicType.name = type->Basic.name; @@ -1740,7 +1740,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity di->DerivedType.tag = irDebugBasicEncoding_pointer_type; di->DerivedType.scope = scope; di->DerivedType.file = file; - di->DerivedType.pos = e->token.pos; + di->DerivedType.pos = e ? e->token.pos : di->DerivedType.pos; di->DerivedType.size = 8*cast(i32)type_size_of(type); di->DerivedType.align = 8*cast(i32)type_align_of(type); di->DerivedType.offset = 0; // TODO(lachsinc) @@ -1767,10 +1767,10 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity di->DerivedType.tag = irDebugBasicEncoding_pointer_type; di->DerivedType.scope = scope; di->DerivedType.file = file; - di->DerivedType.pos = e->token.pos; + di->DerivedType.pos = e ? e->token.pos : di->DerivedType.pos; di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, elem_type, file); - di->DerivedType.size = 64; // TODO(lachsinc): HACK - di->DerivedType.align = 0; // TODO(lachsinc): HACK + di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); // TODO(lachsinc): HACK + di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); // TODO(lachsinc): HACK GB_ASSERT(base->kind != Type_Named); map_set(&module->debug_info, hash_type(type), di); @@ -1779,8 +1779,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity } if (is_type_array(type)) { - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.size = 8*cast(i32)type_size_of(type); // TODO(lachsinc): Confirm correct array sizing. llvm expects size in bits! di->CompositeType.align = 8*cast(i32)type_align_of(type); di->CompositeType.base_type = ir_add_debug_info_type(module, scope, e, type->Array.elem, file); @@ -1793,6 +1793,69 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity return di; } + if (is_type_cstring(type)) { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); + auto elem_type = type->DynamicArray.elem; + di->DerivedType.name = type->Basic.name; + di->DerivedType.tag = irDebugBasicEncoding_pointer_type; + di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_i8, file); // TODO(lachsinc): Is i8 cstring platform agnostic? + di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); // TODO(lachsinc): HACK + di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); // TODO(lachsinc): HACK + + GB_ASSERT(base->kind != Type_Named); + map_set(&module->debug_info, hash_type(type), di); + + return di; + } + + if (is_type_string(type)) { + // TODO(lach): Is there a cleaner way to set up these types without hardcoding values ?? + // Also we may want to just create hardcoded "base type" for things like strings etc. + // and just create a derived (named) type to "inherit" from. That way we can look them up directly + // inside irModule, and avoid lots of map lookups and array creations for their elements. + // In theory this should only occur once, as we hash the type t_string once and return it. + + GB_ASSERT(type->kind == Type_Basic); + GB_ASSERT(type->Basic.kind == Basic_string); + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.name = type->Basic.name; + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + di->CompositeType.size = 8*cast(i32)type_size_of(t_string); + di->CompositeType.align = 8*cast(i32)type_align_of(t_string); + + array_init(&di->CompositeType.elements, ir_allocator(), 0, 2); + + irDebugInfo *str_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + str_di->DerivedType.name = str_lit("data"); // TODO(lachsinc): + str_di->DerivedType.tag = irDebugBasicEncoding_member; + str_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + str_di->DerivedType.offset = 0; + str_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_cstring, file); + + // NOTE(lach): This isn't particularly robust, it assumes all strings will be caught + // by the map lookup (ie this will only be created once). + map_set(&module->debug_info, hash_pointer(str_di), str_di); + + irDebugInfo *len_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + len_di->DerivedType.name = str_lit("len"); // TODO(lachsinc): + len_di->DerivedType.tag = irDebugBasicEncoding_member; + len_di->DerivedType.size = 8*cast(i32)type_size_of(t_i64); + len_di->DerivedType.offset = 8*cast(i32)type_size_of(t_rawptr); + len_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_i64, file); + + // NOTE(lach): This isn't particularly robust, it assumes all strings will be caught + // by the map lookup (ie this will only be created once). + map_set(&module->debug_info, hash_pointer(len_di), len_di); + + array_add(&di->CompositeType.elements, len_di); + array_add(&di->CompositeType.elements, str_di); + + map_set(&module->debug_info, hash_type(type), di); + + return di; + } + // // TODO(lachsinc): HACK For now any remaining types interpreted as a rawptr. // diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 0e4a544f0..c11712aa8 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2067,19 +2067,21 @@ void print_llvm_ir(irGen *ir) { } else { ir_fprintf(f, "!DICompositeType(" "name: \"%.*s\"" - ", scope: !%d" - ", file: !%d" - ", line: %td" ", size: %d" ", align: %d" ", tag: ", LIT(di->CompositeType.name), - di->CompositeType.scope->id, - di->CompositeType.file->id, - di->CompositeType.pos.line, di->CompositeType.size, di->CompositeType.align); ir_print_debug_encoding(f, irDebugInfo_CompositeType, di->CompositeType.tag); + if (di->CompositeType.scope) { + ir_fprintf(f, ", scope: !%d" + ", file: !%d" + ", line: %td", + di->CompositeType.scope->id, + di->CompositeType.file->id, + di->CompositeType.pos.line); + } if (di->CompositeType.base_type) { GB_ASSERT(di->CompositeType.tag == irDebugBasicEncoding_enumeration_type); ir_fprintf(f, ", baseType: !%d", di->CompositeType.base_type->id); From 5961a638802c0846c45680a73d72da6d81e58c10 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Wed, 19 Sep 2018 13:16:56 +1000 Subject: [PATCH 08/39] Expose dynamic array data/len/cap debug info. Minor cleanup of odin string debug info. --- src/ir.cpp | 140 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 104 insertions(+), 36 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index c9a0ed5c0..4f887c4f5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1759,21 +1759,90 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity // 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)) { - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); + // + // TODO(lachsinc): Hardcode McGee. + // - auto elem_type = type->DynamicArray.elem; + // TODO(lachsinc): SPEED? I assume this will create a bunch of new debug infos for _every single_ + // dynamic array type. Maybe that's what we want, but with ability to refer to the _same_ + // derived types for the len/cap/allocator fields. - di->DerivedType.name = str_lit("dynamic_array_todo"); - di->DerivedType.tag = irDebugBasicEncoding_pointer_type; - di->DerivedType.scope = scope; - di->DerivedType.file = file; - di->DerivedType.pos = e ? e->token.pos : di->DerivedType.pos; - di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, elem_type, file); - di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); // TODO(lachsinc): HACK - di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); // TODO(lachsinc): HACK + // TODO(lachsinc): HACK we should handle named's as derived types to + // minimise duplication of work / ir output + Type *named = nullptr; + if (is_type_named(type)) { + named = type; + type = base_type(type); + } - GB_ASSERT(base->kind != Type_Named); - map_set(&module->debug_info, hash_type(type), di); + GB_ASSERT(type->kind == Type_DynamicArray); + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.name = named ? named->Named.name : str_lit("dynamic array"); + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + // 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?? + di->CompositeType.align = 8*cast(i32)type_align_of(t_rawptr); + + array_init(&di->CompositeType.elements, ir_allocator(), 0, 4); + + // Data pointer type + irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + data_ptr_di->DerivedType.name = str_lit("ptr_type_name_todo"); + data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; + data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(type->DynamicArray.elem); + data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type->DynamicArray.elem, file); + + // Field "data" + irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + data_di->DerivedType.name = str_lit("data"); + data_di->DerivedType.tag = irDebugBasicEncoding_member; + data_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + data_di->DerivedType.offset = 0; + data_di->DerivedType.base_type = data_ptr_di; + + // Field "len" + irDebugInfo *len_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + len_di->DerivedType.name = str_lit("len"); + len_di->DerivedType.tag = irDebugBasicEncoding_member; + len_di->DerivedType.size = 8*cast(i32)type_size_of(t_int); + len_di->DerivedType.offset = data_di->DerivedType.size; + len_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_int, file); + + // Field "cap" + irDebugInfo *cap_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + cap_di->DerivedType.name = str_lit("cap"); + cap_di->DerivedType.tag = irDebugBasicEncoding_member; + cap_di->DerivedType.size = 8*cast(i32)type_size_of(t_int); + cap_di->DerivedType.offset = data_di->DerivedType.size + len_di->DerivedType.size; + cap_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_int, file); + + // Field "allocator" + irDebugInfo *alloc_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + alloc_di->DerivedType.name = str_lit("allocator"); + alloc_di->DerivedType.tag = irDebugBasicEncoding_member; + alloc_di->DerivedType.size = 8*cast(i32)type_size_of(t_allocator); + alloc_di->DerivedType.offset = data_di->DerivedType.size + len_di->DerivedType.size + alloc_di->DerivedType.size; + alloc_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_allocator, file); // TODO(lachsinc): Highly doubtful t_allocator creates correct debug info! + + array_add(&di->CompositeType.elements, data_di); + array_add(&di->CompositeType.elements, len_di); + array_add(&di->CompositeType.elements, cap_di); + array_add(&di->CompositeType.elements, alloc_di); + + // NOTE(lach): This isn't particularly robust; we create a new one for every type. A potential workaround + // is to store a pointer for each of these "custom" types inside irModule, creating if not exists + // (and either adding to debug_info map, or assigning id's manually to them). + map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); + map_set(&module->debug_info, hash_pointer(data_di), data_di); + map_set(&module->debug_info, hash_pointer(len_di), len_di); + map_set(&module->debug_info, hash_pointer(cap_di), cap_di); + map_set(&module->debug_info, hash_pointer(alloc_di), alloc_di); + + map_set(&module->debug_info, hash_type(named ? named : type), di); return di; } @@ -1799,8 +1868,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity di->DerivedType.name = type->Basic.name; di->DerivedType.tag = irDebugBasicEncoding_pointer_type; di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_i8, file); // TODO(lachsinc): Is i8 cstring platform agnostic? - di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); // TODO(lachsinc): HACK - di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); // TODO(lachsinc): HACK + di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); GB_ASSERT(base->kind != Type_Named); map_set(&module->debug_info, hash_type(type), di); @@ -1826,31 +1895,28 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity array_init(&di->CompositeType.elements, ir_allocator(), 0, 2); - irDebugInfo *str_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - str_di->DerivedType.name = str_lit("data"); // TODO(lachsinc): - str_di->DerivedType.tag = irDebugBasicEncoding_member; - str_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - str_di->DerivedType.offset = 0; - str_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_cstring, file); - - // NOTE(lach): This isn't particularly robust, it assumes all strings will be caught - // by the map lookup (ie this will only be created once). - map_set(&module->debug_info, hash_pointer(str_di), str_di); + irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + data_di->DerivedType.name = str_lit("data"); // TODO(lachsinc): + data_di->DerivedType.tag = irDebugBasicEncoding_member; + data_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + data_di->DerivedType.offset = 0; + data_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_cstring, file); irDebugInfo *len_di = ir_alloc_debug_info(irDebugInfo_DerivedType); len_di->DerivedType.name = str_lit("len"); // TODO(lachsinc): len_di->DerivedType.tag = irDebugBasicEncoding_member; len_di->DerivedType.size = 8*cast(i32)type_size_of(t_i64); - len_di->DerivedType.offset = 8*cast(i32)type_size_of(t_rawptr); + len_di->DerivedType.offset = data_di->DerivedType.size; len_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_i64, file); + array_add(&di->CompositeType.elements, data_di); + array_add(&di->CompositeType.elements, len_di); + // NOTE(lach): This isn't particularly robust, it assumes all strings will be caught // by the map lookup (ie this will only be created once). + map_set(&module->debug_info, hash_pointer(data_di), data_di); map_set(&module->debug_info, hash_pointer(len_di), len_di); - array_add(&di->CompositeType.elements, len_di); - array_add(&di->CompositeType.elements, str_di); - map_set(&module->debug_info, hash_type(type), di); return di; @@ -1859,15 +1925,17 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity // // TODO(lachsinc): HACK For now any remaining types interpreted as a rawptr. // - - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); - di->BasicType.align = 8*cast(i32)type_align_of(type); - di->BasicType.encoding = irDebugBasicEncoding_address; - di->BasicType.name = str_lit("type_todo"); - di->BasicType.size = 8*cast(i32)type_size_of(type); + { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); + di->BasicType.align = 8*cast(i32)type_align_of(type); + di->BasicType.encoding = irDebugBasicEncoding_address; + di->BasicType.name = str_lit("type_todo"); + di->BasicType.size = 8*cast(i32)type_size_of(type); - map_set(&module->debug_info, hash_type(type), di); - return di; + map_set(&module->debug_info, hash_type(type), di); + + return di; + } } irDebugInfo *ir_add_debug_info_local(irProcedure *proc, irDebugInfo *scope, Entity *e, i32 arg_id) { From 1ee0fe74573fa167c55c78acc372514edb149be1 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Tue, 25 Sep 2018 21:24:15 +1000 Subject: [PATCH 09/39] Add DebugInfoArray as separate debug info type. Minor cleanup of various debug infos. --- src/ir.cpp | 323 +++++++++++++++++++++++++---------------------- src/ir_print.cpp | 50 ++++---- 2 files changed, 195 insertions(+), 178 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 4f887c4f5..6583c0198 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -28,6 +28,7 @@ struct irModule { irDebugInfo * debug_compile_unit; + i32 global_string_index; i32 global_array_index; // For ConstantSlice i32 global_generated_index; @@ -255,7 +256,7 @@ gbAllocator ir_allocator(void) { IR_INSTR_KIND(StartupRuntime, i32) \ IR_INSTR_KIND(DebugDeclare, struct { \ irDebugInfo *scope; \ - Ast * expr; \ + Ast * expr; \ Entity * entity; \ bool is_addr; \ irValue * value; \ @@ -536,6 +537,7 @@ enum irDebugInfoKind { irDebugInfo_GlobalVariable, irDebugInfo_LocalVariable, + irDebugInfo_DebugInfoArray, // array of irDebugInfo *'s irDebugInfo_Count, }; @@ -549,6 +551,8 @@ struct irDebugInfo { AstFile * file; String producer; irDebugInfo *all_procs; + irDebugInfo *enums; // DebugInfoArray + irDebugInfo *globals; // DebugInfoArray } CompileUnit; struct { AstFile *file; @@ -562,16 +566,16 @@ struct irDebugInfo { Scope * scope; // Actual scope } Scope; struct { - Entity * entity; - String name; - irDebugInfo * file; - TokenPos pos; - Array types; // !{return, return, param, param, param.. etc.} + Entity * entity; + String name; + irDebugInfo * file; + TokenPos pos; + irDebugInfo * types; // !{return, return, param, param, param.. etc.} // TODO(lachsinc): variables / retainedNodes ? } Proc; struct { Array procs; - } AllProcs; + } AllProcs; // TODO(lach): Redundant w/ DebugInfoArray. Merge. // NOTE(lachsinc): Many of the following fields could be removed/resolved as we print it? struct { @@ -606,7 +610,7 @@ struct irDebugInfo { irDebugInfo * base_type; // optional, used for enumeration_type. i32 size; i32 align; - Array elements; + irDebugInfo * elements; i32 array_count; // TODO(lach): We could define a new !DISubrange and place ptr to it inside above elements array instead. } CompositeType; struct { @@ -630,6 +634,9 @@ struct irDebugInfo { i32 arg; // Non-zero if proc parameter irDebugInfo *type; } LocalVariable; + struct { + Array elements; + } DebugInfoArray; }; }; @@ -1418,8 +1425,8 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial // TODO(lachsinc): "Arg" is not used yet but should be eventually, if applicable, set to param index // NOTE(lachsinc): The following call recurses through a type creating or finding the necessary debug info. - // This approach may be quite detrimental to perf esp. debug builds! - // This may not be the most appropriate place to place this? + // This approach may be quite detrimental to perf? + // This may not be the most appropriate place to place this? (for proc non-value params etc.) ir_add_debug_info_local(proc, di, e, 0); } @@ -1529,6 +1536,13 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type) { irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file); +irDebugInfo *ir_add_debug_info_array(irModule *module, isize count, isize capacity) { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DebugInfoArray); + array_init(&di->DebugInfoArray.elements, ir_allocator(), count, capacity); + map_set(&module->debug_info, hash_pointer(di), di); + return di; +} + irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) { // if (!proc->module->generate_debug_info) { // return nullptr; @@ -1653,6 +1667,140 @@ irDebugInfo *ir_add_debug_info_enumerator(irModule *module, Entity *e) { return di; } +irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { + // + // TODO(lachsinc): Hardcode McGee. + // + + // TODO(lachsinc): SPEED? I assume this will create a bunch of new debug infos for _every single_ + // dynamic array type. Maybe that's what we want, but with ability to refer to the _same_ + // derived types for the len/cap/allocator fields. + + // TODO(lachsinc): HACK we should handle named's as derived types to + // minimise duplication of work / ir output + Type *named = nullptr; + if (is_type_named(type)) { + named = type; + type = base_type(type); + } + GB_ASSERT(type->kind == Type_DynamicArray); + + // if (!module->debug_dynamic_array_type) { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.name = named ? named->Named.name : str_lit("dynamic array"); + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + + // 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?? + di->CompositeType.align = 8*cast(i32)type_align_of(t_rawptr); + di->CompositeType.elements = ir_add_debug_info_array(module, 0, 4); + + // Data pointer type + irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + data_ptr_di->DerivedType.name = str_lit("ptr_type_name_todo"); + data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; + data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(type->DynamicArray.elem); + data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type->DynamicArray.elem, file); + + // Field "data" + irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + data_di->DerivedType.name = str_lit("data"); + data_di->DerivedType.tag = irDebugBasicEncoding_member; + data_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + data_di->DerivedType.offset = 0; + data_di->DerivedType.base_type = data_ptr_di; + + // Field "len" + irDebugInfo *len_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + len_di->DerivedType.name = str_lit("len"); + len_di->DerivedType.tag = irDebugBasicEncoding_member; + len_di->DerivedType.size = 8*cast(i32)type_size_of(t_int); + len_di->DerivedType.offset = data_di->DerivedType.size; + len_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_int, file); + + // Field "cap" + irDebugInfo *cap_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + cap_di->DerivedType.name = str_lit("cap"); + cap_di->DerivedType.tag = irDebugBasicEncoding_member; + cap_di->DerivedType.size = 8*cast(i32)type_size_of(t_int); + cap_di->DerivedType.offset = data_di->DerivedType.size + len_di->DerivedType.size; + cap_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_int, file); + + // Field "allocator" + irDebugInfo *alloc_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + alloc_di->DerivedType.name = str_lit("allocator"); + alloc_di->DerivedType.tag = irDebugBasicEncoding_member; + alloc_di->DerivedType.size = 8*cast(i32)type_size_of(t_allocator); + alloc_di->DerivedType.offset = data_di->DerivedType.size + len_di->DerivedType.size + alloc_di->DerivedType.size; + alloc_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_allocator, file); // TODO(lachsinc): Highly doubtful t_allocator creates correct debug info! + + array_add(&di->CompositeType.elements->DebugInfoArray.elements, data_di); + array_add(&di->CompositeType.elements->DebugInfoArray.elements, len_di); + array_add(&di->CompositeType.elements->DebugInfoArray.elements, cap_di); + array_add(&di->CompositeType.elements->DebugInfoArray.elements, alloc_di); + + // NOTE(lach): This isn't particularly robust; we create a new one for every type. A potential workaround + // is to store a pointer for each of these "custom" types inside irModule, creating if not exists + // (and either adding to debug_info map, or assigning id's manually to them). + map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); + map_set(&module->debug_info, hash_pointer(data_di), data_di); + map_set(&module->debug_info, hash_pointer(len_di), len_di); + map_set(&module->debug_info, hash_pointer(cap_di), cap_di); + map_set(&module->debug_info, hash_pointer(alloc_di), alloc_di); + + map_set(&module->debug_info, hash_type(named ? named : type), di); + // } + + return di; +} + +irDebugInfo *ir_add_debug_info_string(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { + // TODO(lach): Is there a cleaner way to set up these types without hardcoding values ?? + // Also we may want to just create hardcoded "base type" for things like strings etc. + // and just create a derived (named) type to "inherit" from. That way we can look them up directly + // inside irModule, and avoid lots of map lookups and array creations for their elements. + // In theory this should only occur once, as we hash the type t_string once and return it. + + GB_ASSERT(type->kind == Type_Basic); + GB_ASSERT(type->Basic.kind == Basic_string); + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.name = type->Basic.name; + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + di->CompositeType.size = 8*cast(i32)type_size_of(t_string); + di->CompositeType.align = 8*cast(i32)type_align_of(t_string); + di->CompositeType.elements = ir_add_debug_info_array(module, 0, 2); + + irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + data_di->DerivedType.name = str_lit("data"); // TODO(lachsinc): + data_di->DerivedType.tag = irDebugBasicEncoding_member; + data_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + data_di->DerivedType.offset = 0; + data_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_cstring, file); + + irDebugInfo *len_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + len_di->DerivedType.name = str_lit("len"); // TODO(lachsinc): + len_di->DerivedType.tag = irDebugBasicEncoding_member; + len_di->DerivedType.size = 8*cast(i32)type_size_of(t_i64); + len_di->DerivedType.offset = data_di->DerivedType.size; + len_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_i64, file); + + array_add(&di->CompositeType.elements->DebugInfoArray.elements, data_di); + array_add(&di->CompositeType.elements->DebugInfoArray.elements, len_di); + + // NOTE(lach): This isn't particularly robust, it assumes all strings will be caught + // by the map lookup (ie this will only be created once). + map_set(&module->debug_info, hash_pointer(data_di), data_di); + map_set(&module->debug_info, hash_pointer(len_di), len_di); + + map_set(&module->debug_info, hash_type(type), di); + + return di; +} + irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { // if (!proc->module->generate_debug_info) { // return nullptr; @@ -1695,25 +1843,25 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity } else { di->CompositeType.name = str_lit("struct_name_todo"); } - array_init(&di->CompositeType.elements, ir_allocator(), 0, base->Struct.fields.capacity); + di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Struct.fields.count); for_array(field_index, base->Struct.fields) { - array_add(&di->CompositeType.elements, + 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)); } di->CompositeType.tag = irDebugBasicEncoding_structure_type; } else if (is_type_union(type)) { - di->CompositeType.name = str_lit("union_todo"); - array_init(&di->CompositeType.elements, ir_allocator(), 0, 0); + di->CompositeType.name = str_lit("union_name_todo"); + di->CompositeType.elements = nullptr; // ir_add_debug_info_array(module, 0, 0); // TODO(lachsinc): Add elements for union di->CompositeType.tag = irDebugBasicEncoding_union_type; } else if (is_type_enum(type)) { GB_ASSERT(type->kind == Type_Named); di->CompositeType.name = type->Named.name; di->CompositeType.base_type = ir_add_debug_info_type(module, scope, e, type->Named.base->Enum.base_type, file); - array_init(&di->CompositeType.elements, ir_allocator(), 0, base->Enum.fields.capacity); + di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Enum.fields.count); for_array(field_index, base->Enum.fields) { - array_add(&di->CompositeType.elements, + array_add(&di->CompositeType.elements->DebugInfoArray.elements, ir_add_debug_info_enumerator(module, base->Enum.fields[field_index])); } di->CompositeType.tag = irDebugBasicEncoding_enumeration_type; @@ -1735,7 +1883,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity } else if (deref->kind == Type_Basic) { di->DerivedType.name = deref->Basic.name; } else { - di->DerivedType.name = str_lit("derived_name_todo"); + di->DerivedType.name = str_lit("pointer_name_todo"); } di->DerivedType.tag = irDebugBasicEncoding_pointer_type; di->DerivedType.scope = scope; @@ -1759,92 +1907,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity // 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)) { - // - // TODO(lachsinc): Hardcode McGee. - // - - // TODO(lachsinc): SPEED? I assume this will create a bunch of new debug infos for _every single_ - // dynamic array type. Maybe that's what we want, but with ability to refer to the _same_ - // derived types for the len/cap/allocator fields. - - // TODO(lachsinc): HACK we should handle named's as derived types to - // minimise duplication of work / ir output - Type *named = nullptr; - if (is_type_named(type)) { - named = type; - type = base_type(type); - } - - GB_ASSERT(type->kind == Type_DynamicArray); - - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); - di->CompositeType.name = named ? named->Named.name : str_lit("dynamic array"); - di->CompositeType.tag = irDebugBasicEncoding_structure_type; - // 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?? - di->CompositeType.align = 8*cast(i32)type_align_of(t_rawptr); - - array_init(&di->CompositeType.elements, ir_allocator(), 0, 4); - - // Data pointer type - irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - data_ptr_di->DerivedType.name = str_lit("ptr_type_name_todo"); - data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; - data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(type->DynamicArray.elem); - data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type->DynamicArray.elem, file); - - // Field "data" - irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - data_di->DerivedType.name = str_lit("data"); - data_di->DerivedType.tag = irDebugBasicEncoding_member; - data_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - data_di->DerivedType.offset = 0; - data_di->DerivedType.base_type = data_ptr_di; - - // Field "len" - irDebugInfo *len_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - len_di->DerivedType.name = str_lit("len"); - len_di->DerivedType.tag = irDebugBasicEncoding_member; - len_di->DerivedType.size = 8*cast(i32)type_size_of(t_int); - len_di->DerivedType.offset = data_di->DerivedType.size; - len_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_int, file); - - // Field "cap" - irDebugInfo *cap_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - cap_di->DerivedType.name = str_lit("cap"); - cap_di->DerivedType.tag = irDebugBasicEncoding_member; - cap_di->DerivedType.size = 8*cast(i32)type_size_of(t_int); - cap_di->DerivedType.offset = data_di->DerivedType.size + len_di->DerivedType.size; - cap_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_int, file); - - // Field "allocator" - irDebugInfo *alloc_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - alloc_di->DerivedType.name = str_lit("allocator"); - alloc_di->DerivedType.tag = irDebugBasicEncoding_member; - alloc_di->DerivedType.size = 8*cast(i32)type_size_of(t_allocator); - alloc_di->DerivedType.offset = data_di->DerivedType.size + len_di->DerivedType.size + alloc_di->DerivedType.size; - alloc_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_allocator, file); // TODO(lachsinc): Highly doubtful t_allocator creates correct debug info! - - array_add(&di->CompositeType.elements, data_di); - array_add(&di->CompositeType.elements, len_di); - array_add(&di->CompositeType.elements, cap_di); - array_add(&di->CompositeType.elements, alloc_di); - - // NOTE(lach): This isn't particularly robust; we create a new one for every type. A potential workaround - // is to store a pointer for each of these "custom" types inside irModule, creating if not exists - // (and either adding to debug_info map, or assigning id's manually to them). - map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); - map_set(&module->debug_info, hash_pointer(data_di), data_di); - map_set(&module->debug_info, hash_pointer(len_di), len_di); - map_set(&module->debug_info, hash_pointer(cap_di), cap_di); - map_set(&module->debug_info, hash_pointer(alloc_di), alloc_di); - - map_set(&module->debug_info, hash_type(named ? named : type), di); - - return di; + return ir_add_debug_info_dynamic_array(module, scope, e, type, file); } if (is_type_array(type)) { @@ -1878,48 +1941,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity } if (is_type_string(type)) { - // TODO(lach): Is there a cleaner way to set up these types without hardcoding values ?? - // Also we may want to just create hardcoded "base type" for things like strings etc. - // and just create a derived (named) type to "inherit" from. That way we can look them up directly - // inside irModule, and avoid lots of map lookups and array creations for their elements. - // In theory this should only occur once, as we hash the type t_string once and return it. - - GB_ASSERT(type->kind == Type_Basic); - GB_ASSERT(type->Basic.kind == Basic_string); - - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); - di->CompositeType.name = type->Basic.name; - di->CompositeType.tag = irDebugBasicEncoding_structure_type; - di->CompositeType.size = 8*cast(i32)type_size_of(t_string); - di->CompositeType.align = 8*cast(i32)type_align_of(t_string); - - array_init(&di->CompositeType.elements, ir_allocator(), 0, 2); - - irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - data_di->DerivedType.name = str_lit("data"); // TODO(lachsinc): - data_di->DerivedType.tag = irDebugBasicEncoding_member; - data_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - data_di->DerivedType.offset = 0; - data_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_cstring, file); - - irDebugInfo *len_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - len_di->DerivedType.name = str_lit("len"); // TODO(lachsinc): - len_di->DerivedType.tag = irDebugBasicEncoding_member; - len_di->DerivedType.size = 8*cast(i32)type_size_of(t_i64); - len_di->DerivedType.offset = data_di->DerivedType.size; - len_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_i64, file); - - array_add(&di->CompositeType.elements, data_di); - array_add(&di->CompositeType.elements, len_di); - - // NOTE(lach): This isn't particularly robust, it assumes all strings will be caught - // by the map lookup (ie this will only be created once). - map_set(&module->debug_info, hash_pointer(data_di), data_di); - map_set(&module->debug_info, hash_pointer(len_di), len_di); - - map_set(&module->debug_info, hash_type(type), di); - - return di; + return ir_add_debug_info_string(module, scope, e, type, file); } // @@ -1968,7 +1990,8 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na isize result_count = proc->type->Proc.result_count; isize param_count = proc->type->Proc.param_count; - array_init(&di->Proc.types, ir_allocator(), 0, gb_max(result_count, 1) + param_count); // TODO(lachsinc): ir_allocator() safe to use? + // gb_max(result_count, 1) because llvm expects explicit "null" return type + di->Proc.types = ir_add_debug_info_array(proc->module, 0, gb_max(result_count, 1) + param_count); // Result/return types if (result_count >= 1) { @@ -1981,12 +2004,12 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na irDebugInfo *type_di = ir_add_debug_info_type(proc->module, di, e, e->type, file); GB_ASSERT_NOT_NULL(type_di); - array_add(&di->Proc.types, type_di); + array_add(&di->Proc.types->DebugInfoArray.elements, type_di); } } else { // llvm expects "!{null}" for a function without return type, use nullptr to represent it. // TODO(lachsinc): Is there a specific "void" type we should refer to? - array_add(&di->Proc.types, (irDebugInfo*)nullptr); + array_add(&di->Proc.types->DebugInfoArray.elements, (irDebugInfo*)nullptr); } // Param types @@ -2000,10 +2023,10 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na // TODO(lach): Could technically be a local? irDebugInfo *type_di = ir_add_debug_info_type(proc->module, di, e, e->type, file); GB_ASSERT_NOT_NULL(type_di); - array_add(&di->Proc.types, type_di); + array_add(&di->Proc.types->DebugInfoArray.elements, type_di); } } - + proc->debug_scope = di; map_set(&proc->module->debug_info, hash_entity(entity), di); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index c11712aa8..bf002b68e 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1974,30 +1974,16 @@ void print_llvm_ir(irGen *ir) { ", flags: DIFlagPrototyped" ", isOptimized: false" ", unit: !%d" - ", type: !DISubroutineType(types: !{", + ", type: !DISubroutineType(types: !%d)", LIT(di->Proc.entity->token.string), LIT(di->Proc.name), di->Proc.file->id, // TODO(lachsinc): HACK For now lets pretend all procs scope's == file. di->Proc.file->id, di->Proc.pos.line, di->Proc.pos.line, // NOTE(lachsinc): Assume scopeLine always same as line. - m->debug_compile_unit->id); - if (di->Proc.types.count > 0) { - for_array(type_index, di->Proc.types) { - if (type_index > 0) { - ir_write_byte(f, ','); - } - if (di->Proc.types[type_index]) { - ir_fprintf(f, "!%d", di->Proc.types[type_index]->id); - } else { - ir_write_str_lit(f, "null"); - } - } - } else { - ir_write_str_lit(f, "null"); - } - ir_write_str_lit(f, "})"); // !DISubroutineTypes close - ir_write_byte(f, ')'); + m->debug_compile_unit->id, + di->Proc.types->id); + ir_write_byte(f, ')'); // !DISubprogram( break; case irDebugInfo_LocalVariable: { ir_fprintf(f, "!DILocalVariable(" @@ -2074,7 +2060,7 @@ void print_llvm_ir(irGen *ir) { di->CompositeType.size, di->CompositeType.align); ir_print_debug_encoding(f, irDebugInfo_CompositeType, di->CompositeType.tag); - if (di->CompositeType.scope) { + if (di->CompositeType.scope != nullptr) { ir_fprintf(f, ", scope: !%d" ", file: !%d" ", line: %td", @@ -2082,18 +2068,12 @@ void print_llvm_ir(irGen *ir) { di->CompositeType.file->id, di->CompositeType.pos.line); } - if (di->CompositeType.base_type) { + if (di->CompositeType.base_type != nullptr) { GB_ASSERT(di->CompositeType.tag == irDebugBasicEncoding_enumeration_type); ir_fprintf(f, ", baseType: !%d", di->CompositeType.base_type->id); } - if (di->CompositeType.elements.count > 0) { - ir_write_str_lit(f, ", elements: !{"); - for_array(element_index, di->CompositeType.elements) { - ir_fprintf(f, "%s!%d", - element_index > 0 ? ", " : "", - di->CompositeType.elements[element_index]->id); - } - ir_write_byte(f, '}'); + if (di->CompositeType.elements != nullptr) { + ir_fprintf(f, ", elements: !%d", di->CompositeType.elements->id); } ir_write_byte(f, ')'); } @@ -2108,6 +2088,7 @@ void print_llvm_ir(irGen *ir) { ir_write_byte(f, ')'); break; } + // TODO(lach): Merge w/ DebugInfoArray case irDebugInfo_AllProcs: ir_fprintf(f, "!{"); for_array(proc_index, di->AllProcs.procs) { @@ -2117,6 +2098,19 @@ void print_llvm_ir(irGen *ir) { } ir_write_byte(f, '}'); break; + case irDebugInfo_DebugInfoArray: + ir_fprintf(f, "!{"); + for_array(element_index, di->DebugInfoArray.elements) { + irDebugInfo *elem = di->DebugInfoArray.elements[element_index]; + if (element_index > 0) {ir_write_str_lit(f, ", ");} + if (elem) { + ir_fprintf(f, "!%d", elem->id); + } else { + ir_fprintf(f, "null"); // NOTE(lachsinc): Proc's can contain "nullptr" entries to represent void return values. + } + } + ir_write_byte(f, '}'); + break; default: GB_PANIC("Unhandled irDebugInfo kind %d", di->kind); From 0f6c1f3482c1ec0ccce2d41799ce0281a12f637e Mon Sep 17 00:00:00 2001 From: lachsinc Date: Wed, 26 Sep 2018 02:01:03 +1000 Subject: [PATCH 10/39] Add debug info for globals. Misc debug info cleanup. --- src/ir.cpp | 100 ++++++++++++++++++++++++++++++++++++----------- 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 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, @@ -617,14 +619,18 @@ struct irDebugInfo { String name; 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) { From 7acb49eefb06edba75554574578eed7ac2e6288f Mon Sep 17 00:00:00 2001 From: lachsinc Date: Wed, 26 Sep 2018 02:17:05 +1000 Subject: [PATCH 11/39] Cleanup comments/todos. --- src/ir.cpp | 23 ++++++++--------------- src/ir_print.cpp | 8 +++----- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 878dfc03c..30b03bbb9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -577,7 +577,7 @@ struct irDebugInfo { } Proc; struct { Array procs; - } AllProcs; // TODO(lach): Redundant w/ DebugInfoArray. Merge. + } AllProcs; // TODO(lachsinc): Redundant w/ DebugInfoArray. Merge. // NOTE(lachsinc): Many of the following fields could be removed/resolved as we print it? struct { @@ -613,7 +613,7 @@ struct irDebugInfo { i32 size; i32 align; irDebugInfo * elements; - i32 array_count; // TODO(lach): We could define a new !DISubrange and place ptr to it inside above elements array instead. + i32 array_count; // for DISubrange } CompositeType; struct { String name; @@ -1680,16 +1680,13 @@ irDebugInfo *ir_add_debug_info_enumerator(irModule *module, Entity *e) { } irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { - // - // TODO(lachsinc): Hardcode McGee. - // + // TODO(lachsinc): Cleanup hardcode. // TODO(lachsinc): SPEED? I assume this will create a bunch of new debug infos for _every single_ // dynamic array type. Maybe that's what we want, but with ability to refer to the _same_ // derived types for the len/cap/allocator fields. - // TODO(lachsinc): HACK we should handle named's as derived types to - // minimise duplication of work / ir output + // TODO(lachsinc): HACK named should be handled as derived types, see above. Type *named = nullptr; if (is_type_named(type)) { named = type; @@ -1754,7 +1751,7 @@ irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scop array_add(&di->CompositeType.elements->DebugInfoArray.elements, cap_di); array_add(&di->CompositeType.elements->DebugInfoArray.elements, alloc_di); - // NOTE(lach): This isn't particularly robust; we create a new one for every type. A potential workaround + // NOTE(lachsinc): This isn't particularly robust; we create a new one for every type. A potential workaround // is to store a pointer for each of these "custom" types inside irModule, creating if not exists // (and either adding to debug_info map, or assigning id's manually to them). map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); @@ -1770,11 +1767,7 @@ irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scop } irDebugInfo *ir_add_debug_info_string(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { - // TODO(lach): Is there a cleaner way to set up these types without hardcoding values ?? - // Also we may want to just create hardcoded "base type" for things like strings etc. - // and just create a derived (named) type to "inherit" from. That way we can look them up directly - // inside irModule, and avoid lots of map lookups and array creations for their elements. - // In theory this should only occur once, as we hash the type t_string once and return it. + // TODO(lachsinc): Cleanup hardcode. GB_ASSERT(type->kind == Type_Basic); GB_ASSERT(type->Basic.kind == Basic_string); @@ -1803,7 +1796,7 @@ irDebugInfo *ir_add_debug_info_string(irModule *module, irDebugInfo *scope, Enti array_add(&di->CompositeType.elements->DebugInfoArray.elements, data_di); array_add(&di->CompositeType.elements->DebugInfoArray.elements, len_di); - // NOTE(lach): This isn't particularly robust, it assumes all strings will be caught + // NOTE(lachsinc): This isn't particularly robust, it assumes all strings will be caught // by the map lookup (ie this will only be created once). map_set(&module->debug_info, hash_pointer(data_di), data_di); map_set(&module->debug_info, hash_pointer(len_di), len_di); @@ -2062,7 +2055,7 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na if (e->kind != Entity_Variable) { continue; // TODO(lachsinc): Confirm correct? } - // TODO(lach): Could technically be a local? + // TODO(lachsinc): Could technically be a local? irDebugInfo *type_di = ir_add_debug_info_type(proc->module, di, e, e->type, file); GB_ASSERT_NOT_NULL(type_di); array_add(&di->Proc.types->DebugInfoArray.elements, type_di); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 3ec17d09b..81d2324a6 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1955,7 +1955,7 @@ void print_llvm_ir(irGen *ir) { ", runtimeVersion: 0" ", isOptimized: false" ", emissionKind: FullDebug" - ", retainedTypes: !0" // TODO(lachsinc) + ", retainedTypes: !0" // TODO(lachsinc) ", enums: !%d" ", globals: !%d" ")", @@ -1966,7 +1966,6 @@ void print_llvm_ir(irGen *ir) { break; } case irDebugInfo_File: - // TODO(lachsinc): Does windows debug info expect '/' or '\5C' path separators ?? ir_fprintf(f, "!DIFile(filename: \""); ir_print_escape_path(f, di->File.filename); ir_fprintf(f, "\", directory: \""); ir_print_escape_path(f, di->File.directory); ir_fprintf(f, "\""); @@ -2004,7 +2003,6 @@ void print_llvm_ir(irGen *ir) { 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 { @@ -2043,7 +2041,7 @@ void print_llvm_ir(irGen *ir) { di->LocalVariable.pos.line, di->LocalVariable.type->id); if (di->LocalVariable.arg > 0) { - GB_ASSERT(false); // TODO(lachsinc): "Arg" debug info not implemented yet + GB_PANIC("Param 'Arg' debug info not yet implemented"); // TODO(lachsinc): ir_fprintf(f, ", arg: %d", di->LocalVariable.arg); } ir_write_byte(f, ')'); @@ -2127,7 +2125,7 @@ void print_llvm_ir(irGen *ir) { case irDebugInfo_Enumerator: { ir_fprintf(f, "!DIEnumerator(" "name: \"%.*s\"" - ", value: %d)", // TODO(lachsinc): PRId64 equiv? + ", value: %lld)", LIT(di->Enumerator.name), di->Enumerator.value); break; From 2e5cecf9e6b28e1dbbd6f4438e48ba343b7ad0e4 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Wed, 26 Sep 2018 04:01:16 +1000 Subject: [PATCH 12/39] Cleanup dynamic array/string bloat. --- src/ir.cpp | 191 +++++++++++++++++++++++++++-------------------------- 1 file changed, 98 insertions(+), 93 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 30b03bbb9..cf2b35009 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1679,13 +1679,17 @@ irDebugInfo *ir_add_debug_info_enumerator(irModule *module, Entity *e) { return di; } +irDebugInfo *ir_add_debug_info_field_custom(irModule *module, irDebugInfo *scope, Entity *e, String name, Type *type, i32 offset, irDebugInfo *file) { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); + di->DerivedType.name = name; + di->DerivedType.tag = irDebugBasicEncoding_member; + di->DerivedType.size = 8*cast(i32)type_size_of(type); + di->DerivedType.offset = offset; + di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type, file); + return di; +} + irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { - // TODO(lachsinc): Cleanup hardcode. - - // TODO(lachsinc): SPEED? I assume this will create a bunch of new debug infos for _every single_ - // dynamic array type. Maybe that's what we want, but with ability to refer to the _same_ - // derived types for the len/cap/allocator fields. - // TODO(lachsinc): HACK named should be handled as derived types, see above. Type *named = nullptr; if (is_type_named(type)) { @@ -1694,116 +1698,117 @@ irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scop } GB_ASSERT(type->kind == Type_DynamicArray); - // if (!module->debug_dynamic_array_type) { - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); - di->CompositeType.name = named ? named->Named.name : str_lit("dynamic array"); - di->CompositeType.tag = irDebugBasicEncoding_structure_type; + // TODO(lachsinc): We should insert "type" into map and look it up, and just create a derived type + // for each required dynamic array, named or unnamed. - // 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?? - di->CompositeType.align = 8*cast(i32)type_align_of(t_rawptr); - di->CompositeType.elements = ir_add_debug_info_array(module, 0, 4); + // TODO(lachsinc): Look up in map if dynamic array for type already exists ?? - // Data pointer type - irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - data_ptr_di->DerivedType.name = str_lit("ptr_type_name_todo"); - data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; - data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(type->DynamicArray.elem); - data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type->DynamicArray.elem, file); + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.name = named ? named->Named.name : str_lit("dynamic array"); + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + 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?? + di->CompositeType.align = 8*cast(i32)type_align_of(t_rawptr); - // Field "data" - irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - data_di->DerivedType.name = str_lit("data"); - data_di->DerivedType.tag = irDebugBasicEncoding_member; - data_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - data_di->DerivedType.offset = 0; - data_di->DerivedType.base_type = data_ptr_di; + // Data pointer type + irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + data_ptr_di->DerivedType.name = str_lit("ptr_type_name_todo"); + data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; + data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(type->DynamicArray.elem); + data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type->DynamicArray.elem, file); - // Field "len" - irDebugInfo *len_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - len_di->DerivedType.name = str_lit("len"); - len_di->DerivedType.tag = irDebugBasicEncoding_member; - len_di->DerivedType.size = 8*cast(i32)type_size_of(t_int); - len_di->DerivedType.offset = data_di->DerivedType.size; - len_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_int, file); + // Field "data" + irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + data_di->DerivedType.name = str_lit("data"); + data_di->DerivedType.tag = irDebugBasicEncoding_member; + data_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + data_di->DerivedType.offset = 0; + data_di->DerivedType.base_type = data_ptr_di; - // Field "cap" - irDebugInfo *cap_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - cap_di->DerivedType.name = str_lit("cap"); - cap_di->DerivedType.tag = irDebugBasicEncoding_member; - cap_di->DerivedType.size = 8*cast(i32)type_size_of(t_int); - cap_di->DerivedType.offset = data_di->DerivedType.size + len_di->DerivedType.size; - cap_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_int, file); + // TODO(lachsinc): The following member types could theoretically be shared by all dynamic array di's, + // we could store each inside module, creating them if we haven't already. - // Field "allocator" - irDebugInfo *alloc_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - alloc_di->DerivedType.name = str_lit("allocator"); - alloc_di->DerivedType.tag = irDebugBasicEncoding_member; - alloc_di->DerivedType.size = 8*cast(i32)type_size_of(t_allocator); - alloc_di->DerivedType.offset = data_di->DerivedType.size + len_di->DerivedType.size + alloc_di->DerivedType.size; - alloc_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_allocator, file); // TODO(lachsinc): Highly doubtful t_allocator creates correct debug info! + // Field "len" + irDebugInfo *len_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("len"), t_int, + data_di->DerivedType.size, + file); - array_add(&di->CompositeType.elements->DebugInfoArray.elements, data_di); - array_add(&di->CompositeType.elements->DebugInfoArray.elements, len_di); - array_add(&di->CompositeType.elements->DebugInfoArray.elements, cap_di); - array_add(&di->CompositeType.elements->DebugInfoArray.elements, alloc_di); + // Field "cap" + irDebugInfo *cap_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("cap"), t_int, + data_di->DerivedType.size + + len_di->DerivedType.size, + file); - // NOTE(lachsinc): This isn't particularly robust; we create a new one for every type. A potential workaround - // is to store a pointer for each of these "custom" types inside irModule, creating if not exists - // (and either adding to debug_info map, or assigning id's manually to them). - map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); - map_set(&module->debug_info, hash_pointer(data_di), data_di); - map_set(&module->debug_info, hash_pointer(len_di), len_di); - map_set(&module->debug_info, hash_pointer(cap_di), cap_di); - map_set(&module->debug_info, hash_pointer(alloc_di), alloc_di); + // Field "allocator" + irDebugInfo *alloc_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("allocator"), t_allocator, + data_di->DerivedType.size + + len_di->DerivedType.size + + cap_di->DerivedType.size, + file); - map_set(&module->debug_info, hash_type(named ? named : type), di); - // } + irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 4); + array_add(&elements_di->DebugInfoArray.elements, data_di); + array_add(&elements_di->DebugInfoArray.elements, len_di); + array_add(&elements_di->DebugInfoArray.elements, cap_di); + array_add(&elements_di->DebugInfoArray.elements, alloc_di); + + di->CompositeType.elements = elements_di; + + map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); + map_set(&module->debug_info, hash_pointer(data_di), data_di); + map_set(&module->debug_info, hash_pointer(len_di), len_di); + map_set(&module->debug_info, hash_pointer(cap_di), cap_di); + map_set(&module->debug_info, hash_pointer(alloc_di), alloc_di); + + map_set(&module->debug_info, hash_pointer(elements_di), elements_di); + + map_set(&module->debug_info, hash_type(named ? named : type), di); return di; } irDebugInfo *ir_add_debug_info_string(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { - // TODO(lachsinc): Cleanup hardcode. - GB_ASSERT(type->kind == Type_Basic); GB_ASSERT(type->Basic.kind == Basic_string); - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); - di->CompositeType.name = type->Basic.name; - di->CompositeType.tag = irDebugBasicEncoding_structure_type; - di->CompositeType.size = 8*cast(i32)type_size_of(t_string); - di->CompositeType.align = 8*cast(i32)type_align_of(t_string); - di->CompositeType.elements = ir_add_debug_info_array(module, 0, 2); + // Get or create string composite type (hashed via t_string ptr) + // alternatively we could just store a pointer to it inside irModule. + irDebugInfo **existing = map_get(&module->debug_info, hash_type(t_string)); + if (existing != nullptr) { + GB_ASSERT((*existing)->kind == irDebugInfo_CompositeType); + return *existing; + } else { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.name = type->Basic.name; + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + di->CompositeType.size = 8*cast(i32)type_size_of(t_string); + di->CompositeType.align = 8*cast(i32)type_align_of(t_string); - irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - data_di->DerivedType.name = str_lit("data"); // TODO(lachsinc): - data_di->DerivedType.tag = irDebugBasicEncoding_member; - data_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - data_di->DerivedType.offset = 0; - data_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_cstring, file); + // Field "data" + irDebugInfo *data_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("data"), t_cstring, 0, file); - irDebugInfo *len_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - len_di->DerivedType.name = str_lit("len"); // TODO(lachsinc): - len_di->DerivedType.tag = irDebugBasicEncoding_member; - len_di->DerivedType.size = 8*cast(i32)type_size_of(t_i64); - len_di->DerivedType.offset = data_di->DerivedType.size; - len_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_i64, file); + // Field "len" + irDebugInfo *len_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("len"), t_i64, + data_di->DerivedType.size, file); - array_add(&di->CompositeType.elements->DebugInfoArray.elements, data_di); - array_add(&di->CompositeType.elements->DebugInfoArray.elements, len_di); + irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 2); - // NOTE(lachsinc): This isn't particularly robust, it assumes all strings will be caught - // by the map lookup (ie this will only be created once). - map_set(&module->debug_info, hash_pointer(data_di), data_di); - map_set(&module->debug_info, hash_pointer(len_di), len_di); + array_add(&elements_di->DebugInfoArray.elements, data_di); + array_add(&elements_di->DebugInfoArray.elements, len_di); - map_set(&module->debug_info, hash_type(type), di); + di->CompositeType.elements = elements_di; - return di; + map_set(&module->debug_info, hash_pointer(data_di), data_di); + map_set(&module->debug_info, hash_pointer(len_di), len_di); + + map_set(&module->debug_info, hash_pointer(elements_di), elements_di); + + map_set(&module->debug_info, hash_type(type), di); + + return di; + } } irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { From 54c044ee09f3c630a21be0d5fab7b095bb8a8f46 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Wed, 26 Sep 2018 05:43:37 +1000 Subject: [PATCH 13/39] Add support for any. Fix rawptr debug type. --- src/ir.cpp | 119 ++++++++++++++++++++++++++++++----------------- src/ir_print.cpp | 8 ++-- 2 files changed, 82 insertions(+), 45 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index cf2b35009..6cfac567f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1622,15 +1622,13 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { case Basic_f64: return irDebugBasicEncoding_float; - case Basic_any: - case Basic_rawptr: - return irDebugBasicEncoding_address; - // case Basic_complex32: case Basic_complex64: case Basic_complex128: case Basic_cstring: case Basic_string: + case Basic_any: + case Basic_rawptr: break; // not a "DIBasicType" } @@ -1761,9 +1759,7 @@ irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scop map_set(&module->debug_info, hash_pointer(len_di), len_di); map_set(&module->debug_info, hash_pointer(cap_di), cap_di); map_set(&module->debug_info, hash_pointer(alloc_di), alloc_di); - map_set(&module->debug_info, hash_pointer(elements_di), elements_di); - map_set(&module->debug_info, hash_type(named ? named : type), di); return di; @@ -1790,27 +1786,54 @@ irDebugInfo *ir_add_debug_info_string(irModule *module, irDebugInfo *scope, Enti irDebugInfo *data_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("data"), t_cstring, 0, file); // Field "len" - irDebugInfo *len_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("len"), t_i64, - data_di->DerivedType.size, file); + irDebugInfo *len_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("len"), t_i64, data_di->DerivedType.size, file); irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 2); - array_add(&elements_di->DebugInfoArray.elements, data_di); array_add(&elements_di->DebugInfoArray.elements, len_di); - di->CompositeType.elements = elements_di; map_set(&module->debug_info, hash_pointer(data_di), data_di); map_set(&module->debug_info, hash_pointer(len_di), len_di); - map_set(&module->debug_info, hash_pointer(elements_di), elements_di); - map_set(&module->debug_info, hash_type(type), di); return di; } } +irDebugInfo *ir_add_debug_info_any(irModule *module) { + irDebugInfo **existing = map_get(&module->debug_info, hash_type(t_any)); + if (existing != nullptr) { + GB_ASSERT((*existing)->kind == irDebugInfo_CompositeType); + return *existing; + } else { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.name = t_any->Basic.name; + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + di->CompositeType.size = 8*cast(i32)type_size_of(t_any); // TODO(lachsinc): Correct ?? + di->CompositeType.align = 8*cast(i32)type_align_of(t_any); + + // Field "data" + irDebugInfo *data_di = ir_add_debug_info_field_custom(module, nullptr, nullptr, str_lit("data"), t_rawptr, 0, nullptr); + + // Field "len" + irDebugInfo *len_di = ir_add_debug_info_field_custom(module, nullptr, nullptr, str_lit("id"), t_typeid, data_di->DerivedType.size, nullptr); + + irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 2); + array_add(&elements_di->DebugInfoArray.elements, data_di); + array_add(&elements_di->DebugInfoArray.elements, len_di); + di->CompositeType.elements = elements_di; + + map_set(&module->debug_info, hash_pointer(data_di), data_di); + map_set(&module->debug_info, hash_pointer(len_di), len_di); + map_set(&module->debug_info, hash_pointer(elements_di), elements_di); + map_set(&module->debug_info, hash_type(t_any), di); + + return di; + } +} + irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { // if (!proc->module->generate_debug_info) { // return nullptr; @@ -1821,20 +1844,51 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity return *existing; } - if (type->kind == Type_Basic && !is_type_complex(type) && !is_type_string(type) && !is_type_cstring(type)) { - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); - di->BasicType.encoding = ir_debug_encoding_for_basic(type->Basic.kind); - di->BasicType.name = type->Basic.name; - di->BasicType.size = 8*cast(i32)type_size_of(type); - di->BasicType.align = 8*cast(i32)type_align_of(type); - - map_set(&module->debug_info, hash_type(type), di); - return di; - } - // NOTE(lachsinc): Types are inserted into debug_info map as their named, not base_type()'d counterpart. Type *base = base_type(type); + // TODO(lachsinc): Are all "named" types just able to be DIDerivedTypes? + + // TODO(lachsinc): switch ?? + if (type->kind == Type_Basic) { + if (is_type_rawptr(type)) { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); + di->DerivedType.name = t_rawptr->Basic.name; + di->DerivedType.tag = irDebugBasicEncoding_pointer_type; + di->DerivedType.base_type = nullptr; // NOTE(lachsinc): llvm expects "null", use nullptr + di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); + GB_ASSERT(base->kind != Type_Named); + map_set(&module->debug_info, hash_type(type), di); + return di; + } else if (is_type_cstring(type)) { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); + auto elem_type = type->DynamicArray.elem; + di->DerivedType.name = type->Basic.name; + di->DerivedType.tag = irDebugBasicEncoding_pointer_type; + di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_i8, file); // TODO(lachsinc): Is i8 cstring platform agnostic? + di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); + GB_ASSERT(base->kind != Type_Named); + map_set(&module->debug_info, hash_type(type), di); + return di; + } else if (is_type_string(type)) { + return ir_add_debug_info_string(module, scope, e, type, file); + } else if (is_type_any(type)) { + return ir_add_debug_info_any(module); + } else if (is_type_complex(type)) { + // TODO(lachsinc): + } else { + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); + di->BasicType.encoding = ir_debug_encoding_for_basic(type->Basic.kind); + di->BasicType.name = type->Basic.name; + di->BasicType.size = 8*cast(i32)type_size_of(type); + di->BasicType.align = 8*cast(i32)type_align_of(type); + map_set(&module->debug_info, hash_type(type), di); + return di; + } + } + if (is_type_struct(type) || is_type_union(type) || is_type_enum(type)) { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); di->CompositeType.scope = scope; @@ -1935,25 +1989,6 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity return di; } - if (is_type_cstring(type)) { - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); - auto elem_type = type->DynamicArray.elem; - di->DerivedType.name = type->Basic.name; - di->DerivedType.tag = irDebugBasicEncoding_pointer_type; - di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_i8, file); // TODO(lachsinc): Is i8 cstring platform agnostic? - di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); - - GB_ASSERT(base->kind != Type_Named); - map_set(&module->debug_info, hash_type(type), di); - - return di; - } - - if (is_type_string(type)) { - return ir_add_debug_info_string(module, scope, e, type, file); - } - // // TODO(lachsinc): HACK For now any remaining types interpreted as a rawptr. // diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 81d2324a6..cad0d3d3e 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2058,17 +2058,19 @@ void print_llvm_ir(irGen *ir) { ir_write_byte(f, ')'); break; case irDebugInfo_DerivedType: - GB_ASSERT(di->DerivedType.base_type); ir_fprintf(f, "!DIDerivedType(" "name: \"%.*s\"" - ", baseType: !%d" ", size: %d" ", tag: ", LIT(di->DerivedType.name), - di->DerivedType.base_type->id, di->DerivedType.size, di->DerivedType.align); ir_print_debug_encoding(f, irDebugInfo_DerivedType, di->DerivedType.tag); + if (di->DerivedType.base_type != nullptr) { + ir_fprintf(f, ", baseType: !%d", di->DerivedType.base_type->id); + } else { + ir_write_str_lit(f, ", baseType: null"); // Valid/required for rawptr + } if (di->DerivedType.align > 0) { ir_fprintf(f, ", align: %d", di->DerivedType.align); From 6993777d36e6cbcf291feefcfbebb004e75b0d49 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Wed, 26 Sep 2018 06:04:33 +1000 Subject: [PATCH 14/39] Slices. Fix dynamic array data ptr size. --- src/ir.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/ir.cpp b/src/ir.cpp index 6cfac567f..0f97a0a16 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1714,7 +1714,7 @@ irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scop irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); data_ptr_di->DerivedType.name = str_lit("ptr_type_name_todo"); data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; - data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(type->DynamicArray.elem); + data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type->DynamicArray.elem, file); // Field "data" @@ -1989,6 +1989,47 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity return di; } + if (is_type_slice(type)) { + // NOTE(lachsinc): Every slice type has its own composite type / field debug infos created. This is wasteful!! + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.name = type->Basic.name; + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + di->CompositeType.size = 8*cast(i32)type_size_of(type); // TODO(lachsinc): Correct ?? + di->CompositeType.align = 8*cast(i32)type_align_of(type); + + // Data pointer type + irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + data_ptr_di->DerivedType.name = str_lit("slice_type_todo"); + data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; + data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type->Slice.elem, file); + + // Field "data" + irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); + data_di->DerivedType.name = str_lit("data"); + data_di->DerivedType.tag = irDebugBasicEncoding_member; + data_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + data_di->DerivedType.offset = 0; + data_di->DerivedType.base_type = data_ptr_di; + + // Field "len" + irDebugInfo *len_di = ir_add_debug_info_field_custom(module, nullptr, nullptr, str_lit("len"), t_int, data_di->DerivedType.size, nullptr); + + irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 2); + array_add(&elements_di->DebugInfoArray.elements, data_di); + array_add(&elements_di->DebugInfoArray.elements, len_di); + di->CompositeType.elements = elements_di; + + map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); + map_set(&module->debug_info, hash_pointer(data_di), data_di); + map_set(&module->debug_info, hash_pointer(len_di), len_di); + map_set(&module->debug_info, hash_pointer(elements_di), elements_di); + map_set(&module->debug_info, hash_type(type), di); + + return di; + } + // // TODO(lachsinc): HACK For now any remaining types interpreted as a rawptr. // From d31d4c9bd665d3e05ef7bae37ad9955337f9e0cd Mon Sep 17 00:00:00 2001 From: lachsinc Date: Wed, 26 Sep 2018 07:51:16 +1000 Subject: [PATCH 15/39] (Basic) Map debug info support. Minor slice fix. --- src/ir.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 0f97a0a16..a73b25033 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1636,7 +1636,8 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { return irDebugBasicEncoding_Invalid; } -irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entity *e, i32 index, Type *type, irDebugInfo *file) { +// TODO(lachsinc): Cleanup params. +irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entity *e, Type *struct_type, i32 index, Type *type, irDebugInfo *file) { Type *named = type; type = base_type(type); GB_ASSERT(type->kind != Type_Named); @@ -1653,7 +1654,11 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit di->DerivedType.file = file; di->DerivedType.size = 8*cast(i32)type_size_of(type); di->DerivedType.align = 8*cast(i32)type_align_of(type); - di->DerivedType.offset = 8*cast(i32)type_offset_of(type, index); // TODO(lachsinc): Confirm correct + if (struct_type && struct_type->Struct.are_offsets_set) { + di->DerivedType.offset = 8*cast(i32)struct_type->Struct.offsets[index]; + } else { + di->DerivedType.offset = 8*cast(i32)type_offset_of(type, index); // TODO(lachsinc): Confirm correct + } di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type, file); GB_ASSERT_NOT_NULL(di->DerivedType.base_type); @@ -1910,8 +1915,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Struct.fields.count); 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)); + ir_add_debug_info_field(module, di, base->Struct.fields[field_index], type, + cast(i32)field_index, base->Struct.fields[field_index]->type, file)); } di->CompositeType.tag = irDebugBasicEncoding_structure_type; } else if (is_type_union(type)) { @@ -1993,14 +1998,20 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity // NOTE(lachsinc): Every slice type has its own composite type / field debug infos created. This is wasteful!! irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); - di->CompositeType.name = type->Basic.name; + di->CompositeType.name = str_lit("slice"); di->CompositeType.tag = irDebugBasicEncoding_structure_type; di->CompositeType.size = 8*cast(i32)type_size_of(type); // TODO(lachsinc): Correct ?? di->CompositeType.align = 8*cast(i32)type_align_of(type); // Data pointer type irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - data_ptr_di->DerivedType.name = str_lit("slice_type_todo"); + if (type->Slice.elem->kind == Type_Named) { + data_ptr_di->DerivedType.name = type->Slice.elem->Named.name; // TODO(lachsinc): Ptr?? + } else if (type->Slice.elem->kind == Type_Basic) { + data_ptr_di->DerivedType.name = type->Slice.elem->Basic.name; // TODO(lachsinc): Ptr?? + } else { + data_ptr_di->DerivedType.name = str_lit("slice_ptr_type_todo"); + } data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type->Slice.elem, file); @@ -2030,6 +2041,10 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity return di; } + if (is_type_map(type)) { + return ir_add_debug_info_type(module, scope, e, type->Map.generated_struct_type, file); + } + // // TODO(lachsinc): HACK For now any remaining types interpreted as a rawptr. // From 3106aaaa3dd95c7b8a965ea2b2066beb5d4e1ef7 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Thu, 27 Sep 2018 00:02:35 +1000 Subject: [PATCH 16/39] Fix pointers to all things debug info. Cleanup param order. Make scope/file optional for relevent types. --- src/ir.cpp | 218 ++++++++++++++++++++++++++++------------------- src/ir_print.cpp | 29 +++---- 2 files changed, 144 insertions(+), 103 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index a73b25033..5e196d64b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -593,12 +593,12 @@ struct irDebugInfo { struct { // TODO(lachsinc): Do derived types even need scope/file/line etc. info? irDebugEncoding tag; - String name; - irDebugInfo * scope; // Optional - irDebugInfo * file; // Optional - TokenPos pos; // Optional irDebugInfo * base_type; - i32 size; + String name; // Optional + irDebugInfo * scope; // Optional TODO(lachsinc): Is this used?? + irDebugInfo * file; // Optional TODO(lachsinc): Is this used?? + TokenPos pos; // Optional TODO(lachsinc): Is this used?? + i32 size; // Optional i32 align; // Optional i32 offset; // Optional } DerivedType; @@ -1411,7 +1411,7 @@ void ir_push_context_onto_stack(irProcedure *proc, irValue *ctx) { array_add(&proc->context_stack, cd); } -irDebugInfo *ir_add_debug_info_local(irProcedure *proc, irDebugInfo *scope, Entity *entity, i32 arg_id); +irDebugInfo *ir_add_debug_info_local(irModule *module, Entity *e, i32 arg_id, irDebugInfo *scope, irDebugInfo *file); irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initialized) { irBlock *b = proc->decl_block; // all variables must be in the first block @@ -1433,7 +1433,7 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial // NOTE(lachsinc): The following call recurses through a type creating or finding the necessary debug info. // This approach may be quite detrimental to perf? // This may not be the most appropriate place to place this? (for proc non-value params etc.) - ir_add_debug_info_local(proc, di, e, 0); + ir_add_debug_info_local(proc->module, e, 0, di, di->Proc.file); } return instr; @@ -1540,7 +1540,7 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type) { // //////////////////////////////////////////////////////////////// -irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file); +irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irDebugInfo *scope, irDebugInfo *file); irDebugInfo *ir_add_debug_info_array(irModule *module, isize count, isize capacity) { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DebugInfoArray); @@ -1650,8 +1650,11 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); di->DerivedType.name = e ? e->token.string : str_lit("todo_member_type"); di->DerivedType.tag = irDebugBasicEncoding_member; - di->DerivedType.scope = scope; - di->DerivedType.file = file; + if (e) { + di->DerivedType.scope = scope; // TODO(lachsinc): Ensure this scope is == relevent struct_type debug info ??? + di->DerivedType.file = file; + // di->DerivedType.pos = ; // TODO(lachsinc): + } di->DerivedType.size = 8*cast(i32)type_size_of(type); di->DerivedType.align = 8*cast(i32)type_align_of(type); if (struct_type && struct_type->Struct.are_offsets_set) { @@ -1659,13 +1662,14 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit } else { di->DerivedType.offset = 8*cast(i32)type_offset_of(type, index); // TODO(lachsinc): Confirm correct } - di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type, file); + di->DerivedType.base_type = ir_add_debug_info_type(module, type, e, scope, file); GB_ASSERT_NOT_NULL(di->DerivedType.base_type); map_set(&module->debug_info, hash_entity(e), di); // TODO(lachsinc): Member type hashing to ensure unique?? return di; } +// TODO(lachsinc): Cleanup params. irDebugInfo *ir_add_debug_info_enumerator(irModule *module, Entity *e) { irDebugInfo **existing = map_get(&module->debug_info, hash_entity(e)); if (existing != nullptr) { @@ -1682,16 +1686,19 @@ irDebugInfo *ir_add_debug_info_enumerator(irModule *module, Entity *e) { return di; } +// TODO(lachsinc): Cleanup params. irDebugInfo *ir_add_debug_info_field_custom(irModule *module, irDebugInfo *scope, Entity *e, String name, Type *type, i32 offset, irDebugInfo *file) { + // TODO(lachsinc): Merge with above normal field stuff. irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); di->DerivedType.name = name; di->DerivedType.tag = irDebugBasicEncoding_member; di->DerivedType.size = 8*cast(i32)type_size_of(type); di->DerivedType.offset = offset; - di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type, file); + di->DerivedType.base_type = ir_add_debug_info_type(module, type, e, scope, file); return di; } +// TODO(lachsinc): Cleanup params. irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { // TODO(lachsinc): HACK named should be handled as derived types, see above. Type *named = nullptr; @@ -1720,7 +1727,7 @@ irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scop data_ptr_di->DerivedType.name = str_lit("ptr_type_name_todo"); data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type->DynamicArray.elem, file); + data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, type->DynamicArray.elem, e, scope, file); // Field "data" irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); @@ -1770,6 +1777,7 @@ irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scop return di; } +// TODO(lachsinc): Cleanup params. irDebugInfo *ir_add_debug_info_string(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { GB_ASSERT(type->kind == Type_Basic); GB_ASSERT(type->Basic.kind == Basic_string); @@ -1839,7 +1847,7 @@ irDebugInfo *ir_add_debug_info_any(irModule *module) { } } -irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { +irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irDebugInfo *scope, irDebugInfo *file) { // if (!proc->module->generate_debug_info) { // return nullptr; // } @@ -1849,41 +1857,76 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity return *existing; } - // NOTE(lachsinc): Types are inserted into debug_info map as their named, not base_type()'d counterpart. + // Reset entity info if applicable for every type we try add. + // TODO(lachsinc): Confirm this doesn't mess up struct field scope's. + if (type->kind == Type_Named) { + e = type->Named.type_name; + if (e) { + CheckerInfo *info = module->info; + file = ir_add_debug_info_file(module, ast_file_of_filename(info, e->token.pos.file)); + // TODO(lachsinc): Determine proper scope for type declaration location stuff. + scope = file; + } + } + + // NOTE(lachsinc): Types are inserted into debug_info map as their named, not base_type()'d, counterpart. Type *base = base_type(type); - // TODO(lachsinc): Are all "named" types just able to be DIDerivedTypes? - - // TODO(lachsinc): switch ?? - if (type->kind == Type_Basic) { - if (is_type_rawptr(type)) { + if (type->kind == Type_Named) { + Type *named_base = type->Named.base; + if (named_base->kind == Type_Named || named_base->kind == Type_Basic) { + // distinct / typedef etc. irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); - di->DerivedType.name = t_rawptr->Basic.name; - di->DerivedType.tag = irDebugBasicEncoding_pointer_type; - di->DerivedType.base_type = nullptr; // NOTE(lachsinc): llvm expects "null", use nullptr - di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); - GB_ASSERT(base->kind != Type_Named); + if (type->kind == Type_Named) { + di->DerivedType.name = type->Named.name; + } else if (named_base->kind == Type_Basic) { + di->DerivedType.name = named_base->Basic.name; + } + di->DerivedType.tag = irDebugBasicEncoding_typedef; + // TODO(lachsinc): Do we need to try and resolve a new entity/scope for the base type? + // Maybe we also want to pull out type->Named.type_name ?? in the case it is a Named + di->DerivedType.base_type = ir_add_debug_info_type(module, named_base, e, scope, file); map_set(&module->debug_info, hash_type(type), di); return di; - } else if (is_type_cstring(type)) { + } + } + + if (type->kind == Type_Basic) { + // TODO(lachsinc): TEMP + if (!(type->Basic.kind == Basic_cstring || type->Basic.kind == Basic_rawptr)) { + if ((type->Basic.flags & BasicFlag_Pointer) != 0) { + GB_ASSERT(false); + } + } + + switch (type->Basic.kind) { + // Composite basic types + case Basic_complex64: + case Basic_complex128: { + // TODO(lachsinc): + break; + } + case Basic_string: return ir_add_debug_info_string(module, scope, e, type, file); + case Basic_any: return ir_add_debug_info_any(module); + + // Derived basic types + case Basic_cstring: + case Basic_rawptr: { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); - auto elem_type = type->DynamicArray.elem; di->DerivedType.name = type->Basic.name; di->DerivedType.tag = irDebugBasicEncoding_pointer_type; - di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, t_i8, file); // TODO(lachsinc): Is i8 cstring platform agnostic? di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); - GB_ASSERT(base->kind != Type_Named); + di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); // TODO(lachsinc): Not sure if align is required. + // NOTE(lachsinc): llvm expects "null" for rawptr/voidptr + if (type->Basic.kind == Basic_cstring) { + di->DerivedType.base_type = ir_add_debug_info_type(module, t_i8, e, scope, file); + } map_set(&module->debug_info, hash_type(type), di); return di; - } else if (is_type_string(type)) { - return ir_add_debug_info_string(module, scope, e, type, file); - } else if (is_type_any(type)) { - return ir_add_debug_info_any(module); - } else if (is_type_complex(type)) { - // TODO(lachsinc): - } else { + } + + // Basic basic types + default: { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); di->BasicType.encoding = ir_debug_encoding_for_basic(type->Basic.kind); di->BasicType.name = type->Basic.name; @@ -1892,13 +1935,31 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity map_set(&module->debug_info, hash_type(type), di); return di; } + } + } + + if (is_type_pointer(type)) { + // TODO(lachsinc): Ensure this handles pointers to pointers of same type etc. correctly. + Type *deref = type_deref(base); + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); + di->DerivedType.tag = irDebugBasicEncoding_pointer_type; + di->DerivedType.size = 8*cast(i32)type_size_of(type); + // NOTE(lachsinc): Set in map before creative base_type to avoid circular dependency issues. + map_set(&module->debug_info, hash_type(type), di); + if (is_type_struct(deref)) { + int i = 123; + } + di->DerivedType.base_type = ir_add_debug_info_type(module, deref, e, scope, file); + return di; } if (is_type_struct(type) || is_type_union(type) || is_type_enum(type)) { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); - di->CompositeType.scope = scope; - di->CompositeType.file = file; - di->CompositeType.pos = e->token.pos; + if (e) { + di->CompositeType.file = file; + di->CompositeType.scope = scope; + di->CompositeType.pos = e->token.pos; + } di->CompositeType.size = 8*cast(i32)type_size_of(type); di->CompositeType.align = 8*cast(i32)type_align_of(type); di->CompositeType.base_type = nullptr; @@ -1927,7 +1988,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity } else if (is_type_enum(type)) { GB_ASSERT(type->kind == Type_Named); di->CompositeType.name = type->Named.name; - di->CompositeType.base_type = ir_add_debug_info_type(module, scope, e, type->Named.base->Enum.base_type, file); + di->CompositeType.base_type = ir_add_debug_info_type(module, type->Named.base->Enum.base_type, e, scope, file); di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Enum.fields.count); for_array(field_index, base->Enum.fields) { array_add(&di->CompositeType.elements->DebugInfoArray.elements, @@ -1943,38 +2004,6 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity return di; } - if (is_type_pointer(type)) { - // TODO(lachsinc): Ensure this handles pointers to pointers of same type etc. correctly. - Type *deref_named = type_deref(base); - Type *deref = base_type(deref_named); - - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); - // TODO(lachsinc): Is there a helper for getting a types name string? Also, should pointers - // include '^'? May be better to prepend '^' at ir print time rather than creating a new string here. - if (deref_named->kind == Type_Named) { - di->DerivedType.name = deref_named->Named.name; - } else if (deref->kind == Type_Basic) { - di->DerivedType.name = deref->Basic.name; - } else { - di->DerivedType.name = str_lit("pointer_name_todo"); - } - di->DerivedType.tag = irDebugBasicEncoding_pointer_type; - di->DerivedType.scope = scope; - di->DerivedType.file = file; - di->DerivedType.pos = e ? e->token.pos : di->DerivedType.pos; - di->DerivedType.size = 8*cast(i32)type_size_of(type); - di->DerivedType.align = 8*cast(i32)type_align_of(type); - di->DerivedType.offset = 0; // TODO(lachsinc) - - GB_ASSERT(base->kind != Type_Named); - map_set(&module->debug_info, hash_type(type), di); - - di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, deref, file); - GB_ASSERT_NOT_NULL(di->DerivedType.base_type); - - return di; - } - if (is_type_dynamic_array(type)) { return ir_add_debug_info_dynamic_array(module, scope, e, type, file); } @@ -1984,7 +2013,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity di->CompositeType.size = 8*cast(i32)type_size_of(type); // TODO(lachsinc): Confirm correct array sizing. llvm expects size in bits! di->CompositeType.align = 8*cast(i32)type_align_of(type); - di->CompositeType.base_type = ir_add_debug_info_type(module, scope, e, type->Array.elem, file); + di->CompositeType.base_type = ir_add_debug_info_type(module, type->Array.elem, e, scope, file); di->CompositeType.tag = irDebugBasicEncoding_array_type; di->CompositeType.array_count = (i32)type->Array.count; @@ -2014,7 +2043,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity } data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, scope, e, type->Slice.elem, file); + data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, type->Slice.elem, e, scope, file); // Field "data" irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); @@ -2042,7 +2071,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity } if (is_type_map(type)) { - return ir_add_debug_info_type(module, scope, e, type->Map.generated_struct_type, file); + return ir_add_debug_info_type(module, type->Map.generated_struct_type, e, scope, file); } // @@ -2061,21 +2090,27 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, irDebugInfo *scope, Entity } } -irDebugInfo *ir_add_debug_info_global(irModule *module, irDebugInfo *scope, irValue *v) { +irDebugInfo *ir_add_debug_info_global(irModule *module, irValue *v, irDebugInfo *scope) { // if (!proc->module->generate_debug_info) { // return nullptr; // } Entity *e = v->Global.entity; + // NOTE(lachsinc): Just to be safe/robust; globals are likely added once only? + irDebugInfo **existing = map_get(&module->debug_info, hash_entity(e)); + if (existing != nullptr) { + return *existing; + } + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_GlobalVariableExpression); + map_set(&module->debug_info, hash_entity(e), di); 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 @@ -2083,15 +2118,17 @@ irDebugInfo *ir_add_debug_info_global(irModule *module, irDebugInfo *scope, irVa // unique for the DIGlobalVariable's hash. map_set(&module->debug_info, hash_pointer(var_di), var_di); + var_di->GlobalVariable.type = ir_add_debug_info_type(module, e->type, nullptr, nullptr, nullptr); + GB_ASSERT_NOT_NULL(var_di->GlobalVariable.type); + 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) { +irDebugInfo *ir_add_debug_info_local(irModule *module, Entity *e, i32 arg_id, irDebugInfo *scope, irDebugInfo *file) { // if (!proc->module->generate_debug_info) { // return nullptr; // } @@ -2102,13 +2139,13 @@ irDebugInfo *ir_add_debug_info_local(irProcedure *proc, irDebugInfo *scope, Enti di->LocalVariable.file = scope->Proc.file; di->LocalVariable.pos = e->token.pos; di->LocalVariable.arg = arg_id; - di->LocalVariable.type = ir_add_debug_info_type(proc->module, scope, e, e->type, scope->Proc.file); + di->LocalVariable.type = ir_add_debug_info_type(module, e->type, nullptr, nullptr, nullptr); - map_set(&proc->module->debug_info, hash_entity(e), di); + map_set(&module->debug_info, hash_entity(e), di); return di; } -irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String name, irDebugInfo *file) { +irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String name, irDebugInfo *scope, irDebugInfo *file) { // if (!proc->module->generate_debug_info) { // return nullptr; // } @@ -2133,7 +2170,8 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na continue; // TODO(lachsinc): Confirm correct? } - irDebugInfo *type_di = ir_add_debug_info_type(proc->module, di, e, e->type, file); + // irDebugInfo *type_di = ir_add_debug_info_type(proc->module, di, e, e->type, file); + irDebugInfo *type_di = ir_add_debug_info_type(proc->module, e->type, nullptr, nullptr, nullptr); GB_ASSERT_NOT_NULL(type_di); array_add(&di->Proc.types->DebugInfoArray.elements, type_di); } @@ -2152,7 +2190,8 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na continue; // TODO(lachsinc): Confirm correct? } // TODO(lachsinc): Could technically be a local? - irDebugInfo *type_di = ir_add_debug_info_type(proc->module, di, e, e->type, file); + // irDebugInfo *type_di = ir_add_debug_info_type(proc->module, di, e, e->type, file); + irDebugInfo *type_di = ir_add_debug_info_type(proc->module, e->type, nullptr, nullptr, nullptr); GB_ASSERT_NOT_NULL(type_di); array_add(&di->Proc.types->DebugInfoArray.elements, type_di); } @@ -8129,7 +8168,10 @@ void ir_build_proc(irValue *value, irProcedure *parent) { proc->is_foreign = e->Procedure.is_foreign; irDebugInfo *di_file = ir_add_debug_info_file(m, f); - ir_add_debug_info_proc(proc, e, proc->name, di_file); + // TODO(lachsinc): Procs can be built within other procs correct ?? We should pass + // a proper scope, or determine the scope inside of ir_add_debug_info_proc via + // above method (passing in nullptr as args) + ir_add_debug_info_proc(proc, e, proc->name, di_file, di_file); } if (proc->body != nullptr) { @@ -8214,7 +8256,7 @@ void ir_module_add_value(irModule *m, Entity *e, irValue *v) { 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); + ir_add_debug_info_global(m, v, di_file); } } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index cad0d3d3e..3499ce410 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2058,32 +2058,30 @@ void print_llvm_ir(irGen *ir) { ir_write_byte(f, ')'); break; case irDebugInfo_DerivedType: - ir_fprintf(f, "!DIDerivedType(" - "name: \"%.*s\"" - ", size: %d" - ", tag: ", - LIT(di->DerivedType.name), - di->DerivedType.size, - di->DerivedType.align); + ir_write_str_lit(f, "!DIDerivedType(tag: "); ir_print_debug_encoding(f, irDebugInfo_DerivedType, di->DerivedType.tag); + if (di->DerivedType.name.len > 0) { + ir_fprintf(f, ", name: \"%.*s\"", LIT(di->DerivedType.name)); + } if (di->DerivedType.base_type != nullptr) { ir_fprintf(f, ", baseType: !%d", di->DerivedType.base_type->id); } else { ir_write_str_lit(f, ", baseType: null"); // Valid/required for rawptr } + if (di->DerivedType.size > 0) { + ir_fprintf(f, ", size: %d", di->DerivedType.size); + } if (di->DerivedType.align > 0) { - ir_fprintf(f, ", align: %d", - di->DerivedType.align); + ir_fprintf(f, ", align: %d", di->DerivedType.align); } if (di->DerivedType.offset > 0) { - ir_fprintf(f, ", offset: %d", - di->DerivedType.offset); + ir_fprintf(f, ", offset: %d", di->DerivedType.offset); } ir_write_byte(f, ')'); break; case irDebugInfo_CompositeType: { if (di->CompositeType.tag == irDebugBasicEncoding_array_type) { - GB_ASSERT(di->CompositeType.base_type); + GB_ASSERT_NOT_NULL(di->CompositeType.base_type); ir_fprintf(f, "!DICompositeType(" "tag: DW_TAG_array_type" ", size: %d" @@ -2106,10 +2104,11 @@ void print_llvm_ir(irGen *ir) { di->CompositeType.align); ir_print_debug_encoding(f, irDebugInfo_CompositeType, di->CompositeType.tag); if (di->CompositeType.scope != nullptr) { - ir_fprintf(f, ", scope: !%d" - ", file: !%d" + ir_fprintf(f, ", scope: !%d", di->CompositeType.scope->id); + } + if (di->CompositeType.file != nullptr) { + ir_fprintf(f, ", file: !%d" ", line: %td", - di->CompositeType.scope->id, di->CompositeType.file->id, di->CompositeType.pos.line); } From 9750b1162a712402cce815ab2031789e543089b1 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Thu, 27 Sep 2018 01:34:15 +1000 Subject: [PATCH 17/39] Cleanup. --- src/ir.cpp | 203 +++++++++++++++++++++++++---------------------------- 1 file changed, 96 insertions(+), 107 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 5e196d64b..b6a2c7575 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1636,8 +1636,28 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { return irDebugBasicEncoding_Invalid; } +irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Type *type, i32 offset, irDebugInfo *scope) { + // NOTE(lachsinc): Caller is expected to insert the returned value into map themselves. + // "scope", if set, should be inserted into map prior to calling to ensure no cyclical dependencies. + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); + di->DerivedType.name = name; + di->DerivedType.tag = irDebugBasicEncoding_member; + di->DerivedType.size = 8*cast(i32)type_size_of(type); + di->DerivedType.offset = offset; + di->DerivedType.scope = scope; + + // NOTE(lachsinc): It is "safe" to overwrite this base_type after a call to this function, + // if you need to set a specific type for this field. + di->DerivedType.base_type = ir_add_debug_info_type(module, type, nullptr, nullptr, nullptr); + GB_ASSERT_NOT_NULL(di->DerivedType.base_type); + return di; +} + // TODO(lachsinc): Cleanup params. irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entity *e, Type *struct_type, i32 index, Type *type, irDebugInfo *file) { + GB_ASSERT_NOT_NULL(e); + Type *named = type; type = base_type(type); GB_ASSERT(type->kind != Type_Named); @@ -1647,25 +1667,20 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit return *existing; } - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); - di->DerivedType.name = e ? e->token.string : str_lit("todo_member_type"); - di->DerivedType.tag = irDebugBasicEncoding_member; - if (e) { - di->DerivedType.scope = scope; // TODO(lachsinc): Ensure this scope is == relevent struct_type debug info ??? - di->DerivedType.file = file; - // di->DerivedType.pos = ; // TODO(lachsinc): - } - di->DerivedType.size = 8*cast(i32)type_size_of(type); - di->DerivedType.align = 8*cast(i32)type_align_of(type); + i32 offset = 0; if (struct_type && struct_type->Struct.are_offsets_set) { - di->DerivedType.offset = 8*cast(i32)struct_type->Struct.offsets[index]; + offset = 8*cast(i32)struct_type->Struct.offsets[index]; } else { - di->DerivedType.offset = 8*cast(i32)type_offset_of(type, index); // TODO(lachsinc): Confirm correct + offset = 8*cast(i32)type_offset_of(type, index); // TODO(lachsinc): Confirm correct } - di->DerivedType.base_type = ir_add_debug_info_type(module, type, e, scope, file); - GB_ASSERT_NOT_NULL(di->DerivedType.base_type); - map_set(&module->debug_info, hash_entity(e), di); // TODO(lachsinc): Member type hashing to ensure unique?? + irDebugInfo *di = ir_add_debug_info_field_internal(module, e->token.string, type, offset, scope); + map_set(&module->debug_info, hash_entity(e), di); + // di->DerivedType.align = 8*cast(i32)type_align_of(type); + di->DerivedType.file = file; + di->DerivedType.pos = e->token.pos; + // di->DerivedType.base_type = ir_add_debug_info_type(module, type, e, scope, file); + return di; } @@ -1687,19 +1702,7 @@ irDebugInfo *ir_add_debug_info_enumerator(irModule *module, Entity *e) { } // TODO(lachsinc): Cleanup params. -irDebugInfo *ir_add_debug_info_field_custom(irModule *module, irDebugInfo *scope, Entity *e, String name, Type *type, i32 offset, irDebugInfo *file) { - // TODO(lachsinc): Merge with above normal field stuff. - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); - di->DerivedType.name = name; - di->DerivedType.tag = irDebugBasicEncoding_member; - di->DerivedType.size = 8*cast(i32)type_size_of(type); - di->DerivedType.offset = offset; - di->DerivedType.base_type = ir_add_debug_info_type(module, type, e, scope, file); - return di; -} - -// TODO(lachsinc): Cleanup params. -irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { +irDebugInfo *ir_add_debug_info_type_dynamic_array(irModule *module, Type *type, Entity *e, irDebugInfo *scope, irDebugInfo *file) { // TODO(lachsinc): HACK named should be handled as derived types, see above. Type *named = nullptr; if (is_type_named(type)) { @@ -1721,69 +1724,57 @@ irDebugInfo *ir_add_debug_info_dynamic_array(irModule *module, irDebugInfo *scop 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); + map_set(&module->debug_info, hash_type(named ? named : type), di); // Data pointer type irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); data_ptr_di->DerivedType.name = str_lit("ptr_type_name_todo"); data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, type->DynamicArray.elem, e, scope, file); - // Field "data" - irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - data_di->DerivedType.name = str_lit("data"); - data_di->DerivedType.tag = irDebugBasicEncoding_member; - data_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - data_di->DerivedType.offset = 0; + irDebugInfo *data_di = ir_add_debug_info_field_internal(module, str_lit("data"), t_rawptr, + 0, + di); data_di->DerivedType.base_type = data_ptr_di; + map_set(&module->debug_info, hash_pointer(data_di), data_di); - // TODO(lachsinc): The following member types could theoretically be shared by all dynamic array di's, - // we could store each inside module, creating them if we haven't already. + irDebugInfo *len_di = ir_add_debug_info_field_internal(module, str_lit("len"), t_int, + data_di->DerivedType.size, + di); + map_set(&module->debug_info, hash_pointer(len_di), len_di); - // Field "len" - irDebugInfo *len_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("len"), t_int, - data_di->DerivedType.size, - file); - - // Field "cap" - irDebugInfo *cap_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("cap"), t_int, - data_di->DerivedType.size + - len_di->DerivedType.size, - file); - - // Field "allocator" - irDebugInfo *alloc_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("allocator"), t_allocator, + irDebugInfo *cap_di = ir_add_debug_info_field_internal(module, str_lit("cap"), t_int, data_di->DerivedType.size + - len_di->DerivedType.size + - cap_di->DerivedType.size, - file); + len_di->DerivedType.size, + di); + map_set(&module->debug_info, hash_pointer(cap_di), cap_di); + + irDebugInfo *alloc_di = ir_add_debug_info_field_internal(module, str_lit("allocator"), t_allocator, + data_di->DerivedType.size + + len_di->DerivedType.size + + cap_di->DerivedType.size, + di); + map_set(&module->debug_info, hash_pointer(alloc_di), alloc_di); irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 4); array_add(&elements_di->DebugInfoArray.elements, data_di); array_add(&elements_di->DebugInfoArray.elements, len_di); array_add(&elements_di->DebugInfoArray.elements, cap_di); array_add(&elements_di->DebugInfoArray.elements, alloc_di); - di->CompositeType.elements = elements_di; - - map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); - map_set(&module->debug_info, hash_pointer(data_di), data_di); - map_set(&module->debug_info, hash_pointer(len_di), len_di); - map_set(&module->debug_info, hash_pointer(cap_di), cap_di); - map_set(&module->debug_info, hash_pointer(alloc_di), alloc_di); map_set(&module->debug_info, hash_pointer(elements_di), elements_di); - map_set(&module->debug_info, hash_type(named ? named : type), di); return di; } // TODO(lachsinc): Cleanup params. -irDebugInfo *ir_add_debug_info_string(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { +irDebugInfo *ir_add_debug_info_type_string(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { GB_ASSERT(type->kind == Type_Basic); GB_ASSERT(type->Basic.kind == Basic_string); - // Get or create string composite type (hashed via t_string ptr) - // alternatively we could just store a pointer to it inside irModule. + // TODO(lachsinc): Does this only occur once ?? irDebugInfo **existing = map_get(&module->debug_info, hash_type(t_string)); if (existing != nullptr) { GB_ASSERT((*existing)->kind == irDebugInfo_CompositeType); @@ -1795,27 +1786,31 @@ irDebugInfo *ir_add_debug_info_string(irModule *module, irDebugInfo *scope, Enti di->CompositeType.size = 8*cast(i32)type_size_of(t_string); di->CompositeType.align = 8*cast(i32)type_align_of(t_string); + map_set(&module->debug_info, hash_type(type), di); + // Field "data" - irDebugInfo *data_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("data"), t_cstring, 0, file); + irDebugInfo *data_di = ir_add_debug_info_field_internal(module, str_lit("data"), t_cstring, + 0, + di); + map_set(&module->debug_info, hash_pointer(data_di), data_di); // Field "len" - irDebugInfo *len_di = ir_add_debug_info_field_custom(module, scope, e, str_lit("len"), t_i64, data_di->DerivedType.size, file); + irDebugInfo *len_di = ir_add_debug_info_field_internal(module, str_lit("len"), t_i64, + data_di->DerivedType.size, + di); + map_set(&module->debug_info, hash_pointer(len_di), len_di); irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 2); array_add(&elements_di->DebugInfoArray.elements, data_di); array_add(&elements_di->DebugInfoArray.elements, len_di); di->CompositeType.elements = elements_di; - - map_set(&module->debug_info, hash_pointer(data_di), data_di); - map_set(&module->debug_info, hash_pointer(len_di), len_di); map_set(&module->debug_info, hash_pointer(elements_di), elements_di); - map_set(&module->debug_info, hash_type(type), di); return di; } } -irDebugInfo *ir_add_debug_info_any(irModule *module) { +irDebugInfo *ir_add_debug_info_type_any(irModule *module) { irDebugInfo **existing = map_get(&module->debug_info, hash_type(t_any)); if (existing != nullptr) { GB_ASSERT((*existing)->kind == irDebugInfo_CompositeType); @@ -1827,21 +1822,25 @@ irDebugInfo *ir_add_debug_info_any(irModule *module) { di->CompositeType.size = 8*cast(i32)type_size_of(t_any); // TODO(lachsinc): Correct ?? di->CompositeType.align = 8*cast(i32)type_align_of(t_any); - // Field "data" - irDebugInfo *data_di = ir_add_debug_info_field_custom(module, nullptr, nullptr, str_lit("data"), t_rawptr, 0, nullptr); + map_set(&module->debug_info, hash_type(t_any), di); - // Field "len" - irDebugInfo *len_di = ir_add_debug_info_field_custom(module, nullptr, nullptr, str_lit("id"), t_typeid, data_di->DerivedType.size, nullptr); + // Field "data" + irDebugInfo *data_di = ir_add_debug_info_field_internal(module, str_lit("data"), t_rawptr, + 0, + di); + map_set(&module->debug_info, hash_pointer(data_di), data_di); + + // Field "id" + irDebugInfo *id_di = ir_add_debug_info_field_internal(module, str_lit("id"), t_typeid, + data_di->DerivedType.size, + di); + map_set(&module->debug_info, hash_pointer(id_di), id_di); irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 2); array_add(&elements_di->DebugInfoArray.elements, data_di); - array_add(&elements_di->DebugInfoArray.elements, len_di); + array_add(&elements_di->DebugInfoArray.elements, id_di); di->CompositeType.elements = elements_di; - - map_set(&module->debug_info, hash_pointer(data_di), data_di); - map_set(&module->debug_info, hash_pointer(len_di), len_di); map_set(&module->debug_info, hash_pointer(elements_di), elements_di); - map_set(&module->debug_info, hash_type(t_any), di); return di; } @@ -1883,22 +1882,15 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD di->DerivedType.name = named_base->Basic.name; } di->DerivedType.tag = irDebugBasicEncoding_typedef; + map_set(&module->debug_info, hash_type(type), di); // TODO(lachsinc): Do we need to try and resolve a new entity/scope for the base type? // Maybe we also want to pull out type->Named.type_name ?? in the case it is a Named di->DerivedType.base_type = ir_add_debug_info_type(module, named_base, e, scope, file); - map_set(&module->debug_info, hash_type(type), di); return di; } } if (type->kind == Type_Basic) { - // TODO(lachsinc): TEMP - if (!(type->Basic.kind == Basic_cstring || type->Basic.kind == Basic_rawptr)) { - if ((type->Basic.flags & BasicFlag_Pointer) != 0) { - GB_ASSERT(false); - } - } - switch (type->Basic.kind) { // Composite basic types case Basic_complex64: @@ -1906,8 +1898,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD // TODO(lachsinc): break; } - case Basic_string: return ir_add_debug_info_string(module, scope, e, type, file); - case Basic_any: return ir_add_debug_info_any(module); + case Basic_string: return ir_add_debug_info_type_string(module, scope, e, type, file); + case Basic_any: return ir_add_debug_info_type_any(module); // Derived basic types case Basic_cstring: @@ -1917,11 +1909,11 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD di->DerivedType.tag = irDebugBasicEncoding_pointer_type; di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); // TODO(lachsinc): Not sure if align is required. + map_set(&module->debug_info, hash_type(type), di); // NOTE(lachsinc): llvm expects "null" for rawptr/voidptr if (type->Basic.kind == Basic_cstring) { di->DerivedType.base_type = ir_add_debug_info_type(module, t_i8, e, scope, file); } - map_set(&module->debug_info, hash_type(type), di); return di; } @@ -1953,7 +1945,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD return di; } - if (is_type_struct(type) || is_type_union(type) || is_type_enum(type)) { + if (is_type_struct(type) || is_type_enum(type)) { // || is_type_union(type) TODO(lachsinc): irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); if (e) { di->CompositeType.file = file; @@ -2005,7 +1997,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD } if (is_type_dynamic_array(type)) { - return ir_add_debug_info_dynamic_array(module, scope, e, type, file); + return ir_add_debug_info_type_dynamic_array(module, type, e, scope, file); } if (is_type_array(type)) { @@ -2013,12 +2005,12 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD di->CompositeType.size = 8*cast(i32)type_size_of(type); // TODO(lachsinc): Confirm correct array sizing. llvm expects size in bits! di->CompositeType.align = 8*cast(i32)type_align_of(type); - di->CompositeType.base_type = ir_add_debug_info_type(module, type->Array.elem, e, scope, file); di->CompositeType.tag = irDebugBasicEncoding_array_type; di->CompositeType.array_count = (i32)type->Array.count; - GB_ASSERT(base->kind != Type_Named); map_set(&module->debug_info, hash_type(type), di); + di->CompositeType.base_type = ir_add_debug_info_type(module, type->Array.elem, e, scope, file); + GB_ASSERT(base->kind != Type_Named); return di; } @@ -2031,6 +2023,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD di->CompositeType.tag = irDebugBasicEncoding_structure_type; di->CompositeType.size = 8*cast(i32)type_size_of(type); // TODO(lachsinc): Correct ?? di->CompositeType.align = 8*cast(i32)type_align_of(type); + map_set(&module->debug_info, hash_type(type), di); // Data pointer type irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); @@ -2043,29 +2036,25 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD } data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, type->Slice.elem, e, scope, file); - // Field "data" - irDebugInfo *data_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - data_di->DerivedType.name = str_lit("data"); - data_di->DerivedType.tag = irDebugBasicEncoding_member; - data_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - data_di->DerivedType.offset = 0; + irDebugInfo *data_di = ir_add_debug_info_field_internal(module, str_lit("data"), t_rawptr, + 0, + di); data_di->DerivedType.base_type = data_ptr_di; + map_set(&module->debug_info, hash_pointer(data_di), data_di); - // Field "len" - irDebugInfo *len_di = ir_add_debug_info_field_custom(module, nullptr, nullptr, str_lit("len"), t_int, data_di->DerivedType.size, nullptr); + irDebugInfo *len_di = ir_add_debug_info_field_internal(module, str_lit("len"), t_int, + data_di->DerivedType.size, + di); + map_set(&module->debug_info, hash_pointer(len_di), len_di); irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 2); array_add(&elements_di->DebugInfoArray.elements, data_di); array_add(&elements_di->DebugInfoArray.elements, len_di); di->CompositeType.elements = elements_di; - - map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); - map_set(&module->debug_info, hash_pointer(data_di), data_di); - map_set(&module->debug_info, hash_pointer(len_di), len_di); map_set(&module->debug_info, hash_pointer(elements_di), elements_di); - map_set(&module->debug_info, hash_type(type), di); return di; } From 0818a272e27c75132e2bdf9215bae6355d28a053 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Thu, 27 Sep 2018 17:55:37 +1000 Subject: [PATCH 18/39] Cleanup hardcoded bytes to bits --- src/ir.cpp | 88 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index b6a2c7575..633ee65db 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1636,6 +1636,18 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { return irDebugBasicEncoding_Invalid; } +i32 ir_debug_info_bits(i64 size) { + return 8*cast(i32)size; +} + +i32 ir_debug_size_bits(Type *type) { + return ir_debug_info_bits(type_size_of(type)); +} + +i32 ir_debug_align_bits(Type *type) { + return ir_debug_info_bits(type_align_of(type)); +} + irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Type *type, i32 offset, irDebugInfo *scope) { // NOTE(lachsinc): Caller is expected to insert the returned value into map themselves. // "scope", if set, should be inserted into map prior to calling to ensure no cyclical dependencies. @@ -1643,7 +1655,7 @@ irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Typ irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); di->DerivedType.name = name; di->DerivedType.tag = irDebugBasicEncoding_member; - di->DerivedType.size = 8*cast(i32)type_size_of(type); + di->DerivedType.size = ir_debug_size_bits(type); di->DerivedType.offset = offset; di->DerivedType.scope = scope; @@ -1669,14 +1681,14 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit i32 offset = 0; if (struct_type && struct_type->Struct.are_offsets_set) { - offset = 8*cast(i32)struct_type->Struct.offsets[index]; + offset = ir_debug_info_bits(struct_type->Struct.offsets[index]); } else { - offset = 8*cast(i32)type_offset_of(type, index); // TODO(lachsinc): Confirm correct + offset = ir_debug_info_bits(type_offset_of(type, index)); } irDebugInfo *di = ir_add_debug_info_field_internal(module, e->token.string, type, offset, scope); map_set(&module->debug_info, hash_entity(e), di); - // di->DerivedType.align = 8*cast(i32)type_align_of(type); + // di->DerivedType.align = ir_debug_align_bits(type); di->DerivedType.file = file; di->DerivedType.pos = e->token.pos; // di->DerivedType.base_type = ir_add_debug_info_type(module, type, e, scope, file); @@ -1703,34 +1715,26 @@ irDebugInfo *ir_add_debug_info_enumerator(irModule *module, Entity *e) { // TODO(lachsinc): Cleanup params. irDebugInfo *ir_add_debug_info_type_dynamic_array(irModule *module, Type *type, Entity *e, irDebugInfo *scope, irDebugInfo *file) { - // TODO(lachsinc): HACK named should be handled as derived types, see above. - Type *named = nullptr; - if (is_type_named(type)) { - named = type; - type = base_type(type); - } GB_ASSERT(type->kind == Type_DynamicArray); // TODO(lachsinc): We should insert "type" into map and look it up, and just create a derived type // for each required dynamic array, named or unnamed. - // TODO(lachsinc): Look up in map if dynamic array for type already exists ?? - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); - di->CompositeType.name = named ? named->Named.name : str_lit("dynamic array"); + di->CompositeType.name = str_lit("dynamic array"); // TODO(lachsinc): [dynamic] .. type->DynamicArray.elem name di->CompositeType.tag = irDebugBasicEncoding_structure_type; - 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?? - di->CompositeType.align = 8*cast(i32)type_align_of(t_rawptr); - map_set(&module->debug_info, hash_type(named ? named : type), di); + di->CompositeType.size = ir_debug_size_bits(t_rawptr) + + ir_debug_size_bits(t_int) + + ir_debug_size_bits(t_int) + + ir_debug_size_bits(t_allocator); + di->CompositeType.align = ir_debug_align_bits(t_rawptr); + map_set(&module->debug_info, hash_type(type), di); // Data pointer type irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - data_ptr_di->DerivedType.name = str_lit("ptr_type_name_todo"); + // data_ptr_di->DerivedType.name = str_lit("ptr_type_name_todo"); data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; - data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + data_ptr_di->DerivedType.size = ir_debug_size_bits(t_rawptr); map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, type->DynamicArray.elem, e, scope, file); @@ -1771,9 +1775,6 @@ irDebugInfo *ir_add_debug_info_type_dynamic_array(irModule *module, Type *type, // TODO(lachsinc): Cleanup params. irDebugInfo *ir_add_debug_info_type_string(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { - GB_ASSERT(type->kind == Type_Basic); - GB_ASSERT(type->Basic.kind == Basic_string); - // TODO(lachsinc): Does this only occur once ?? irDebugInfo **existing = map_get(&module->debug_info, hash_type(t_string)); if (existing != nullptr) { @@ -1783,8 +1784,8 @@ irDebugInfo *ir_add_debug_info_type_string(irModule *module, irDebugInfo *scope, irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); di->CompositeType.name = type->Basic.name; di->CompositeType.tag = irDebugBasicEncoding_structure_type; - di->CompositeType.size = 8*cast(i32)type_size_of(t_string); - di->CompositeType.align = 8*cast(i32)type_align_of(t_string); + di->CompositeType.size = ir_debug_size_bits(t_string); + di->CompositeType.align = ir_debug_align_bits(t_string); map_set(&module->debug_info, hash_type(type), di); @@ -1819,8 +1820,8 @@ irDebugInfo *ir_add_debug_info_type_any(irModule *module) { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); di->CompositeType.name = t_any->Basic.name; di->CompositeType.tag = irDebugBasicEncoding_structure_type; - di->CompositeType.size = 8*cast(i32)type_size_of(t_any); // TODO(lachsinc): Correct ?? - di->CompositeType.align = 8*cast(i32)type_align_of(t_any); + di->CompositeType.size = ir_debug_size_bits(t_any); // TODO(lachsinc): Correct ?? + di->CompositeType.align = ir_debug_align_bits(t_any); map_set(&module->debug_info, hash_type(t_any), di); @@ -1873,7 +1874,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD if (type->kind == Type_Named) { Type *named_base = type->Named.base; - if (named_base->kind == Type_Named || named_base->kind == Type_Basic) { + // TODO(lachsinc): Better way to determine distinct etc. or just handle structs, enums before we reach here. + if (named_base->kind != Type_Struct && named_base->kind != Type_Enum) { // distinct / typedef etc. irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); if (type->kind == Type_Named) { @@ -1907,8 +1909,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); di->DerivedType.name = type->Basic.name; di->DerivedType.tag = irDebugBasicEncoding_pointer_type; - di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); - di->DerivedType.align = 8*cast(i32)type_align_of(t_rawptr); // TODO(lachsinc): Not sure if align is required. + di->DerivedType.size = ir_debug_size_bits(t_rawptr); + di->DerivedType.align = ir_debug_align_bits(t_rawptr); // TODO(lachsinc): Not sure if align is required. map_set(&module->debug_info, hash_type(type), di); // NOTE(lachsinc): llvm expects "null" for rawptr/voidptr if (type->Basic.kind == Basic_cstring) { @@ -1922,8 +1924,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); di->BasicType.encoding = ir_debug_encoding_for_basic(type->Basic.kind); di->BasicType.name = type->Basic.name; - di->BasicType.size = 8*cast(i32)type_size_of(type); - di->BasicType.align = 8*cast(i32)type_align_of(type); + di->BasicType.size = ir_debug_size_bits(type); + di->BasicType.align = ir_debug_align_bits(type); map_set(&module->debug_info, hash_type(type), di); return di; } @@ -1935,7 +1937,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD Type *deref = type_deref(base); irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); di->DerivedType.tag = irDebugBasicEncoding_pointer_type; - di->DerivedType.size = 8*cast(i32)type_size_of(type); + di->DerivedType.size = ir_debug_size_bits(type); // NOTE(lachsinc): Set in map before creative base_type to avoid circular dependency issues. map_set(&module->debug_info, hash_type(type), di); if (is_type_struct(deref)) { @@ -1952,8 +1954,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD di->CompositeType.scope = scope; di->CompositeType.pos = e->token.pos; } - di->CompositeType.size = 8*cast(i32)type_size_of(type); - di->CompositeType.align = 8*cast(i32)type_align_of(type); + di->CompositeType.size = ir_debug_size_bits(type); + di->CompositeType.align = ir_debug_align_bits(type); di->CompositeType.base_type = nullptr; // NOTE(lachsinc): Set map value before resolving field types to avoid circular dependencies. @@ -2003,8 +2005,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD if (is_type_array(type)) { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); - di->CompositeType.size = 8*cast(i32)type_size_of(type); // TODO(lachsinc): Confirm correct array sizing. llvm expects size in bits! - di->CompositeType.align = 8*cast(i32)type_align_of(type); + di->CompositeType.size = ir_debug_size_bits(type); // TODO(lachsinc): Confirm correct array sizing. llvm expects size in bits! + di->CompositeType.align = ir_debug_align_bits(type); di->CompositeType.tag = irDebugBasicEncoding_array_type; di->CompositeType.array_count = (i32)type->Array.count; @@ -2021,8 +2023,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); di->CompositeType.name = str_lit("slice"); di->CompositeType.tag = irDebugBasicEncoding_structure_type; - di->CompositeType.size = 8*cast(i32)type_size_of(type); // TODO(lachsinc): Correct ?? - di->CompositeType.align = 8*cast(i32)type_align_of(type); + di->CompositeType.size = ir_debug_size_bits(type); // TODO(lachsinc): Correct ?? + di->CompositeType.align = ir_debug_align_bits(type); map_set(&module->debug_info, hash_type(type), di); // Data pointer type @@ -2035,7 +2037,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD data_ptr_di->DerivedType.name = str_lit("slice_ptr_type_todo"); } data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; - data_ptr_di->DerivedType.size = 8*cast(i32)type_size_of(t_rawptr); + data_ptr_di->DerivedType.size = ir_debug_size_bits(t_rawptr); map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, type->Slice.elem, e, scope, file); @@ -2068,10 +2070,10 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD // { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); - di->BasicType.align = 8*cast(i32)type_align_of(type); + di->BasicType.align = ir_debug_align_bits(type); di->BasicType.encoding = irDebugBasicEncoding_address; di->BasicType.name = str_lit("type_todo"); - di->BasicType.size = 8*cast(i32)type_size_of(type); + di->BasicType.size = ir_debug_size_bits(type); map_set(&module->debug_info, hash_type(type), di); From 11bddf270c9f96c01768fe3e0d6c64c372300dd0 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Thu, 27 Sep 2018 18:34:59 +1000 Subject: [PATCH 19/39] Cleanup debug info 'name' stuff. --- src/ir.cpp | 36 +++++++++++++------------- src/ir_print.cpp | 67 ++++++++++++++++++++++++------------------------ 2 files changed, 51 insertions(+), 52 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 633ee65db..7f494d363 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1648,7 +1648,7 @@ i32 ir_debug_align_bits(Type *type) { return ir_debug_info_bits(type_align_of(type)); } -irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Type *type, i32 offset, irDebugInfo *scope) { +irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Type *type, i32 offset_bits, irDebugInfo *scope) { // NOTE(lachsinc): Caller is expected to insert the returned value into map themselves. // "scope", if set, should be inserted into map prior to calling to ensure no cyclical dependencies. @@ -1656,7 +1656,7 @@ irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Typ di->DerivedType.name = name; di->DerivedType.tag = irDebugBasicEncoding_member; di->DerivedType.size = ir_debug_size_bits(type); - di->DerivedType.offset = offset; + di->DerivedType.offset = offset_bits; di->DerivedType.scope = scope; // NOTE(lachsinc): It is "safe" to overwrite this base_type after a call to this function, @@ -1731,8 +1731,8 @@ irDebugInfo *ir_add_debug_info_type_dynamic_array(irModule *module, Type *type, map_set(&module->debug_info, hash_type(type), di); // Data pointer type + // TODO(lachsinc): Perhaps lookup/alloc-a-fake Type_Pointer type and go via ir_add_debug_info_type() with it. irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - // data_ptr_di->DerivedType.name = str_lit("ptr_type_name_todo"); data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; data_ptr_di->DerivedType.size = ir_debug_size_bits(t_rawptr); map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); @@ -1857,8 +1857,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD return *existing; } - // Reset entity info if applicable for every type we try add. - // TODO(lachsinc): Confirm this doesn't mess up struct field scope's. + // Reset entity/location info, if applicable, for every type we try add. + // TODO(lachsinc): Confirm this doesn't mess up field's scopes etc. if (type->kind == Type_Named) { e = type->Named.type_name; if (e) { @@ -1962,10 +1962,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD map_set(&module->debug_info, hash_type(type), di); if (is_type_struct(type)) { - if (type->kind == Type_Named) { - di->CompositeType.name = type->Named.name; - } else { - di->CompositeType.name = str_lit("struct_name_todo"); + if (is_type_named(type)) { + di->CompositeType.name = type->kind == Type_Named ? type->Named.name : type->Basic.name; } di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Struct.fields.count); for_array(field_index, base->Struct.fields) { @@ -1980,8 +1978,9 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD // TODO(lachsinc): Add elements for union di->CompositeType.tag = irDebugBasicEncoding_union_type; } else if (is_type_enum(type)) { - GB_ASSERT(type->kind == Type_Named); - di->CompositeType.name = type->Named.name; + if (type->kind == Type_Named) { + di->CompositeType.name = type->Named.name; + } di->CompositeType.base_type = ir_add_debug_info_type(module, type->Named.base->Enum.base_type, e, scope, file); di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Enum.fields.count); for_array(field_index, base->Enum.fields) { @@ -2029,17 +2028,14 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD // Data pointer type irDebugInfo *data_ptr_di = ir_alloc_debug_info(irDebugInfo_DerivedType); - if (type->Slice.elem->kind == Type_Named) { - data_ptr_di->DerivedType.name = type->Slice.elem->Named.name; // TODO(lachsinc): Ptr?? - } else if (type->Slice.elem->kind == Type_Basic) { - data_ptr_di->DerivedType.name = type->Slice.elem->Basic.name; // TODO(lachsinc): Ptr?? - } else { - data_ptr_di->DerivedType.name = str_lit("slice_ptr_type_todo"); + Type *elem_type = type->Slice.elem; + if (is_type_named(elem_type)) { + data_ptr_di->DerivedType.name = elem_type->kind == Type_Named ? elem_type->Named.name : elem_type->Basic.name; } data_ptr_di->DerivedType.tag = irDebugBasicEncoding_pointer_type; data_ptr_di->DerivedType.size = ir_debug_size_bits(t_rawptr); map_set(&module->debug_info, hash_pointer(data_ptr_di), data_ptr_di); - data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, type->Slice.elem, e, scope, file); + data_ptr_di->DerivedType.base_type = ir_add_debug_info_type(module, elem_type, e, scope, file); irDebugInfo *data_di = ir_add_debug_info_field_internal(module, str_lit("data"), t_rawptr, 0, @@ -2062,6 +2058,10 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD } if (is_type_map(type)) { + // TODO(lachsinc): Looks like "generated_struct_type" map.entries.data is just a u8*, we could + // always look at the map header and create the debug info manually (if we + // want struct members to be interpreted as the correct type). + // Also; are hashes meant to be interpreted as bool*'s ?? return ir_add_debug_info_type(module, type->Map.generated_struct_type, e, scope, file); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 3499ce410..c5d3eff2f 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2082,45 +2082,44 @@ void print_llvm_ir(irGen *ir) { case irDebugInfo_CompositeType: { if (di->CompositeType.tag == irDebugBasicEncoding_array_type) { GB_ASSERT_NOT_NULL(di->CompositeType.base_type); - ir_fprintf(f, "!DICompositeType(" - "tag: DW_TAG_array_type" - ", size: %d" - ", align: %d" - ", baseType: !%d" - ", elements: !{!DISubrange(count: %d)}" - ")", - di->CompositeType.size, - di->CompositeType.align, - di->CompositeType.base_type->id, - di->CompositeType.array_count); + GB_ASSERT(di->CompositeType.array_count > 0); + GB_ASSERT(di->CompositeType.name.len == 0); + GB_ASSERT(di->CompositeType.size > 0); + } + + ir_write_str_lit(f, "!DICompositeType(tag: "); + ir_print_debug_encoding(f, irDebugInfo_CompositeType, di->CompositeType.tag); + if (di->CompositeType.name.len > 0) { + ir_fprintf(f, ", name: \"%.*s\"", LIT(di->CompositeType.name)); + } + if (di->CompositeType.scope != nullptr) { + ir_fprintf(f, ", scope: !%d", di->CompositeType.scope->id); + } + if (di->CompositeType.file != nullptr) { + ir_fprintf(f, ", file: !%d" + ", line: %td", + di->CompositeType.file->id, + di->CompositeType.pos.line); + } + if (di->CompositeType.size > 0) { + ir_fprintf(f, ", size: %d", di->CompositeType.size); + } + if (di->CompositeType.align > 0) { + ir_fprintf(f, ", align: %d", di->CompositeType.align); + } + if (di->CompositeType.base_type != nullptr) { + GB_ASSERT(di->CompositeType.tag != irDebugBasicEncoding_structure_type); + GB_ASSERT(di->CompositeType.tag != irDebugBasicEncoding_union_type); + ir_fprintf(f, ", baseType: !%d", di->CompositeType.base_type->id); + } + if (di->CompositeType.tag == irDebugBasicEncoding_array_type) { + ir_fprintf(f, ", elements: !{!DISubrange(count: %d)}", di->CompositeType.array_count); } else { - ir_fprintf(f, "!DICompositeType(" - "name: \"%.*s\"" - ", size: %d" - ", align: %d" - ", tag: ", - LIT(di->CompositeType.name), - di->CompositeType.size, - di->CompositeType.align); - ir_print_debug_encoding(f, irDebugInfo_CompositeType, di->CompositeType.tag); - if (di->CompositeType.scope != nullptr) { - ir_fprintf(f, ", scope: !%d", di->CompositeType.scope->id); - } - if (di->CompositeType.file != nullptr) { - ir_fprintf(f, ", file: !%d" - ", line: %td", - di->CompositeType.file->id, - di->CompositeType.pos.line); - } - if (di->CompositeType.base_type != nullptr) { - GB_ASSERT(di->CompositeType.tag == irDebugBasicEncoding_enumeration_type); - ir_fprintf(f, ", baseType: !%d", di->CompositeType.base_type->id); - } if (di->CompositeType.elements != nullptr) { ir_fprintf(f, ", elements: !%d", di->CompositeType.elements->id); } - ir_write_byte(f, ')'); } + ir_write_byte(f, ')'); break; } case irDebugInfo_Enumerator: { From 9e73189d636b7723302553f48dddf93cea8f073f Mon Sep 17 00:00:00 2001 From: lachsinc Date: Thu, 27 Sep 2018 21:50:57 +1000 Subject: [PATCH 20/39] Tagged union debug info. Aggregate type fixes (unions inside structs etc.). --- src/ir.cpp | 115 ++++++++++++++++++++++++++++++----------------- src/ir_print.cpp | 4 ++ 2 files changed, 79 insertions(+), 40 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 7f494d363..7219bead2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1666,32 +1666,53 @@ irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Typ return di; } -// TODO(lachsinc): Cleanup params. -irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entity *e, Type *struct_type, i32 index, Type *type, irDebugInfo *file) { - GB_ASSERT_NOT_NULL(e); - - Type *named = type; - type = base_type(type); - GB_ASSERT(type->kind != Type_Named); - - irDebugInfo **existing = map_get(&module->debug_info, hash_entity(e)); - if (existing != nullptr) { - return *existing; +// TODO(lachsinc): Cleanup params, either scope or scope_type, not both. +// Pass name, file, pos in manually? Would be much cleaner. +irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entity *e, Type *scope_type, i32 index, Type *type, irDebugInfo *file) { + // NOTE(lachsinc): This lookup will only work for struct fields!! + // TODO(lachsinc): Do we even need to do this? + if (e) { + irDebugInfo **existing = map_get(&module->debug_info, hash_entity(e)); + if (existing != nullptr) { + return *existing; + } } - i32 offset = 0; - if (struct_type && struct_type->Struct.are_offsets_set) { - offset = ir_debug_info_bits(struct_type->Struct.offsets[index]); - } else { - offset = ir_debug_info_bits(type_offset_of(type, index)); + // TODO(lachsinc): Cleanup + irDebugInfo *di = ir_add_debug_info_field_internal(module, make_string(nullptr, 0), type, 0, scope); + void *ptr_to_hash = nullptr; + if (scope_type) { + Type *scope_base = base_type(scope_type); + if (is_type_struct(scope_type)) { + if (scope_base->Struct.are_offsets_set) { + di->DerivedType.offset = ir_debug_info_bits(scope_base->Struct.offsets[index]); + } else { + di->DerivedType.offset = ir_debug_info_bits(type_offset_of(scope_base, index)); + } + if (e) { + ptr_to_hash = e; + di->DerivedType.name = e->token.string; + di->DerivedType.pos = e->token.pos; + } else { + GB_PANIC("Unreachable"); // struct field Entity's should be provided. + } + } else if (is_type_union(scope_base)) { + // TODO(lachsinc): Handle this in a more generic manner/pass in??... + // Token token = base_type(scope_base)->Union.node->UnionType.token; + // di->DerivedType.name = token.string; + // di->DerivedType.pos = token.pos; + if (is_type_named(type)) { + di->DerivedType.name = type->kind == Type_Named ? type->Named.name : type->Basic.name; + } + ptr_to_hash = di; // TODO(lachsinc): Correct ?? I don't think unions have individual entities for their fields?? idk. + } } - irDebugInfo *di = ir_add_debug_info_field_internal(module, e->token.string, type, offset, scope); - map_set(&module->debug_info, hash_entity(e), di); - // di->DerivedType.align = ir_debug_align_bits(type); di->DerivedType.file = file; - di->DerivedType.pos = e->token.pos; - // di->DerivedType.base_type = ir_add_debug_info_type(module, type, e, scope, file); + // di->DerivedType.align = ir_debug_align_bits(type); + + GB_ASSERT_NOT_NULL(ptr_to_hash); + map_set(&module->debug_info, hash_pointer(ptr_to_hash), di); return di; } @@ -1869,13 +1890,16 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD } } - // NOTE(lachsinc): Types are inserted into debug_info map as their named, not base_type()'d, counterpart. + // NOTE(lachsinc): Types should be inserted into debug_info map as their named, not base_type()'d, counterpart. Type *base = base_type(type); if (type->kind == Type_Named) { Type *named_base = type->Named.base; // TODO(lachsinc): Better way to determine distinct etc. or just handle structs, enums before we reach here. - if (named_base->kind != Type_Struct && named_base->kind != Type_Enum) { + // ir_is_type_aggregate() except with no call to base_type(). + if (named_base->kind != Type_Struct && + named_base->kind != Type_Union && + named_base->kind != Type_Enum) { // distinct / typedef etc. irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); if (type->kind == Type_Named) { @@ -1947,24 +1971,28 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD return di; } - if (is_type_struct(type) || is_type_enum(type)) { // || is_type_union(type) TODO(lachsinc): + if (is_type_struct(type) || is_type_union(type) || is_type_enum(type)) { + if (type->kind == Type_Named) { + // Named named's should be handled prior as typedefs. + GB_ASSERT(type->Named.base->kind != Type_Named); + } + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + // NOTE(lachsinc): Set map value before resolving field types to avoid circular dependencies. + map_set(&module->debug_info, hash_type(type), di); + if (is_type_named(type)) { + di->CompositeType.name = type->kind == Type_Named ? type->Named.name : type->Basic.name; + } if (e) { di->CompositeType.file = file; di->CompositeType.scope = scope; di->CompositeType.pos = e->token.pos; } di->CompositeType.size = ir_debug_size_bits(type); - di->CompositeType.align = ir_debug_align_bits(type); - di->CompositeType.base_type = nullptr; - - // NOTE(lachsinc): Set map value before resolving field types to avoid circular dependencies. - map_set(&module->debug_info, hash_type(type), di); + di->CompositeType.align = ir_debug_align_bits(type); // TODO(lachsinc): Necessary? if (is_type_struct(type)) { - if (is_type_named(type)) { - di->CompositeType.name = type->kind == Type_Named ? type->Named.name : type->Basic.name; - } + GB_ASSERT(base->kind == Type_Struct); di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Struct.fields.count); for_array(field_index, base->Struct.fields) { array_add(&di->CompositeType.elements->DebugInfoArray.elements, @@ -1973,15 +2001,22 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD } di->CompositeType.tag = irDebugBasicEncoding_structure_type; } else if (is_type_union(type)) { - di->CompositeType.name = str_lit("union_name_todo"); - di->CompositeType.elements = nullptr; // ir_add_debug_info_array(module, 0, 0); - // TODO(lachsinc): Add elements for union + GB_ASSERT(base->kind == Type_Union); di->CompositeType.tag = irDebugBasicEncoding_union_type; - } else if (is_type_enum(type)) { - if (type->kind == Type_Named) { - di->CompositeType.name = type->Named.name; + di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Union.variants.count); + // TODO(lachsinc): Cleanup; this should be handled in a more generic manner for all types. + file = ir_add_debug_info_file(module, base->Union.node->file); + GB_ASSERT_NOT_NULL(file); // Union debug info requires file info + di->CompositeType.file = file; + di->CompositeType.pos = base->Union.node->UnionType.token.pos; + for_array(field_index, base->Union.variants) { + array_add(&di->CompositeType.elements->DebugInfoArray.elements, + ir_add_debug_info_field(module, di, nullptr, type, cast(i32)field_index, + base->Union.variants[field_index], file)); } - di->CompositeType.base_type = ir_add_debug_info_type(module, type->Named.base->Enum.base_type, e, scope, file); + } else if (is_type_enum(type)) { + GB_ASSERT(base->kind == Type_Enum); + di->CompositeType.base_type = ir_add_debug_info_type(module, base->Enum.base_type, e, scope, file); di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Enum.fields.count); for_array(field_index, base->Enum.fields) { array_add(&di->CompositeType.elements->DebugInfoArray.elements, @@ -2061,7 +2096,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD // TODO(lachsinc): Looks like "generated_struct_type" map.entries.data is just a u8*, we could // always look at the map header and create the debug info manually (if we // want struct members to be interpreted as the correct type). - // Also; are hashes meant to be interpreted as bool*'s ?? + // Also; are hashes meant to be interpreted as bool*'s ?? or is that simply slot occupied data? return ir_add_debug_info_type(module, type->Map.generated_struct_type, e, scope, file); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index c5d3eff2f..7aa08a1fb 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2087,6 +2087,10 @@ void print_llvm_ir(irGen *ir) { GB_ASSERT(di->CompositeType.size > 0); } + if (di->CompositeType.tag == irDebugBasicEncoding_union_type) { + GB_ASSERT_NOT_NULL(di->CompositeType.file); // Union _requires_ file to be valid. + } + ir_write_str_lit(f, "!DICompositeType(tag: "); ir_print_debug_encoding(f, irDebugInfo_CompositeType, di->CompositeType.tag); if (di->CompositeType.name.len > 0) { From ecce1d9974d63a6cb41d24f230b8201fa07f0e63 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Sun, 30 Sep 2018 04:24:24 +1000 Subject: [PATCH 21/39] 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; } From 79ade6ac7bb5f41f2e5c8da8a287cac187e66c58 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Sun, 30 Sep 2018 04:47:21 +1000 Subject: [PATCH 22/39] Add various debug location stuff. --- src/ir.cpp | 22 ++++++++++++++++++++++ src/ir_print.cpp | 5 ++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index b9803aeb7..6b5c4ab63 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -28,6 +28,7 @@ struct irModule { irDebugInfo * debug_compile_unit; irDebugInfo * debug_all_enums; // TODO(lachsinc): Move into irDebugInfo_CompileUnit irDebugInfo * debug_all_globals; // TODO(lachsinc): Move into irDebugInfo_CompileUnit + irDebugInfo * curr_debug_loc; // TODO(lachsinc): Temporary, remove me. Array debug_location_stack; @@ -807,6 +808,8 @@ Array *ir_value_referrers(irValue *v) { //////////////////////////////////////////////////////////////// void ir_module_add_value (irModule *m, Entity *e, irValue *v); +void ir_module_push_debug_location(irModule *m, Ast *node, irDebugInfo *scope); +void ir_module_pop_debug_location (irModule *m); void ir_emit_zero_init (irProcedure *p, irValue *address, Ast *expr); irValue *ir_emit_comment (irProcedure *p, String text); irValue *ir_emit_store (irProcedure *p, irValue *address, irValue *value); @@ -1508,6 +1511,12 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type) { irValue *v = ir_value_param(proc, e, abi_type); irValueParam *p = &v->Param; + // TODO(lachsinc): Correct? Params we want or dont want debug info output ?? + // if so we should save/restore stack or something. + GB_ASSERT_NOT_NULL(proc->debug_scope); + ir_module_push_debug_location(proc->module, e->identifier, proc->debug_scope); + defer (ir_module_pop_debug_location(proc->module)); // TODO(lachsinc): does this happen after return value calculated ?? + switch (p->kind) { case irParamPass_Value: { irValue *l = ir_add_local(proc, e, expr, false); @@ -7016,7 +7025,9 @@ void ir_build_stmt(irProcedure *proc, Ast *node) { proc->module->stmt_state_flags = out; } + ir_module_push_debug_location(proc->module, node, proc->debug_scope); ir_build_stmt_internal(proc, node); + ir_module_pop_debug_location(proc->module); proc->module->stmt_state_flags = prev_stmt_state_flags; } @@ -8078,6 +8089,11 @@ void ir_begin_procedure_body(irProcedure *proc) { } } + if (proc->entity) { // TODO(lachsinc): Necessary ?? + GB_ASSERT_NOT_NULL(proc->debug_scope); + ir_module_push_debug_location(proc->module, proc->entity->identifier, proc->debug_scope); + } + proc->decl_block = ir_new_block(proc, proc->type_expr, "decls"); ir_start_block(proc, proc->decl_block); proc->entry_block = ir_new_block(proc, proc->type_expr, "entry"); @@ -8205,6 +8221,10 @@ void ir_end_procedure_body(irProcedure *proc) { proc->curr_block = nullptr; ir_number_proc_registers(proc); + + if (proc->entity) { + ir_module_pop_debug_location(proc->module); + } } @@ -8328,6 +8348,8 @@ 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); + // TODO(lachsinc): Ensure validity? if not valid we should push a nullptr on to ensure + // calls to pop are safe. array_add(&m->debug_location_stack, debug_location); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 70f5e9f0a..214fdaaa9 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1550,7 +1550,6 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { irInstrDebugDeclare *dd = &instr->DebugDeclare; Type *vt = ir_type(dd->value); - irDebugInfo *di = dd->scope; Entity *e = dd->entity; String name = e->token.string; TokenPos pos = e->token.pos; @@ -1565,8 +1564,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_write_byte(f, ' '); ir_print_value(f, m, dd->value, vt); ir_fprintf(f, ", metadata !%d", local_var_di->id); - ir_write_str_lit(f, ", metadata !DIExpression())"); - ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, di->id); + ir_write_str_lit(f, ", metadata !DIExpression())"); + ir_print_debug_location(f, m, value); break; } } From db0756a1190b694e46c733498480b071265a0baf Mon Sep 17 00:00:00 2001 From: lachsinc Date: Mon, 1 Oct 2018 00:02:41 +1000 Subject: [PATCH 23/39] Stepping working. Cleanup. --- src/ir.cpp | 132 ++++++++++++++++++++++++----------------------- src/ir_print.cpp | 43 ++++++++------- 2 files changed, 88 insertions(+), 87 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 6b5c4ab63..5163a631e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -808,8 +808,6 @@ Array *ir_value_referrers(irValue *v) { //////////////////////////////////////////////////////////////// void ir_module_add_value (irModule *m, Entity *e, irValue *v); -void ir_module_push_debug_location(irModule *m, Ast *node, irDebugInfo *scope); -void ir_module_pop_debug_location (irModule *m); void ir_emit_zero_init (irProcedure *p, irValue *address, Ast *expr); irValue *ir_emit_comment (irProcedure *p, String text); irValue *ir_emit_store (irProcedure *p, irValue *address, irValue *value); @@ -827,8 +825,11 @@ 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); +void ir_push_debug_location (irModule *m, Ast *node, irDebugInfo *scope); +void ir_pop_debug_location (irModule *m); irDebugInfo *ir_add_debug_info_local(irModule *module, Entity *e, i32 arg_id, irDebugInfo *scope, irDebugInfo *file); - +irDebugInfo *ir_add_debug_info_file(irModule *module, AstFile *file); +irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String name, irDebugInfo *scope, irDebugInfo *file); irValue *ir_alloc_value(irValueKind kind) { @@ -1135,9 +1136,8 @@ irValue *ir_instr_comment(irProcedure *p, String text) { return v; } -irValue *ir_instr_debug_declare(irProcedure *p, irDebugInfo *scope, Ast *expr, Entity *entity, bool is_addr, irValue *value) { +irValue *ir_instr_debug_declare(irProcedure *p, Ast *expr, Entity *entity, bool is_addr, irValue *value) { irValue *v = ir_alloc_instr(p, irInstr_DebugDeclare); - // TODO(lachsinc): Set v->loc ?? v->Instr.DebugDeclare.expr = expr; v->Instr.DebugDeclare.entity = entity; v->Instr.DebugDeclare.is_addr = is_addr; @@ -1432,17 +1432,19 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial ir_emit_zero_init(proc, instr, expr); } - 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)); + if (expr != nullptr && proc->entity != nullptr) { + GB_ASSERT_NOT_NULL(proc->debug_scope); + ir_push_debug_location(proc->module, expr, proc->debug_scope); + + ir_emit(proc, ir_instr_debug_declare(proc, expr, e, true, instr)); // TODO(lachsinc): "Arg" is not used yet but should be eventually, if applicable, set to param index // NOTE(lachsinc): The following call recurses through a type creating or finding the necessary debug info. // This approach may be quite detrimental to perf? // This may not be the most appropriate place to place this? (for proc non-value params etc.) + irDebugInfo *di = *map_get(&proc->module->debug_info, hash_entity(proc->entity)); // TODO(lachsinc): Cleanup; lookup di for proc inside ir_add_debug_info_local() ? ir_add_debug_info_local(proc->module, e, 0, di, di->Proc.file); + ir_pop_debug_location(proc->module); } return instr; @@ -1511,11 +1513,8 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type) { irValue *v = ir_value_param(proc, e, abi_type); irValueParam *p = &v->Param; - // TODO(lachsinc): Correct? Params we want or dont want debug info output ?? - // if so we should save/restore stack or something. - GB_ASSERT_NOT_NULL(proc->debug_scope); - ir_module_push_debug_location(proc->module, e->identifier, proc->debug_scope); - defer (ir_module_pop_debug_location(proc->module)); // TODO(lachsinc): does this happen after return value calculated ?? + ir_push_debug_location(proc->module, e ? e->identifier : nullptr, proc->debug_scope); + defer (ir_pop_debug_location(proc->module)); // TODO(lachsinc): This happens after the return calls to ir_emit_xxx right?? switch (p->kind) { case irParamPass_Value: { @@ -2131,7 +2130,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD } } -irDebugInfo *ir_add_debug_info_global(irModule *module, irValue *v, irDebugInfo *scope) { +irDebugInfo *ir_add_debug_info_global(irModule *module, irValue *v) { // if (!proc->module->generate_debug_info) { // return nullptr; // } @@ -2147,6 +2146,13 @@ irDebugInfo *ir_add_debug_info_global(irModule *module, irValue *v, irDebugInfo irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_GlobalVariableExpression); map_set(&module->debug_info, hash_entity(e), di); + // Create or fetch file debug info. + CheckerInfo *info = module->info; + String filename = e->token.pos.file; + AstFile *f = ast_file_of_filename(info, filename); + GB_ASSERT_NOT_NULL(f); + irDebugInfo *scope = ir_add_debug_info_file(module, f); + irDebugInfo *var_di = ir_alloc_debug_info(irDebugInfo_GlobalVariable); var_di->GlobalVariable.name = e->token.string; var_di->GlobalVariable.scope = scope; @@ -2211,7 +2217,6 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na continue; // TODO(lachsinc): Confirm correct? } - // irDebugInfo *type_di = ir_add_debug_info_type(proc->module, di, e, e->type, file); irDebugInfo *type_di = ir_add_debug_info_type(proc->module, e->type, nullptr, nullptr, nullptr); GB_ASSERT_NOT_NULL(type_di); array_add(&di->Proc.types->DebugInfoArray.elements, type_di); @@ -2230,8 +2235,7 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na if (e->kind != Entity_Variable) { continue; // TODO(lachsinc): Confirm correct? } - // TODO(lachsinc): Could technically be a local? - // irDebugInfo *type_di = ir_add_debug_info_type(proc->module, di, e, e->type, file); + irDebugInfo *type_di = ir_add_debug_info_type(proc->module, e->type, nullptr, nullptr, nullptr); GB_ASSERT_NOT_NULL(type_di); array_add(&di->Proc.types->DebugInfoArray.elements, type_di); @@ -2245,10 +2249,12 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na } irDebugInfo *ir_add_debug_info_location(irModule *m, Ast *node, irDebugInfo *scope) { - GB_ASSERT_NOT_NULL(node); + if (node == nullptr || scope == nullptr) { + // GB_ASSERT(proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0)); + return nullptr; + } // 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; @@ -2260,6 +2266,16 @@ irDebugInfo *ir_add_debug_info_location(irModule *m, Ast *node, irDebugInfo *sco return di; } +void ir_push_debug_location(irModule *m, Ast *node, irDebugInfo *scope) { + irDebugInfo *debug_location = ir_add_debug_info_location(m, node, scope); + array_add(&m->debug_location_stack, debug_location); +} + +void ir_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); +} + //////////////////////////////////////////////////////////////// // // @Emit @@ -2299,6 +2315,7 @@ irValue *ir_emit_select(irProcedure *p, irValue *cond, irValue *t, irValue *f) { 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 } @@ -2308,6 +2325,11 @@ void ir_value_set_debug_location(irProcedure *proc, irValue *v) { 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); + if (v->loc == nullptr) { + // NOTE(lachsinc): Entry point (main()) and runtime_startup don't have entity set; + // they are the only ones where null debug info is considered valid. + GB_ASSERT(proc->entity != nullptr); + } // TODO(lachsinc): HACK; This shouldn't be done here. Proc's debug info should be created prior // to adding proc-values. @@ -7025,9 +7047,9 @@ void ir_build_stmt(irProcedure *proc, Ast *node) { proc->module->stmt_state_flags = out; } - ir_module_push_debug_location(proc->module, node, proc->debug_scope); + ir_push_debug_location(proc->module, node, proc->debug_scope); ir_build_stmt_internal(proc, node); - ir_module_pop_debug_location(proc->module); + ir_pop_debug_location(proc->module); proc->module->stmt_state_flags = prev_stmt_state_flags; } @@ -8089,9 +8111,23 @@ void ir_begin_procedure_body(irProcedure *proc) { } } - if (proc->entity) { // TODO(lachsinc): Necessary ?? + // NOTE(lachsinc): This is somewhat of a fallback/catch-all; We use the procedure's identifer as a debug location.. + // Additional debug locations should be pushed for the procedures statements/expressions themselves. + if (proc->entity && proc->entity->identifier) { // TODO(lachsinc): Better way to determine if these procs are main/runtime_startup. + // TODO(lachsinc): Cleanup file stuff, move inside ir_add_debug_info_proc(). + CheckerInfo *info = proc->module->info; + String filename = proc->entity->token.pos.file; + AstFile *f = ast_file_of_filename(info, filename); + GB_ASSERT_NOT_NULL(f); + irDebugInfo *di_file = ir_add_debug_info_file(proc->module, f); + // TODO(lachsinc): Passing the file for the scope may not be correct for nested procedures? This should probably be + // handled all inside push_debug_location, with just the Ast * we can pull out everything we need to construct scope/file debug info etc. + ir_add_debug_info_proc(proc, proc->entity, proc->name, di_file, di_file); + ir_push_debug_location(proc->module, proc->entity->identifier, proc->debug_scope); GB_ASSERT_NOT_NULL(proc->debug_scope); - ir_module_push_debug_location(proc->module, proc->entity->identifier, proc->debug_scope); + } else { + GB_ASSERT(proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0)); + ir_push_debug_location(proc->module, nullptr, nullptr); } proc->decl_block = ir_new_block(proc, proc->type_expr, "decls"); @@ -8222,9 +8258,7 @@ void ir_end_procedure_body(irProcedure *proc) { ir_number_proc_registers(proc); - if (proc->entity) { - ir_module_pop_debug_location(proc->module); - } + ir_pop_debug_location(proc->module); } @@ -8241,23 +8275,6 @@ void ir_build_proc(irValue *value, irProcedure *parent) { proc->parent = parent; - if (proc->entity != nullptr) { - irModule *m = proc->module; - CheckerInfo *info = m->info; - Entity *e = proc->entity; - String filename = e->token.pos.file; - AstFile *f = ast_file_of_filename(info, filename); - - proc->is_export = e->Procedure.is_export; - proc->is_foreign = e->Procedure.is_foreign; - - irDebugInfo *di_file = ir_add_debug_info_file(m, f); - // TODO(lachsinc): Procs can be built within other procs correct ?? We should pass - // a proper scope, or determine the scope inside of ir_add_debug_info_proc via - // above method (passing in nullptr as args) - ir_add_debug_info_proc(proc, e, proc->name, di_file, di_file); - } - if (proc->body != nullptr) { u64 prev_stmt_state_flags = proc->module->stmt_state_flags; @@ -8282,6 +8299,8 @@ void ir_build_proc(irValue *value, irProcedure *parent) { proc->module->stmt_state_flags = prev_stmt_state_flags; } + // TODO(lachsinc): For now we pop the debug location inside ir_end_procedure_body(). + // This may result in debug info being missing for below. if (proc->type->Proc.has_proc_default_values) { auto *p = &proc->type->Proc; @@ -8335,29 +8354,10 @@ void ir_module_add_value(irModule *m, Entity *e, irValue *v) { // 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, v, di_file); + ir_add_debug_info_global(m, 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); - // TODO(lachsinc): Ensure validity? if not valid we should push a nullptr on to ensure - // calls to pop are safe. - 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; @@ -9577,6 +9577,8 @@ void ir_gen_tree(irGen *s) { ir_build_proc(p, p->Proc.parent); } + GB_ASSERT_MSG(m->debug_location_stack.count == 0, "Debug location stack contains unpopped entries."); + // Number debug info for_array(i, m->debug_info.entries) { auto *entry = &m->debug_info.entries[i]; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 214fdaaa9..f331d13f3 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -218,29 +218,15 @@ bool ir_print_debug_location(irFileBuffer *f, irModule *m, irValue *v) { } GB_ASSERT_NOT_NULL(v); + GB_ASSERT(v->kind == irValue_Instr); - 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); + if (v->loc != nullptr) { + GB_ASSERT(v->loc->kind == irDebugInfo_Location); + ir_fprintf(f, ", !dbg !%d", v->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; - } - GB_PANIC("Inlinable 'call' instructions in a debuggable proc must have !dbg metadata attachment"); - } + } else { + irProcedure *proc = v->Instr.block->proc; + GB_ASSERT(proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0)); } return false; } @@ -1681,7 +1667,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { if (di_ != nullptr) { irDebugInfo *di = *di_; GB_ASSERT(di->kind == irDebugInfo_Proc); - ir_fprintf(f, "!dbg !%d ", di->id); + ir_fprintf(f, "!dbg !%d ", di->id); // TODO(lachsinc): !dbg } } @@ -2002,6 +1988,19 @@ void print_llvm_ir(irGen *ir) { di->Proc.types->id); ir_write_byte(f, ')'); // !DISubprogram( break; + case irDebugInfo_Location: { + GB_ASSERT_NOT_NULL(di->Location.scope); + // TODO(lachsinc): Temporary. + GB_ASSERT(di->Location.pos.line >= 0 && di->Location.pos.line < 65536); + GB_ASSERT(di->Location.pos.column >= 0 && di->Location.pos.column < 65536); + ir_fprintf(f, "!DILocation(" + "line: %td" + ", column: %td" + ", scope: !%d)", + di->Location.pos.line, + di->Location.pos.column, + di->Location.scope->id); + break;} case irDebugInfo_GlobalVariableExpression: { ir_fprintf(f, "!DIGlobalVariableExpression(" "var: !%d" From f8d7f422089edfb2f1bf532cfbfcaaccf4bfc14c Mon Sep 17 00:00:00 2001 From: lachsinc Date: Mon, 1 Oct 2018 00:17:42 +1000 Subject: [PATCH 24/39] Minor cleanup. --- src/ir.cpp | 15 +++------------ src/ir_print.cpp | 24 +++++++----------------- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 5163a631e..e0d7229ee 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -503,7 +503,7 @@ enum irDebugEncoding { irDebugBasicEncoding_unsigned = 6, irDebugBasicEncoding_unsigned_char = 7, - // NOTE(lachsinc): Should the following be renamed from basic -> tag to mirror their DW_TAG_* + // TODO(lachsinc): Should the following be renamed from basic -> tag to mirror their DW_TAG_* // counterparts? Perhaps separate out if they truly have different meaning. irDebugBasicEncoding_member = 13, @@ -527,7 +527,6 @@ enum irDebugInfoKind { irDebugInfo_AllProcs, irDebugInfo_BasicType, // basic types - irDebugInfo_ProcType, irDebugInfo_DerivedType, // pointer, typedef irDebugInfo_CompositeType, // array, struct, enum, (raw_)union irDebugInfo_Enumerator, // For irDebugInfo_CompositeType if enum @@ -579,17 +578,12 @@ struct irDebugInfo { Array procs; } AllProcs; // TODO(lachsinc): Redundant w/ DebugInfoArray. Merge. - // NOTE(lachsinc): Many of the following fields could be removed/resolved as we print it? struct { String name; i32 size; i32 align; irDebugEncoding encoding; } BasicType; - struct { - irDebugInfo * return_type; - Array param_types; - } ProcType; // TODO(lachsinc): Unused? struct { // TODO(lachsinc): Do derived types even need scope/file/line etc. info? irDebugEncoding tag; @@ -641,7 +635,7 @@ struct irDebugInfo { irDebugInfo *type; } LocalVariable; struct { - Array elements; // TODO(lachsinc): Never cleaned up? + Array elements; // TODO(lachsinc): Leak? } DebugInfoArray; }; }; @@ -1439,9 +1433,6 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial ir_emit(proc, ir_instr_debug_declare(proc, expr, e, true, instr)); // TODO(lachsinc): "Arg" is not used yet but should be eventually, if applicable, set to param index - // NOTE(lachsinc): The following call recurses through a type creating or finding the necessary debug info. - // This approach may be quite detrimental to perf? - // This may not be the most appropriate place to place this? (for proc non-value params etc.) irDebugInfo *di = *map_get(&proc->module->debug_info, hash_entity(proc->entity)); // TODO(lachsinc): Cleanup; lookup di for proc inside ir_add_debug_info_local() ? ir_add_debug_info_local(proc->module, e, 0, di, di->Proc.file); ir_pop_debug_location(proc->module); @@ -2235,7 +2226,7 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na if (e->kind != Entity_Variable) { continue; // TODO(lachsinc): Confirm correct? } - + irDebugInfo *type_di = ir_add_debug_info_type(proc->module, e->type, nullptr, nullptr, nullptr); GB_ASSERT_NOT_NULL(type_di); array_add(&di->Proc.types->DebugInfoArray.elements, type_di); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index f331d13f3..1511a3e85 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2073,15 +2073,9 @@ void print_llvm_ir(irGen *ir) { } else { ir_write_str_lit(f, ", baseType: null"); // Valid/required for rawptr } - if (di->DerivedType.size > 0) { - ir_fprintf(f, ", size: %d", di->DerivedType.size); - } - if (di->DerivedType.align > 0) { - ir_fprintf(f, ", align: %d", di->DerivedType.align); - } - if (di->DerivedType.offset > 0) { - ir_fprintf(f, ", offset: %d", di->DerivedType.offset); - } + if (di->DerivedType.size > 0) ir_fprintf(f, ", size: %d", di->DerivedType.size); + if (di->DerivedType.align > 0) ir_fprintf(f, ", align: %d", di->DerivedType.align); + if (di->DerivedType.offset > 0) ir_fprintf(f, ", offset: %d", di->DerivedType.offset); ir_write_byte(f, ')'); break; case irDebugInfo_CompositeType: { @@ -2110,12 +2104,8 @@ void print_llvm_ir(irGen *ir) { di->CompositeType.file->id, di->CompositeType.pos.line); } - if (di->CompositeType.size > 0) { - ir_fprintf(f, ", size: %d", di->CompositeType.size); - } - if (di->CompositeType.align > 0) { - ir_fprintf(f, ", align: %d", di->CompositeType.align); - } + if (di->CompositeType.size > 0) ir_fprintf(f, ", size: %d", di->CompositeType.size); + if (di->CompositeType.align > 0) ir_fprintf(f, ", align: %d", di->CompositeType.align); if (di->CompositeType.base_type != nullptr) { GB_ASSERT(di->CompositeType.tag != irDebugBasicEncoding_structure_type); GB_ASSERT(di->CompositeType.tag != irDebugBasicEncoding_union_type); @@ -2153,8 +2143,8 @@ void print_llvm_ir(irGen *ir) { ir_fprintf(f, "!{"); for_array(element_index, di->DebugInfoArray.elements) { irDebugInfo *elem = di->DebugInfoArray.elements[element_index]; - if (element_index > 0) {ir_write_str_lit(f, ", ");} - if (elem) { + if (element_index > 0) ir_write_str_lit(f, ", "); + if (elem != nullptr) { ir_fprintf(f, "!%d", elem->id); } else { ir_fprintf(f, "null"); // NOTE(lachsinc): Proc's can contain "nullptr" entries to represent void return values. From b37b7a0f72ac8aa71bf5e387ccbb5af0da6237d2 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Mon, 1 Oct 2018 01:10:22 +1000 Subject: [PATCH 25/39] Cleanup. --- src/ir.cpp | 5 +---- src/ir_print.cpp | 12 ++++-------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index e0d7229ee..7518dca29 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -28,7 +28,6 @@ struct irModule { irDebugInfo * debug_compile_unit; irDebugInfo * debug_all_enums; // TODO(lachsinc): Move into irDebugInfo_CompileUnit irDebugInfo * debug_all_globals; // TODO(lachsinc): Move into irDebugInfo_CompileUnit - irDebugInfo * curr_debug_loc; // TODO(lachsinc): Temporary, remove me. Array debug_location_stack; @@ -599,7 +598,6 @@ struct irDebugInfo { struct { irDebugEncoding tag; String name; - String identifier; // TODO(lachsinc): Unused? irDebugInfo * scope; irDebugInfo * file; TokenPos pos; @@ -624,7 +622,6 @@ struct irDebugInfo { TokenPos pos; irDebugInfo *type; irValue *variable; - // irDebugInfo *declaration; } GlobalVariable; struct { String name; @@ -1612,6 +1609,7 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { case Basic_i64: case Basic_int: case Basic_rune: // TODO(lachsinc) signed or unsigned? + case Basic_typeid: return irDebugBasicEncoding_signed; case Basic_u16: @@ -1619,7 +1617,6 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { case Basic_u64: case Basic_uint: case Basic_uintptr: // TODO(lachsinc) unsigned or address? - case Basic_typeid: // TODO(lachsinc) underlying type? return irDebugBasicEncoding_unsigned; // case Basic_f16: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1511a3e85..0732d0af6 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1943,7 +1943,6 @@ void print_llvm_ir(irGen *ir) { "language: DW_LANG_C_plus_plus" // Is this good enough? ", file: !%d" ", producer: \"Odin %.*s\"" - // ", flags: \"\"" // TODO(lachsinc): Removed for now, check if correct ", runtimeVersion: 0" ", isOptimized: false" ", emissionKind: FullDebug" @@ -1973,7 +1972,7 @@ void print_llvm_ir(irGen *ir) { ", line: %td" ", scopeLine: %td" ", isDefinition: true" - ", isLocal: false" // TODO(lachsinc): This used to be always set to true, pretend no local for now. We need to check if scope == file. + ", isLocal: false" // TODO(lachsinc): Is this fine? ", flags: DIFlagPrototyped" ", isOptimized: false" ", unit: !%d" @@ -1990,9 +1989,6 @@ void print_llvm_ir(irGen *ir) { break; case irDebugInfo_Location: { GB_ASSERT_NOT_NULL(di->Location.scope); - // TODO(lachsinc): Temporary. - GB_ASSERT(di->Location.pos.line >= 0 && di->Location.pos.line < 65536); - GB_ASSERT(di->Location.pos.column >= 0 && di->Location.pos.column < 65536); ir_fprintf(f, "!DILocation(" "line: %td" ", column: %td" @@ -2024,8 +2020,8 @@ void print_llvm_ir(irGen *ir) { ", file: !%d" ", line: %d" ", type: !%d" - ", isLocal: true" // TODO(lachsinc): Check is_foreign ?? - ", isDefinition: true)", // TODO(lachsinc): Check is_foreign ?? + ", isLocal: true" // TODO(lachsinc): Check locality ?? + ", isDefinition: true)", // TODO(lachsinc): ?? LIT(di->GlobalVariable.name), di->GlobalVariable.scope->id, di->GlobalVariable.file->id, @@ -2046,7 +2042,7 @@ void print_llvm_ir(irGen *ir) { di->LocalVariable.pos.line, di->LocalVariable.type->id); if (di->LocalVariable.arg > 0) { - GB_PANIC("Param 'Arg' debug info not yet implemented"); // TODO(lachsinc): + GB_PANIC("Param 'Arg' debug info not yet implemented"); // TODO(lachsinc): Proper param index support. ir_fprintf(f, ", arg: %d", di->LocalVariable.arg); } ir_write_byte(f, ')'); From f38d70a235b2b40bcd48dd7fabeeff8f6daf8664 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Mon, 1 Oct 2018 01:21:15 +1000 Subject: [PATCH 26/39] Cleanup. --- src/ir.cpp | 47 +++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 7518dca29..35f8a1639 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -820,7 +820,7 @@ void ir_push_debug_location (irModule *m, Ast *node, irDebugInfo *scope); void ir_pop_debug_location (irModule *m); irDebugInfo *ir_add_debug_info_local(irModule *module, Entity *e, i32 arg_id, irDebugInfo *scope, irDebugInfo *file); irDebugInfo *ir_add_debug_info_file(irModule *module, AstFile *file); -irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String name, irDebugInfo *scope, irDebugInfo *file); +irDebugInfo *ir_add_debug_info_proc(irProcedure *proc); irValue *ir_alloc_value(irValueKind kind) { @@ -2180,14 +2180,26 @@ irDebugInfo *ir_add_debug_info_local(irModule *module, Entity *e, i32 arg_id, ir return di; } -irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String name, irDebugInfo *scope, irDebugInfo *file) { +irDebugInfo *ir_add_debug_info_proc(irProcedure *proc) { // if (!proc->module->generate_debug_info) { // return nullptr; // } + Entity *entity = proc->entity; + + // Add / retrieve debug info for file. + CheckerInfo *info = proc->module->info; + String filename = proc->entity->token.pos.file; + AstFile *f = ast_file_of_filename(info, filename); + irDebugInfo *file = nullptr; + if (f) { + file = ir_add_debug_info_file(proc->module, f); + } + irDebugInfo *scope = file; // TODO(lachsinc): Should scope be made separate to file? + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_Proc); di->Proc.entity = entity; - di->Proc.name = name; + di->Proc.name = proc->name; di->Proc.file = file; di->Proc.pos = entity->token.pos; @@ -2308,29 +2320,14 @@ void ir_value_set_debug_location(irProcedure *proc, irValue *v) { 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. + // TODO(lachsinc): Assert scope info contained in stack top is appropriate against proc ?? v->loc = *array_end_ptr(&m->debug_location_stack); if (v->loc == nullptr) { - // NOTE(lachsinc): Entry point (main()) and runtime_startup don't have entity set; - // they are the only ones where null debug info is considered valid. - GB_ASSERT(proc->entity != nullptr); + // NOTE(lachsinc): Entry point (main()) and runtime_startup are the only ones where null location is considered valid. + GB_ASSERT(proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0)); } - - // 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) { @@ -8102,15 +8099,9 @@ void ir_begin_procedure_body(irProcedure *proc) { // NOTE(lachsinc): This is somewhat of a fallback/catch-all; We use the procedure's identifer as a debug location.. // Additional debug locations should be pushed for the procedures statements/expressions themselves. if (proc->entity && proc->entity->identifier) { // TODO(lachsinc): Better way to determine if these procs are main/runtime_startup. - // TODO(lachsinc): Cleanup file stuff, move inside ir_add_debug_info_proc(). - CheckerInfo *info = proc->module->info; - String filename = proc->entity->token.pos.file; - AstFile *f = ast_file_of_filename(info, filename); - GB_ASSERT_NOT_NULL(f); - irDebugInfo *di_file = ir_add_debug_info_file(proc->module, f); // TODO(lachsinc): Passing the file for the scope may not be correct for nested procedures? This should probably be // handled all inside push_debug_location, with just the Ast * we can pull out everything we need to construct scope/file debug info etc. - ir_add_debug_info_proc(proc, proc->entity, proc->name, di_file, di_file); + ir_add_debug_info_proc(proc); ir_push_debug_location(proc->module, proc->entity->identifier, proc->debug_scope); GB_ASSERT_NOT_NULL(proc->debug_scope); } else { From 1ccc8700e4f8d12650f95fad11f617e70dd870c7 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Tue, 2 Oct 2018 03:39:35 +1000 Subject: [PATCH 27/39] bit_set / bit_field debug info. --- src/ir.cpp | 154 ++++++++++++++++++++++++++++++++++++++++++----- src/ir_print.cpp | 11 +++- 2 files changed, 148 insertions(+), 17 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 35f8a1639..096af7532 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -515,6 +515,10 @@ enum irDebugEncoding { irDebugBasicEncoding_union_type = 23, }; +enum irDebugInfoFlags { + irDebugInfoFlag_Bitfield = (1 << 19), +}; + enum irDebugInfoKind { irDebugInfo_Invalid, @@ -585,15 +589,16 @@ struct irDebugInfo { } BasicType; struct { // TODO(lachsinc): Do derived types even need scope/file/line etc. info? - irDebugEncoding tag; - irDebugInfo * base_type; - String name; // Optional - irDebugInfo * scope; // Optional TODO(lachsinc): Is this used?? - irDebugInfo * file; // Optional TODO(lachsinc): Is this used?? - TokenPos pos; // Optional TODO(lachsinc): Is this used?? - i32 size; // Optional - i32 align; // Optional - i32 offset; // Optional + irDebugEncoding tag; + irDebugInfo * base_type; + String name; // Optional + irDebugInfo * scope; // Optional + irDebugInfo * file; // Optional + TokenPos pos; // Optional + i32 size; // Optional + i32 align; // Optional + i32 offset; // Optional + irDebugInfoFlags flags; // Optional; used only for DIFlagBitField atm. } DerivedType; struct { irDebugEncoding tag; @@ -1409,8 +1414,6 @@ void ir_push_context_onto_stack(irProcedure *proc, irValue *ctx) { array_add(&proc->context_stack, cd); } -irDebugInfo *ir_add_debug_info_local(irModule *module, Entity *e, i32 arg_id, irDebugInfo *scope, irDebugInfo *file); - irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initialized) { irBlock *b = proc->decl_block; // all variables must be in the first block irValue *instr = ir_instr_local(proc, e, true); @@ -1652,7 +1655,7 @@ i32 ir_debug_align_bits(Type *type) { irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Type *type, i32 offset_bits, irDebugInfo *scope) { // NOTE(lachsinc): Caller is expected to insert the returned value into map themselves. - // "scope", if set, should be inserted into map prior to calling to ensure no cyclical dependencies. + // "scope", if set, should be inserted into map prior to calling to ensure no cyclical dependency issues. irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); di->DerivedType.name = name; @@ -1719,7 +1722,6 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit return di; } -// TODO(lachsinc): Cleanup params. irDebugInfo *ir_add_debug_info_enumerator(irModule *module, Entity *e) { irDebugInfo **existing = map_get(&module->debug_info, hash_entity(e)); if (existing != nullptr) { @@ -1744,7 +1746,7 @@ irDebugInfo *ir_add_debug_info_type_dynamic_array(irModule *module, Type *type, // for each required dynamic array, named or unnamed. irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); - di->CompositeType.name = str_lit("dynamic array"); // TODO(lachsinc): [dynamic] .. type->DynamicArray.elem name + di->CompositeType.name = str_lit("dynamic_array"); // TODO(lachsinc): [dynamic] .. type->DynamicArray.elem name di->CompositeType.tag = irDebugBasicEncoding_structure_type; di->CompositeType.size = ir_debug_size_bits(t_rawptr) + ir_debug_size_bits(t_int) + @@ -1796,6 +1798,100 @@ irDebugInfo *ir_add_debug_info_type_dynamic_array(irModule *module, Type *type, return di; } +// TODO(lachsinc): Cleanup params. +irDebugInfo *ir_add_debug_info_type_bit_field(irModule *module, Type *type, Entity *e, irDebugInfo *scope, irDebugInfo *file) { + GB_ASSERT(type->kind == Type_BitField || (type->kind == Type_Named && type->Named.base->kind == Type_BitField)); + + Type *bf_type = base_type(type); + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.name = is_type_named(type) ? type->Named.name : str_lit("bit_field"); + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + di->CompositeType.size = ir_debug_size_bits(bf_type); + // di->CompositeType.align = ir_debug_align_bits(bf_type); + map_set(&module->debug_info, hash_type(type), di); + + GB_ASSERT(bf_type->BitField.fields.count == bf_type->BitField.offsets.count && + bf_type->BitField.fields.count == bf_type->BitField.sizes.count); + + irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, bf_type->BitField.fields.count); + di->CompositeType.elements = elements_di; + map_set(&module->debug_info, hash_pointer(elements_di), elements_di); + + for_array(field_index, bf_type->BitField.fields) { + Entity *field = bf_type->BitField.fields[field_index]; + u32 offset = bf_type->BitField.offsets[field_index]; + u32 size = bf_type->BitField.sizes[field_index]; + String name = str_lit("field_todo"); + if (field != nullptr && field->token.string.len > 0) { + name = field->token.string; + } + irDebugInfo *field_di = ir_add_debug_info_field_internal(module, name, t_i64, // TODO(lachsinc): Safe to use i64 for all bitfields? + 0, + di); + // NOTE(lachsinc): Above calls BitFieldValues type_size_of() which returns size in bits, replace with its true bit value here.. + field_di->DerivedType.size = size; + field_di->DerivedType.offset = offset; // Offset stored in bits already, no need to convert + field_di->DerivedType.flags = irDebugInfoFlag_Bitfield; + map_set(&module->debug_info, hash_pointer(field_di), field_di); + array_add(&elements_di->DebugInfoArray.elements, field_di); + } + + return di; +} + +// TODO(lachsinc): Cleanup params. +irDebugInfo *ir_add_debug_info_type_bit_set(irModule *module, Type *type, Entity *e, irDebugInfo *scope, irDebugInfo *file) { + GB_ASSERT(type->kind == Type_BitSet || type->kind == Type_Named); + + Type *base = base_type(type); + + Type *named = nullptr; + if (type->kind == Type_Named) { + named = type; + } + + Type *elem_type = nullptr; + if (base->BitSet.elem != nullptr) { + // TODO(lachsinc): Do bitsets have integration with other types other than enums? (except ints ofcourse, + // but we can't name those fields..) + elem_type = base->BitSet.elem; + if (elem_type->kind == Type_Enum) { + GB_ASSERT(elem_type->Enum.fields.count == base->BitSet.upper + 1); + } + } + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + di->CompositeType.name = named != nullptr ? named->Named.name : str_lit("bit_set"); + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + di->CompositeType.size = ir_debug_size_bits(base); + // di->CompositeType.align = ir_debug_align_bits(base); + map_set(&module->debug_info, hash_type(type), di); + + irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, base->BitSet.upper + 1); + di->CompositeType.elements = elements_di; + map_set(&module->debug_info, hash_pointer(elements_di), elements_di); + + for (i64 i = 0; i <= base->BitSet.upper; ++i) { + u32 offset = cast(u32)i; + // TODO(lachsinc): Maybe name these fields numbered ascending? + String name = str_lit("field_todo"); + if (elem_type != nullptr && is_type_enum(elem_type)) { + name = base_type(elem_type)->Enum.fields[i]->token.string; + } + irDebugInfo *field_di = ir_add_debug_info_field_internal(module, name, t_u32, // TODO(lachsinc): u32 fine?? + 0, + di); + field_di->DerivedType.size = 1; + field_di->DerivedType.offset = offset; // Offset stored in bits already, no need to convert + field_di->DerivedType.flags = irDebugInfoFlag_Bitfield; + map_set(&module->debug_info, hash_pointer(field_di), field_di); + array_add(&elements_di->DebugInfoArray.elements, field_di); + } + + return di; +} + // TODO(lachsinc): Cleanup params. irDebugInfo *ir_add_debug_info_type_string(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { // TODO(lachsinc): Does this only occur once ?? @@ -1892,6 +1988,9 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD } } + // TODO(lachsinc): Reorder if tests, "unique" types, like basic etc. should go last, they are most likely to hit the existing hashed type + // and no point checking them for the rest of the types. Or just use a massive switch... + // NOTE(lachsinc): Types should be inserted into debug_info map as their named, not base_type()'d, counterpart. Type *base = base_type(type); @@ -1900,8 +1999,10 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD // TODO(lachsinc): Better way to determine distinct etc. or just handle structs, enums before we reach here. // ir_is_type_aggregate() except with no call to base_type(). if (named_base->kind != Type_Struct && - named_base->kind != Type_Union && - named_base->kind != Type_Enum) { + named_base->kind != Type_Union && + named_base->kind != Type_Enum && + named_base->kind != Type_BitField) { + // named_base->kind != Type_BitSet) { // distinct / typedef etc. irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); if (type->kind == Type_Named) { @@ -2102,6 +2203,27 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD return ir_add_debug_info_type(module, type->Map.generated_struct_type, e, scope, file); } + // NOTE(lachsinc): For now we just interpret all BitFieldValues as i64 inside ir_add_debug_info_type_bit_field(). + /* + if (is_type_bit_field_value(type)) { + // NOTE(Lachsinc): Suboptimal; creates a new type for each unique bit field value type + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); + di->BasicType.encoding = irDebugBasicEncoding_unsigned; + // di->BasicType.name = str_lit("todo"); + di->BasicType.size = base->BitFieldValue.bits; + map_set(&module->debug_info, hash_type(type), di); + return di; + } + */ + + if (is_type_bit_field(type)) { + return ir_add_debug_info_type_bit_field(module, type, e, scope, file); + } + + if (is_type_bit_set(type)) { + return ir_add_debug_info_type_bit_set(module, type, e, scope, file); + } + // // TODO(lachsinc): HACK For now any remaining types interpreted as a rawptr. // diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 0732d0af6..beb465fdd 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2058,7 +2058,11 @@ void print_llvm_ir(irGen *ir) { ir_print_debug_encoding(f, irDebugInfo_BasicType, di->BasicType.encoding); ir_write_byte(f, ')'); break; - case irDebugInfo_DerivedType: + case irDebugInfo_DerivedType: { + if (di->DerivedType.tag == irDebugBasicEncoding_member) { + // NOTE(lachsinc): We crash llvm super hard if we don't specify a name :) + GB_ASSERT(di->DerivedType.name.len > 0); + } ir_write_str_lit(f, "!DIDerivedType(tag: "); ir_print_debug_encoding(f, irDebugInfo_DerivedType, di->DerivedType.tag); if (di->DerivedType.name.len > 0) { @@ -2072,8 +2076,13 @@ void print_llvm_ir(irGen *ir) { if (di->DerivedType.size > 0) ir_fprintf(f, ", size: %d", di->DerivedType.size); if (di->DerivedType.align > 0) ir_fprintf(f, ", align: %d", di->DerivedType.align); if (di->DerivedType.offset > 0) ir_fprintf(f, ", offset: %d", di->DerivedType.offset); + if (di->DerivedType.flags > 0) { + // TODO(lachsinc): Handle in a more generic manner. + if (di->DerivedType.flags & irDebugInfoFlag_Bitfield) ir_write_str_lit(f, ", flags: DIFlagBitField, extraData: i64 0"); + } ir_write_byte(f, ')'); break; + } case irDebugInfo_CompositeType: { if (di->CompositeType.tag == irDebugBasicEncoding_array_type) { GB_ASSERT_NOT_NULL(di->CompositeType.base_type); From 79d49f1955c7ae8509f1221fe533a1df5ef4bfaa Mon Sep 17 00:00:00 2001 From: lachsinc Date: Thu, 4 Oct 2018 13:43:52 +1000 Subject: [PATCH 28/39] Lexical block debug info. --- src/ir.cpp | 59 ++++++++++++++++++++++++++++++++++++++++-------- src/ir_print.cpp | 17 ++++++++++++-- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 096af7532..56a03a4f6 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -527,6 +527,7 @@ enum irDebugInfoKind { irDebugInfo_Scope, irDebugInfo_Proc, irDebugInfo_Location, + irDebugInfo_LexicalBlock, irDebugInfo_AllProcs, irDebugInfo_BasicType, // basic types @@ -577,6 +578,11 @@ struct irDebugInfo { TokenPos pos; irDebugInfo *scope; } Location; + struct { + TokenPos pos; + irDebugInfo *file; + irDebugInfo *scope; + } LexicalBlock; struct { Array procs; } AllProcs; // TODO(lachsinc): Redundant w/ DebugInfoArray. Merge. @@ -823,7 +829,7 @@ irValue *ir_get_type_info_ptr (irProcedure *proc, Type *type); void ir_value_set_debug_location(irProcedure *proc, irValue *v); void ir_push_debug_location (irModule *m, Ast *node, irDebugInfo *scope); void ir_pop_debug_location (irModule *m); -irDebugInfo *ir_add_debug_info_local(irModule *module, Entity *e, i32 arg_id, irDebugInfo *scope, irDebugInfo *file); +irDebugInfo *ir_add_debug_info_local(irProcedure *proc, Entity *e, i32 arg_id); irDebugInfo *ir_add_debug_info_file(irModule *module, AstFile *file); irDebugInfo *ir_add_debug_info_proc(irProcedure *proc); @@ -1433,8 +1439,8 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial ir_emit(proc, ir_instr_debug_declare(proc, expr, e, true, instr)); // TODO(lachsinc): "Arg" is not used yet but should be eventually, if applicable, set to param index - irDebugInfo *di = *map_get(&proc->module->debug_info, hash_entity(proc->entity)); // TODO(lachsinc): Cleanup; lookup di for proc inside ir_add_debug_info_local() ? - ir_add_debug_info_local(proc->module, e, 0, di, di->Proc.file); + // irDebugInfo *di = *map_get(&proc->module->debug_info, hash_entity(proc->entity)); // TODO(lachsinc): Cleanup; lookup di for proc inside ir_add_debug_info_local() ? + ir_add_debug_info_local(proc, e, 0); // TODO(lachsinc): Cleanup, lookup file / di scope inside. ir_pop_debug_location(proc->module); } @@ -1853,8 +1859,7 @@ irDebugInfo *ir_add_debug_info_type_bit_set(irModule *module, Type *type, Entity Type *elem_type = nullptr; if (base->BitSet.elem != nullptr) { - // TODO(lachsinc): Do bitsets have integration with other types other than enums? (except ints ofcourse, - // but we can't name those fields..) + // TODO(lachsinc): Do bitsets have integration with non-primitive types other than enums? elem_type = base->BitSet.elem; if (elem_type->kind == Type_Enum) { GB_ASSERT(elem_type->Enum.fields.count == base->BitSet.upper + 1); @@ -2285,15 +2290,46 @@ irDebugInfo *ir_add_debug_info_global(irModule *module, irValue *v) { return di; } -irDebugInfo *ir_add_debug_info_local(irModule *module, Entity *e, i32 arg_id, irDebugInfo *scope, irDebugInfo *file) { - // if (!proc->module->generate_debug_info) { - // return nullptr; - // } +irDebugInfo *ir_add_debug_info_block(irProcedure *proc, Scope *scope) { + // GB_ASSERT(block->kind == Ast_BlockStmt); + + irModule *module = proc->module; + + irDebugInfo **existing = map_get(&module->debug_info, hash_pointer(scope)); + if (existing != nullptr) { + GB_ASSERT((*existing)->kind == irDebugInfo_LexicalBlock); + return *existing; + } + + Ast *block = scope->node; + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_LexicalBlock); + di->LexicalBlock.file = proc->debug_scope->Proc.file; + di->LexicalBlock.scope = proc->debug_scope; + di->LexicalBlock.pos = ast_token(block).pos; + map_set(&module->debug_info, hash_pointer(scope), di); + return di; +} + +irDebugInfo *ir_add_debug_info_local(irProcedure *proc, Entity *e, i32 arg_id) { + irModule *module = proc->module; + + irDebugInfo *scope = nullptr; + irDebugInfo *file = nullptr; + if (e->scope->node->kind == Ast_ProcType) { + scope = proc->debug_scope; + file = proc->debug_scope->Proc.file; + } else { + scope = ir_add_debug_info_block(proc, e->scope); + file = scope->LexicalBlock.file; + } + GB_ASSERT_NOT_NULL(scope); + GB_ASSERT_NOT_NULL(file); irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_LocalVariable); di->LocalVariable.name = e->token.string; di->LocalVariable.scope = scope; - di->LocalVariable.file = scope->Proc.file; + di->LocalVariable.file = file; di->LocalVariable.pos = e->token.pos; di->LocalVariable.arg = arg_id; di->LocalVariable.type = ir_add_debug_info_type(module, e->type, nullptr, nullptr, nullptr); @@ -2375,6 +2411,7 @@ irDebugInfo *ir_add_debug_info_location(irModule *m, Ast *node, irDebugInfo *sco // GB_ASSERT(proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0)); return nullptr; } + // GB_ASSERT(node->kind != Ast_BlockStmt); // TODO(lachsinc): Should we traverse the node/children until we find one with // valid token/pos and use that instead?? irDebugInfo **existing = map_get(&m->debug_info, hash_node(node)); @@ -5562,6 +5599,8 @@ irValue *ir_build_expr(irProcedure *proc, Ast *expr) { irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { expr = unparen_expr(expr); + // ir_push_debug_location(proc->module, expr, proc->debug_scope); + // defer (ir_pop_debug_location(proc->module)); TypeAndValue tv = type_and_value_of_expr(expr); GB_ASSERT(tv.mode != Addressing_Invalid); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index beb465fdd..dc0a84900 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1987,7 +1987,7 @@ void print_llvm_ir(irGen *ir) { di->Proc.types->id); ir_write_byte(f, ')'); // !DISubprogram( break; - case irDebugInfo_Location: { + case irDebugInfo_Location: GB_ASSERT_NOT_NULL(di->Location.scope); ir_fprintf(f, "!DILocation(" "line: %td" @@ -1996,7 +1996,20 @@ void print_llvm_ir(irGen *ir) { di->Location.pos.line, di->Location.pos.column, di->Location.scope->id); - break;} + break; + case irDebugInfo_LexicalBlock: + GB_ASSERT_NOT_NULL(di->LexicalBlock.file); + GB_ASSERT_NOT_NULL(di->LexicalBlock.scope); + ir_fprintf(f, "distinct !DILexicalBlock(" + "line: %td" + ", column: %td" + ", file: !%d" + ", scope: !%d)", + di->LexicalBlock.pos.line, + di->LexicalBlock.pos.column, + di->LexicalBlock.file->id, + di->LexicalBlock.scope->id); + break; case irDebugInfo_GlobalVariableExpression: { ir_fprintf(f, "!DIGlobalVariableExpression(" "var: !%d" From 48ad1478181d9b24cfd0ae7b22c186aaa01933db Mon Sep 17 00:00:00 2001 From: lachsinc Date: Thu, 4 Oct 2018 14:09:17 +1000 Subject: [PATCH 29/39] Cleanup; Move enums/globals di inside CompileUnit. Minor comment cleanup. --- src/ir.cpp | 38 +++++++++++++++++--------------------- src/ir_print.cpp | 4 ++-- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 56a03a4f6..eb0857de6 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26,8 +26,6 @@ struct irModule { Map anonymous_proc_lits; // Key: Ast * irDebugInfo * debug_compile_unit; - irDebugInfo * debug_all_enums; // TODO(lachsinc): Move into irDebugInfo_CompileUnit - irDebugInfo * debug_all_globals; // TODO(lachsinc): Move into irDebugInfo_CompileUnit Array debug_location_stack; @@ -1438,9 +1436,8 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial ir_emit(proc, ir_instr_debug_declare(proc, expr, e, true, instr)); - // TODO(lachsinc): "Arg" is not used yet but should be eventually, if applicable, set to param index - // irDebugInfo *di = *map_get(&proc->module->debug_info, hash_entity(proc->entity)); // TODO(lachsinc): Cleanup; lookup di for proc inside ir_add_debug_info_local() ? - ir_add_debug_info_local(proc, e, 0); // TODO(lachsinc): Cleanup, lookup file / di scope inside. + // TODO(lachsinc): "Arg" is not used yet but should be eventually, if applicable, set to param index. + ir_add_debug_info_local(proc, e, 0); ir_pop_debug_location(proc->module); } @@ -1511,7 +1508,7 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type) { irValueParam *p = &v->Param; ir_push_debug_location(proc->module, e ? e->identifier : nullptr, proc->debug_scope); - defer (ir_pop_debug_location(proc->module)); // TODO(lachsinc): This happens after the return calls to ir_emit_xxx right?? + defer (ir_pop_debug_location(proc->module)); switch (p->kind) { case irParamPass_Value: { @@ -1625,7 +1622,7 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { case Basic_u32: case Basic_u64: case Basic_uint: - case Basic_uintptr: // TODO(lachsinc) unsigned or address? + case Basic_uintptr: return irDebugBasicEncoding_unsigned; // case Basic_f16: @@ -1996,7 +1993,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD // TODO(lachsinc): Reorder if tests, "unique" types, like basic etc. should go last, they are most likely to hit the existing hashed type // and no point checking them for the rest of the types. Or just use a massive switch... - // NOTE(lachsinc): Types should be inserted into debug_info map as their named, not base_type()'d, counterpart. + // NOTE(lachsinc): Types should be inserted into debug_info map as their named, not base_type()'d counterparts. Type *base = base_type(type); if (type->kind == Type_Named) { @@ -2007,7 +2004,6 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD named_base->kind != Type_Union && named_base->kind != Type_Enum && named_base->kind != Type_BitField) { - // named_base->kind != Type_BitSet) { // distinct / typedef etc. irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); if (type->kind == Type_Named) { @@ -2044,9 +2040,10 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD di->DerivedType.size = ir_debug_size_bits(t_rawptr); di->DerivedType.align = ir_debug_align_bits(t_rawptr); // TODO(lachsinc): Not sure if align is required. map_set(&module->debug_info, hash_type(type), di); - // NOTE(lachsinc): llvm expects "null" for rawptr/voidptr if (type->Basic.kind == Basic_cstring) { di->DerivedType.base_type = ir_add_debug_info_type(module, t_i8, e, scope, file); + } else { + // NOTE(lachsinc): llvm expects "null" for rawptr/voidptr } return di; } @@ -2065,12 +2062,12 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD } if (is_type_pointer(type)) { - // TODO(lachsinc): Ensure this handles pointers to pointers of same type etc. correctly. + // TODO(lachsinc): Ensure this handles pointer-to-pointer of same type etc. correctly. Type *deref = type_deref(base); irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); di->DerivedType.tag = irDebugBasicEncoding_pointer_type; di->DerivedType.size = ir_debug_size_bits(type); - // NOTE(lachsinc): Set in map before creative base_type to avoid circular dependency issues. + // NOTE(lachsinc): Map set before creating base_type to avoid circular dependency issues. map_set(&module->debug_info, hash_type(type), di); if (is_type_struct(deref)) { int i = 123; @@ -2081,7 +2078,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD if (is_type_struct(type) || is_type_union(type) || is_type_enum(type)) { if (type->kind == Type_Named) { - // Named named's should be handled prior as typedefs. + // NOTE(lachsinc): Named named's should always be handled prior as typedefs. GB_ASSERT(type->Named.base->kind != Type_Named); } @@ -2134,7 +2131,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD // 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); + array_add(&module->debug_compile_unit->CompileUnit.enums->DebugInfoArray.elements, di); } return di; @@ -2146,8 +2143,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD if (is_type_array(type)) { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); - - di->CompositeType.size = ir_debug_size_bits(type); // TODO(lachsinc): Confirm correct array sizing. llvm expects size in bits! + di->CompositeType.size = ir_debug_size_bits(type); di->CompositeType.align = ir_debug_align_bits(type); di->CompositeType.tag = irDebugBasicEncoding_array_type; di->CompositeType.array_count = (i32)type->Array.count; @@ -2160,7 +2156,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD } if (is_type_slice(type)) { - // NOTE(lachsinc): Every slice type has its own composite type / field debug infos created. This is wasteful!! + // NOTE(lachsinc): Every slice type has its own composite type / field debug infos created. This is sorta wasteful. irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); di->CompositeType.name = str_lit("slice"); @@ -2285,7 +2281,7 @@ irDebugInfo *ir_add_debug_info_global(irModule *module, irValue *v) { di->GlobalVariableExpression.var = var_di; - array_add(&module->debug_all_globals->DebugInfoArray.elements, di); + array_add(&module->debug_compile_unit->CompileUnit.globals->DebugInfoArray.elements, di); return di; } @@ -8439,7 +8435,7 @@ void ir_build_proc(irValue *value, irProcedure *parent) { proc->module->stmt_state_flags = prev_stmt_state_flags; } - // TODO(lachsinc): For now we pop the debug location inside ir_end_procedure_body(). + // NOTE(lachsinc): For now we pop the debug location inside ir_end_procedure_body(). // This may result in debug info being missing for below. if (proc->type->Proc.has_proc_default_values) { @@ -8620,12 +8616,12 @@ void ir_init_module(irModule *m, Checker *c) { 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; + m->debug_compile_unit->CompileUnit.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; + m->debug_compile_unit->CompileUnit.globals = globals_di; array_init(&m->debug_location_stack, heap_allocator()); // TODO(lachsinc): ir_allocator() ?? } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index dc0a84900..0e8f8234b 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1952,8 +1952,8 @@ void print_llvm_ir(irGen *ir) { ")", file->id, LIT(build_context.ODIN_VERSION), - m->debug_all_enums->id, - m->debug_all_globals->id); + m->debug_compile_unit->CompileUnit.enums->id, + m->debug_compile_unit->CompileUnit.globals->id); break; } case irDebugInfo_File: From ab46406f4d3eaa4625c96db673c35d0cd96a5575 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Fri, 5 Oct 2018 12:27:36 +1000 Subject: [PATCH 30/39] Fix debug info for unnamed aggregate types. --- src/ir.cpp | 75 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index eb0857de6..529b5a609 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -595,26 +595,26 @@ struct irDebugInfo { // TODO(lachsinc): Do derived types even need scope/file/line etc. info? irDebugEncoding tag; irDebugInfo * base_type; - String name; // Optional - irDebugInfo * scope; // Optional - irDebugInfo * file; // Optional - TokenPos pos; // Optional - i32 size; // Optional - i32 align; // Optional - i32 offset; // Optional - irDebugInfoFlags flags; // Optional; used only for DIFlagBitField atm. + String name; + irDebugInfo * scope; + irDebugInfo * file; + TokenPos pos; + i32 size; + i32 align; + i32 offset; + irDebugInfoFlags flags; // Used only for DIFlagBitField. } DerivedType; struct { - irDebugEncoding tag; - String name; - irDebugInfo * scope; - irDebugInfo * file; - TokenPos pos; - irDebugInfo * base_type; // optional, used for enumeration_type. - i32 size; - i32 align; - irDebugInfo * elements; - i32 array_count; // for DISubrange + irDebugEncoding tag; + String name; + irDebugInfo * scope; + irDebugInfo * file; + TokenPos pos; + irDebugInfo * base_type; // optional, used for enumeration_type. + i32 size; + i32 align; + irDebugInfo * elements; + i32 array_count; // for DISubrange } CompositeType; struct { String name; @@ -1656,7 +1656,7 @@ i32 ir_debug_align_bits(Type *type) { return ir_debug_info_bits(type_align_of(type)); } -irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Type *type, i32 offset_bits, irDebugInfo *scope) { +irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Type *type, i32 offset_bits, Entity *e, irDebugInfo *scope) { // NOTE(lachsinc): Caller is expected to insert the returned value into map themselves. // "scope", if set, should be inserted into map prior to calling to ensure no cyclical dependency issues. @@ -1669,7 +1669,7 @@ irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Typ // NOTE(lachsinc): It is "safe" to overwrite this base_type after a call to this function, // if you need to set a specific type for this field. - di->DerivedType.base_type = ir_add_debug_info_type(module, type, nullptr, nullptr, nullptr); + di->DerivedType.base_type = ir_add_debug_info_type(module, type, e, scope, nullptr); GB_ASSERT_NOT_NULL(di->DerivedType.base_type); return di; } @@ -1687,7 +1687,7 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit } // TODO(lachsinc): Cleanup - irDebugInfo *di = ir_add_debug_info_field_internal(module, make_string(nullptr, 0), type, 0, scope); + irDebugInfo *di = ir_add_debug_info_field_internal(module, make_string(nullptr, 0), type, 0, e, scope); void *ptr_to_hash = nullptr; if (scope_type) { Type *scope_base = base_type(scope_type); @@ -1768,18 +1768,21 @@ irDebugInfo *ir_add_debug_info_type_dynamic_array(irModule *module, Type *type, irDebugInfo *data_di = ir_add_debug_info_field_internal(module, str_lit("data"), t_rawptr, 0, + nullptr, di); data_di->DerivedType.base_type = data_ptr_di; map_set(&module->debug_info, hash_pointer(data_di), data_di); irDebugInfo *len_di = ir_add_debug_info_field_internal(module, str_lit("len"), t_int, data_di->DerivedType.size, + nullptr, di); map_set(&module->debug_info, hash_pointer(len_di), len_di); irDebugInfo *cap_di = ir_add_debug_info_field_internal(module, str_lit("cap"), t_int, data_di->DerivedType.size + len_di->DerivedType.size, + nullptr, di); map_set(&module->debug_info, hash_pointer(cap_di), cap_di); @@ -1787,6 +1790,7 @@ irDebugInfo *ir_add_debug_info_type_dynamic_array(irModule *module, Type *type, data_di->DerivedType.size + len_di->DerivedType.size + cap_di->DerivedType.size, + nullptr, di); map_set(&module->debug_info, hash_pointer(alloc_di), alloc_di); @@ -1831,6 +1835,7 @@ irDebugInfo *ir_add_debug_info_type_bit_field(irModule *module, Type *type, Enti } irDebugInfo *field_di = ir_add_debug_info_field_internal(module, name, t_i64, // TODO(lachsinc): Safe to use i64 for all bitfields? 0, + nullptr, di); // NOTE(lachsinc): Above calls BitFieldValues type_size_of() which returns size in bits, replace with its true bit value here.. field_di->DerivedType.size = size; @@ -1883,6 +1888,7 @@ irDebugInfo *ir_add_debug_info_type_bit_set(irModule *module, Type *type, Entity } irDebugInfo *field_di = ir_add_debug_info_field_internal(module, name, t_u32, // TODO(lachsinc): u32 fine?? 0, + nullptr, di); field_di->DerivedType.size = 1; field_di->DerivedType.offset = offset; // Offset stored in bits already, no need to convert @@ -1913,12 +1919,14 @@ irDebugInfo *ir_add_debug_info_type_string(irModule *module, irDebugInfo *scope, // Field "data" irDebugInfo *data_di = ir_add_debug_info_field_internal(module, str_lit("data"), t_cstring, 0, + nullptr, di); map_set(&module->debug_info, hash_pointer(data_di), data_di); // Field "len" irDebugInfo *len_di = ir_add_debug_info_field_internal(module, str_lit("len"), t_i64, data_di->DerivedType.size, + nullptr, di); map_set(&module->debug_info, hash_pointer(len_di), len_di); @@ -1949,12 +1957,14 @@ irDebugInfo *ir_add_debug_info_type_any(irModule *module) { // Field "data" irDebugInfo *data_di = ir_add_debug_info_field_internal(module, str_lit("data"), t_rawptr, 0, + nullptr, di); map_set(&module->debug_info, hash_pointer(data_di), data_di); // Field "id" irDebugInfo *id_di = ir_add_debug_info_field_internal(module, str_lit("id"), t_typeid, data_di->DerivedType.size, + nullptr, di); map_set(&module->debug_info, hash_pointer(id_di), id_di); @@ -2098,6 +2108,11 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD if (is_type_struct(type)) { GB_ASSERT(base->kind == Type_Struct); + if (!is_type_named(type)) { + di->CompositeType.name = str_lit("struct"); + GB_ASSERT_NOT_NULL(scope); + di->CompositeType.scope = scope; + } di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Struct.fields.count); for_array(field_index, base->Struct.fields) { array_add(&di->CompositeType.elements->DebugInfoArray.elements, @@ -2107,6 +2122,11 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD di->CompositeType.tag = irDebugBasicEncoding_structure_type; } else if (is_type_union(type)) { GB_ASSERT(base->kind == Type_Union); + if (!is_type_named(type)) { + di->CompositeType.name = str_lit("union"); + GB_ASSERT_NOT_NULL(scope); + di->CompositeType.scope = scope; + } di->CompositeType.tag = irDebugBasicEncoding_union_type; di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Union.variants.count); // TODO(lachsinc): Cleanup; this should be handled in a more generic manner for all types. @@ -2121,6 +2141,11 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD } } else if (is_type_enum(type)) { GB_ASSERT(base->kind == Type_Enum); + if (!is_type_named(type)) { + di->CompositeType.name = str_lit("enum"); + GB_ASSERT_NOT_NULL(scope); + di->CompositeType.scope = scope; + } di->CompositeType.base_type = ir_add_debug_info_type(module, base->Enum.base_type, e, scope, file); di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Enum.fields.count); for_array(field_index, base->Enum.fields) { @@ -2178,12 +2203,14 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD irDebugInfo *data_di = ir_add_debug_info_field_internal(module, str_lit("data"), t_rawptr, 0, + nullptr, di); data_di->DerivedType.base_type = data_ptr_di; map_set(&module->debug_info, hash_pointer(data_di), data_di); irDebugInfo *len_di = ir_add_debug_info_field_internal(module, str_lit("len"), t_int, data_di->DerivedType.size, + nullptr, di); map_set(&module->debug_info, hash_pointer(len_di), len_di); @@ -2328,7 +2355,7 @@ irDebugInfo *ir_add_debug_info_local(irProcedure *proc, Entity *e, i32 arg_id) { di->LocalVariable.file = file; di->LocalVariable.pos = e->token.pos; di->LocalVariable.arg = arg_id; - di->LocalVariable.type = ir_add_debug_info_type(module, e->type, nullptr, nullptr, nullptr); + di->LocalVariable.type = ir_add_debug_info_type(module, e->type, e, scope, file); // TODO(lachsinc): Is this the correct entity to pass? Or do we want TypeName ?? map_set(&module->debug_info, hash_entity(e), di); return di; @@ -2371,7 +2398,7 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc) { continue; // TODO(lachsinc): Confirm correct? } - irDebugInfo *type_di = ir_add_debug_info_type(proc->module, e->type, nullptr, nullptr, nullptr); + irDebugInfo *type_di = ir_add_debug_info_type(proc->module, e->type, e, nullptr, nullptr); GB_ASSERT_NOT_NULL(type_di); array_add(&di->Proc.types->DebugInfoArray.elements, type_di); } @@ -2390,7 +2417,7 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc) { continue; // TODO(lachsinc): Confirm correct? } - irDebugInfo *type_di = ir_add_debug_info_type(proc->module, e->type, nullptr, nullptr, nullptr); + irDebugInfo *type_di = ir_add_debug_info_type(proc->module, e->type, e, nullptr, nullptr); GB_ASSERT_NOT_NULL(type_di); array_add(&di->Proc.types->DebugInfoArray.elements, type_di); } From dfeefc51799372307036ea9520261ee0d6059dc1 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Fri, 5 Oct 2018 12:46:53 +1000 Subject: [PATCH 31/39] Fix dgb.declare using different location to it's associated instructions. --- src/ir.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 529b5a609..956959141 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1432,13 +1432,11 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial if (expr != nullptr && proc->entity != nullptr) { GB_ASSERT_NOT_NULL(proc->debug_scope); - ir_push_debug_location(proc->module, expr, proc->debug_scope); - + ir_emit(proc, ir_instr_debug_declare(proc, expr, e, true, instr)); // TODO(lachsinc): "Arg" is not used yet but should be eventually, if applicable, set to param index. ir_add_debug_info_local(proc, e, 0); - ir_pop_debug_location(proc->module); } return instr; From 99b4d59f44842327eaee08886a7aa0cbd538588d Mon Sep 17 00:00:00 2001 From: lachsinc Date: Fri, 5 Oct 2018 12:57:06 +1000 Subject: [PATCH 32/39] Add arg # for proc param locals. --- src/ir.cpp | 14 +++++++------- src/ir_print.cpp | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 956959141..266b94e05 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1418,7 +1418,7 @@ void ir_push_context_onto_stack(irProcedure *proc, irValue *ctx) { array_add(&proc->context_stack, cd); } -irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initialized) { +irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initialized, i32 param_index = 0) { irBlock *b = proc->decl_block; // all variables must be in the first block irValue *instr = ir_instr_local(proc, e, true); instr->Instr.block = b; @@ -1436,7 +1436,7 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial ir_emit(proc, ir_instr_debug_declare(proc, expr, e, true, instr)); // TODO(lachsinc): "Arg" is not used yet but should be eventually, if applicable, set to param index. - ir_add_debug_info_local(proc, e, 0); + ir_add_debug_info_local(proc, e, param_index); } return instr; @@ -1501,7 +1501,7 @@ irValue *ir_add_global_generated(irModule *m, Type *type, irValue *value) { } -irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type) { +irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type, i32 index) { irValue *v = ir_value_param(proc, e, abi_type); irValueParam *p = &v->Param; @@ -1510,7 +1510,7 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type) { switch (p->kind) { case irParamPass_Value: { - irValue *l = ir_add_local(proc, e, expr, false); + irValue *l = ir_add_local(proc, e, expr, false, index); irValue *x = v; if (abi_type == t_llvm_bool) { x = ir_emit_conv(proc, x, t_bool); @@ -1523,7 +1523,7 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type) { return ir_emit_load(proc, v); case irParamPass_Integer: { - irValue *l = ir_add_local(proc, e, expr, false); + irValue *l = ir_add_local(proc, e, expr, false, index); irValue *iptr = ir_emit_conv(proc, l, alloc_type_pointer(p->type)); ir_emit_store(proc, iptr, v); return ir_emit_load(proc, l); @@ -8336,7 +8336,7 @@ void ir_begin_procedure_body(irProcedure *proc) { Type *abi_type = proc->type->Proc.abi_compat_params[i]; if (e->token.string != "" && !is_blank_ident(e->token)) { - irValue *param = ir_add_param(proc, e, name, abi_type); + irValue *param = ir_add_param(proc, e, name, abi_type, cast(i32)(i+1)); array_add(&proc->params, param); } } @@ -8353,7 +8353,7 @@ void ir_begin_procedure_body(irProcedure *proc) { abi_type = abi_types[i]; } if (e->token.string != "" && !is_blank_ident(e->token)) { - irValue *param = ir_add_param(proc, e, nullptr, abi_type); + irValue *param = ir_add_param(proc, e, nullptr, abi_type, cast(i32)(i+1)); array_add(&proc->params, param); } } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 0e8f8234b..a4b595289 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2055,7 +2055,6 @@ void print_llvm_ir(irGen *ir) { di->LocalVariable.pos.line, di->LocalVariable.type->id); if (di->LocalVariable.arg > 0) { - GB_PANIC("Param 'Arg' debug info not yet implemented"); // TODO(lachsinc): Proper param index support. ir_fprintf(f, ", arg: %d", di->LocalVariable.arg); } ir_write_byte(f, ')'); From 11ea03d2e8de0cf9a6628baef5b1b8ec612ae418 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Fri, 5 Oct 2018 14:33:39 +1000 Subject: [PATCH 33/39] Tuple debug info (untested). Generated locals now flow through debug info. --- src/ir.cpp | 82 +++++++++++++++++++++++++++++++++++------------- src/ir_print.cpp | 7 +++-- 2 files changed, 64 insertions(+), 25 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 266b94e05..47909a7bd 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1430,13 +1430,15 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial ir_emit_zero_init(proc, instr, expr); } - if (expr != nullptr && proc->entity != nullptr) { - GB_ASSERT_NOT_NULL(proc->debug_scope); - - ir_emit(proc, ir_instr_debug_declare(proc, expr, e, true, instr)); - - // TODO(lachsinc): "Arg" is not used yet but should be eventually, if applicable, set to param index. - ir_add_debug_info_local(proc, e, param_index); + // if (proc->module->generate_debug_info && expr != nullptr && proc->entity != nullptr) { + if (proc->module->generate_debug_info && proc->entity != nullptr) { + // GB_ASSERT_NOT_NULL(proc->debug_scope); + if (expr != nullptr) { + ir_emit(proc, ir_instr_debug_declare(proc, expr, e, true, instr)); + } + if (e->scope != nullptr && proc->debug_scope != nullptr) { + irDebugInfo *di_local = ir_add_debug_info_local(proc, e, param_index); + } } return instr; @@ -1689,15 +1691,24 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit void *ptr_to_hash = nullptr; if (scope_type) { Type *scope_base = base_type(scope_type); - if (is_type_struct(scope_type)) { - if (scope_base->Struct.are_offsets_set) { + if (is_type_struct(scope_type) || is_type_tuple(scope_type)) { + if (is_type_struct(scope_type) && scope_base->Struct.are_offsets_set) { di->DerivedType.offset = ir_debug_info_bits(scope_base->Struct.offsets[index]); + } else if (is_type_tuple(scope_type) && scope_base->Tuple.are_offsets_set) { + di->DerivedType.offset = ir_debug_info_bits(scope_base->Tuple.offsets[index]); } else { di->DerivedType.offset = ir_debug_info_bits(type_offset_of(scope_base, index)); } if (e) { ptr_to_hash = e; di->DerivedType.name = e->token.string; + if (e->token.string.len == 0) { + // If no name available for field, use its field index as its name. + isize max_len = 8; + u8 *str = cast(u8 *)gb_alloc_array(heap_allocator(), u8, max_len); + isize len = gb_snprintf(cast(char *)str, 8, "%d", index); + di->DerivedType.name = make_string(str, len-1); + } di->DerivedType.pos = e->token.pos; } else { GB_PANIC("Unreachable"); // struct field Entity's should be provided. @@ -2011,7 +2022,8 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD if (named_base->kind != Type_Struct && named_base->kind != Type_Union && named_base->kind != Type_Enum && - named_base->kind != Type_BitField) { + named_base->kind != Type_BitField && + named_base->kind != Type_Tuple) { // distinct / typedef etc. irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); if (type->kind == Type_Named) { @@ -2084,7 +2096,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD return di; } - if (is_type_struct(type) || is_type_union(type) || is_type_enum(type)) { + if (is_type_struct(type) || is_type_union(type) || is_type_enum(type) || is_type_tuple(type)) { if (type->kind == Type_Named) { // NOTE(lachsinc): Named named's should always be handled prior as typedefs. GB_ASSERT(type->Named.base->kind != Type_Named); @@ -2111,13 +2123,13 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD GB_ASSERT_NOT_NULL(scope); di->CompositeType.scope = scope; } + di->CompositeType.tag = irDebugBasicEncoding_structure_type; di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Struct.fields.count); 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], type, cast(i32)field_index, base->Struct.fields[field_index]->type, file)); } - di->CompositeType.tag = irDebugBasicEncoding_structure_type; } else if (is_type_union(type)) { GB_ASSERT(base->kind == Type_Union); if (!is_type_named(type)) { @@ -2144,17 +2156,32 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD GB_ASSERT_NOT_NULL(scope); di->CompositeType.scope = scope; } + di->CompositeType.tag = irDebugBasicEncoding_enumeration_type; di->CompositeType.base_type = ir_add_debug_info_type(module, base->Enum.base_type, e, scope, file); di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Enum.fields.count); for_array(field_index, base->Enum.fields) { array_add(&di->CompositeType.elements->DebugInfoArray.elements, 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_compile_unit->CompileUnit.enums->DebugInfoArray.elements, di); + } else if (is_type_tuple(type)) { + GB_ASSERT(base->kind == Type_Tuple); + if (!is_type_named(type)) { + di->CompositeType.name = str_lit("tuple"); + GB_ASSERT_NOT_NULL(scope); + di->CompositeType.scope = scope; + } + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + di->CompositeType.elements = ir_add_debug_info_array(module, 0, base->Tuple.variables.count); + // TODO(lachsinc): Ensure offsets are set properly? + for_array(var_index, base->Tuple.variables) { + array_add(&di->CompositeType.elements->DebugInfoArray.elements, + ir_add_debug_info_field(module, di, base->Tuple.variables[var_index], type, + cast(i32)var_index, base->Tuple.variables[var_index]->type, file)); + } } return di; @@ -2250,6 +2277,10 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD return ir_add_debug_info_type_bit_set(module, type, e, scope, file); } + if (is_type_tuple(type)) { + int i = 0; + } + // // TODO(lachsinc): HACK For now any remaining types interpreted as a rawptr. // @@ -2267,9 +2298,9 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD } irDebugInfo *ir_add_debug_info_global(irModule *module, irValue *v) { - // if (!proc->module->generate_debug_info) { - // return nullptr; - // } + if (!module->generate_debug_info) { + return nullptr; + } Entity *e = v->Global.entity; @@ -2333,11 +2364,17 @@ irDebugInfo *ir_add_debug_info_block(irProcedure *proc, Scope *scope) { } irDebugInfo *ir_add_debug_info_local(irProcedure *proc, Entity *e, i32 arg_id) { + // TODO(lachsinc): Not sure if this handles generated locals properly as they may not have + // enough information inside "e". + irModule *module = proc->module; + if (!module->generate_debug_info) { + return nullptr; + } irDebugInfo *scope = nullptr; irDebugInfo *file = nullptr; - if (e->scope->node->kind == Ast_ProcType) { + if (e->scope && e->scope->node->kind == Ast_ProcType) { scope = proc->debug_scope; file = proc->debug_scope->Proc.file; } else { @@ -2360,9 +2397,10 @@ irDebugInfo *ir_add_debug_info_local(irProcedure *proc, Entity *e, i32 arg_id) { } irDebugInfo *ir_add_debug_info_proc(irProcedure *proc) { - // if (!proc->module->generate_debug_info) { - // return nullptr; - // } + irModule *module = proc->module; + if (!module->generate_debug_info) { + return nullptr; + } Entity *entity = proc->entity; @@ -8280,14 +8318,14 @@ void ir_begin_procedure_body(irProcedure *proc) { // NOTE(lachsinc): This is somewhat of a fallback/catch-all; We use the procedure's identifer as a debug location.. // Additional debug locations should be pushed for the procedures statements/expressions themselves. - if (proc->entity && proc->entity->identifier) { // TODO(lachsinc): Better way to determine if these procs are main/runtime_startup. + if (proc->module->generate_debug_info && proc->entity && proc->entity->identifier) { // TODO(lachsinc): Better way to determine if these procs are main/runtime_startup. // TODO(lachsinc): Passing the file for the scope may not be correct for nested procedures? This should probably be // handled all inside push_debug_location, with just the Ast * we can pull out everything we need to construct scope/file debug info etc. ir_add_debug_info_proc(proc); ir_push_debug_location(proc->module, proc->entity->identifier, proc->debug_scope); GB_ASSERT_NOT_NULL(proc->debug_scope); } else { - GB_ASSERT(proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0)); + // GB_ASSERT(proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0)); ir_push_debug_location(proc->module, nullptr, nullptr); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index a4b595289..33bfe440f 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2044,16 +2044,17 @@ void print_llvm_ir(irGen *ir) { } case irDebugInfo_LocalVariable: { ir_fprintf(f, "!DILocalVariable(" - "name: \"%.*s\"" - ", scope: !%d" + "scope: !%d" ", file: !%d" ", line: %d" ", type: !%d", - LIT(di->LocalVariable.name), di->LocalVariable.scope->id, di->LocalVariable.file->id, di->LocalVariable.pos.line, di->LocalVariable.type->id); + if (di->DerivedType.name.len > 0) { + ir_fprintf(f, ", name: \"%.*s\"", LIT(di->LocalVariable.name)); + } if (di->LocalVariable.arg > 0) { ir_fprintf(f, ", arg: %d", di->LocalVariable.arg); } From f881ebd00726d1bfb4540f7792cff3e8d1a33e4d Mon Sep 17 00:00:00 2001 From: lachsinc Date: Fri, 5 Oct 2018 14:51:08 +1000 Subject: [PATCH 34/39] Cleanup unused AllProcs. --- src/ir.cpp | 31 +++---------------------------- src/ir_print.cpp | 10 ---------- 2 files changed, 3 insertions(+), 38 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 47909a7bd..1996d19ad 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -549,7 +549,6 @@ struct irDebugInfo { struct { AstFile * file; String producer; - irDebugInfo *all_procs; irDebugInfo *enums; // DebugInfoArray irDebugInfo *globals; // DebugInfoArray } CompileUnit; @@ -581,10 +580,7 @@ struct irDebugInfo { irDebugInfo *file; irDebugInfo *scope; } LexicalBlock; - struct { - Array procs; - } AllProcs; // TODO(lachsinc): Redundant w/ DebugInfoArray. Merge. - + struct { String name; i32 size; @@ -8678,12 +8674,12 @@ void ir_init_module(irModule *m, Checker *c) { 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? + map_set(&m->debug_info, hash_pointer(enums_di), enums_di); m->debug_compile_unit->CompileUnit.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? + map_set(&m->debug_info, hash_pointer(globals_di), globals_di); m->debug_compile_unit->CompileUnit.globals = globals_di; array_init(&m->debug_location_stack, heap_allocator()); // TODO(lachsinc): ir_allocator() ?? @@ -9455,27 +9451,6 @@ void ir_gen_tree(irGen *s) { irDebugInfo *compile_unit = m->debug_info.entries[0].value; GB_ASSERT(compile_unit->kind == irDebugInfo_CompileUnit); - irDebugInfo *all_procs = ir_alloc_debug_info(irDebugInfo_AllProcs); - - isize all_proc_max_count = 0; - for_array(i, m->debug_info.entries) { - irDebugInfo *di = m->debug_info.entries[i].value; - if (di->kind == irDebugInfo_Proc) { - all_proc_max_count++; - } - } - - array_init(&all_procs->AllProcs.procs, ir_allocator(), 0, all_proc_max_count); - map_set(&m->debug_info, hash_pointer(all_procs), all_procs); // NOTE(bill): This doesn't need to be mapped - compile_unit->CompileUnit.all_procs = all_procs; - - - for_array(i, m->debug_info.entries) { - irDebugInfo *di = m->debug_info.entries[i].value; - if (di->kind == irDebugInfo_Proc) { - array_add(&all_procs->AllProcs.procs, di); - } - } #if defined(GB_SYSTEM_WINDOWS) diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 33bfe440f..e880f8c9c 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2147,16 +2147,6 @@ void print_llvm_ir(irGen *ir) { di->Enumerator.value); break; } - // TODO(lachsinc): Merge w/ DebugInfoArray - case irDebugInfo_AllProcs: - ir_fprintf(f, "!{"); - for_array(proc_index, di->AllProcs.procs) { - irDebugInfo *p = di->AllProcs.procs[proc_index]; - if (proc_index > 0) {ir_fprintf(f, ",");} - ir_fprintf(f, "!%d", p->id); - } - ir_write_byte(f, '}'); - break; case irDebugInfo_DebugInfoArray: ir_fprintf(f, "!{"); for_array(element_index, di->DebugInfoArray.elements) { From edc3a9392a35b7a3c90f6503617ccc2a1fb5a372 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Fri, 5 Oct 2018 15:03:13 +1000 Subject: [PATCH 35/39] Cleanup. --- src/ir.cpp | 41 +++++++++++++---------------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 1996d19ad..edf3ad3ba 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -522,17 +522,16 @@ enum irDebugInfoKind { irDebugInfo_CompileUnit, irDebugInfo_File, - irDebugInfo_Scope, irDebugInfo_Proc, irDebugInfo_Location, irDebugInfo_LexicalBlock, irDebugInfo_AllProcs, - irDebugInfo_BasicType, // basic types - irDebugInfo_DerivedType, // pointer, typedef - irDebugInfo_CompositeType, // array, struct, enum, (raw_)union + irDebugInfo_BasicType, // primitive types + irDebugInfo_DerivedType, // pointer, distinct etc. + irDebugInfo_CompositeType, // array, struct, enum, union etc. irDebugInfo_Enumerator, // For irDebugInfo_CompositeType if enum - irDebugInfo_GlobalVariableExpression, // for describe if global is const or not + irDebugInfo_GlobalVariableExpression, // used to describe if global is const or not irDebugInfo_GlobalVariable, irDebugInfo_LocalVariable, @@ -557,12 +556,6 @@ struct irDebugInfo { String filename; String directory; } File; - struct { - irDebugInfo *parent; - irDebugInfo *file; - TokenPos pos; - Scope * scope; // Actual scope - } Scope; struct { Entity * entity; String name; @@ -588,7 +581,6 @@ struct irDebugInfo { irDebugEncoding encoding; } BasicType; struct { - // TODO(lachsinc): Do derived types even need scope/file/line etc. info? irDebugEncoding tag; irDebugInfo * base_type; String name; @@ -1610,7 +1602,7 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { case Basic_i32: case Basic_i64: case Basic_int: - case Basic_rune: // TODO(lachsinc) signed or unsigned? + case Basic_rune: case Basic_typeid: return irDebugBasicEncoding_signed; @@ -1670,8 +1662,6 @@ irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Typ return di; } -// TODO(lachsinc): Cleanup params, either scope or scope_type, not both. -// Pass name, file, pos in manually? Would be much cleaner. irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entity *e, Type *scope_type, i32 index, Type *type, irDebugInfo *file) { // NOTE(lachsinc): This lookup will only work for struct fields!! // TODO(lachsinc): Do we even need to do this? @@ -1682,7 +1672,6 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit } } - // TODO(lachsinc): Cleanup irDebugInfo *di = ir_add_debug_info_field_internal(module, make_string(nullptr, 0), type, 0, e, scope); void *ptr_to_hash = nullptr; if (scope_type) { @@ -1722,7 +1711,6 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit } di->DerivedType.file = file; - // di->DerivedType.align = ir_debug_align_bits(type); GB_ASSERT_NOT_NULL(ptr_to_hash); map_set(&module->debug_info, hash_pointer(ptr_to_hash), di); @@ -1746,7 +1734,6 @@ irDebugInfo *ir_add_debug_info_enumerator(irModule *module, Entity *e) { return di; } -// TODO(lachsinc): Cleanup params. irDebugInfo *ir_add_debug_info_type_dynamic_array(irModule *module, Type *type, Entity *e, irDebugInfo *scope, irDebugInfo *file) { GB_ASSERT(type->kind == Type_DynamicArray); @@ -1810,8 +1797,7 @@ irDebugInfo *ir_add_debug_info_type_dynamic_array(irModule *module, Type *type, return di; } -// TODO(lachsinc): Cleanup params. -irDebugInfo *ir_add_debug_info_type_bit_field(irModule *module, Type *type, Entity *e, irDebugInfo *scope, irDebugInfo *file) { +irDebugInfo *ir_add_debug_info_type_bit_field(irModule *module, Type *type, Entity *e, irDebugInfo *scope) { GB_ASSERT(type->kind == Type_BitField || (type->kind == Type_Named && type->Named.base->kind == Type_BitField)); Type *bf_type = base_type(type); @@ -1838,7 +1824,8 @@ irDebugInfo *ir_add_debug_info_type_bit_field(irModule *module, Type *type, Enti if (field != nullptr && field->token.string.len > 0) { name = field->token.string; } - irDebugInfo *field_di = ir_add_debug_info_field_internal(module, name, t_i64, // TODO(lachsinc): Safe to use i64 for all bitfields? + // TODO(lachsinc): t_i64 may not be safe to use for all bitfields? + irDebugInfo *field_di = ir_add_debug_info_field_internal(module, name, t_i64, 0, nullptr, di); @@ -1853,8 +1840,7 @@ irDebugInfo *ir_add_debug_info_type_bit_field(irModule *module, Type *type, Enti return di; } -// TODO(lachsinc): Cleanup params. -irDebugInfo *ir_add_debug_info_type_bit_set(irModule *module, Type *type, Entity *e, irDebugInfo *scope, irDebugInfo *file) { +irDebugInfo *ir_add_debug_info_type_bit_set(irModule *module, Type *type, Entity *e, irDebugInfo *scope) { GB_ASSERT(type->kind == Type_BitSet || type->kind == Type_Named); Type *base = base_type(type); @@ -1905,8 +1891,7 @@ irDebugInfo *ir_add_debug_info_type_bit_set(irModule *module, Type *type, Entity return di; } -// TODO(lachsinc): Cleanup params. -irDebugInfo *ir_add_debug_info_type_string(irModule *module, irDebugInfo *scope, Entity *e, Type *type, irDebugInfo *file) { +irDebugInfo *ir_add_debug_info_type_string(irModule *module, irDebugInfo *scope, Entity *e, Type *type) { // TODO(lachsinc): Does this only occur once ?? irDebugInfo **existing = map_get(&module->debug_info, hash_type(t_string)); if (existing != nullptr) { @@ -2044,7 +2029,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD // TODO(lachsinc): break; } - case Basic_string: return ir_add_debug_info_type_string(module, scope, e, type, file); + case Basic_string: return ir_add_debug_info_type_string(module, scope, e, type); case Basic_any: return ir_add_debug_info_type_any(module); // Derived basic types @@ -2266,11 +2251,11 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD */ if (is_type_bit_field(type)) { - return ir_add_debug_info_type_bit_field(module, type, e, scope, file); + return ir_add_debug_info_type_bit_field(module, type, e, scope); } if (is_type_bit_set(type)) { - return ir_add_debug_info_type_bit_set(module, type, e, scope, file); + return ir_add_debug_info_type_bit_set(module, type, e, scope); } if (is_type_tuple(type)) { From 992502f03b347b10db3bf45e31e93a02ba2f9b82 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Fri, 5 Oct 2018 16:49:48 +1000 Subject: [PATCH 36/39] Add debug info for proc ptrs. --- src/ir.cpp | 125 ++++++++++++++++++++++++++++------------------- src/ir_print.cpp | 9 +++- 2 files changed, 83 insertions(+), 51 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index edf3ad3ba..406a1c544 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -523,6 +523,7 @@ enum irDebugInfoKind { irDebugInfo_CompileUnit, irDebugInfo_File, irDebugInfo_Proc, + irDebugInfo_ProcType, irDebugInfo_Location, irDebugInfo_LexicalBlock, irDebugInfo_AllProcs, @@ -561,9 +562,12 @@ struct irDebugInfo { String name; irDebugInfo * file; TokenPos pos; - irDebugInfo * types; // !{return, return, param, param, param.. etc.} + irDebugInfo * type; // TODO(lachsinc): variables / retainedNodes ? } Proc; + struct { + irDebugInfo * types; // !{return, return, param, param, param.. etc.} + } ProcType; struct { TokenPos pos; irDebugInfo *scope; @@ -1968,10 +1972,76 @@ irDebugInfo *ir_add_debug_info_type_any(irModule *module) { } } +irDebugInfo *ir_add_debug_info_proc_type(irModule *module, Type *type) { + GB_ASSERT(type->kind == Type_Proc); + + irDebugInfo **existing = map_get(&module->debug_info, hash_type(type)); + if (existing != nullptr) { + GB_ASSERT((*existing)->kind == irDebugInfo_ProcType); + return *existing; + } + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_ProcType); + map_set(&module->debug_info, hash_type(type), di); + + isize result_count = type->Proc.result_count; + isize param_count = type->Proc.param_count; + // gb_max(result_count, 1) because llvm expects explicit "null" return type + di->ProcType.types = ir_add_debug_info_array(module, 0, gb_max(result_count, 1) + param_count); + + // Result/return types + if (result_count >= 1) { + TypeTuple *results_tuple = &type->Proc.results->Tuple; + for_array(i, results_tuple->variables) { + Entity *e = results_tuple->variables[i]; + if (e->kind != Entity_Variable) { + continue; // TODO(lachsinc): Confirm correct? + } + + irDebugInfo *type_di = ir_add_debug_info_type(module, e->type, e, nullptr, nullptr); + GB_ASSERT_NOT_NULL(type_di); + array_add(&di->ProcType.types->DebugInfoArray.elements, type_di); + } + } else { + // llvm expects "!{null}" for a function without return type, use nullptr to represent it. + // TODO(lachsinc): Is there a specific "void" type we should refer to? + array_add(&di->ProcType.types->DebugInfoArray.elements, (irDebugInfo*)nullptr); + } + + // Param types + if (param_count >= 1) { + TypeTuple *params_tuple = &type->Proc.params->Tuple; + for_array(i, params_tuple->variables) { + Entity *e = params_tuple->variables[i]; + if (e->kind != Entity_Variable) { + continue; // TODO(lachsinc): Confirm correct? + } + + irDebugInfo *type_di = ir_add_debug_info_type(module, e->type, e, nullptr, nullptr); + GB_ASSERT_NOT_NULL(type_di); + array_add(&di->ProcType.types->DebugInfoArray.elements, type_di); + } + } + + return di; +} + irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irDebugInfo *scope, irDebugInfo *file) { - // if (!proc->module->generate_debug_info) { - // return nullptr; - // } + // NOTE(lachsinc): Special handling for procedure pointers - we hash their types directly into DISubroutineType's + // but we need them interpreted as pointers when we use them as variables. + if (type->kind == Type_Proc) { + if (e->kind == Entity_Variable || e->kind == Entity_TypeName) { + // TODO(lachsinc): Wasteful (maybe?). Create a derived type for _every_ different proc ptr type + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType); + map_set(&module->debug_info, hash_pointer(di), di); + di->DerivedType.tag = irDebugBasicEncoding_pointer_type; + di->DerivedType.size = ir_debug_size_bits(t_rawptr); + di->DerivedType.base_type = ir_add_debug_info_proc_type(module, type); + return di; + } else { + GB_PANIC("Proc definitions should have their type created manually (not through this function)"); + } + } irDebugInfo **existing = map_get(&module->debug_info, hash_type(type)); if (existing != nullptr) { @@ -2258,10 +2328,6 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD return ir_add_debug_info_type_bit_set(module, type, e, scope); } - if (is_type_tuple(type)) { - int i = 0; - } - // // TODO(lachsinc): HACK For now any remaining types interpreted as a rawptr. // @@ -2396,53 +2462,14 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc) { irDebugInfo *scope = file; // TODO(lachsinc): Should scope be made separate to file? irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_Proc); + map_set(&proc->module->debug_info, hash_entity(entity), di); di->Proc.entity = entity; di->Proc.name = proc->name; di->Proc.file = file; di->Proc.pos = entity->token.pos; - - isize result_count = proc->type->Proc.result_count; - isize param_count = proc->type->Proc.param_count; - // gb_max(result_count, 1) because llvm expects explicit "null" return type - di->Proc.types = ir_add_debug_info_array(proc->module, 0, gb_max(result_count, 1) + param_count); - - // Result/return types - if (result_count >= 1) { - TypeTuple *results_tuple = &proc->type->Proc.results->Tuple; - for_array(i, results_tuple->variables) { - Entity *e = results_tuple->variables[i]; - if (e->kind != Entity_Variable) { - continue; // TODO(lachsinc): Confirm correct? - } - - irDebugInfo *type_di = ir_add_debug_info_type(proc->module, e->type, e, nullptr, nullptr); - GB_ASSERT_NOT_NULL(type_di); - array_add(&di->Proc.types->DebugInfoArray.elements, type_di); - } - } else { - // llvm expects "!{null}" for a function without return type, use nullptr to represent it. - // TODO(lachsinc): Is there a specific "void" type we should refer to? - array_add(&di->Proc.types->DebugInfoArray.elements, (irDebugInfo*)nullptr); - } - - // Param types - if (param_count >= 1) { - TypeTuple *params_tuple = &proc->type->Proc.params->Tuple; - for_array(i, params_tuple->variables) { - Entity *e = params_tuple->variables[i]; - if (e->kind != Entity_Variable) { - continue; // TODO(lachsinc): Confirm correct? - } - - irDebugInfo *type_di = ir_add_debug_info_type(proc->module, e->type, e, nullptr, nullptr); - GB_ASSERT_NOT_NULL(type_di); - array_add(&di->Proc.types->DebugInfoArray.elements, type_di); - } - } + di->Proc.type = ir_add_debug_info_proc_type(proc->module, proc->type); proc->debug_scope = di; - - map_set(&proc->module->debug_info, hash_entity(entity), di); return di; } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index e880f8c9c..ef7e701da 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1964,6 +1964,7 @@ void print_llvm_ir(irGen *ir) { break; case irDebugInfo_Proc: // TODO(lachsinc): We need to store scope info inside di, not just file info, for procs. + // Should all subprograms have distinct ?? ir_fprintf(f, "distinct !DISubprogram(" "name: \"%.*s\"" ", linkageName: \"%.*s\"" @@ -1976,7 +1977,7 @@ void print_llvm_ir(irGen *ir) { ", flags: DIFlagPrototyped" ", isOptimized: false" ", unit: !%d" - ", type: !DISubroutineType(types: !%d)", + ", type: !%d", LIT(di->Proc.entity->token.string), LIT(di->Proc.name), di->Proc.file->id, // TODO(lachsinc): HACK For now lets pretend all procs scope's == file. @@ -1984,9 +1985,13 @@ void print_llvm_ir(irGen *ir) { di->Proc.pos.line, di->Proc.pos.line, // NOTE(lachsinc): Assume scopeLine always same as line. m->debug_compile_unit->id, - di->Proc.types->id); + di->Proc.type->id); ir_write_byte(f, ')'); // !DISubprogram( break; + case irDebugInfo_ProcType: + ir_fprintf(f, "!DISubroutineType(types: !%d)", + di->ProcType.types->id); + break; case irDebugInfo_Location: GB_ASSERT_NOT_NULL(di->Location.scope); ir_fprintf(f, "!DILocation(" From 39db428603a81d2190e51ea79692a95fc4aa722d Mon Sep 17 00:00:00 2001 From: lachsinc Date: Fri, 5 Oct 2018 17:10:58 +1000 Subject: [PATCH 37/39] Add complex debug info. --- src/ir.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 16 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 406a1c544..82fcb088c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1972,6 +1972,47 @@ irDebugInfo *ir_add_debug_info_type_any(irModule *module) { } } +irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) { + GB_ASSERT(type->kind == Type_Basic && is_type_complex(type)); + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + map_set(&module->debug_info, hash_type(type), di); + + di->CompositeType.name = type->Basic.name; + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + di->CompositeType.size = ir_debug_size_bits(type); + + Type *field_type = nullptr; + if (type->Basic.kind == Basic_complex64) { + field_type = t_f32; + } else if (type->Basic.kind == Basic_complex128) { + field_type = t_f64; + } else { + GB_PANIC("Unreachable"); + } + + // Field "real" + irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, + 0, + nullptr, + di); + map_set(&module->debug_info, hash_pointer(real_di), real_di); + + // Field "imag" + irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type, + real_di->DerivedType.size, + nullptr, + di); + map_set(&module->debug_info, hash_pointer(imag_di), imag_di); + + irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 2); + array_add(&elements_di->DebugInfoArray.elements, real_di); + array_add(&elements_di->DebugInfoArray.elements, imag_di); + di->CompositeType.elements = elements_di; + map_set(&module->debug_info, hash_pointer(elements_di), elements_di); + + return di; +} irDebugInfo *ir_add_debug_info_proc_type(irModule *module, Type *type) { GB_ASSERT(type->kind == Type_Proc); @@ -2095,12 +2136,9 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD switch (type->Basic.kind) { // Composite basic types case Basic_complex64: - case Basic_complex128: { - // TODO(lachsinc): - break; - } - case Basic_string: return ir_add_debug_info_type_string(module, scope, e, type); - case Basic_any: return ir_add_debug_info_type_any(module); + case Basic_complex128: return ir_add_debug_info_type_complex(module, type); + case Basic_string: return ir_add_debug_info_type_string(module, scope, e, type); + case Basic_any: return ir_add_debug_info_type_any(module); // Derived basic types case Basic_cstring: @@ -2165,7 +2203,7 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD di->CompositeType.pos = e->token.pos; } di->CompositeType.size = ir_debug_size_bits(type); - di->CompositeType.align = ir_debug_align_bits(type); // TODO(lachsinc): Necessary? + // di->CompositeType.align = ir_debug_align_bits(type); // TODO(lachsinc): Necessary? if (is_type_struct(type)) { GB_ASSERT(base->kind == Type_Struct); @@ -2328,20 +2366,23 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD return ir_add_debug_info_type_bit_set(module, type, e, scope); } + GB_PANIC("Unreachable"); + return nullptr; + // // TODO(lachsinc): HACK For now any remaining types interpreted as a rawptr. // - { - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); - di->BasicType.align = ir_debug_align_bits(type); - di->BasicType.encoding = irDebugBasicEncoding_address; - di->BasicType.name = str_lit("type_todo"); - di->BasicType.size = ir_debug_size_bits(type); + // { + // irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); + // di->BasicType.align = ir_debug_align_bits(type); + // di->BasicType.encoding = irDebugBasicEncoding_address; + // di->BasicType.name = str_lit("type_todo"); + // di->BasicType.size = ir_debug_size_bits(type); - map_set(&module->debug_info, hash_type(type), di); + // map_set(&module->debug_info, hash_type(type), di); - return di; - } + // return di; + // } } irDebugInfo *ir_add_debug_info_global(irModule *module, irValue *v) { From b6ca913cff6ff6073806a83ab6117109c8d28e6a Mon Sep 17 00:00:00 2001 From: lachsinc Date: Fri, 5 Oct 2018 17:12:45 +1000 Subject: [PATCH 38/39] Cleanup hack as all types appear to be handled!.. --- src/ir.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 82fcb088c..efd2ad1b3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2368,21 +2368,6 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD GB_PANIC("Unreachable"); return nullptr; - - // - // TODO(lachsinc): HACK For now any remaining types interpreted as a rawptr. - // - // { - // irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_BasicType); - // di->BasicType.align = ir_debug_align_bits(type); - // di->BasicType.encoding = irDebugBasicEncoding_address; - // di->BasicType.name = str_lit("type_todo"); - // di->BasicType.size = ir_debug_size_bits(type); - - // map_set(&module->debug_info, hash_type(type), di); - - // return di; - // } } irDebugInfo *ir_add_debug_info_global(irModule *module, irValue *v) { From d894fb37087a100eeea2a0de1da89bda390e1306 Mon Sep 17 00:00:00 2001 From: lachsinc Date: Sat, 6 Oct 2018 09:09:12 +1000 Subject: [PATCH 39/39] Cleanup comments. --- src/ir.cpp | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index efd2ad1b3..e9fecd4d0 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1668,7 +1668,6 @@ irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Typ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entity *e, Type *scope_type, i32 index, Type *type, irDebugInfo *file) { // NOTE(lachsinc): This lookup will only work for struct fields!! - // TODO(lachsinc): Do we even need to do this? if (e) { irDebugInfo **existing = map_get(&module->debug_info, hash_entity(e)); if (existing != nullptr) { @@ -1710,7 +1709,7 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit if (is_type_named(type)) { di->DerivedType.name = type->kind == Type_Named ? type->Named.name : type->Basic.name; } - ptr_to_hash = di; // TODO(lachsinc): Correct ?? I don't think unions have individual entities for their fields?? idk. + ptr_to_hash = di; } } @@ -1741,9 +1740,6 @@ irDebugInfo *ir_add_debug_info_enumerator(irModule *module, Entity *e) { irDebugInfo *ir_add_debug_info_type_dynamic_array(irModule *module, Type *type, Entity *e, irDebugInfo *scope, irDebugInfo *file) { GB_ASSERT(type->kind == Type_DynamicArray); - // TODO(lachsinc): We should insert "type" into map and look it up, and just create a derived type - // for each required dynamic array, named or unnamed. - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); di->CompositeType.name = str_lit("dynamic_array"); // TODO(lachsinc): [dynamic] .. type->DynamicArray.elem name di->CompositeType.tag = irDebugBasicEncoding_structure_type; @@ -1810,7 +1806,6 @@ irDebugInfo *ir_add_debug_info_type_bit_field(irModule *module, Type *type, Enti di->CompositeType.name = is_type_named(type) ? type->Named.name : str_lit("bit_field"); di->CompositeType.tag = irDebugBasicEncoding_structure_type; di->CompositeType.size = ir_debug_size_bits(bf_type); - // di->CompositeType.align = ir_debug_align_bits(bf_type); map_set(&module->debug_info, hash_type(type), di); GB_ASSERT(bf_type->BitField.fields.count == bf_type->BitField.offsets.count && @@ -1833,7 +1828,8 @@ irDebugInfo *ir_add_debug_info_type_bit_field(irModule *module, Type *type, Enti 0, nullptr, di); - // NOTE(lachsinc): Above calls BitFieldValues type_size_of() which returns size in bits, replace with its true bit value here.. + // NOTE(lachsinc): Above calls BitFieldValues type_size_of() which returns size in bits, + // replace with its true bit value here.. field_di->DerivedType.size = size; field_di->DerivedType.offset = offset; // Offset stored in bits already, no need to convert field_di->DerivedType.flags = irDebugInfoFlag_Bitfield; @@ -1867,7 +1863,6 @@ irDebugInfo *ir_add_debug_info_type_bit_set(irModule *module, Type *type, Entity di->CompositeType.name = named != nullptr ? named->Named.name : str_lit("bit_set"); di->CompositeType.tag = irDebugBasicEncoding_structure_type; di->CompositeType.size = ir_debug_size_bits(base); - // di->CompositeType.align = ir_debug_align_bits(base); map_set(&module->debug_info, hash_type(type), di); irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, base->BitSet.upper + 1); @@ -1943,7 +1938,7 @@ irDebugInfo *ir_add_debug_info_type_any(irModule *module) { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); di->CompositeType.name = t_any->Basic.name; di->CompositeType.tag = irDebugBasicEncoding_structure_type; - di->CompositeType.size = ir_debug_size_bits(t_any); // TODO(lachsinc): Correct ?? + di->CompositeType.size = ir_debug_size_bits(t_any); di->CompositeType.align = ir_debug_align_bits(t_any); map_set(&module->debug_info, hash_type(t_any), di); @@ -2013,6 +2008,7 @@ irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) { return di; } + irDebugInfo *ir_add_debug_info_proc_type(irModule *module, Type *type) { GB_ASSERT(type->kind == Type_Proc); @@ -2036,7 +2032,7 @@ irDebugInfo *ir_add_debug_info_proc_type(irModule *module, Type *type) { for_array(i, results_tuple->variables) { Entity *e = results_tuple->variables[i]; if (e->kind != Entity_Variable) { - continue; // TODO(lachsinc): Confirm correct? + continue; } irDebugInfo *type_di = ir_add_debug_info_type(module, e->type, e, nullptr, nullptr); @@ -2045,7 +2041,6 @@ irDebugInfo *ir_add_debug_info_proc_type(irModule *module, Type *type) { } } else { // llvm expects "!{null}" for a function without return type, use nullptr to represent it. - // TODO(lachsinc): Is there a specific "void" type we should refer to? array_add(&di->ProcType.types->DebugInfoArray.elements, (irDebugInfo*)nullptr); } @@ -2055,7 +2050,7 @@ irDebugInfo *ir_add_debug_info_proc_type(irModule *module, Type *type) { for_array(i, params_tuple->variables) { Entity *e = params_tuple->variables[i]; if (e->kind != Entity_Variable) { - continue; // TODO(lachsinc): Confirm correct? + continue; } irDebugInfo *type_di = ir_add_debug_info_type(module, e->type, e, nullptr, nullptr); @@ -2296,7 +2291,6 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD if (is_type_slice(type)) { // NOTE(lachsinc): Every slice type has its own composite type / field debug infos created. This is sorta wasteful. - irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); di->CompositeType.name = str_lit("slice"); di->CompositeType.tag = irDebugBasicEncoding_structure_type; @@ -2416,8 +2410,6 @@ irDebugInfo *ir_add_debug_info_global(irModule *module, irValue *v) { } irDebugInfo *ir_add_debug_info_block(irProcedure *proc, Scope *scope) { - // GB_ASSERT(block->kind == Ast_BlockStmt); - irModule *module = proc->module; irDebugInfo **existing = map_get(&module->debug_info, hash_pointer(scope)); @@ -2438,7 +2430,7 @@ irDebugInfo *ir_add_debug_info_block(irProcedure *proc, Scope *scope) { irDebugInfo *ir_add_debug_info_local(irProcedure *proc, Entity *e, i32 arg_id) { // TODO(lachsinc): Not sure if this handles generated locals properly as they may not have - // enough information inside "e". + // enough information contained inside "e". irModule *module = proc->module; if (!module->generate_debug_info) { @@ -2463,7 +2455,7 @@ irDebugInfo *ir_add_debug_info_local(irProcedure *proc, Entity *e, i32 arg_id) { di->LocalVariable.file = file; di->LocalVariable.pos = e->token.pos; di->LocalVariable.arg = arg_id; - di->LocalVariable.type = ir_add_debug_info_type(module, e->type, e, scope, file); // TODO(lachsinc): Is this the correct entity to pass? Or do we want TypeName ?? + di->LocalVariable.type = ir_add_debug_info_type(module, e->type, e, scope, file); // TODO(lachsinc): Is this the correct entity to pass? Or do we want a TypeName ?? map_set(&module->debug_info, hash_entity(e), di); return di; @@ -2485,7 +2477,8 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc) { if (f) { file = ir_add_debug_info_file(proc->module, f); } - irDebugInfo *scope = file; // TODO(lachsinc): Should scope be made separate to file? + // TODO(lachsinc): Should scope be made separate to file? + irDebugInfo *scope = file; irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_Proc); map_set(&proc->module->debug_info, hash_entity(entity), di); @@ -2501,10 +2494,8 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc) { irDebugInfo *ir_add_debug_info_location(irModule *m, Ast *node, irDebugInfo *scope) { if (node == nullptr || scope == nullptr) { - // GB_ASSERT(proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0)); return nullptr; } - // GB_ASSERT(node->kind != Ast_BlockStmt); // TODO(lachsinc): Should we traverse the node/children until we find one with // valid token/pos and use that instead?? irDebugInfo **existing = map_get(&m->debug_info, hash_node(node)); @@ -2574,7 +2565,6 @@ void ir_value_set_debug_location(irProcedure *proc, irValue *v) { 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); if (v->loc == nullptr) { // NOTE(lachsinc): Entry point (main()) and runtime_startup are the only ones where null location is considered valid. @@ -8585,7 +8575,7 @@ 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. + // ir_value_global itself doesn't have access to module though. if (v->kind == irValue_Global && v->Global.value != nullptr && e->state == EntityState_Resolved) { ir_add_debug_info_global(m, v); }