mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Begin work on hash types
This commit is contained in:
+42
-2
@@ -3,7 +3,10 @@
|
|||||||
#include "entity.cpp"
|
#include "entity.cpp"
|
||||||
#include "types.cpp"
|
#include "types.cpp"
|
||||||
|
|
||||||
String get_final_microarchitecture();
|
|
||||||
|
gb_internal u64 type_hash_canonical_type(Type *type);
|
||||||
|
|
||||||
|
gb_internal String get_final_microarchitecture();
|
||||||
|
|
||||||
gb_internal void check_expr(CheckerContext *c, Operand *operand, Ast *expression);
|
gb_internal void check_expr(CheckerContext *c, Operand *operand, Ast *expression);
|
||||||
gb_internal void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr);
|
gb_internal void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr);
|
||||||
@@ -2037,7 +2040,8 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
|
|||||||
// Unique entry
|
// Unique entry
|
||||||
// NOTE(bill): map entries grow linearly and in order
|
// NOTE(bill): map entries grow linearly and in order
|
||||||
ti_index = c->info->type_info_types.count;
|
ti_index = c->info->type_info_types.count;
|
||||||
array_add(&c->info->type_info_types, t);
|
Type_Info_Type tt = {t, type_hash_canonical_type(t)};
|
||||||
|
array_add(&c->info->type_info_types, tt);
|
||||||
}
|
}
|
||||||
map_set(&c->checker->info.type_info_map, t, ti_index);
|
map_set(&c->checker->info.type_info_map, t, ti_index);
|
||||||
|
|
||||||
@@ -6725,6 +6729,42 @@ gb_internal void check_parsed_files(Checker *c) {
|
|||||||
add_type_and_value(&c->builtin_ctx, u.expr, u.info->mode, u.info->type, u.info->value);
|
add_type_and_value(&c->builtin_ctx, u.expr, u.info->mode, u.info->type, u.info->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TIME_SECTION("check for type hash collisions");
|
||||||
|
{
|
||||||
|
PtrSet<uintptr> found = {};
|
||||||
|
ptr_set_init(&found, c->info.type_info_types.count);
|
||||||
|
defer (ptr_set_destroy(&found));
|
||||||
|
for (auto const &tt : c->info.type_info_types) {
|
||||||
|
if (ptr_set_update(&found, cast(uintptr)tt.hash)) {
|
||||||
|
Type *other_type = nullptr;
|
||||||
|
for (auto const &other : c->info.type_info_types) {
|
||||||
|
if (&tt == &other) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cast(uintptr)other.hash == cast(uintptr)tt.hash &&
|
||||||
|
!are_types_identical(tt.type, other.type)) {
|
||||||
|
other_type = other.type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (other_type != nullptr) {
|
||||||
|
String ts = type_to_canonical_string(temporary_allocator(), tt.type);
|
||||||
|
String os = type_to_canonical_string(temporary_allocator(), other_type);
|
||||||
|
if (ts != os) {
|
||||||
|
compiler_error("%s found type hash collision with %s (hash = %llu)\n"
|
||||||
|
"%s vs %s\n",
|
||||||
|
type_to_string(tt.type), type_to_string(other_type), cast(unsigned long long)tt.hash,
|
||||||
|
temp_canonical_string(tt.type),
|
||||||
|
temp_canonical_string(other_type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TIME_SECTION("sort init and fini procedures");
|
TIME_SECTION("sort init and fini procedures");
|
||||||
check_sort_init_and_fini_procedures(c);
|
check_sort_init_and_fini_procedures(c);
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -409,6 +409,11 @@ struct Defineable {
|
|||||||
String pos_str;
|
String pos_str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Type_Info_Type {
|
||||||
|
Type *type;
|
||||||
|
u64 hash; // see: type_hash_canonical_type
|
||||||
|
};
|
||||||
|
|
||||||
// CheckerInfo stores all the symbol information for a type-checked program
|
// CheckerInfo stores all the symbol information for a type-checked program
|
||||||
struct CheckerInfo {
|
struct CheckerInfo {
|
||||||
Checker *checker;
|
Checker *checker;
|
||||||
@@ -453,7 +458,7 @@ struct CheckerInfo {
|
|||||||
PtrMap<Type *, GenTypesData *> gen_types;
|
PtrMap<Type *, GenTypesData *> gen_types;
|
||||||
|
|
||||||
BlockingMutex type_info_mutex; // NOT recursive
|
BlockingMutex type_info_mutex; // NOT recursive
|
||||||
Array<Type *> type_info_types;
|
Array<Type_Info_Type> type_info_types;
|
||||||
PtrMap<Type *, isize> type_info_map;
|
PtrMap<Type *, isize> type_info_map;
|
||||||
|
|
||||||
BlockingMutex foreign_mutex; // NOT recursive
|
BlockingMutex foreign_mutex; // NOT recursive
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
#include "llvm_backend_stmt.cpp"
|
#include "llvm_backend_stmt.cpp"
|
||||||
#include "llvm_backend_proc.cpp"
|
#include "llvm_backend_proc.cpp"
|
||||||
|
|
||||||
String get_default_microarchitecture() {
|
gb_internal String get_default_microarchitecture() {
|
||||||
String default_march = str_lit("generic");
|
String default_march = str_lit("generic");
|
||||||
if (build_context.metrics.arch == TargetArch_amd64) {
|
if (build_context.metrics.arch == TargetArch_amd64) {
|
||||||
// NOTE(bill): x86-64-v2 is more than enough for everyone
|
// NOTE(bill): x86-64-v2 is more than enough for everyone
|
||||||
@@ -47,7 +47,7 @@ String get_default_microarchitecture() {
|
|||||||
return default_march;
|
return default_march;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get_final_microarchitecture() {
|
gb_internal String get_final_microarchitecture() {
|
||||||
BuildContext *bc = &build_context;
|
BuildContext *bc = &build_context;
|
||||||
|
|
||||||
String microarch = bc->microarch;
|
String microarch = bc->microarch;
|
||||||
@@ -3182,7 +3182,8 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
|||||||
isize count = 0;
|
isize count = 0;
|
||||||
isize offsets_extra = 0;
|
isize offsets_extra = 0;
|
||||||
|
|
||||||
for (Type *t : m->info->type_info_types) {
|
for (auto const &tt : m->info->type_info_types) {
|
||||||
|
Type *t = tt.type;
|
||||||
isize index = lb_type_info_index(m->info, t, false);
|
isize index = lb_type_info_index(m->info, t, false);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -1460,8 +1460,6 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e) {
|
|||||||
w = write_canonical_entity_name(w, e);
|
w = write_canonical_entity_name(w, e);
|
||||||
defer (gb_string_free(w));
|
defer (gb_string_free(w));
|
||||||
|
|
||||||
gb_printf_err("%s\n", w);
|
|
||||||
|
|
||||||
String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w)));
|
String name = copy_string(permanent_allocator(), make_string(cast(u8 const *)w, gb_string_length(w)));
|
||||||
|
|
||||||
if (e->kind == Entity_TypeName) {
|
if (e->kind == Entity_TypeName) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_
|
|||||||
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(type), index, set->count);
|
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(type), index, set->count);
|
||||||
for (auto const &entry : *set) {
|
for (auto const &entry : *set) {
|
||||||
isize type_info_index = entry.key;
|
isize type_info_index = entry.key;
|
||||||
gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index]));
|
gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index].type));
|
||||||
}
|
}
|
||||||
GB_PANIC("NOT FOUND");
|
GB_PANIC("NOT FOUND");
|
||||||
}
|
}
|
||||||
@@ -280,7 +280,7 @@ 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);
|
LLVMTypeRef *modified_types = lb_setup_modified_types_for_type_info(m, global_type_info_data_entity_count);
|
||||||
defer (gb_free(heap_allocator(), modified_types));
|
defer (gb_free(heap_allocator(), modified_types));
|
||||||
for_array(type_info_type_index, info->type_info_types) {
|
for_array(type_info_type_index, info->type_info_types) {
|
||||||
Type *t = info->type_info_types[type_info_type_index];
|
Type *t = info->type_info_types[type_info_type_index].type;
|
||||||
if (t == nullptr || t == t_invalid) {
|
if (t == nullptr || t == t_invalid) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -343,7 +343,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
|
|||||||
};
|
};
|
||||||
|
|
||||||
for_array(type_info_type_index, info->type_info_types) {
|
for_array(type_info_type_index, info->type_info_types) {
|
||||||
Type *t = info->type_info_types[type_info_type_index];
|
Type *t = info->type_info_types[type_info_type_index].type;
|
||||||
if (t == nullptr || t == t_invalid) {
|
if (t == nullptr || t == t_invalid) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* builtin names - just their normal name e.g. `i32` or `string`
|
* builtin names - just their normal name e.g. `i32` or `string`
|
||||||
* nested - pkg.parent1.parent2.name
|
* nested - pkg.parent1.parent2.name
|
||||||
* file private - pkg.[file_name].name
|
* file private - pkg.[file_name].name
|
||||||
* Example: `foo.[bar.odin].Type`
|
* Example: `pkg.[file.odin].Type`
|
||||||
* polymorphic procedure/type - pkg.foo::TYPE
|
* polymorphic procedure/type - pkg.foo::TYPE
|
||||||
* naming convention for parameters
|
* naming convention for parameters
|
||||||
* type
|
* type
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
* $$constant_parameter
|
* $$constant_parameter
|
||||||
* Example: `foo.to_thing::proc(u64)->([]u8)`
|
* Example: `foo.to_thing::proc(u64)->([]u8)`
|
||||||
* nested decl in polymorphic procedure - pkg.foo::TYPE.name
|
* nested decl in polymorphic procedure - pkg.foo::TYPE.name
|
||||||
* anonymous procedures - pkg.foo.$anon123
|
* anonymous procedures - pkg.foo.$anon[file.odin:123]
|
||||||
* 123 is the file offset in bytes
|
* 123 is the file offset in bytes
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +38,12 @@
|
|||||||
|
|
||||||
#define CANONICAL_NONE_TYPE "<>"
|
#define CANONICAL_NONE_TYPE "<>"
|
||||||
|
|
||||||
|
|
||||||
gb_internal gbString write_type_to_canonical_string(gbString w, Type *type);
|
gb_internal gbString write_type_to_canonical_string(gbString w, Type *type);
|
||||||
|
gb_internal u64 type_hash_canonical_type(Type *type);
|
||||||
|
gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type);
|
||||||
|
gb_internal gbString temp_canonical_string(Type *type);
|
||||||
|
|
||||||
gb_internal gbString write_canonical_params(gbString w, Type *params) {
|
gb_internal gbString write_canonical_params(gbString w, Type *params) {
|
||||||
w = gb_string_appendc(w, "(");
|
w = gb_string_appendc(w, "(");
|
||||||
if (params) {
|
if (params) {
|
||||||
@@ -81,7 +86,7 @@ gb_internal u64 type_hash_canonical_type(Type *type) {
|
|||||||
TEMPORARY_ALLOCATOR_GUARD();
|
TEMPORARY_ALLOCATOR_GUARD();
|
||||||
gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type);
|
gbString w = write_type_to_canonical_string(gb_string_make(temporary_allocator(), ""), type);
|
||||||
u64 hash = fnv64a(w, gb_string_length(w));
|
u64 hash = fnv64a(w, gb_string_length(w));
|
||||||
return hash;
|
return hash ? hash : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) {
|
gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) {
|
||||||
@@ -90,6 +95,11 @@ gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) {
|
|||||||
return make_string(cast(u8 const *)w, gb_string_length(w));
|
return make_string(cast(u8 const *)w, gb_string_length(w));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb_internal gbString temp_canonical_string(Type *type) {
|
||||||
|
gbString w = gb_string_make(temporary_allocator(), "");
|
||||||
|
return write_type_to_canonical_string(w, type);
|
||||||
|
}
|
||||||
|
|
||||||
gb_internal void print_scope_flags(Scope *s) {
|
gb_internal void print_scope_flags(Scope *s) {
|
||||||
if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg ");
|
if (s->flags & ScopeFlag_Pkg) gb_printf_err("Pkg ");
|
||||||
if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin ");
|
if (s->flags & ScopeFlag_Builtin) gb_printf_err("Builtin ");
|
||||||
@@ -156,7 +166,8 @@ gb_internal gbString write_canonical_parent_prefix(gbString w, Entity *e, bool i
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) {
|
if (e->kind == Entity_Procedure && e->Procedure.is_anonymous) {
|
||||||
w = gb_string_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "%d", e->token.pos.offset));
|
String file_name = filename_without_directory(e->file->fullpath);
|
||||||
|
w = gb_string_appendc(w, gb_bprintf(CANONICAL_ANON_PREFIX "[%.*s:%d]", LIT(file_name), e->token.pos.offset));
|
||||||
} else {
|
} else {
|
||||||
w = gb_string_append_length(w, e->token.string.text, e->token.string.len);
|
w = gb_string_append_length(w, e->token.string.text, e->token.string.len);
|
||||||
}
|
}
|
||||||
@@ -449,8 +460,12 @@ gb_internal gbString write_type_to_canonical_string(gbString w, Type *type) {
|
|||||||
}
|
}
|
||||||
return w;
|
return w;
|
||||||
|
|
||||||
|
case Type_Tuple:
|
||||||
|
w = gb_string_appendc(w, "params");
|
||||||
|
w = write_canonical_params(w, type);
|
||||||
|
return w;
|
||||||
default:
|
default:
|
||||||
GB_PANIC("unknown type kind %d", type->kind);
|
GB_PANIC("unknown type kind %d %.*s", type->kind, LIT(type_strings[type->kind]));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -42,7 +42,7 @@ gb_internal void ptr_set_destroy(PtrSet<T> *s) {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
gb_internal isize ptr_set__find(PtrSet<T> *s, T ptr) {
|
gb_internal isize ptr_set__find(PtrSet<T> *s, T ptr) {
|
||||||
GB_ASSERT(ptr != nullptr);
|
GB_ASSERT(ptr != 0);
|
||||||
if (s->count != 0) {
|
if (s->count != 0) {
|
||||||
#if 0
|
#if 0
|
||||||
for (usize i = 0; i < s->capacity; i++) {
|
for (usize i = 0; i < s->capacity; i++) {
|
||||||
@@ -58,7 +58,7 @@ gb_internal isize ptr_set__find(PtrSet<T> *s, T ptr) {
|
|||||||
T key = s->keys[hash_index];
|
T key = s->keys[hash_index];
|
||||||
if (key == ptr) {
|
if (key == ptr) {
|
||||||
return hash_index;
|
return hash_index;
|
||||||
} else if (key == nullptr) {
|
} else if (key == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
hash_index = (hash_index+1)&mask;
|
hash_index = (hash_index+1)&mask;
|
||||||
@@ -122,7 +122,7 @@ gb_internal bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it pre
|
|||||||
for (usize i = 0; i < s->capacity; i++) {
|
for (usize i = 0; i < s->capacity; i++) {
|
||||||
T *key = &s->keys[hash_index];
|
T *key = &s->keys[hash_index];
|
||||||
GB_ASSERT(*key != ptr);
|
GB_ASSERT(*key != ptr);
|
||||||
if (*key == (T)PtrSet<T>::TOMBSTONE || *key == nullptr) {
|
if (*key == (T)PtrSet<T>::TOMBSTONE || *key == 0) {
|
||||||
*key = ptr;
|
*key = ptr;
|
||||||
s->count++;
|
s->count++;
|
||||||
return false;
|
return false;
|
||||||
@@ -169,7 +169,7 @@ struct PtrSetIterator {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
T key = set->keys[index];
|
T key = set->keys[index];
|
||||||
if (key != nullptr && key != (T)PtrSet<T>::TOMBSTONE) {
|
if (key != 0 && key != (T)PtrSet<T>::TOMBSTONE) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,7 +191,7 @@ gb_internal PtrSetIterator<T> begin(PtrSet<T> &set) noexcept {
|
|||||||
usize index = 0;
|
usize index = 0;
|
||||||
while (index < set.capacity) {
|
while (index < set.capacity) {
|
||||||
T key = set.keys[index];
|
T key = set.keys[index];
|
||||||
if (key != nullptr && key != (T)PtrSet<T>::TOMBSTONE) {
|
if (key != 0 && key != (T)PtrSet<T>::TOMBSTONE) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
|
|||||||
+34
-2
@@ -2774,7 +2774,37 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
|
|||||||
|
|
||||||
|
|
||||||
case Type_Enum:
|
case Type_Enum:
|
||||||
return x == y; // NOTE(bill): All enums are unique
|
if (x == y) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (x->Enum.fields.count != y->Enum.fields.count) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!are_types_identical(x->Enum.base_type, y->Enum.base_type)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (x->Enum.min_value_index != y->Enum.min_value_index) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (x->Enum.max_value_index != y->Enum.max_value_index) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (isize i = 0; i < x->Enum.fields.count; i++) {
|
||||||
|
Entity *a = x->Enum.fields[i];
|
||||||
|
Entity *b = y->Enum.fields[i];
|
||||||
|
if (a->token.string != b->token.string) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GB_ASSERT(a->kind == b->kind);
|
||||||
|
GB_ASSERT(a->kind == Entity_Constant);
|
||||||
|
bool same = compare_exact_values(Token_CmpEq, a->Constant.value, b->Constant.value);
|
||||||
|
if (!same) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
case Type_Union:
|
case Type_Union:
|
||||||
if (x->Union.variants.count == y->Union.variants.count &&
|
if (x->Union.variants.count == y->Union.variants.count &&
|
||||||
@@ -2832,7 +2862,9 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return are_types_identical(x->Struct.polymorphic_params, y->Struct.polymorphic_params);
|
// TODO(bill): Which is the correct logic here?
|
||||||
|
// return are_types_identical(x->Struct.polymorphic_params, y->Struct.polymorphic_params);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user