aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp259
1 files changed, 248 insertions, 11 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<irDebugInfo *> return_types;
+ // TODO(lachsinc): variables / retainedNodes ?
} Proc;
struct {
Array<irDebugInfo *> 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<irDebugInfo *> 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<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.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<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);