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

Deterministic Canonical Naming for Link Names and Types #4855

Merged
merged 20 commits into from
Feb 20, 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
10 changes: 8 additions & 2 deletions src/check_decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1742,8 +1742,8 @@ gb_internal void add_deps_from_child_to_parent(DeclInfo *decl) {
rw_mutex_shared_lock(&decl->type_info_deps_mutex);
rw_mutex_lock(&decl->parent->type_info_deps_mutex);

for (Type *t : decl->type_info_deps) {
ptr_set_add(&decl->parent->type_info_deps, t);
for (auto const &tt : decl->type_info_deps) {
type_set_add(&decl->parent->type_info_deps, tt);
}

rw_mutex_unlock(&decl->parent->type_info_deps_mutex);
Expand Down Expand Up @@ -1784,6 +1784,10 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
ctx->curr_proc_sig = type;
ctx->curr_proc_calling_convention = type->Proc.calling_convention;

if (decl->parent && decl->entity && decl->parent->entity) {
decl->entity->parent_proc_decl = decl->parent;
}

if (ctx->pkg->name != "runtime") {
switch (type->Proc.calling_convention) {
case ProcCC_None:
Expand Down Expand Up @@ -1873,6 +1877,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de

check_open_scope(ctx, body);
{
ctx->scope->decl_info = decl;

for (auto const &entry : using_entities) {
Entity *uvar = entry.uvar;
Entity *prev = scope_insert(ctx->scope, uvar);
Expand Down
2 changes: 1 addition & 1 deletion src/check_expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ gb_internal void check_scope_decls(CheckerContext *c, Slice<Ast *> const &nodes,
check_collect_entities(c, nodes);

for (auto const &entry : s->elements) {
Entity *e = entry.value;
Entity *e = entry.value;\
switch (e->kind) {
case Entity_Constant:
case Entity_TypeName:
Expand Down
138 changes: 91 additions & 47 deletions src/checker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
#include "entity.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_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr);
Expand Down Expand Up @@ -170,7 +173,7 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) {
d->parent = parent;
d->scope = scope;
ptr_set_init(&d->deps, 0);
ptr_set_init(&d->type_info_deps, 0);
type_set_init(&d->type_info_deps, 0);
d->labels.allocator = heap_allocator();
d->variadic_reuses.allocator = heap_allocator();
d->variadic_reuse_max_bytes = 0;
Expand Down Expand Up @@ -355,6 +358,10 @@ gb_internal void check_open_scope(CheckerContext *c, Ast *node) {
scope->flags |= ScopeFlag_Type;
break;
}
if (c->decl && c->decl->proc_lit) {
// Number the scopes within a procedure body depth-first
scope->index = c->decl->scope_index++;
}
c->scope = scope;
c->state_flags |= StateFlag_bounds_check;
}
Expand Down Expand Up @@ -825,11 +832,17 @@ gb_internal void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) {
rw_mutex_unlock(&d->deps_mutex);
}
gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type) {
if (d == nullptr) {
if (d == nullptr || type == nullptr) {
return;
}
if (type->kind == Type_Named) {
Entity *e = type->Named.type_name;
if (e->TypeName.is_type_alias) {
type = type->Named.base;
}
}
rw_mutex_lock(&d->type_info_deps_mutex);
ptr_set_add(&d->type_info_deps, type);
type_set_add(&d->type_info_deps, type);
rw_mutex_unlock(&d->type_info_deps_mutex);
}

Expand Down Expand Up @@ -1358,8 +1371,12 @@ gb_internal void init_checker_info(CheckerInfo *i) {
string_map_init(&i->foreigns);
// map_init(&i->gen_procs);
map_init(&i->gen_types);

array_init(&i->type_info_types, a);
map_init(&i->type_info_map);
type_set_init(&i->min_dep_type_info_set);
map_init(&i->minimum_dependency_type_info_index_map);

// map_init(&i->type_info_map);
string_map_init(&i->files);
string_map_init(&i->packages);
array_init(&i->variable_init_order, a);
Expand Down Expand Up @@ -1392,8 +1409,11 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
string_map_destroy(&i->foreigns);
// map_destroy(&i->gen_procs);
map_destroy(&i->gen_types);

array_free(&i->type_info_types);
map_destroy(&i->type_info_map);
type_set_destroy(&i->min_dep_type_info_set);
map_destroy(&i->minimum_dependency_type_info_index_map);

string_map_destroy(&i->files);
string_map_destroy(&i->packages);
array_free(&i->variable_init_order);
Expand Down Expand Up @@ -1627,41 +1647,36 @@ gb_internal void check_remove_expr_info(CheckerContext *c, Ast *e) {
}
}


gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) {
type = default_type(type);
if (type == t_llvm_bool) {
type = t_bool;
}

mutex_lock(&info->type_info_mutex);
gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool error_on_failure) {
mutex_lock(&info->minimum_dependency_type_info_mutex);

isize entry_index = -1;
isize *found_entry_index = map_get(&info->type_info_map, type);
uintptr hash = cast(uintptr)pair.hash;
isize *found_entry_index = map_get(&info->minimum_dependency_type_info_index_map, hash);
if (found_entry_index) {
entry_index = *found_entry_index;
}
if (entry_index < 0) {
// NOTE(bill): Do manual linear search
for (auto const &e : info->type_info_map) {
if (are_types_identical_unique_tuples(e.key, type)) {
entry_index = e.value;
// NOTE(bill): Add it to the search map
map_set(&info->type_info_map, type, entry_index);
break;
}
}
}

mutex_unlock(&info->type_info_mutex);
mutex_unlock(&info->minimum_dependency_type_info_mutex);

if (error_on_failure && entry_index < 0) {
compiler_error("Type_Info for '%s' could not be found", type_to_string(type));
compiler_error("Type_Info for '%s' could not be found", type_to_string(pair.type));
}
return entry_index;
}


gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) {
type = default_type(type);
if (type == t_llvm_bool) {
type = t_bool;
}

u64 hash = type_hash_canonical_type(type);
return type_info_index(info, {type, hash}, error_on_failure);
}



gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) {
if (expr == nullptr) {
return;
Expand Down Expand Up @@ -2013,8 +2028,12 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
}

add_type_info_dependency(c->info, c->decl, t);

#if 0
MUTEX_GUARD_BLOCK(&c->info->type_info_mutex) {
if (type_set_update(&c->info->type_info_set, t)) {
// return;
}

auto found = map_get(&c->info->type_info_map, t);
if (found != nullptr) {
// Types have already been added
Expand All @@ -2037,7 +2056,8 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
// Unique entry
// NOTE(bill): map entries grow linearly and in order
ti_index = c->info->type_info_types.count;
array_add(&c->info->type_info_types, t);
TypeInfoPair 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);

Expand Down Expand Up @@ -2232,6 +2252,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
break;
}
#endif
}


Expand Down Expand Up @@ -2289,19 +2310,7 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
return;
}

auto *set = &c->info.minimum_dependency_type_info_set;

isize ti_index = type_info_index(&c->info, t, false);
if (ti_index < 0) {
add_type_info_type(&c->builtin_ctx, t); // Missing the type information
ti_index = type_info_index(&c->info, t, false);
}
GB_ASSERT(ti_index >= 0);
// IMPORTANT NOTE(bill): this must be copied as `map_set` takes a const ref
// and effectively assigns the `+1` of the value
isize const count = set->count;
if (map_set_if_not_previously_exists(set, ti_index+1, count)) {
// Type already exists;
if (type_set_update(&c->info.min_dep_type_info_set, t)) {
return;
}

Expand Down Expand Up @@ -2501,8 +2510,8 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) {
if (decl == nullptr) {
return;
}
for (Type *t : decl->type_info_deps) {
add_min_dep_type_info(c, t);
for (TypeInfoPair const tt : decl->type_info_deps) {
add_min_dep_type_info(c, tt.type);
}

for (Entity *e : decl->deps) {
Expand Down Expand Up @@ -2702,7 +2711,6 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) {
isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor

ptr_set_init(&c->info.minimum_dependency_set, min_dep_set_cap);
map_init(&c->info.minimum_dependency_type_info_set);

#define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do { \
if (condition) { \
Expand Down Expand Up @@ -3894,6 +3902,7 @@ gb_internal DECL_ATTRIBUTE_PROC(type_decl_attribute) {
#include "check_expr.cpp"
#include "check_builtin.cpp"
#include "check_type.cpp"
#include "name_canonicalization.cpp"
#include "check_decl.cpp"
#include "check_stmt.cpp"

Expand Down Expand Up @@ -6724,6 +6733,41 @@ 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);
}

TIME_SECTION("initialize and check for collisions in type info array");
{
for (auto const &tt : c->info.min_dep_type_info_set) {
array_add(&c->info.type_info_types, tt);
}
array_sort(c->info.type_info_types, type_info_pair_cmp);

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, cast(uintptr)tt.hash, i);
if (!exists) {
continue;
}
for (auto const &entry : c->info.minimum_dependency_type_info_index_map) {
if (entry.key != cast(uintptr)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);
}
}

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


TIME_SECTION("sort init and fini procedures");
check_sort_init_and_fini_procedures(c);

Expand Down
25 changes: 18 additions & 7 deletions src/checker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);

gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &attributes, DeclAttributeProc *proc, AttributeContext *ac);

#include "name_canonicalization.hpp"

enum ProcCheckedState : u8 {
ProcCheckedState_Unchecked,
Expand Down Expand Up @@ -221,13 +222,15 @@ struct DeclInfo {
RwMutex deps_mutex;
PtrSet<Entity *> deps;

RwMutex type_info_deps_mutex;
PtrSet<Type *> type_info_deps;
RwMutex type_info_deps_mutex;
TypeSet type_info_deps;

BlockingMutex type_and_value_mutex;

Array<BlockLabel> labels;

i32 scope_index;

Array<VariadicReuseData> variadic_reuses;
i64 variadic_reuse_max_bytes;
i64 variadic_reuse_max_align;
Expand Down Expand Up @@ -272,10 +275,14 @@ struct Scope {
std::atomic<Scope *> next;
std::atomic<Scope *> head_child;

i32 index; // within a procedure

RwMutex mutex;
StringMap<Entity *> elements;
PtrSet<Scope *> imported;

DeclInfo *decl_info;

i32 flags; // ScopeFlag
union {
AstPackage *pkg;
Expand Down Expand Up @@ -421,8 +428,10 @@ struct CheckerInfo {
Scope * init_scope;
Entity * entry_point;
PtrSet<Entity *> minimum_dependency_set;
PtrMap</*type info index*/isize, /*min dep index*/isize> minimum_dependency_type_info_set;

BlockingMutex minimum_dependency_type_info_mutex;
PtrMap</*type info hash*/uintptr, /*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<Entity *> testing_procedures;
Expand Down Expand Up @@ -450,9 +459,10 @@ struct CheckerInfo {
BlockingMutex gen_types_mutex;
PtrMap<Type *, GenTypesData *> gen_types;

BlockingMutex type_info_mutex; // NOT recursive
Array<Type *> type_info_types;
PtrMap<Type *, isize> type_info_map;
// BlockingMutex type_info_mutex; // NOT recursive
// Array<TypeInfoPair> type_info_types;
// PtrMap<Type *, isize> type_info_map;
// TypeSet type_info_set;

BlockingMutex foreign_mutex; // NOT recursive
StringMap<Entity *> foreigns;
Expand Down Expand Up @@ -571,6 +581,7 @@ gb_internal DeclInfo * decl_info_of_entity (Entity * e);
gb_internal AstFile * ast_file_of_filename (CheckerInfo *i, String filename);
// IMPORTANT: Only to use once checking is done
gb_internal isize type_info_index (CheckerInfo *i, Type *type, bool error_on_failure);
gb_internal isize type_info_index (CheckerInfo *info, TypeInfoPair pair, bool error_on_failure);

// Will return nullptr if not found
gb_internal Entity *entity_of_node(Ast *expr);
Expand Down
4 changes: 2 additions & 2 deletions src/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ gb_internal u32 fnv32a(void const *data, isize len) {
return h;
}

gb_internal u64 fnv64a(void const *data, isize len) {
gb_internal u64 fnv64a(void const *data, isize len, u64 seed=0xcbf29ce484222325ull) {
u8 const *bytes = cast(u8 const *)data;
u64 h = 0xcbf29ce484222325ull;
u64 h = seed;

for (; len >= 8; len -= 8, bytes += 8) {
h = (h ^ bytes[0]) * 0x100000001b3ull;
Expand Down
1 change: 1 addition & 0 deletions src/entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ struct Entity {
bool has_instrumentation : 1;
bool is_memcpy_like : 1;
bool uses_branch_location : 1;
bool is_anonymous : 1;
} Procedure;
struct {
Array<Entity *> entities;
Expand Down
Loading