diff options
Diffstat (limited to 'src/ir.cpp')
| -rw-r--r-- | src/ir.cpp | 323 |
1 files changed, 173 insertions, 150 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<irDebugInfo *> 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<irDebugInfo *> 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<irDebugInfo *> 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<irDebugInfo *> 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); |