diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index db759b767..798f51bb3 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -396,6 +396,8 @@ gb_internal cgModule *cg_module_create(Checker *c) { map_init(&m->file_id_map); + map_init(&m->debug_type_map); + for_array(id, global_files) { if (AstFile *f = global_files[id]) { @@ -411,6 +413,7 @@ gb_internal void cg_module_destroy(cgModule *m) { map_destroy(&m->values); array_free(&m->procedures_to_generate); map_destroy(&m->file_id_map); + map_destroy(&m->debug_type_map); tb_module_destroy(m->mod); } diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index b2192cce4..032229193 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -176,6 +176,9 @@ struct cgModule { PtrMap procedure_values; Array procedures_to_generate; + RecursiveMutex debug_type_mutex; + PtrMap debug_type_map; + PtrMap file_id_map; // Key: AstFile.id (i32 cast to uintptr) std::atomic nested_type_name_guid; diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index af9bee189..49af695ee 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -409,7 +409,7 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { } // TB_Node *ptr = tb_inst_param_addr(p->func, param_index); - TB_Node *param = tb_inst_param(p->func, param_index); + TB_Node *param = tb_inst_param(p->func, param_index++); TB_Node *ptr = tb_inst_local(p->func, cast(TB_CharUnits)type_size_of(e->type), cast(TB_CharUnits)type_align_of(e->type)); TB_DataType dt = cg_data_type(e->type); tb_inst_store(p->func, dt, ptr, param, cast(TB_CharUnits)type_align_of(e->type), false); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 6c0e8cf76..4e49199f9 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -629,7 +629,345 @@ gb_internal void cg_pop_target_list(cgProcedure *p) { p->target_list = p->target_list->prev; } +gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type); gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type) { + mutex_lock(&m->debug_type_mutex); + defer (mutex_unlock(&m->debug_type_mutex)); + TB_DebugType **found = map_get(&m->debug_type_map, type); + if (found) { + return *found; + } + + TB_DebugType *res = cg_debug_type_internal(m, type); + map_set(&m->debug_type_map, type, res); + return res; +} + +gb_internal TB_DebugType *cg_debug_type_internal_record(cgModule *m, Type *type, String const &record_name) { + Type *bt = base_type(type); + switch (bt->kind) { + case Type_Struct: + { + type_set_offsets(bt); + + TB_DebugType *record = nullptr; + if (bt->Struct.is_raw_union) { + record = tb_debug_create_union(m->mod, record_name.len, cast(char const *)record_name.text); + } else { + record = tb_debug_create_struct(m->mod, record_name.len, cast(char const *)record_name.text); + } + if (record_name.len != 0) { + map_set(&m->debug_type_map, type, record); + } + + TB_DebugType **fields = tb_debug_record_begin(record, bt->Struct.fields.count); + for_array(i, bt->Struct.fields) { + Entity *e = bt->Struct.fields[i]; + Type *type = e->type; + if (is_type_proc(type)) { + type = t_rawptr; + } + TB_DebugType *field_type = cg_debug_type(m, type); + String name = e->token.string; + TB_CharUnits offset = cast(TB_CharUnits)bt->Struct.offsets[i]; + if (name.len == 0) { + name = str_lit("_"); + } + + fields[i] = tb_debug_create_field(m->mod, field_type, name.len, cast(char const *)name.text, offset); + } + tb_debug_record_end( + record, + cast(TB_CharUnits)type_size_of(type), + cast(TB_CharUnits)type_align_of(type) + ); + return record; + } + break; + case Type_Union: + { + TB_DebugType *record = tb_debug_create_struct(m->mod, record_name.len, cast(char const *)record_name.text); + if (record_name.len != 0) { + map_set(&m->debug_type_map, type, record); + } + + i64 variant_count = bt->Union.variants.count; + if (is_type_union_maybe_pointer(bt)) { + // NO TAG + GB_ASSERT(variant_count == 1); + TB_DebugType **fields = tb_debug_record_begin(record, variant_count); + TB_DebugType *variant_type = cg_debug_type(m, bt->Union.variants[0]); + fields[0] = tb_debug_create_field(m->mod, variant_type, -1, "v0", 0); + tb_debug_record_end( + record, + cast(TB_CharUnits)type_size_of(type), + cast(TB_CharUnits)type_align_of(type) + ); + } else { + TB_DebugType **fields = tb_debug_record_begin(record, variant_count+1); + for_array(i, bt->Union.variants) { + Type *v = bt->Union.variants[i]; + TB_DebugType *variant_type = cg_debug_type(m, v); + char name[32] = {}; + u32 v_index = cast(u32)i; + if (bt->Union.kind != UnionType_no_nil) { + v_index += 1; + } + gb_snprintf(name, 31, "v%u", v_index); + fields[i] = tb_debug_create_field(m->mod, variant_type, -1, name, 0); + } + + TB_DebugType *tag_type = cg_debug_type(m, union_tag_type(bt)); + fields[variant_count] = tb_debug_create_field(m->mod, tag_type, -1, "tag", cast(TB_CharUnits)bt->Union.variant_block_size); + + } + tb_debug_record_end( + record, + cast(TB_CharUnits)type_size_of(type), + cast(TB_CharUnits)type_align_of(type) + ); + return record; + } + break; + } + return nullptr; +} + + +gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type) { + if (type == nullptr) { + return tb_debug_get_void(m->mod); + } + if (type->kind == Type_Named) { + String name = type->Named.name; + TB_DebugType *res = cg_debug_type_internal_record(m, type, name); + if (res) { + return res; + } + type = base_type(type->Named.base); + } + + TB_CharUnits int_size = cast(TB_CharUnits)build_context.int_size; + TB_CharUnits ptr_size = cast(TB_CharUnits)build_context.ptr_size; + TB_CharUnits size = cast(TB_CharUnits)type_size_of(type); + TB_CharUnits align = cast(TB_CharUnits)type_align_of(type); + int bits = cast(int)(8*size); + bool is_signed = is_type_integer(core_type(type)) && !is_type_unsigned(core_type(type)); + + switch (type->kind) { + case Type_Basic: + switch (type->Basic.kind) { + case Basic_bool: return tb_debug_get_bool(m->mod); + case Basic_b8: return tb_debug_get_bool(m->mod); + case Basic_b16: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_b32: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_b64: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i8: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u8: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i16: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u16: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i32: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u32: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i64: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u64: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i128: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_u128: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_rune: return tb_debug_get_integer(m->mod, is_signed, bits); + + case Basic_f16: return tb_debug_get_integer(m->mod, false, bits); + case Basic_f32: return tb_debug_get_float(m->mod, TB_FLT_32); + case Basic_f64: return tb_debug_get_float(m->mod,TB_FLT_64); + + case Basic_complex32: + case Basic_complex64: + case Basic_complex128: + { + String name = basic_types[type->Basic.kind].Basic.name; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + Type *et = base_complex_elem_type(type); + TB_CharUnits elem_size = cast(TB_CharUnits)type_size_of(et); + TB_DebugType *elem = cg_debug_type(m, et); + + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, elem, -1, "real", 0*elem_size); + fields[1] = tb_debug_create_field(m->mod, elem, -1, "imag", 1*elem_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Basic_quaternion64: + case Basic_quaternion128: + case Basic_quaternion256: + { + String name = basic_types[type->Basic.kind].Basic.name; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + Type *et = base_complex_elem_type(type); + TB_CharUnits elem_size = cast(TB_CharUnits)type_size_of(et); + TB_DebugType *elem = cg_debug_type(m, et); + + // @QuaternionLayout + TB_DebugType **fields = tb_debug_record_begin(record, 4); + fields[0] = tb_debug_create_field(m->mod, elem, -1, "imag", 0*elem_size); + fields[1] = tb_debug_create_field(m->mod, elem, -1, "jmag", 1*elem_size); + fields[2] = tb_debug_create_field(m->mod, elem, -1, "kmag", 2*elem_size); + fields[3] = tb_debug_create_field(m->mod, elem, -1, "real", 3*elem_size); + + tb_debug_record_end(record, size, align); + return record; + } + + case Basic_int: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_uint: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_uintptr: return tb_debug_get_integer(m->mod, is_signed, bits); + + case Basic_rawptr: return tb_debug_create_ptr(m->mod, tb_debug_get_void(m->mod)); + case Basic_string: + { + String name = basic_types[type->Basic.kind].Basic.name; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + // @QuaternionLayout + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, t_u8_ptr), -1, "data", 0*int_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Basic_cstring: + return tb_debug_create_ptr(m->mod, tb_debug_get_integer(m->mod, false, 8)); + + case Basic_any: + { + String name = basic_types[type->Basic.kind].Basic.name; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + // @QuaternionLayout + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, t_rawptr), -1, "data", 0*ptr_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_typeid), -1, "id", 1*ptr_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Basic_typeid: return tb_debug_get_integer(m->mod, is_signed, bits); + + case Basic_i16le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u16le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i32le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u32le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i64le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u64le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i128le: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_u128le: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_i16be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u16be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i32be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u32be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i64be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u64be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i128be: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_u128be: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + + case Basic_f16le: return tb_debug_get_integer(m->mod, false, bits); + case Basic_f32le: return tb_debug_get_float(m->mod, TB_FLT_32); + case Basic_f64le: return tb_debug_get_float(m->mod,TB_FLT_64); + case Basic_f16be: return tb_debug_get_integer(m->mod, false, bits); + case Basic_f32be: return tb_debug_get_float(m->mod, TB_FLT_32); + case Basic_f64be: return tb_debug_get_float(m->mod,TB_FLT_64); + } + break; + case Type_Generic: + GB_PANIC("SHOULD NEVER HIT"); + break; + case Type_Pointer: + return tb_debug_create_ptr(m->mod, cg_debug_type(m, type->Pointer.elem)); + case Type_MultiPointer: + return tb_debug_create_ptr(m->mod, cg_debug_type(m, type->MultiPointer.elem)); + case Type_Array: + return tb_debug_create_array(m->mod, cg_debug_type(m, type->Array.elem), type->Array.count); + case Type_EnumeratedArray: + return tb_debug_create_array(m->mod, cg_debug_type(m, type->EnumeratedArray.elem), type->EnumeratedArray.count); + case Type_Slice: + { + String name = {}; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->Slice.elem)), -1, "data", 0*int_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Type_DynamicArray: + { + String name = {}; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + TB_DebugType **fields = tb_debug_record_begin(record, 4); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->Slice.elem)), -1, "data", 0*int_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); + fields[2] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "cap", 2*int_size); + fields[3] = tb_debug_create_field(m->mod, cg_debug_type(m, t_allocator), -1, "allocator", 3*int_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Type_Map: + return cg_debug_type(m, t_raw_map); + case Type_Struct: + return cg_debug_type_internal_record(m, type, {}); + case Type_Union: + return cg_debug_type_internal_record(m, type, {}); + case Type_Enum: + return tb_debug_get_integer(m->mod, is_signed, bits); + case Type_Tuple: + GB_PANIC("SHOULD NEVER HIT"); + break; + case Type_Proc: + { + TypeProc *pt = &type->Proc; + isize param_count = 0; + isize return_count = 0; + TB_DebugType *func = tb_debug_create_func(m->mod, TB_CDECL, param_count, return_count, pt->c_vararg); + return func; + } + break; + case Type_BitSet: + return cg_debug_type(m, bit_set_to_int(type)); + case Type_SimdVector: + return tb_debug_create_array(m->mod, cg_debug_type(m, type->SimdVector.elem), type->SimdVector.count); + case Type_RelativePointer: + return cg_debug_type(m, type->RelativePointer.base_integer); + case Type_RelativeSlice: + { + String name = {}; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + + TB_DebugType *base_integer = cg_debug_type(m, type->RelativeSlice.base_integer); + TB_CharUnits bi_size = cast(TB_CharUnits)type_size_of(type->RelativeSlice.base_integer); + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, base_integer, -1, "data", 0*bi_size); + fields[1] = tb_debug_create_field(m->mod, base_integer, -1, "len", 1*bi_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Type_Matrix: + { + i64 count = matrix_type_total_internal_elems(type); + return tb_debug_create_array(m->mod, cg_debug_type(m, type->Matrix.elem), count); + } + case Type_SoaPointer: + { + String name = {}; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->SoaPointer.elem)), -1, "ptr", 0*int_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "offset", 1*int_size); + + tb_debug_record_end(record, size, align); + return record; + } + } + // TODO(bill): cg_debug_type return tb_debug_get_void(m->mod); }