diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 5d0fc5ed3..ca1118a30 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -102,7 +102,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array operands = {}; array_init(&operands, c->tmp_allocator, 2*lhs_count); - check_unpack_arguments(c, lhs_count, &operands, inits, true); + check_unpack_arguments(c, lhs, lhs_count, &operands, inits, true); isize rhs_count = operands.count; for_array(i, operands) { @@ -113,7 +113,13 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Arrayinfo, e); + Operand *o = &operands[i]; + check_init_variable(c, e, o, context_name); + if (d != nullptr) { + d->init_expr = o->expr; + } } if (rhs_count > 0 && lhs_count != rhs_count) { error(lhs[0]->token, "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); @@ -550,7 +556,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { } } -void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) { +void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, Array init_expr_list) { GB_ASSERT(e->type == nullptr); GB_ASSERT(e->kind == Entity_Variable); @@ -581,7 +587,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count if (e->Variable.is_foreign) { - if (init_expr != nullptr) { + if (init_expr_list.count > 0) { error(e->token, "A foreign variable declaration cannot have a default value"); } init_entity_foreign_library(c, e); @@ -606,31 +612,20 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count } } - if (init_expr == nullptr) { + if (init_expr_list.count == 0) { if (type_expr == nullptr) { e->type = t_invalid; } return; } - if (entities == nullptr || entity_count == 1) { - GB_ASSERT(entities == nullptr || entities[0] == e); - Operand operand = {}; - check_expr(c, &operand, init_expr); - check_init_variable(c, e, &operand, context_name); - } - if (type_expr != nullptr) { for (isize i = 0; i < entity_count; i++) { entities[i]->type = e->type; } } - - Array inits; - array_init(&inits, c->allocator, 1); - array_add(&inits, init_expr); - check_init_variables(c, entities, entity_count, inits, context_name); + check_init_variables(c, entities, entity_count, init_expr_list, context_name); } void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { @@ -657,7 +652,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { switch (e->kind) { case Entity_Variable: - check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr); + check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr_list); break; case Entity_Constant: check_const_decl(c, e, d->type_expr, d->init_expr, named_type); @@ -757,9 +752,8 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod if (decl->parent != nullptr) { // NOTE(bill): Add the dependencies from the procedure literal (lambda) for_array(i, decl->deps.entries) { - HashKey key = decl->deps.entries[i].key; - Entity *e = cast(Entity *)key.ptr; - map_set(&decl->parent->deps, key, true); + Entity *e = decl->deps.entries[i].ptr; + ptr_set_add(&decl->parent->deps, e); } } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 0519aad4f..99ea66450 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5968,19 +5968,44 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } +isize add_dependencies_from_unpacking(Checker *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) { + if (lhs != nullptr) { + for (isize j = 0; tuple_index < lhs_count && j < tuple_count; j++) { + Entity *e = lhs[tuple_index + j]; + DeclInfo *decl = decl_info_of_entity(&c->info, e); + if (decl != nullptr) { + c->context.decl = decl; // will be reset by the `defer` any way + for_array(k, decl->deps.entries) { + Entity *dep = decl->deps.entries[k].ptr; + add_declaration_dependency(c, dep); // TODO(bill): Should this be here? + } + } + } + } + return tuple_count; +} - -bool check_unpack_arguments(Checker *c, isize lhs_count, Array *operands, Array rhs, bool allow_ok) { +void check_unpack_arguments(Checker *c, Entity **lhs, isize lhs_count, Array *operands, Array rhs, bool allow_ok, bool *optional_ok_ = nullptr) { bool optional_ok = false; + isize tuple_index = 0; for_array(i, rhs) { + CheckerContext prev_context = c->context; + defer (c->context = prev_context); + Operand o = {}; + + if (lhs != nullptr && tuple_index < lhs_count) { + // NOTE(bill): override DeclInfo for dependency control + DeclInfo *decl = decl_info_of_entity(&c->info, lhs[tuple_index]); + if (decl) c->context.decl = decl; + } + check_expr_base(c, &o, rhs[i], nullptr); if (o.mode == Addressing_NoValue) { error_operand_no_value(&o); o.mode = Addressing_Invalid; } - // check_multi_expr(c, &o, rhs[i]); if (o.type == nullptr || o.type->kind != Type_Tuple) { @@ -5998,8 +6023,10 @@ bool check_unpack_arguments(Checker *c, isize lhs_count, Array *operand array_add(operands, ok); optional_ok = true; + tuple_index += add_dependencies_from_unpacking(c, lhs, lhs_count, tuple_index, 2); } else { array_add(operands, o); + tuple_index += 1; } } else { TypeTuple *tuple = &o.type->Tuple; @@ -6007,10 +6034,13 @@ bool check_unpack_arguments(Checker *c, isize lhs_count, Array *operand o.type = tuple->variables[j]->type; array_add(operands, o); } + + isize count = tuple->variables.count; + tuple_index += add_dependencies_from_unpacking(c, lhs, lhs_count, tuple_index, count); } } - return optional_ok; + if (optional_ok_) *optional_ok_ = optional_ok; } @@ -6404,7 +6434,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t } else { array_init(&operands, heap_allocator(), 2*ce->args.count); - check_unpack_arguments(c, -1, &operands, ce->args, false); + check_unpack_arguments(c, nullptr, -1, &operands, ce->args, false); } if (operand->mode == Addressing_Overload) { @@ -6644,7 +6674,7 @@ CallArgumentError check_polymorphic_struct_type(Checker *c, Operand *operand, As } else { array_init(&operands, heap_allocator(), 2*ce->args.count); - check_unpack_arguments(c, -1, &operands, ce->args, false); + check_unpack_arguments(c, nullptr, -1, &operands, ce->args, false); } CallArgumentError err = CallArgumentError_None; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 8c7586a12..d6c8f654d 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -692,7 +692,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { // an extra allocation Array operands = {}; array_init(&operands, c->tmp_allocator, 2 * lhs_count); - check_unpack_arguments(c, lhs_count, &operands, as->rhs, true); + check_unpack_arguments(c, nullptr, lhs_count, &operands, as->rhs, true); isize rhs_count = operands.count; for_array(i, operands) { @@ -849,7 +849,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } } else { array_init(&operands, heap_allocator(), 2*rs->results.count); - check_unpack_arguments(c, -1, &operands, rs->results, false); + check_unpack_arguments(c, nullptr, -1, &operands, rs->results, false); } diff --git a/src/checker.cpp b/src/checker.cpp index d40e05bfa..9f6ba76d5 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -181,10 +181,11 @@ struct DeclInfo { AstNode * type_expr; AstNode * init_expr; + Array init_expr_list; AstNode * proc_lit; // AstNode_ProcLit Type * gen_proc_type; // Precalculated - Map deps; // Key: Entity * + PtrSet deps; Array labels; }; @@ -273,6 +274,69 @@ struct CheckerFileNode { i32 score; // Higher the score, the better }; +struct GraphNode; +typedef PtrSet GraphNodeSet; + +void graph_node_set_destroy(GraphNodeSet *s) { + if (s->hashes.data != nullptr) { + ptr_set_destroy(s); + } +} + +void graph_node_set_add(GraphNodeSet *s, GraphNode *n) { + if (s->hashes.data == nullptr) { + ptr_set_init(s, heap_allocator()); + } + ptr_set_add(s, n); +} + +bool graph_node_set_exists(GraphNodeSet *s, GraphNode *n) { + return ptr_set_exists(s, n); +} + +void graph_node_set_remove(GraphNodeSet *s, GraphNode *n) { + ptr_set_remove(s, n); +} + + +struct GraphNode { + Entity * entity; // Procedure, Variable, Constant + GraphNodeSet pred; + GraphNodeSet succ; + isize index; // Index in array/queue + isize dep_count; +}; + + +void graph_node_destroy(GraphNode *n, gbAllocator a) { + graph_node_set_destroy(&n->pred); + graph_node_set_destroy(&n->succ); + gb_free(a, n); +} + + +int graph_node_cmp(GraphNode **data, isize i, isize j) { + GraphNode *x = data[i]; + GraphNode *y = data[j]; + isize a = x->entity->order_in_src; + isize b = y->entity->order_in_src; + if (x->dep_count < y->dep_count) return -1; + if (x->dep_count > y->dep_count) return +1; + return a < b ? -1 : b > a; +} + +void graph_node_swap(GraphNode **data, isize i, isize j) { + GraphNode *x = data[i]; + GraphNode *y = data[j]; + data[i] = y; + data[j] = x; + x->index = j; + y->index = i; +} + + + + struct CheckerContext { Scope * file_scope; Scope * scope; @@ -303,8 +367,15 @@ struct CheckerInfo { Map entities; // Key: Entity * Map foreigns; // Key: String Map files; // Key: String (full path) + Array variable_init_order; + + Map type_info_map; // Key: Type * isize type_info_count; + + Entity * entry_point; + PtrSet minimum_dependency_map; + }; struct Checker { @@ -372,8 +443,8 @@ void add_implicit_entity(Checker *c, AstNode *node, Entity *e); void init_declaration_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { d->parent = parent; d->scope = scope; - map_init(&d->deps, heap_allocator()); - array_init(&d->labels, heap_allocator()); + ptr_set_init(&d->deps, heap_allocator()); + array_init (&d->labels, heap_allocator()); } DeclInfo *make_declaration_info(gbAllocator a, Scope *scope, DeclInfo *parent) { @@ -383,7 +454,8 @@ DeclInfo *make_declaration_info(gbAllocator a, Scope *scope, DeclInfo *parent) { } void destroy_declaration_info(DeclInfo *d) { - map_destroy(&d->deps); + ptr_set_destroy(&d->deps); + array_free(&d->labels); } bool decl_info_has_init(DeclInfo *d) { @@ -626,7 +698,7 @@ void check_scope_usage(Checker *c, Scope *scope) { void add_dependency(DeclInfo *d, Entity *e) { - map_set(&d->deps, hash_entity(e), cast(bool)true); + ptr_set_add(&d->deps, e); } void add_declaration_dependency(Checker *c, Entity *e) { @@ -634,10 +706,8 @@ void add_declaration_dependency(Checker *c, Entity *e) { return; } if (c->context.decl != nullptr) { - DeclInfo **found = map_get(&c->info.entities, hash_entity(e)); - if (found) { - add_dependency(c->context.decl, e); - } + DeclInfo *decl = decl_info_of_entity(&c->info, e); + if (decl) add_dependency(c->context.decl, e); } } @@ -744,8 +814,9 @@ void init_checker_info(CheckerInfo *i) { map_init(&i->gen_types, a); map_init(&i->type_info_map, a); map_init(&i->files, a); - i->type_info_count = 0; + array_init(&i->variable_init_order, a); + i->type_info_count = 0; } void destroy_checker_info(CheckerInfo *i) { @@ -761,6 +832,7 @@ void destroy_checker_info(CheckerInfo *i) { map_destroy(&i->gen_types); map_destroy(&i->type_info_map); map_destroy(&i->files); + array_free(&i->variable_init_order); } @@ -1049,6 +1121,7 @@ void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclIn if (e->scope != nullptr) add_entity(c, e->scope, identifier, e); add_entity_definition(&c->info, identifier, e); map_set(&c->info.entities, hash_entity(e), d); + e->order_in_src = c->info.entities.entries.count; } @@ -1253,7 +1326,7 @@ void add_curr_ast_file(Checker *c, AstFile *file) { } -void add_dependency_to_map(Map *map, CheckerInfo *info, Entity *entity) { +void add_dependency_to_map(PtrSet *map, CheckerInfo *info, Entity *entity) { if (entity == nullptr) { return; } @@ -1265,26 +1338,23 @@ void add_dependency_to_map(Map *map, CheckerInfo *info, Entity *entity } } - if (map_get(map, hash_entity(entity)) != nullptr) { + if (ptr_set_exists(map, entity)) { return; } - map_set(map, hash_entity(entity), entity); - + ptr_set_add(map, entity); DeclInfo *decl = decl_info_of_entity(info, entity); - if (decl == nullptr) { - return; - } - - for_array(i, decl->deps.entries) { - Entity *e = cast(Entity *)decl->deps.entries[i].key.ptr; - add_dependency_to_map(map, info, e); + if (decl != nullptr) { + for_array(i, decl->deps.entries) { + Entity *e = decl->deps.entries[i].ptr; + add_dependency_to_map(map, info, e); + } } } -Map generate_minimum_dependency_map(CheckerInfo *info, Entity *start) { - Map map = {}; // Key: Entity * - map_init(&map, heap_allocator()); +PtrSet generate_minimum_dependency_map(CheckerInfo *info, Entity *start) { + PtrSet map = {}; // Key: Entity * + ptr_set_init(&map, heap_allocator()); for_array(i, info->definitions.entries) { Entity *e = info->definitions.entries[i].value; @@ -1309,8 +1379,101 @@ Map generate_minimum_dependency_map(CheckerInfo *info, Entity *start) return map; } -bool is_entity_in_dependency_map(Map *map, Entity *e) { - return map_get(map, hash_entity(e)) != nullptr; +bool is_entity_a_dependency(Entity *e) { + if (e == nullptr) return false; + switch (e->kind) { + case Entity_Procedure: + case Entity_Variable: + case Entity_Constant: + return true; + } + return false; +} + +Array generate_dependency_graph(CheckerInfo *info) { + gbAllocator a = heap_allocator(); + + Map M = {}; // Key: Entity * + map_init(&M, a); + defer (map_destroy(&M)); + for_array(i, info->entities.entries) { + auto *entry = &info->entities.entries[i]; + Entity * e = cast(Entity *)entry->key.ptr; + DeclInfo *d = entry->value; + if (is_entity_a_dependency(e)) { + GraphNode *n = gb_alloc_item(a, GraphNode); + n->entity = e; + map_set(&M, hash_pointer(e), n); + } + } + + + // Calculate edges for graph M + for_array(i, M.entries) { + Entity * e = cast(Entity *)M.entries[i].key.ptr; + GraphNode *n = M.entries[i].value; + + DeclInfo *decl = decl_info_of_entity(info, e); + if (decl != nullptr) { + for_array(j, decl->deps.entries) { + auto entry = decl->deps.entries[j]; + Entity *dep = entry.ptr; + if (dep && is_entity_a_dependency(dep)) { + GraphNode **m_ = map_get(&M, hash_pointer(dep)); + if (m_ != nullptr) { + GraphNode *m = *m_; + graph_node_set_add(&n->succ, m); + graph_node_set_add(&m->pred, n); + } + } + } + } + } + + Array G = {}; + array_init(&G, a); + + for_array(i, M.entries) { + auto *entry = &M.entries[i]; + Entity * e = cast(Entity *)entry->key.ptr; + GraphNode *n = entry->value; + + if (e->kind == Entity_Procedure) { + // Connect each pred `p` of `n` with each succ `s` and frop + // the procedure node + for_array(j, n->pred.entries) { + GraphNode *p = cast(GraphNode *)n->pred.entries[j].ptr; + + // Ignore self-cycles + if (p != n) { + // Each succ `s` of `n` becomes a succ of `p`, and + // each pred `p` of `n` becomes a pred of `s` + for_array(k, n->succ.entries) { + GraphNode *s = n->succ.entries[k].ptr; + // Ignore self-cycles + if (s != n) { + graph_node_set_add(&p->succ, s); + graph_node_set_add(&s->pred, p); + // Remove edge to `n` + graph_node_set_remove(&s->pred, n); + } + } + // Remove edge to `n` + graph_node_set_remove(&p->succ, n); + } + } + } else { + array_add(&G, n); + } + } + + for_array(i, G) { + GraphNode *n = G[i]; + n->index = i; + n->dep_count = n->succ.entries.count; + } + + return G; } @@ -1668,6 +1831,7 @@ void check_collect_entities(Checker *c, Array nodes, bool is_file_sco di->entities = entities; di->type_expr = vd->type; di->init_expr = vd->values[0]; + di->init_expr_list = vd->values; if (vd->flags & VarDeclFlag_thread_local) { @@ -1676,6 +1840,7 @@ void check_collect_entities(Checker *c, Array nodes, bool is_file_sco } + for_array(i, vd->names) { AstNode *name = vd->names[i]; AstNode *value = nullptr; @@ -1705,7 +1870,7 @@ void check_collect_entities(Checker *c, Array nodes, bool is_file_sco entities[entity_count++] = e; DeclInfo *d = di; - if (d == nullptr) { + if (d == nullptr || i > 0) { AstNode *init_expr = value; d = make_declaration_info(heap_allocator(), e->scope, c->context.decl); d->type_expr = vd->type; @@ -1719,6 +1884,10 @@ void check_collect_entities(Checker *c, Array nodes, bool is_file_sco di->entity_count = entity_count; } + if (vd->values.count > 0 && entity_count != vd->values.count) { + error(decl, "Variable declarations in the global scope can only declare 1 variable at a time"); + } + check_arity_match(c, vd); } else { for_array(i, vd->names) { @@ -2271,6 +2440,134 @@ void check_import_entities(Checker *c, Map *file_scopes) { } } +Array find_entity_path(Map *map, Entity *start, Entity *end, Map *visited = nullptr) { + Map visited_ = {}; + bool made_visited = false; + if (visited == nullptr) { + made_visited = true; + map_init(&visited_, heap_allocator()); + visited = &visited_; + } + defer (if (made_visited) { + map_destroy(&visited_); + }); + + Array empty_path = {}; + + HashKey key = hash_pointer(start); + + if (map_get(visited, key) != nullptr) { + return empty_path; + } + map_set(visited, key, start); + + DeclInfo **found = map_get(map, key); + if (found) { + DeclInfo *decl = *found; + for_array(i, decl->deps.entries) { + Entity *dep = decl->deps.entries[i].ptr; + if (dep == end) { + Array path = {}; + array_init(&path, heap_allocator()); + array_add(&path, dep); + return path; + } + Array next_path = find_entity_path(map, dep, end, visited); + if (next_path.count > 0) { + array_add(&next_path, dep); + return next_path; + } + } + } + return empty_path; +} + + +void calculate_variable_init_order(Checker *c) { + CheckerInfo *info = &c->info; + auto *m = &info->entities; + + Array dep_graph = generate_dependency_graph(info); + defer ({ + for_array(i, dep_graph) { + graph_node_destroy(dep_graph[i], heap_allocator()); + } + array_free(&dep_graph); + }); + + // NOTE(bill): Priority queue + auto pq = priority_queue_create(dep_graph, graph_node_cmp, graph_node_swap); + + PtrSet emitted = {}; + ptr_set_init(&emitted, heap_allocator()); + defer (ptr_set_destroy(&emitted)); + + while (pq.queue.count > 0) { + GraphNode *n = priority_queue_pop(&pq); + Entity *e = n->entity; + + if (n->dep_count > 0) { + // TODO(bill): print out the cyclic initialization order + auto path = find_entity_path(m, e, e); + defer (array_free(&path)); + + if (path.count > 0) { + Entity *e = path[0]; + error(e->token, "Cyclic initialization of `%.*s`", LIT(e->token.string)); + for (isize i = path.count-1; i >= 0; i--) { + error(e->token, "\t`%.*s` refers to", LIT(e->token.string)); + e = path[i]; + } + error(e->token, "\t`%.*s`", LIT(e->token.string)); + } + } + + for_array(i, n->pred.entries) { + GraphNode *p = n->pred.entries[i].ptr; + p->dep_count -= 1; + priority_queue_fix(&pq, p->index); + } + + if (e == nullptr || e->kind != Entity_Variable) { + continue; + } + DeclInfo *d = decl_info_of_entity(info, e); + + // if (!decl_info_has_init(d)) { + // continue; + // } + + if (ptr_set_exists(&emitted, d)) { + continue; + } + ptr_set_add(&emitted, d); + + // TODO(bill): add to init order + + if (d->entities == nullptr) { + d->entities = gb_alloc_array(c->allocator, Entity *, 1); + d->entities[0] = e; + d->entity_count = 1; + } + array_add(&info->variable_init_order, d); + } + + if (false) { + gb_printf("Variable Initialization Order:\n"); + for_array(i, info->variable_init_order) { + DeclInfo *d = info->variable_init_order[i]; + for (isize j = 0; j < d->entity_count; j++) { + Entity *e = d->entities[j]; + if (j == 0) gb_printf("\t"); + if (j > 0) gb_printf(", "); + gb_printf("`%.*s` %td", LIT(e->token.string), e->order_in_src); + } + gb_printf("\n"); + } + gb_printf("\n"); + } +} + void check_parsed_files(Checker *c) { Map file_scopes; // Key: String (fullpath) @@ -2355,6 +2652,25 @@ void check_parsed_files(Checker *c) { check_proc_body(c, pi->token, pi->decl, pi->type, pi->body); } + { + for_array(i, c->info.entities.entries) { + auto *entry = &c->info.entities.entries[i]; + Entity *e = cast(Entity *)entry->key.ptr; + String name = e->token.string; + if (e->kind == Entity_Procedure && !e->scope->is_global) { + if (e->scope->is_init && name == "main") { + c->info.entry_point = e; + break; + } + } + } + c->info.minimum_dependency_map = generate_minimum_dependency_map(&c->info, c->info.entry_point); + } + + // Calculate initialization order of global variables + calculate_variable_init_order(c); + + // Add untyped expression values for_array(i, c->info.untyped.entries) { auto *entry = &c->info.untyped.entries[i]; diff --git a/src/common.cpp b/src/common.cpp index 74fbbb019..06cb674dd 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -107,6 +107,8 @@ u128 fnv128a(void const *data, isize len) { } #include "map.cpp" +#include "ptr_set.cpp" +#include "priority_queue.cpp" diff --git a/src/entity.cpp b/src/entity.cpp index 21ef9095f..2b0b0c379 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -78,6 +78,8 @@ struct Entity { Entity * using_parent; AstNode * using_expr; + isize order_in_src; + union { struct { ExactValue value; diff --git a/src/ir.cpp b/src/ir.cpp index c777280bd..714af2a6a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19,7 +19,7 @@ struct irModule { String layout; // String triple; - Map min_dep_map; // Key: Entity * + PtrSet min_dep_map; Map values; // Key: Entity * Map members; // Key: String Map entity_names; // Key: Entity * of the typename @@ -5783,7 +5783,7 @@ irValue *ir_build_cond(irProcedure *proc, AstNode *cond, irBlock *true_block, ir void ir_build_poly_proc(irProcedure *proc, AstNodeProcLit *pd, Entity *e) { GB_ASSERT(pd->body != nullptr); - if (is_entity_in_dependency_map(&proc->module->min_dep_map, e) == false) { + if (ptr_set_exists(&proc->module->min_dep_map, e) == false) { // NOTE(bill): Nothing depends upon it so doesn't need to be built return; } @@ -5845,7 +5845,7 @@ void ir_build_constant_value_decl(irProcedure *proc, AstNodeValueDecl *vd) { } } - if (!polymorphic_struct && map_get(&proc->module->min_dep_map, hash_pointer(e)) == nullptr) { + if (!polymorphic_struct && !ptr_set_exists(&proc->module->min_dep_map, e)) { continue; } @@ -5874,7 +5874,7 @@ void ir_build_constant_value_decl(irProcedure *proc, AstNodeValueDecl *vd) { auto procs = *found; for_array(i, procs) { Entity *e = procs[i]; - if (map_get(&proc->module->min_dep_map, hash_pointer(e)) == nullptr) { + if (!ptr_set_exists(&proc->module->min_dep_map, e)) { continue; } DeclInfo *d = decl_info_of_entity(info, e); @@ -7545,7 +7545,7 @@ void ir_gen_tree(irGen *s) { } isize global_variable_max_count = 0; - Entity *entry_point = nullptr; + Entity *entry_point = info->entry_point; bool has_dll_main = false; bool has_win_main = false; @@ -7557,7 +7557,8 @@ void ir_gen_tree(irGen *s) { global_variable_max_count++; } else if (e->kind == Entity_Procedure && !e->scope->is_global) { if (e->scope->is_init && name == "main") { - entry_point = e; + GB_ASSERT(e == entry_point); + // entry_point = e; } if ((e->Procedure.tags & ProcTag_export) != 0 || (e->Procedure.link_name.len > 0) || @@ -7582,7 +7583,63 @@ void ir_gen_tree(irGen *s) { array_init(&global_variables, m->tmp_allocator, global_variable_max_count); m->entry_point_entity = entry_point; - m->min_dep_map = generate_minimum_dependency_map(info, entry_point); + m->min_dep_map = info->minimum_dependency_map; + + for_array(i, info->variable_init_order) { + DeclInfo *d = info->variable_init_order[i]; + + for (isize j = 0; j < d->entity_count; j++) { + Entity *e = d->entities[j]; + + if (!e->scope->is_file) { + continue; + } + + if (!ptr_set_exists(&m->min_dep_map, e)) { + continue; + } + DeclInfo *decl = decl_info_of_entity(info, e); + if (decl == nullptr) { + continue; + } + + String name = e->token.string; + String original_name = name; + if (!e->scope->is_global) { + name = ir_mangle_name(s, e->token.pos.file, e); + } + map_set(&m->entity_names, hash_entity(e), name); + + irValue *g = ir_value_global(a, e, nullptr); + g->Global.name = name; + g->Global.is_thread_local = e->Variable.is_thread_local; + + + irGlobalVariable var = {}; + var.var = g; + var.decl = decl; + + if (decl->init_expr != nullptr) { + if (is_type_any(e->type)) { + } else { + TypeAndValue tav = type_and_value_of_expr(info, decl->init_expr); + if (tav.mode != Addressing_Invalid) { + if (tav.value.kind != ExactValue_Invalid) { + ExactValue v = tav.value; + g->Global.value = ir_add_module_constant(m, tav.type, v); + } + } + } + } + + // if (g->Global.value == nullptr) { + array_add(&global_variables, var); + // } + + ir_module_add_value(m, e, g); + map_set(&m->members, hash_string(name), g); + } + } for_array(i, info->entities.entries) { auto *entry = &info->entities.entries[i]; @@ -7595,6 +7652,10 @@ void ir_gen_tree(irGen *s) { continue; } + if (e->kind == Entity_Variable) { + // NOTE(bill): Handled above as it requires a specific load order + continue; + } bool polymorphic_struct = false; if (e->type != nullptr && e->kind == Entity_TypeName) { @@ -7604,7 +7665,7 @@ void ir_gen_tree(irGen *s) { } } - if (!polymorphic_struct && map_get(&m->min_dep_map, hash_entity(e)) == nullptr) { + if (!polymorphic_struct && !ptr_set_exists(&m->min_dep_map, e)) { // NOTE(bill): Nothing depends upon it so doesn't need to be built continue; } @@ -7622,7 +7683,6 @@ void ir_gen_tree(irGen *s) { } else if (check_is_entity_overloaded(e)) { name = ir_mangle_name(s, e->token.pos.file, e); } - map_set(&m->entity_names, hash_entity(e), name); switch (e->kind) { @@ -7631,39 +7691,6 @@ void ir_gen_tree(irGen *s) { ir_gen_global_type_name(m, e, name); break; - case Entity_Variable: { - irValue *g = ir_value_global(a, e, nullptr); - g->Global.name = name; - g->Global.is_thread_local = e->Variable.is_thread_local; - - irGlobalVariable var = {}; - var.var = g; - var.decl = decl; - - if (decl->init_expr != nullptr) { - if (is_type_any(e->type)) { - - } else { - TypeAndValue tav = type_and_value_of_expr(info, decl->init_expr); - if (tav.mode != Addressing_Invalid) { - if (tav.value.kind != ExactValue_Invalid) { - ExactValue v = tav.value; - // if (v.kind != ExactValue_String) { - g->Global.value = ir_add_module_constant(m, tav.type, v); - // } - } - } - } - } - - if (g->Global.value == nullptr) { - array_add(&global_variables, var); - } - - ir_module_add_value(m, e, g); - map_set(&m->members, hash_string(name), g); - } break; - case Entity_Procedure: { ast_node(pl, ProcLit, decl->proc_lit); String original_name = name; @@ -7863,52 +7890,7 @@ void ir_gen_tree(irGen *s) { ir_emit_global_call(proc, "__init_context", args, 1); } - // TODO(bill): Should do a dependency graph do check which order to initialize them in? - for_array(i, global_variables) { - irGlobalVariable *var = &global_variables[i]; - if (var->decl->init_expr != nullptr) { - var->init = ir_build_expr(proc, var->decl->init_expr); - } - } - // NOTE(bill): Initialize constants first - for_array(i, global_variables) { - irGlobalVariable *var = &global_variables[i]; - if (var->init != nullptr && var->init->kind == irValue_Constant) { - Type *t = type_deref(ir_type(var->var)); - if (is_type_any(t)) { - // NOTE(bill): Edge case for `any` type - Type *var_type = default_type(ir_type(var->init)); - irValue *g = ir_add_global_generated(proc->module, var_type, var->init); - irValue *data = ir_emit_struct_ep(proc, var->var, 0); - irValue *ti = ir_emit_struct_ep(proc, var->var, 1); - ir_emit_store(proc, data, ir_emit_conv(proc, g, t_rawptr)); - ir_emit_store(proc, ti, ir_type_info(proc, var_type)); - } else { - ir_emit_store(proc, var->var, var->init); - } - } - } - - for_array(i, global_variables) { - irGlobalVariable *var = &global_variables[i]; - if (var->init != nullptr && var->init->kind != irValue_Constant) { - Type *t = type_deref(ir_type(var->var)); - if (is_type_any(t)) { - // NOTE(bill): Edge case for `any` type - Type *var_type = default_type(ir_type(var->init)); - irValue *g = ir_add_global_generated(proc->module, var_type, var->init); - ir_emit_store(proc, g, var->init); - - irValue *data = ir_emit_struct_ep(proc, var->var, 0); - irValue *ti = ir_emit_struct_ep(proc, var->var, 1); - ir_emit_store(proc, data, ir_emit_conv(proc, g, t_rawptr)); - ir_emit_store(proc, ti, ir_type_info(proc, var_type)); - } else { - ir_emit_store(proc, var->var, var->init); - } - } - } { // NOTE(bill): Setup type_info data CheckerInfo *info = proc->module->info; @@ -8312,6 +8294,31 @@ void ir_gen_tree(irGen *s) { } } + for_array(i, global_variables) { + irGlobalVariable *var = &global_variables[i]; + if (var->decl->init_expr != nullptr) { + var->init = ir_build_expr(proc, var->decl->init_expr); + } + + if (var->init != nullptr) { + Type *t = type_deref(ir_type(var->var)); + + if (is_type_any(t)) { + // NOTE(bill): Edge case for `any` type + Type *var_type = default_type(ir_type(var->init)); + irValue *g = ir_add_global_generated(proc->module, var_type, var->init); + ir_emit_store(proc, g, var->init); + + irValue *data = ir_emit_struct_ep(proc, var->var, 0); + irValue *ti = ir_emit_struct_ep(proc, var->var, 1); + ir_emit_store(proc, data, ir_emit_conv(proc, g, t_rawptr)); + ir_emit_store(proc, ti, ir_type_info(proc, var_type)); + } else { + ir_emit_store(proc, var->var, var->init); + } + } + } + ir_end_procedure_body(proc); } diff --git a/src/parser.cpp b/src/parser.cpp index de2da964a..e504a0d62 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5086,10 +5086,11 @@ ParseFileError parse_files(Parser *p, String init_filename) { array_add(&p->imports, runtime_file); shared_file_count++; } + array_add(&p->imports, init_imported_file); p->init_fullpath = init_fullpath; - +/* // IMPORTANT TODO(bill): Figure out why this doesn't work on *nix sometimes #if USE_THREADED_PARSER && defined(GB_SYSTEM_WINDOWS) isize thread_count = gb_max(build_context.thread_count, 1); @@ -5148,14 +5149,15 @@ ParseFileError parse_files(Parser *p, String init_filename) { } } } -#else - for_array(i, p->imports) { - ParseFileError err = parse_import(p, p->imports[i]); +#else */ + isize import_index = 0; + for (; import_index < p->imports.count; import_index++) { + ParseFileError err = parse_import(p, p->imports[import_index]); if (err != ParseFile_None) { return err; } } -#endif +// #endif for_array(i, p->files) { p->total_token_count += p->files[i].tokens.count; diff --git a/src/ssa.cpp b/src/ssa.cpp index 5862cca20..25afef118 100644 --- a/src/ssa.cpp +++ b/src/ssa.cpp @@ -159,7 +159,7 @@ struct ssaModule { gbAllocator tmp_allocator; gbArena tmp_arena; - Map min_dep_map; // Key: Entity * + PtrSet min_dep_map; Map values; // Key: Entity * // List of registers for the specific architecture Array registers; @@ -2464,7 +2464,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { continue; } - if (map_get(&m.min_dep_map, hash_pointer(e)) == nullptr) { + if (!ptr_set_exists(&m.min_dep_map, e)) { // NOTE(bill): Nothing depends upon it so doesn't need to be built continue; }