Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change typeid definition to be based around the canonical type hash #4860

Merged
merged 5 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 11 additions & 47 deletions base/runtime/core.odin
Original file line number Diff line number Diff line change
Expand Up @@ -239,47 +239,6 @@ Type_Info :: struct {
},
}

// NOTE(bill): This must match the compiler's
Typeid_Kind :: enum u8 {
Invalid,
Integer,
Rune,
Float,
Complex,
Quaternion,
String,
Boolean,
Any,
Type_Id,
Pointer,
Multi_Pointer,
Procedure,
Array,
Enumerated_Array,
Dynamic_Array,
Slice,
Tuple,
Struct,
Union,
Enum,
Map,
Bit_Set,
Simd_Vector,
Matrix,
Soa_Pointer,
Bit_Field,
}
#assert(len(Typeid_Kind) < 32)

Typeid_Bit_Field :: bit_field uintptr {
index: uintptr | 8*size_of(uintptr) - 8,
kind: Typeid_Kind | 5, // Typeid_Kind
named: bool | 1,
special: bool | 1, // signed, cstring, etc
reserved: bool | 1,
}
#assert(size_of(Typeid_Bit_Field) == size_of(uintptr))

// NOTE(bill): only the ones that are needed (not all types)
// This will be set by the compiler
type_table: []^Type_Info
Expand Down Expand Up @@ -483,10 +442,12 @@ Raw_Any :: struct {
data: rawptr,
id: typeid,
}
#assert(size_of(Raw_Any) == size_of(any))

Raw_Cstring :: struct {
data: [^]byte,
}
#assert(size_of(Raw_Cstring) == size_of(cstring))

Raw_Soa_Pointer :: struct {
data: rawptr,
Expand Down Expand Up @@ -686,13 +647,16 @@ type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
type_info_base_without_enum :: type_info_core

__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check {
MASK :: 1<<(8*size_of(typeid) - 8) - 1
data := transmute(uintptr)id
n := int(data & MASK)
if n < 0 || n >= len(type_table) {
n = 0
n := u64(len(type_table))
i := transmute(u64)id % n
for _ in 0..<n {
ptr := type_table[i]
if ptr != nil && ptr.id == id {
return ptr
}
i = i+1 if i+1 < n else 0
}
return type_table[n]
return type_table[0]
}

when !ODIN_NO_RTTI {
Expand Down
Binary file removed odin.rdi
Binary file not shown.
45 changes: 29 additions & 16 deletions src/checker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6740,30 +6740,43 @@ gb_internal void check_parsed_files(Checker *c) {
}
array_sort(c->info.type_info_types, type_info_pair_cmp);

array_init(&c->info.type_info_types_hash_map, heap_allocator(), c->info.type_info_types.count*2 + 1);
map_reserve(&c->info.minimum_dependency_type_info_index_map, c->info.type_info_types.count);

for_array(i, c->info.type_info_types) {
auto const &tt = c->info.type_info_types[i];
bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, tt.hash, i);
if (!exists) {
continue;
}
for (auto const &entry : c->info.minimum_dependency_type_info_index_map) {
if (entry.key != tt.hash) {
isize hash_map_len = c->info.type_info_types_hash_map.count;
for (auto const &tt : c->info.type_info_types) {
isize index = tt.hash % hash_map_len;
// NOTE(bill): no need for a sanity check since there
// will always be enough space for the entries
for (;;) {
if (index == 0 || c->info.type_info_types_hash_map[index].hash != 0) {
index = (index+1) % hash_map_len;
continue;
}
auto const &other = c->info.type_info_types[entry.value];
if (are_types_identical_unique_tuples(tt.type, other.type)) {
continue;
break;
}
c->info.type_info_types_hash_map[index] = tt;

bool exists = map_set_if_not_previously_exists(&c->info.minimum_dependency_type_info_index_map, tt.hash, index);
if (exists) {
for (auto const &entry : c->info.minimum_dependency_type_info_index_map) {
if (entry.key != tt.hash) {
continue;
}
auto const &other = c->info.type_info_types[entry.value];
if (are_types_identical_unique_tuples(tt.type, other.type)) {
continue;
}
gbString t = temp_canonical_string(tt.type);
gbString o = temp_canonical_string(other.type);
GB_PANIC("%s (%s) %llu vs %s (%s) %llu",
type_to_string(tt.type, false), t, cast(unsigned long long)tt.hash,
type_to_string(other.type, false), o, cast(unsigned long long)other.hash);
}
gbString t = temp_canonical_string(tt.type);
gbString o = temp_canonical_string(other.type);
GB_PANIC("%s (%s) %llu vs %s (%s) %llu",
type_to_string(tt.type, false), t, cast(unsigned long long)tt.hash,
type_to_string(other.type, false), o, cast(unsigned long long)other.hash);
}
}


GB_ASSERT(c->info.minimum_dependency_type_info_index_map.count <= c->info.type_info_types.count);
}

Expand Down
1 change: 1 addition & 0 deletions src/checker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ struct CheckerInfo {
PtrMap</*type info hash*/u64, /*min dep index*/isize> minimum_dependency_type_info_index_map;
TypeSet min_dep_type_info_set;
Array<TypeInfoPair> type_info_types; // sorted after filled
Array<TypeInfoPair> type_info_types_hash_map; // 2 * type_info_types.count


Array<Entity *> testing_procedures;
Expand Down
5 changes: 3 additions & 2 deletions src/llvm_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3154,9 +3154,10 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
lbModule *m = default_module;

{ // Add type info data
GB_ASSERT_MSG(info->minimum_dependency_type_info_index_map.count == info->type_info_types.count, "%tu vs %tu", info->minimum_dependency_type_info_index_map.count, info->type_info_types.count);
// GB_ASSERT_MSG(info->minimum_dependency_type_info_index_map.count == info->type_info_types.count, "%tu vs %tu", info->minimum_dependency_type_info_index_map.count, info->type_info_types.count);

isize max_type_info_count = info->minimum_dependency_type_info_index_map.count+1;
// isize max_type_info_count = info->minimum_dependency_type_info_index_map.count+1;
isize max_type_info_count = info->type_info_types_hash_map.count;
Type *t = alloc_type_array(t_type_info_ptr, max_type_info_count);

// IMPORTANT NOTE(bill): As LLVM does not have a union type, an array of unions cannot be initialized
Expand Down
21 changes: 15 additions & 6 deletions src/llvm_backend_general.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1784,15 +1784,24 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
return type;
}
type = LLVMStructCreateNamed(ctx, name);
LLVMTypeRef fields[2] = {
lb_type(m, t_rawptr),
lb_type(m, t_typeid),
};
LLVMStructSetBody(type, fields, 2, false);
if (build_context.ptr_size == 4) {
LLVMTypeRef fields[3] = {
lb_type(m, t_rawptr),
lb_type_padding_filler(m, build_context.ptr_size, build_context.ptr_size), // padding
lb_type(m, t_typeid),
};
LLVMStructSetBody(type, fields, 3, false);
} else {
LLVMTypeRef fields[2] = {
lb_type(m, t_rawptr),
lb_type(m, t_typeid),
};
LLVMStructSetBody(type, fields, 2, false);
}
return type;
}

case Basic_typeid: return LLVMIntTypeInContext(m->ctx, 8*cast(unsigned)build_context.ptr_size);
case Basic_typeid: return LLVMIntTypeInContext(m->ctx, 64);

// Endian Specific Types
case Basic_i16le: return LLVMInt16TypeInContext(ctx);
Expand Down
52 changes: 14 additions & 38 deletions src/llvm_backend_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
gb_internal isize lb_type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err_on_not_found=true) {
isize index = type_info_index(info, pair, err_on_not_found);
if (index >= 0) {
return index+1;
return index;
}
if (err_on_not_found) {
gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(pair.type), index, info->minimum_dependency_type_info_index_map.count);
for (auto const &entry : info->minimum_dependency_type_info_index_map) {
isize type_info_index = entry.key;
gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index].type));
gb_printf_err("\t%s\n", type_to_string(info->type_info_types_hash_map[type_info_index].type));
}
GB_PANIC("NOT FOUND");
}
Expand Down Expand Up @@ -73,37 +73,8 @@ gb_internal lbValue lb_typeid(lbModule *m, Type *type) {

type = default_type(type);

u64 id = cast(u64)lb_type_info_index(m->info, type);
GB_ASSERT(id >= 0);

u64 kind = lb_typeid_kind(m, type, id);
u64 named = is_type_named(type) && type->kind != Type_Basic;
u64 special = 0;
u64 reserved = 0;

if (is_type_cstring(type)) {
special = 1;
} else if (is_type_integer(type) && !is_type_unsigned(type)) {
special = 1;
}

u64 data = 0;
if (build_context.ptr_size == 4) {
GB_ASSERT(id <= (1u<<24u));
data |= (id &~ (1u<<24)) << 0u; // index
data |= (kind &~ (1u<<5)) << 24u; // kind
data |= (named &~ (1u<<1)) << 29u; // named
data |= (special &~ (1u<<1)) << 30u; // special
data |= (reserved &~ (1u<<1)) << 31u; // reserved
} else {
GB_ASSERT(build_context.ptr_size == 8);
GB_ASSERT(id <= (1ull<<56u));
data |= (id &~ (1ull<<56)) << 0ul; // index
data |= (kind &~ (1ull<<5)) << 56ull; // kind
data |= (named &~ (1ull<<1)) << 61ull; // named
data |= (special &~ (1ull<<1)) << 62ull; // special
data |= (reserved &~ (1ull<<1)) << 63ull; // reserved
}
u64 data = type_hash_canonical_type(type);
GB_ASSERT(data != 0);

lbValue res = {};
res.value = LLVMConstInt(lb_type(m, t_typeid), data, false);
Expand Down Expand Up @@ -279,8 +250,8 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ

LLVMTypeRef *modified_types = lb_setup_modified_types_for_type_info(m, global_type_info_data_entity_count);
defer (gb_free(heap_allocator(), modified_types));
for_array(type_info_type_index, info->type_info_types) {
auto const &tt = info->type_info_types[type_info_type_index];
for_array(type_info_type_index, info->type_info_types_hash_map) {
auto const &tt = info->type_info_types_hash_map[type_info_type_index];
Type *t = tt.type;
if (t == nullptr || t == t_invalid) {
continue;
Expand Down Expand Up @@ -343,8 +314,8 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
return giant_const_values[index];
};

for_array(type_info_type_index, info->type_info_types) {
Type *t = info->type_info_types[type_info_type_index].type;
for_array(type_info_type_index, info->type_info_types_hash_map) {
Type *t = info->type_info_types_hash_map[type_info_type_index].type;
if (t == nullptr || t == t_invalid) {
continue;
}
Expand Down Expand Up @@ -1072,7 +1043,12 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
LLVMSetInitializer(giant_const_values[entry_index], LLVMConstNamedStruct(stype, small_const_values, variant_index+1));
}
for (isize i = 0; i < global_type_info_data_entity_count; i++) {
giant_const_values[i] = LLVMConstPointerCast(giant_const_values[i], lb_type(m, t_type_info_ptr));
auto *ptr = &giant_const_values[i];
if (*ptr != nullptr) {
*ptr = LLVMConstPointerCast(*ptr, lb_type(m, t_type_info_ptr));
} else {
*ptr = LLVMConstNull(lb_type(m, t_type_info_ptr));
}
}


Expand Down
7 changes: 7 additions & 0 deletions src/llvm_backend_utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,13 @@ gb_internal i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
if (t->kind == Type_Struct) {
auto field_remapping = lb_get_struct_remapping(m, t);
return field_remapping[index];
} else if (is_type_any(t) && build_context.ptr_size == 4) {
GB_ASSERT(t->kind == Type_Basic);
GB_ASSERT(t->Basic.kind == Basic_any);
switch (index) {
case 0: return 0; // data
case 1: return 2; // id
}
} else if (build_context.ptr_size != build_context.int_size) {
switch (t->kind) {
case Type_Basic:
Expand Down
22 changes: 11 additions & 11 deletions src/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,9 +503,9 @@ gb_global Type basic_types[] = {
{Type_Basic, {Basic_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}},
{Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}},
{Type_Basic, {Basic_cstring, BasicFlag_String, -1, STR_LIT("cstring")}},
{Type_Basic, {Basic_any, 0, -1, STR_LIT("any")}},
{Type_Basic, {Basic_any, 0, 16, STR_LIT("any")}},

{Type_Basic, {Basic_typeid, 0, -1, STR_LIT("typeid")}},
{Type_Basic, {Basic_typeid, 0, 8, STR_LIT("typeid")}},

// Endian
{Type_Basic, {Basic_i16le, BasicFlag_Integer | BasicFlag_EndianLittle, 2, STR_LIT("i16le")}},
Expand Down Expand Up @@ -3700,8 +3700,8 @@ gb_internal i64 type_size_of(Type *t) {
switch (t->Basic.kind) {
case Basic_string: size = 2*build_context.int_size; break;
case Basic_cstring: size = build_context.ptr_size; break;
case Basic_any: size = 2*build_context.ptr_size; break;
case Basic_typeid: size = build_context.ptr_size; break;
case Basic_any: size = 16; break;
case Basic_typeid: size = 8; break;

case Basic_int: case Basic_uint:
size = build_context.int_size;
Expand Down Expand Up @@ -3763,8 +3763,8 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
switch (t->Basic.kind) {
case Basic_string: return build_context.int_size;
case Basic_cstring: return build_context.ptr_size;
case Basic_any: return build_context.ptr_size;
case Basic_typeid: return build_context.ptr_size;
case Basic_any: return 8;
case Basic_typeid: return 8;

case Basic_int: case Basic_uint:
return build_context.int_size;
Expand Down Expand Up @@ -4014,8 +4014,8 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
switch (kind) {
case Basic_string: return 2*build_context.int_size;
case Basic_cstring: return build_context.ptr_size;
case Basic_any: return 2*build_context.ptr_size;
case Basic_typeid: return build_context.ptr_size;
case Basic_any: return 16;
case Basic_typeid: return 8;

case Basic_int: case Basic_uint:
return build_context.int_size;
Expand Down Expand Up @@ -4251,7 +4251,7 @@ gb_internal i64 type_offset_of(Type *t, i64 index, Type **field_type_) {
return 0; // data
case 1:
if (field_type_) *field_type_ = t_typeid;
return build_context.ptr_size; // id
return 8; // id
}
}
break;
Expand Down Expand Up @@ -4322,8 +4322,8 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) {
}
} else if (t->Basic.kind == Basic_any) {
switch (index) {
case 0: t = t_type_info_ptr; break;
case 1: t = t_rawptr; break;
case 0: t = t_rawptr; break;
case 1: t = t_typeid; break;
}
}
break;
Expand Down