mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Provide llvm ir with more debug info (for Visual Studio debugger support).
This commit is contained in:
+248
-11
@@ -505,6 +505,9 @@ enum irDebugEncoding {
|
|||||||
irDebugBasicEncoding_unsigned = 6,
|
irDebugBasicEncoding_unsigned = 6,
|
||||||
irDebugBasicEncoding_unsigned_char = 7,
|
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_member = 13,
|
||||||
irDebugBasicEncoding_pointer_type = 15,
|
irDebugBasicEncoding_pointer_type = 15,
|
||||||
irDebugBasicEncoding_typedef = 22,
|
irDebugBasicEncoding_typedef = 22,
|
||||||
@@ -559,15 +562,18 @@ struct irDebugInfo {
|
|||||||
Scope * scope; // Actual scope
|
Scope * scope; // Actual scope
|
||||||
} Scope;
|
} Scope;
|
||||||
struct {
|
struct {
|
||||||
Entity * entity;
|
Entity * entity;
|
||||||
String name;
|
String name;
|
||||||
irDebugInfo *file;
|
irDebugInfo * file;
|
||||||
TokenPos pos;
|
TokenPos pos;
|
||||||
|
Array<irDebugInfo *> return_types;
|
||||||
|
// TODO(lachsinc): variables / retainedNodes ?
|
||||||
} Proc;
|
} Proc;
|
||||||
struct {
|
struct {
|
||||||
Array<irDebugInfo *> procs;
|
Array<irDebugInfo *> procs;
|
||||||
} AllProcs;
|
} AllProcs;
|
||||||
|
|
||||||
|
// NOTE(lachsinc): Many of the following fields could be removed/resolved as we print it?
|
||||||
struct {
|
struct {
|
||||||
String name;
|
String name;
|
||||||
i32 size;
|
i32 size;
|
||||||
@@ -577,17 +583,26 @@ struct irDebugInfo {
|
|||||||
struct {
|
struct {
|
||||||
irDebugInfo * return_type;
|
irDebugInfo * return_type;
|
||||||
Array<irDebugInfo *> param_types;
|
Array<irDebugInfo *> param_types;
|
||||||
} ProcType;
|
} ProcType; // TODO(lachsinc): Unused?
|
||||||
struct {
|
struct {
|
||||||
|
irDebugEncoding tag;
|
||||||
|
String name;
|
||||||
|
irDebugInfo * scope;
|
||||||
|
irDebugInfo * file;
|
||||||
|
TokenPos pos;
|
||||||
irDebugInfo * base_type;
|
irDebugInfo * base_type;
|
||||||
irDebugEncoding encoding;
|
i32 size;
|
||||||
|
i32 align;
|
||||||
|
i32 offset;
|
||||||
} DerivedType;
|
} DerivedType;
|
||||||
struct {
|
struct {
|
||||||
irDebugEncoding encoding;
|
irDebugEncoding tag;
|
||||||
String name;
|
String name;
|
||||||
String identifier;
|
String identifier; // TODO(lachsinc): Unused?
|
||||||
|
irDebugInfo * scope;
|
||||||
irDebugInfo * file;
|
irDebugInfo * file;
|
||||||
TokenPos pos;
|
TokenPos pos;
|
||||||
|
irDebugInfo * base_type; // optional, used for enumeration_type.
|
||||||
i32 size;
|
i32 size;
|
||||||
i32 align;
|
i32 align;
|
||||||
Array<irDebugInfo *> elements;
|
Array<irDebugInfo *> 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.is_addr = is_addr;
|
||||||
v->Instr.DebugDeclare.value = value;
|
v->Instr.DebugDeclare.value = value;
|
||||||
return v;
|
return v;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1382,6 +1396,8 @@ void ir_push_context_onto_stack(irProcedure *proc, irValue *ctx) {
|
|||||||
array_add(&proc->context_stack, cd);
|
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) {
|
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
|
irBlock *b = proc->decl_block; // all variables must be in the first block
|
||||||
irValue *instr = ir_instr_local(proc, e, true);
|
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) {
|
if (expr != nullptr && proc->entity != nullptr) {
|
||||||
irDebugInfo *di = *map_get(&proc->module->debug_info, hash_entity(proc->entity));
|
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));
|
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;
|
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) {
|
irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) {
|
||||||
// if (!proc->module->generate_debug_info) {
|
// if (!proc->module->generate_debug_info) {
|
||||||
// return nullptr;
|
// return nullptr;
|
||||||
@@ -1534,32 +1558,245 @@ irDebugInfo *ir_add_debug_info_file(irProcedure *proc, AstFile *file) {
|
|||||||
return di;
|
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) {
|
irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String name, irDebugInfo *file) {
|
||||||
// if (!proc->module->generate_debug_info) {
|
// if (!proc->module->generate_debug_info) {
|
||||||
// return nullptr;
|
// return nullptr;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
GB_ASSERT(entity != nullptr);
|
|
||||||
irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_Proc);
|
irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_Proc);
|
||||||
di->Proc.entity = entity;
|
di->Proc.entity = entity;
|
||||||
di->Proc.name = name;
|
di->Proc.name = name;
|
||||||
di->Proc.file = file;
|
di->Proc.file = file;
|
||||||
di->Proc.pos = entity->token.pos;
|
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;
|
proc->debug_scope = di;
|
||||||
|
|
||||||
map_set(&proc->module->debug_info, hash_entity(entity), di);
|
map_set(&proc->module->debug_info, hash_entity(entity), di);
|
||||||
return di;
|
return di;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// @Emit
|
// @Emit
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
irValue *ir_emit_runtime_call (irProcedure *proc, char const *name_, Array<irValue *> args, Ast *expr = nullptr);
|
irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array<irValue *> args, Ast *expr = nullptr);
|
||||||
irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array<irValue *> args, Ast *expr = nullptr);
|
irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array<irValue *> args, Ast *expr = nullptr);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+134
-10
@@ -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_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type);
|
||||||
|
|
||||||
void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type *elem_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;
|
String name = e->token.string;
|
||||||
TokenPos pos = e->token.pos;
|
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, "call void @llvm.dbg.declare(");
|
||||||
ir_write_str_lit(f, "metadata ");
|
ir_write_str_lit(f, "metadata ");
|
||||||
ir_print_type(f, m, vt);
|
ir_print_type(f, m, vt);
|
||||||
ir_write_byte(f, ' ');
|
ir_write_byte(f, ' ');
|
||||||
ir_print_value(f, m, dd->value, vt);
|
ir_print_value(f, m, dd->value, vt);
|
||||||
ir_write_str_lit(f, ", metadata !DILocalVariable(name: \"");
|
ir_fprintf(f, ", metadata !%d", local_var_di->id);
|
||||||
ir_print_escape_string(f, name, false, false);
|
ir_write_str_lit(f, ", metadata !DIExpression())");
|
||||||
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, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, di->id);
|
ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, di->id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1764,7 +1795,7 @@ void print_llvm_ir(irGen *ir) {
|
|||||||
ir_print_type(f, m, t_typeid);
|
ir_print_type(f, m, t_typeid);
|
||||||
ir_write_str_lit(f, "} ; Basic_any\n");
|
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');
|
ir_write_byte(f, '\n');
|
||||||
|
|
||||||
|
|
||||||
@@ -1875,9 +1906,11 @@ void print_llvm_ir(irGen *ir) {
|
|||||||
ir_write_byte(f, '\n');
|
ir_write_byte(f, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(lachsinc): Attribute map inside ir module?
|
||||||
ir_fprintf(f, "attributes #0 = {nounwind uwtable}\n");
|
ir_fprintf(f, "attributes #0 = {nounwind uwtable}\n");
|
||||||
ir_fprintf(f, "attributes #1 = {nounwind alwaysinline 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 #2 = {nounwind noinline optnone uwtable}\n");
|
||||||
|
ir_fprintf(f, "attributes #3 = {nounwind readnone}\n");
|
||||||
|
|
||||||
if (m->generate_debug_info) {
|
if (m->generate_debug_info) {
|
||||||
ir_write_byte(f, '\n');
|
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?
|
"language: DW_LANG_C_plus_plus" // Is this good enough?
|
||||||
", file: !%d"
|
", file: !%d"
|
||||||
", producer: \"Odin %.*s\""
|
", producer: \"Odin %.*s\""
|
||||||
", flags: \"\""
|
// ", flags: \"\"" // TODO(lachsinc): Removed for now, check if correct
|
||||||
", runtimeVersion: 0"
|
", runtimeVersion: 0"
|
||||||
", isOptimized: false"
|
", isOptimized: false"
|
||||||
", emissionKind: FullDebug"
|
", emissionKind: FullDebug"
|
||||||
@@ -1938,13 +1971,104 @@ void print_llvm_ir(irGen *ir) {
|
|||||||
", flags: DIFlagPrototyped"
|
", flags: DIFlagPrototyped"
|
||||||
", isOptimized: false"
|
", isOptimized: false"
|
||||||
", unit: !%d"
|
", unit: !%d"
|
||||||
")",
|
", type: !DISubroutineType(types: !{",
|
||||||
LIT(di->Proc.entity->token.string),
|
LIT(di->Proc.entity->token.string),
|
||||||
LIT(di->Proc.name),
|
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);
|
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;
|
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:
|
case irDebugInfo_AllProcs:
|
||||||
ir_fprintf(f, "!{");
|
ir_fprintf(f, "!{");
|
||||||
for_array(proc_index, di->AllProcs.procs) {
|
for_array(proc_index, di->AllProcs.procs) {
|
||||||
|
|||||||
+12
-2
@@ -661,6 +661,9 @@ void remove_temp_files(String output_base) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
i32 exec_llvm_opt(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)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
// For more passes arguments: http://llvm.org/docs/Passes.html
|
// For more passes arguments: http://llvm.org/docs/Passes.html
|
||||||
return system_exec_command_line_app("llvm-opt", false,
|
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) {
|
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)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
||||||
return system_exec_command_line_app("llvm-llc", false,
|
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\" "
|
"-o \"%.*s.obj\" "
|
||||||
"%.*s "
|
"%.*s "
|
||||||
"",
|
"",
|
||||||
LIT(build_context.ODIN_ROOT),
|
LIT(build_context.ODIN_ROOT),
|
||||||
LIT(output_base),
|
LIT(output_base),
|
||||||
|
build_context.ODIN_DEBUG ? ".ll" : ".bc",
|
||||||
build_context.optimization_level,
|
build_context.optimization_level,
|
||||||
LIT(output_base),
|
LIT(output_base),
|
||||||
LIT(build_context.llc_flags));
|
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.
|
// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
|
||||||
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
||||||
return system_exec_command_line_app("llc", false,
|
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 "
|
||||||
"%s"
|
"%s"
|
||||||
"",
|
"",
|
||||||
LIT(output_base),
|
LIT(output_base),
|
||||||
|
build_context.ODIN_DEBUG ? ".ll" : ".bc",
|
||||||
build_context.optimization_level,
|
build_context.optimization_level,
|
||||||
LIT(build_context.llc_flags),
|
LIT(build_context.llc_flags),
|
||||||
str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : "");
|
str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : "");
|
||||||
|
|||||||
Reference in New Issue
Block a user