From bfdcf900ef25566e57e46ec46683f8b6f2a9515a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Jan 2023 00:56:06 +0000 Subject: Remove `global_` prefix from `global_thread_pool_*` procedures --- src/llvm_backend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 146cb2944..1c401552e 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2272,7 +2272,7 @@ gb_internal void lb_generate_code(lbGenerator *gen) { wd->code_gen_file_type = code_gen_file_type; wd->filepath_obj = filepath_obj; wd->m = m; - global_thread_pool_add_task(lb_llvm_emit_worker_proc, wd); + thread_pool_add_task(lb_llvm_emit_worker_proc, wd); } thread_pool_wait(&global_thread_pool); -- cgit v1.2.3 From 529383f5b17d74f66bebb8679820a69476635b6a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Jan 2023 15:30:04 +0000 Subject: Correct a race condition when checking the procedure body --- src/build_settings.cpp | 1 + src/check_decl.cpp | 25 ++--- src/check_expr.cpp | 23 ++++- src/checker.cpp | 224 ++++++++++++++++++++++++++++++++++--------- src/checker.hpp | 21 +++- src/llvm_backend.cpp | 6 ++ src/llvm_backend.hpp | 1 + src/llvm_backend_expr.cpp | 6 +- src/llvm_backend_general.cpp | 5 +- src/llvm_backend_proc.cpp | 3 +- src/llvm_backend_stmt.cpp | 6 +- src/main.cpp | 5 + 12 files changed, 260 insertions(+), 66 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 97b512b81..f59b5c0f7 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -291,6 +291,7 @@ struct BuildContext { bool show_error_line; bool ignore_lazy; + bool ignore_llvm_build; bool use_subsystem_windows; bool ignore_microsoft_magic; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 4e3c1b405..8f95c1a49 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1419,9 +1419,9 @@ struct ProcUsingVar { }; -gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) { +gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) { if (body == nullptr) { - return; + return false; } GB_ASSERT(body->kind == Ast_BlockStmt); @@ -1502,7 +1502,7 @@ gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de MUTEX_GUARD_BLOCK(ctx->scope->mutex) for_array(i, using_entities) { Entity *e = using_entities[i].e; Entity *uvar = using_entities[i].uvar; - Entity *prev = scope_insert(ctx->scope, uvar, false); + Entity *prev = scope_insert_no_mutex(ctx->scope, uvar); if (prev != nullptr) { error(e->token, "Namespace collision while 'using' procedure argument '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string)); error_line("%.*s != %.*s\n", LIT(uvar->token.string), LIT(prev->token.string)); @@ -1514,7 +1514,7 @@ gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de bool where_clause_ok = evaluate_where_clauses(ctx, nullptr, decl->scope, &decl->proc_lit->ProcLit.where_clauses, !decl->where_clauses_evaluated); if (!where_clause_ok) { // NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed - return; + return false; } check_open_scope(ctx, body); @@ -1526,7 +1526,12 @@ gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de // NOTE(bill): Don't err here } - GB_ASSERT(decl->defer_use_checked == false); + GB_ASSERT(decl->proc_checked_state != ProcCheckedState_Checked); + if (decl->defer_use_checked) { + GB_ASSERT(is_type_polymorphic(type, true)); + error(token, "Defer Use Checked: %.*s", LIT(decl->entity->token.string)); + GB_ASSERT(decl->defer_use_checked == false); + } check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls); @@ -1575,10 +1580,8 @@ gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de if (decl->parent != nullptr) { Scope *ps = decl->parent->scope; if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) { - return; - } else { - mutex_lock(&ctx->info->deps_mutex); - + return true; + } else MUTEX_GUARD_BLOCK(&ctx->info->deps_mutex) { // NOTE(bill): Add the dependencies from the procedure literal (lambda) // But only at the procedure level for (auto const &entry : decl->deps) { @@ -1589,8 +1592,8 @@ gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de Type *t = entry.ptr; ptr_set_add(&decl->parent->type_info_deps, t); } - - mutex_unlock(&ctx->info->deps_mutex); } } + + return true; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index eb9f76547..5445e73c7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -86,7 +86,6 @@ gb_internal Entity * find_polymorphic_record_entity (CheckerContext *c, Type *or gb_internal void check_not_tuple (CheckerContext *c, Operand *operand); gb_internal void convert_to_typed (CheckerContext *c, Operand *operand, Type *target_type); gb_internal gbString expr_to_string (Ast *expression); -gb_internal void check_proc_body (CheckerContext *c, Token token, DeclInfo *decl, Type *type, Ast *body); gb_internal void update_untyped_expr_type (CheckerContext *c, Ast *e, Type *type, bool final); gb_internal bool check_is_terminating (Ast *node, String const &label); gb_internal bool check_has_break (Ast *stmt, String const &label, bool implicit); @@ -478,6 +477,22 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E if (poly_proc_data) { poly_proc_data->gen_entity = other; } + + DeclInfo *decl = other->decl_info; + if (decl->proc_checked_state != ProcCheckedState_Checked) { + ProcInfo *proc_info = gb_alloc_item(permanent_allocator(), ProcInfo); + proc_info->file = other->file; + proc_info->token = other->token; + proc_info->decl = decl; + proc_info->type = other->type; + proc_info->body = decl->proc_lit->ProcLit.body; + proc_info->tags = other->Procedure.tags;; + proc_info->generated_from_polymorphic = true; + proc_info->poly_def_node = poly_def_node; + + check_procedure_later(nctx.checker, proc_info); + } + return true; } } @@ -518,7 +533,8 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E d->gen_proc_type = final_proc_type; d->type_expr = pl->type; d->proc_lit = proc_lit; - d->proc_checked = false; + d->proc_checked_state = ProcCheckedState_Unchecked; + d->defer_use_checked = false; Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags); entity->identifier = ident; @@ -528,7 +544,8 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E entity->scope = scope->parent; entity->file = base_entity->file; entity->pkg = base_entity->pkg; - entity->flags &= ~EntityFlag_ProcBodyChecked; + entity->flags = 0; + d->entity = entity; AstFile *file = nullptr; { diff --git a/src/checker.cpp b/src/checker.cpp index d3a9c3d2c..f4c9b6822 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1,3 +1,5 @@ +#define DEBUG_CHECK_ALL_PROCEDURES 1 + #include "entity.cpp" #include "types.cpp" @@ -179,6 +181,7 @@ gb_internal void import_graph_node_swap(ImportGraphNode **data, isize i, isize j gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { + gb_zero_item(d); d->parent = parent; d->scope = scope; ptr_set_init(&d->deps, heap_allocator()); @@ -438,9 +441,44 @@ gb_internal Entity *scope_lookup(Scope *s, String const &name) { return entity; } +gb_internal Entity *scope_insert_with_name_no_mutex(Scope *s, String const &name, Entity *entity) { + if (name == "") { + return nullptr; + } + StringHashKey key = string_hash_string(name); + Entity **found = nullptr; + Entity *result = nullptr; + + found = string_map_get(&s->elements, key); + + if (found) { + if (entity != *found) { + result = *found; + } + goto end; + } + if (s->parent != nullptr && (s->parent->flags & ScopeFlag_Proc) != 0) { + found = string_map_get(&s->parent->elements, key); + if (found) { + if ((*found)->flags & EntityFlag_Result) { + if (entity != *found) { + result = *found; + } + goto end; + } + } + } + + string_map_set(&s->elements, key, entity); + if (entity->scope == nullptr) { + entity->scope = s; + } +end:; + return result; +} -gb_internal Entity *scope_insert_with_name(Scope *s, String const &name, Entity *entity, bool use_mutex=true) { +gb_internal Entity *scope_insert_with_name(Scope *s, String const &name, Entity *entity) { if (name == "") { return nullptr; } @@ -448,9 +486,8 @@ gb_internal Entity *scope_insert_with_name(Scope *s, String const &name, Entity Entity **found = nullptr; Entity *result = nullptr; - if (use_mutex) mutex_lock(&s->mutex); - defer (if (use_mutex) mutex_unlock(&s->mutex)); - + MUTEX_GUARD(&s->mutex); + found = string_map_get(&s->elements, key); if (found) { @@ -479,9 +516,14 @@ end:; return result; } -gb_internal Entity *scope_insert(Scope *s, Entity *entity, bool use_mutex) { +gb_internal Entity *scope_insert(Scope *s, Entity *entity) { String name = entity->token.string; - return scope_insert_with_name(s, name, entity, use_mutex); + return scope_insert_with_name(s, name, entity); +} + +gb_internal Entity *scope_insert_no_mutex(Scope *s, Entity *entity) { + String name = entity->token.string; + return scope_insert_with_name_no_mutex(s, name, entity); } @@ -1135,6 +1177,9 @@ gb_internal void init_checker_info(CheckerInfo *i) { map_init(&i->objc_msgSend_types, a); string_map_init(&i->load_file_cache, a); + + array_init(&i->all_procedures, heap_allocator()); + } gb_internal void destroy_checker_info(CheckerInfo *i) { @@ -1934,6 +1979,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { gb_global std::atomic global_procedure_body_in_worker_queue = false; +gb_global std::atomic global_after_checking_procedure_bodies = false; gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc); @@ -1941,12 +1987,24 @@ gb_internal void check_procedure_later(Checker *c, ProcInfo *info) { GB_ASSERT(info != nullptr); GB_ASSERT(info->decl != nullptr); - if (global_procedure_body_in_worker_queue) { + if (global_after_checking_procedure_bodies) { + Entity *e = info->decl->entity; + debugf("CHECK PROCEDURE LATER! %.*s :: %s {...}\n", LIT(e->token.string), type_to_string(e->type)); + } + + if (global_procedure_body_in_worker_queue.load()) { thread_pool_add_task(check_proc_info_worker_proc, info); } else { - GB_ASSERT(global_procedure_body_in_worker_queue == false); array_add(&c->procs_to_check, info); } + + if (DEBUG_CHECK_ALL_PROCEDURES) { + MUTEX_GUARD_BLOCK(&c->info.all_procedures_mutex) { + GB_ASSERT(info != nullptr); + GB_ASSERT(info->decl != nullptr); + array_add(&c->info.all_procedures, info); + } + } } gb_internal void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, Ast *body, u64 tags) { @@ -5010,24 +5068,26 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u if (pi->type == nullptr) { return false; } - Entity *e = pi->decl->entity; - MUTEX_GUARD_BLOCK(&pi->decl->proc_checked_mutex) { - if (pi->decl->proc_checked) { - if (e != nullptr) { - GB_ASSERT(e->flags & EntityFlag_ProcBodyChecked); - } - return true; - } - if (e != nullptr && (e->flags & EntityFlag_ProcBodyChecked) != 0) { - GB_ASSERT(pi->decl->proc_checked); - return true; + MUTEX_GUARD(&pi->decl->proc_checked_mutex); + + Entity *e = pi->decl->entity; + switch (pi->decl->proc_checked_state.load()) { + case ProcCheckedState_InProgress: + if (e) { + GB_ASSERT(global_procedure_body_in_worker_queue.load()); } - pi->decl->proc_checked = true; + return false; + case ProcCheckedState_Checked: if (e != nullptr) { - e->flags |= EntityFlag_ProcBodyChecked; + GB_ASSERT(e->flags & EntityFlag_ProcBodyChecked); } + return true; + case ProcCheckedState_Unchecked: + // okay + break; } + pi->decl->proc_checked_state.store(ProcCheckedState_InProgress); GB_ASSERT(pi->type->kind == Type_Proc); TypeProc *pt = &pi->type->Proc; @@ -5039,17 +5099,21 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u token = ast_token(pi->poly_def_node); } error(token, "Unspecialized polymorphic procedure '%.*s'", LIT(name)); + pi->decl->proc_checked_state.store(ProcCheckedState_Unchecked); return false; } if (pt->is_polymorphic && pt->is_poly_specialized) { + Entity *e = pi->decl->entity; + GB_ASSERT(e != nullptr); if ((e->flags & EntityFlag_Used) == 0) { // NOTE(bill, 2019-08-31): It was never used, don't check + // NOTE(bill, 2023-01-02): This may need to be checked again if it is used elsewhere? + pi->decl->proc_checked_state.store(ProcCheckedState_Unchecked); return false; } } - CheckerContext ctx = make_checker_context(c); defer (destroy_checker_context(&ctx)); reset_checker_context(&ctx, pi->file, untyped); @@ -5077,14 +5141,34 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u ctx.state_flags &= ~StateFlag_type_assert; } - check_proc_body(&ctx, pi->token, pi->decl, pi->type, pi->body); + bool body_was_checked = check_proc_body(&ctx, pi->token, pi->decl, pi->type, pi->body); + + if (body_was_checked) { + pi->decl->proc_checked_state.store(ProcCheckedState_Checked); + if (pi->body) { + Entity *e = pi->decl->entity; + if (e != nullptr) { + e->flags |= EntityFlag_ProcBodyChecked; + } + } + } else { + pi->decl->proc_checked_state.store(ProcCheckedState_Unchecked); + if (pi->body) { + Entity *e = pi->decl->entity; + if (e != nullptr) { + e->flags &= ~EntityFlag_ProcBodyChecked; + } + } + } + add_untyped_expressions(&c->info, ctx.untyped); + return true; } GB_STATIC_ASSERT(sizeof(isize) == sizeof(void *)); -gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped); +gb_internal bool consume_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped); gb_internal void check_unchecked_bodies(Checker *c) { // NOTE(2021-02-26, bill): Sanity checker @@ -5092,10 +5176,15 @@ gb_internal void check_unchecked_bodies(Checker *c) { // even ones which should not exist, due to the multithreaded nature of the parser // HACK TODO(2021-02-26, bill): Actually fix this race condition + GB_ASSERT(c->procs_to_check.count == 0); + UntypedExprInfoMap untyped = {}; map_init(&untyped, heap_allocator()); defer (map_destroy(&untyped)); + // use the `procs_to_check` array + global_procedure_body_in_worker_queue = false; + for (auto const &entry : c->info.minimum_dependency_set) { Entity *e = entry.ptr; if (e == nullptr || e->kind != Entity_Procedure) { @@ -5122,19 +5211,22 @@ gb_internal void check_unchecked_bodies(Checker *c) { } debugf("unchecked: %.*s\n", LIT(e->token.string)); - array_add(&c->procs_to_check, pi); + check_procedure_later(c, pi); } } - for (ProcInfo *pi : c->procs_to_check) { - Entity *e = pi->decl->entity; - if (consume_proc_info_queue(c, pi, &untyped)) { - add_dependency_to_set(c, e); - GB_ASSERT(e->flags & EntityFlag_ProcBodyChecked); + if (!global_procedure_body_in_worker_queue) { + for_array(i, c->procs_to_check) { + ProcInfo *pi = c->procs_to_check[i]; + consume_proc_info(c, pi, &untyped); } + array_clear(&c->procs_to_check); + } else { + thread_pool_wait(); } - thread_pool_wait(); + global_procedure_body_in_worker_queue = false; + global_after_checking_procedure_bodies = true; } gb_internal void check_test_procedures(Checker *c) { @@ -5172,8 +5264,15 @@ gb_internal void check_test_procedures(Checker *c) { gb_global std::atomic total_bodies_checked; -gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped) { +gb_internal bool consume_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped) { GB_ASSERT(pi->decl != nullptr); + switch (pi->decl->proc_checked_state.load()) { + case ProcCheckedState_InProgress: + return false; + case ProcCheckedState_Checked: + return true; + } + if (pi->decl->parent && pi->decl->parent->entity) { Entity *parent = pi->decl->parent->entity; // NOTE(bill): Only check a nested procedure if its parent's body has been checked first @@ -5187,9 +5286,11 @@ gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, UntypedExprIn if (untyped) { map_clear(untyped); } - bool ok = check_proc_info(c, pi, untyped); - total_bodies_checked.fetch_add(1, std::memory_order_relaxed); - return ok; + if (check_proc_info(c, pi, untyped)) { + total_bodies_checked.fetch_add(1, std::memory_order_relaxed); + return true; + } + return false; } struct CheckProcedureBodyWorkerData { @@ -5218,9 +5319,11 @@ gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc) { } } map_clear(untyped); - bool ok = check_proc_info(c, pi, untyped); - total_bodies_checked.fetch_add(1, std::memory_order_relaxed); - return !ok; + if (check_proc_info(c, pi, untyped)) { + total_bodies_checked.fetch_add(1, std::memory_order_relaxed); + return 0; + } + return 1; } @@ -5247,7 +5350,7 @@ gb_internal void check_procedure_bodies(Checker *c) { if (thread_count == 1) { UntypedExprInfoMap *untyped = &check_procedure_bodies_worker_data[0].untyped; for_array(i, c->procs_to_check) { - consume_proc_info_queue(c, c->procs_to_check[i], untyped); + consume_proc_info(c, c->procs_to_check[i], untyped); } array_clear(&c->procs_to_check); @@ -5266,9 +5369,6 @@ gb_internal void check_procedure_bodies(Checker *c) { thread_pool_wait(); - debugf("Total Procedure Bodies Checked: %td\n", total_bodies_checked.load(std::memory_order_relaxed)); - - global_procedure_body_in_worker_queue = false; } gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped) { @@ -5662,9 +5762,6 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("check test procedures"); check_test_procedures(c); - TIME_SECTION("check bodies have all been checked"); - check_unchecked_bodies(c); - TIME_SECTION("add type info for type definitions"); add_type_info_for_type_definitions(c); check_merge_queues_into_arrays(c); @@ -5672,6 +5769,12 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("generate minimum dependency set"); generate_minimum_dependency_set(c, c->info.entry_point); + TIME_SECTION("check bodies have all been checked"); + check_unchecked_bodies(c); + + check_merge_queues_into_arrays(c); + + TIME_SECTION("check entry point"); if (build_context.build_mode == BuildMode_Executable && !build_context.no_entry_point && build_context.command_kind != Command_test) { Scope *s = c->info.init_scope; @@ -5694,11 +5797,39 @@ gb_internal void check_parsed_files(Checker *c) { } } + thread_pool_wait(); + GB_ASSERT(c->procs_to_check.count == 0); + + if (DEBUG_CHECK_ALL_PROCEDURES) { + UntypedExprInfoMap untyped = {}; + map_init(&untyped, heap_allocator()); + defer (map_destroy(&untyped)); + + for_array(i, c->info.all_procedures) { + ProcInfo *pi = c->info.all_procedures[i]; + GB_ASSERT(pi != nullptr); + GB_ASSERT(pi->decl != nullptr); + Entity *e = pi->decl->entity; + auto proc_checked_state = pi->decl->proc_checked_state.load(); + if (e && ((e->flags & EntityFlag_ProcBodyChecked) == 0)) { + if ((e->flags & EntityFlag_Used) != 0) { + debugf("%.*s :: %s\n", LIT(e->token.string), type_to_string(e->type)); + debugf("proc body unchecked\n"); + debugf("Checked State: %s\n\n", ProcCheckedState_strings[proc_checked_state]); + + consume_proc_info(c, pi, &untyped); + } + } + } + } + + debugf("Total Procedure Bodies Checked: %td\n", total_bodies_checked.load(std::memory_order_relaxed)); + TIME_SECTION("check unique package names"); check_unique_package_names(c); - TIME_SECTION("sanity checks"); + check_merge_queues_into_arrays(c); GB_ASSERT(c->info.entity_queue.count.load(std::memory_order_relaxed) == 0); GB_ASSERT(c->info.definition_queue.count.load(std::memory_order_relaxed) == 0); @@ -5717,5 +5848,6 @@ gb_internal void check_parsed_files(Checker *c) { } } + TIME_SECTION("type check finish"); } diff --git a/src/checker.hpp b/src/checker.hpp index eaad1fa63..37aff41b1 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -142,6 +142,20 @@ typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc); gb_internal void check_decl_attributes(CheckerContext *c, Array const &attributes, DeclAttributeProc *proc, AttributeContext *ac); +enum ProcCheckedState : u8 { + ProcCheckedState_Unchecked, + ProcCheckedState_InProgress, + ProcCheckedState_Checked, + + ProcCheckedState_COUNT +}; + +char const *ProcCheckedState_strings[ProcCheckedState_COUNT] { + "Unchecked", + "In Progress", + "Checked", +}; + // DeclInfo is used to store information of certain declarations to allow for "any order" usage struct DeclInfo { DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment @@ -157,7 +171,7 @@ struct DeclInfo { Type * gen_proc_type; // Precalculated bool is_using; bool where_clauses_evaluated; - bool proc_checked; + std::atomic proc_checked_state; BlockingMutex proc_checked_mutex; isize defer_used; bool defer_use_checked; @@ -375,6 +389,9 @@ struct CheckerInfo { BlockingMutex load_file_mutex; StringMap load_file_cache; + + BlockingMutex all_procedures_mutex;; + Array all_procedures; }; struct CheckerContext { @@ -458,7 +475,7 @@ gb_internal Entity *entity_of_node(Ast *expr); gb_internal Entity *scope_lookup_current(Scope *s, String const &name); gb_internal Entity *scope_lookup (Scope *s, String const &name); gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_); -gb_internal Entity *scope_insert (Scope *s, Entity *entity, bool use_mutex=true); +gb_internal Entity *scope_insert (Scope *s, Entity *entity); gb_internal void add_type_and_value (CheckerInfo *i, Ast *expression, AddressingMode mode, Type *type, ExactValue value); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 1c401552e..3e62f678a 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2255,6 +2255,12 @@ gb_internal void lb_generate_code(lbGenerator *gen) { } } + if (build_context.ignore_llvm_build) { + gb_printf_err("LLVM SUCCESS!\n"); + gb_exit(1); + return; + } + if (do_threading && non_empty_module_count > 1) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 9f7caa3bb..50fb5701f 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -301,6 +301,7 @@ struct lbProcedure { lbBlock * curr_block; lbTargetList * target_list; PtrMap direct_parameters; + PtrMap local_entity_map; Ast *curr_stmt; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index d574caf4c..28a68b065 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3404,7 +3404,11 @@ gb_internal lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *exp lbValue v = {}; - lbValue *found = map_get(&p->module->values, e); + lbValue *found = nullptr; + found = map_get(&p->local_entity_map, e); + if (found == nullptr) { + found = map_get(&p->module->values, e); + } if (found) { v = *found; } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 0508c6171..940c94a13 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2714,7 +2714,6 @@ gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e) { return g; } } - GB_PANIC("\n\tError in: %s, missing value '%.*s'\n", token_pos_to_string(e->token.pos), LIT(e->token.string)); return {}; } @@ -2845,6 +2844,10 @@ gb_internal lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero lb_mem_zero_ptr(p, ptr, type, alignment); } + if (e != nullptr) { + map_set(&p->local_entity_map, e, val); + } + return lb_addr(val); } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 384d29ca7..9691afebc 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -68,7 +68,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i GB_ASSERT(entity != nullptr); GB_ASSERT(entity->kind == Entity_Procedure); if (!entity->Procedure.is_foreign) { - GB_ASSERT_MSG(entity->flags & EntityFlag_ProcBodyChecked, "%.*s :: %s", LIT(entity->token.string), type_to_string(entity->type)); + GB_ASSERT_MSG(entity->flags & EntityFlag_ProcBodyChecked, "%.*s :: %s (was parapoly: %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true)); } String link_name = {}; @@ -487,6 +487,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { lb_start_block(p, p->entry_block); map_init(&p->direct_parameters, heap_allocator()); + map_init(&p->local_entity_map, heap_allocator()); GB_ASSERT(p->type != nullptr); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 6400a8a9d..cdfb28aa7 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1531,6 +1531,9 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { lbValue global_val = {global, alloc_type_pointer(e->type)}; lb_add_entity(p->module, e, global_val); lb_add_member(p->module, mangled_name, global_val); + if (e) { + map_set(&p->local_entity_map, e, global_val); + } } } gb_internal void lb_append_tuple_values(lbProcedure *p, Array *dst_values, lbValue src_value) { @@ -2188,9 +2191,10 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { for_array(i, vd->names) { Ast *name = vd->names[i]; if (!is_blank_ident(name)) { + GB_ASSERT(name->kind == Ast_Ident); Entity *e = entity_of_node(name); TokenPos pos = ast_token(name).pos; - GB_ASSERT_MSG(e != nullptr, "%s", token_pos_to_string(pos)); + GB_ASSERT_MSG(e != nullptr, "\n%s missing entity for %.*s", token_pos_to_string(pos), LIT(name->Ident.token.string)); if (e->flags & EntityFlag_Static) { // NOTE(bill): If one of the entities is static, they all are is_static = true; diff --git a/src/main.cpp b/src/main.cpp index 3ad0e160f..42d6f8e87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -660,6 +660,7 @@ enum BuildFlagKind { // internal use only BuildFlag_InternalIgnoreLazy, + BuildFlag_InternalIgnoreLLVMBuild, #if defined(GB_SYSTEM_WINDOWS) BuildFlag_IgnoreVsSearch, @@ -832,6 +833,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_ErrorPosStyle, str_lit("error-pos-style"), BuildFlagParam_String, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all); #if defined(GB_SYSTEM_WINDOWS) add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build); @@ -1491,6 +1493,9 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_InternalIgnoreLazy: build_context.ignore_lazy = true; break; + case BuildFlag_InternalIgnoreLLVMBuild: + build_context.ignore_llvm_build = true; + break; #if defined(GB_SYSTEM_WINDOWS) case BuildFlag_IgnoreVsSearch: { GB_ASSERT(value.kind == ExactValue_Invalid); -- cgit v1.2.3 From 69934c3b0b1b8ad0a499574c39c1ab177a1fe30a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 Jan 2023 13:04:09 +0000 Subject: More `for_array(i, y)` to `for (x : y)` translations --- src/check_builtin.cpp | 15 ++++------ src/check_decl.cpp | 27 +++++++---------- src/check_stmt.cpp | 73 ++++++++++++++++------------------------------ src/llvm_backend.cpp | 9 ++---- src/llvm_backend_expr.cpp | 18 ++++-------- src/llvm_backend_stmt.cpp | 74 +++++++++++++++++++---------------------------- 6 files changed, 80 insertions(+), 136 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index af196234e..7c5521dde 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -96,8 +96,7 @@ gb_internal void check_or_else_expr_no_value_error(CheckerContext *c, String con gbString th = nullptr; if (type_hint != nullptr) { GB_ASSERT(bsrc->kind == Type_Union); - for_array(i, bsrc->Union.variants) { - Type *vt = bsrc->Union.variants[i]; + for (Type *vt : bsrc->Union.variants) { if (are_types_identical(vt, type_hint)) { th = type_to_string(type_hint); break; @@ -198,8 +197,7 @@ gb_internal void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_t { auto variables = array_make(permanent_allocator(), 0, param_types.count); - for_array(i, param_types) { - Type *type = param_types[i]; + for (Type *type : param_types) { Entity *param = alloc_entity_param(scope, blank_token, type, false, true); array_add(&variables, param); } @@ -3071,8 +3069,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As bool first_is_field_value = (ce->args[0]->kind == Ast_FieldValue); bool fail = false; - for_array(i, ce->args) { - Ast *arg = ce->args[i]; + for (Ast *arg : ce->args) { bool mix = false; if (first_is_field_value) { mix = arg->kind != Ast_FieldValue; @@ -3088,9 +3085,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As StringSet name_set = {}; string_set_init(&name_set, 2*ce->args.count); - for_array(i, ce->args) { + for (Ast *arg : ce->args) { String name = {}; - Ast *arg = ce->args[i]; if (arg->kind == Ast_FieldValue) { Ast *ename = arg->FieldValue.field; if (!fail && ename->kind != Ast_Ident) { @@ -4987,8 +4983,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As bool is_variant = false; - for_array(i, u->Union.variants) { - Type *vt = u->Union.variants[i]; + for (Type *vt : u->Union.variants) { if (are_types_identical(v, vt)) { is_variant = true; break; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 7b229db08..66f16546c 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -354,8 +354,7 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *t = base_type(e->type); if (t->kind == Type_Enum) { - for_array(i, t->Enum.fields) { - Entity *f = t->Enum.fields[i]; + for (Entity *f : t->Enum.fields) { if (f->kind != Entity_Constant) { continue; } @@ -1237,8 +1236,7 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, PtrSet entity_set = {}; ptr_set_init(&entity_set, 2*pg->args.count); - for_array(i, pg->args) { - Ast *arg = pg->args[i]; + for (Ast *arg : pg->args) { Entity *e = nullptr; Operand o = {}; if (arg->kind == Ast_Ident) { @@ -1271,7 +1269,7 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, ptr_set_destroy(&entity_set); - for_array(j, pge->entities) { + for (isize j = 0; j < pge->entities.count; j++) { Entity *p = pge->entities[j]; if (p->type == t_invalid) { // NOTE(bill): This invalid overload has already been handled @@ -1462,8 +1460,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de { if (type->Proc.param_count > 0) { TypeTuple *params = &type->Proc.params->Tuple; - for_array(i, params->variables) { - Entity *e = params->variables[i]; + for (Entity *e : params->variables) { if (e->kind != Entity_Variable) { continue; } @@ -1499,9 +1496,9 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de } } - MUTEX_GUARD_BLOCK(ctx->scope->mutex) for_array(i, using_entities) { - Entity *e = using_entities[i].e; - Entity *uvar = using_entities[i].uvar; + MUTEX_GUARD_BLOCK(ctx->scope->mutex) for (auto const &entry : using_entities) { + Entity *e = entry.e; + Entity *uvar = entry.uvar; Entity *prev = scope_insert_no_mutex(ctx->scope, uvar); if (prev != nullptr) { error(e->token, "Namespace collision while 'using' procedure argument '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string)); @@ -1519,8 +1516,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de check_open_scope(ctx, body); { - for_array(i, using_entities) { - Entity *uvar = using_entities[i].uvar; + for (auto const &entry : using_entities) { + Entity *uvar = entry.uvar; Entity *prev = scope_insert(ctx->scope, uvar); gb_unused(prev); // NOTE(bill): Don't err here @@ -1537,12 +1534,10 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de decl->defer_use_checked = true; - for_array(i, bs->stmts) { - Ast *stmt = bs->stmts[i]; + for (Ast *stmt : bs->stmts) { if (stmt->kind == Ast_ValueDecl) { ast_node(vd, ValueDecl, stmt); - for_array(j, vd->names) { - Ast *name = vd->names[j]; + for (Ast *name : vd->names) { if (!is_blank_ident(name)) { if (name->kind == Ast_Ident) { GB_ASSERT(name->Ident.entity != nullptr); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 7192b16b5..e075297a4 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -931,16 +931,15 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags SeenMap seen = {}; // NOTE(bill): Multimap, Key: ExactValue defer (map_destroy(&seen)); - for_array(stmt_index, bs->stmts) { - Ast *stmt = bs->stmts[stmt_index]; + for (Ast *stmt : bs->stmts) { if (stmt->kind != Ast_CaseClause) { // NOTE(bill): error handled by above multiple default checker continue; } ast_node(cc, CaseClause, stmt); - for_array(j, cc->list) { - Ast *expr = unparen_expr(cc->list[j]); + for (Ast *expr : cc->list) { + expr = unparen_expr(expr); if (is_ast_range(expr)) { ast_node(be, BinaryExpr, expr); @@ -1052,8 +1051,7 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags auto unhandled = array_make(temporary_allocator(), 0, fields.count); - for_array(i, fields) { - Entity *f = fields[i]; + for (Entity *f : fields) { if (f->kind != Entity_Constant) { continue; } @@ -1072,8 +1070,7 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags error_no_newline(node, "Unhandled switch case: %.*s", LIT(unhandled[0]->token.string)); } else { error(node, "Unhandled switch cases:"); - for_array(i, unhandled) { - Entity *f = unhandled[i]; + for (Entity *f : unhandled) { error_line("\t%.*s\n", LIT(f->token.string)); } } @@ -1154,8 +1151,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ // NOTE(bill): Check for multiple defaults Ast *first_default = nullptr; ast_node(bs, BlockStmt, ss->body); - for_array(i, bs->stmts) { - Ast *stmt = bs->stmts[i]; + for (Ast *stmt : bs->stmts) { Ast *default_stmt = nullptr; if (stmt->kind == Ast_CaseClause) { ast_node(cc, CaseClause, stmt); @@ -1186,8 +1182,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ PtrSet seen = {}; defer (ptr_set_destroy(&seen)); - for_array(i, bs->stmts) { - Ast *stmt = bs->stmts[i]; + for (Ast *stmt : bs->stmts) { if (stmt->kind != Ast_CaseClause) { // NOTE(bill): error handled by above multiple default checker continue; @@ -1198,8 +1193,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ Type *bt = base_type(type_deref(x.type)); Type *case_type = nullptr; - for_array(type_index, cc->list) { - Ast *type_expr = cc->list[type_index]; + for (Ast *type_expr : cc->list) { if (type_expr != nullptr) { // Otherwise it's a default expression Operand y = {}; check_expr_or_type(ctx, &y, type_expr); @@ -1213,8 +1207,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ if (switch_kind == TypeSwitch_Union) { GB_ASSERT(is_type_union(bt)); bool tag_type_found = false; - for_array(j, bt->Union.variants) { - Type *vt = bt->Union.variants[j]; + for (Type *vt : bt->Union.variants) { if (are_types_identical(vt, y.type)) { tag_type_found = true; break; @@ -1288,8 +1281,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ auto unhandled = array_make(temporary_allocator(), 0, variants.count); - for_array(i, variants) { - Type *t = variants[i]; + for (Type *t : variants) { if (!type_ptr_set_exists(&seen, t)) { array_add(&unhandled, t); } @@ -1302,8 +1294,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ gb_string_free(s); } else { error_no_newline(node, "Unhandled switch cases:\n"); - for_array(i, unhandled) { - Type *t = unhandled[i]; + for (Type *t : unhandled) { gbString s = type_to_string(t); error_line("\t%s\n", s); gb_string_free(s); @@ -1340,8 +1331,7 @@ gb_internal void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) { isize stmt_count = 0; Ast *the_stmt = nullptr; - for_array(i, bs->stmts) { - Ast *stmt = bs->stmts[i]; + for (Ast *stmt : bs->stmts) { GB_ASSERT(stmt != nullptr); switch (stmt->kind) { case_ast_node(es, EmptyStmt, stmt); @@ -1359,8 +1349,7 @@ gb_internal void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) { if (stmt_count == 1) { if (the_stmt->kind == Ast_ValueDecl) { - for_array(i, the_stmt->ValueDecl.names) { - Ast *name = the_stmt->ValueDecl.names[i]; + for (Ast *name : the_stmt->ValueDecl.names) { if (name->kind != Ast_Ident) { continue; } @@ -1376,8 +1365,8 @@ gb_internal void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) { gb_internal bool all_operands_valid(Array const &operands) { if (any_errors()) { - for_array(i, operands) { - if (operands[i].type == t_invalid) { + for (Operand const &o : operands) { + if (o.type == t_invalid) { return false; } } @@ -1548,16 +1537,9 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) check_assignment_arguments(ctx, lhs_operands, &rhs_operands, as->rhs); - isize rhs_count = rhs_operands.count; - for_array(i, rhs_operands) { - if (rhs_operands[i].mode == Addressing_Invalid) { - // TODO(bill): Should I ignore invalid parameters? - // rhs_count--; - } - } - auto lhs_to_ignore = array_make(temporary_allocator(), lhs_count); + isize rhs_count = rhs_operands.count; isize max = gb_min(lhs_count, rhs_count); for (isize i = 0; i < max; i++) { if (lhs_to_ignore[i]) { @@ -1856,8 +1838,8 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) break; } - for_array(ti, t->Tuple.variables) { - array_add(&vals, t->Tuple.variables[ti]->type); + for (Entity *e : t->Tuple.variables) { + array_add(&vals, e->type); } if (rs->vals.count > 1 && rs->vals[1] != nullptr && count < 3) { @@ -1976,8 +1958,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) } } - for_array(i, entities) { - Entity *e = entities[i]; + for (Entity *e : entities) { DeclInfo *d = decl_info_of_entity(e); GB_ASSERT(d == nullptr); add_entity(ctx, ctx->scope, e->identifier, e); @@ -2091,8 +2072,8 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) error(us->token, "Empty 'using' list"); return; } - for_array(i, us->list) { - Ast *expr = unparen_expr(us->list[i]); + for (Ast *expr : us->list) { + expr = unparen_expr(expr); Entity *e = nullptr; bool is_selector = false; @@ -2132,8 +2113,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) check_decl_attributes(&c, fb->attributes, foreign_block_decl_attribute, nullptr); ast_node(block, BlockStmt, fb->body); - for_array(i, block->stmts) { - Ast *decl = block->stmts[i]; + for (Ast *decl : block->stmts) { if (decl->kind == Ast_ValueDecl && decl->ValueDecl.is_mutable) { check_stmt(&c, decl, flags); } @@ -2146,8 +2126,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) isize entity_count = 0; isize new_name_count = 0; - for_array(i, vd->names) { - Ast *name = vd->names[i]; + for (Ast *name : vd->names) { Entity *entity = nullptr; if (name->kind != Ast_Ident) { error(name, "A variable declaration must be an identifier"); @@ -2193,8 +2172,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) begin_error_block(); error(node, "No new declarations on the left hand side"); bool all_underscore = true; - for_array(i, vd->names) { - Ast *name = vd->names[i]; + for (Ast *name : vd->names) { if (name->kind == Ast_Ident) { if (!is_blank_ident(name)) { all_underscore = false; @@ -2388,8 +2366,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) } else { // constant value declaration // NOTE(bill): Check `_` declarations - for_array(i, vd->names) { - Ast *name = vd->names[i]; + for (Ast *name : vd->names) { if (is_blank_ident(name)) { Entity *e = name->Ident.entity; DeclInfo *d = decl_info_of_entity(e); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 3e62f678a..304e5ef36 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -240,11 +240,10 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) { LLVMValueRef v_switch = LLVMBuildSwitch(p->builder, left_tag.value, block_false->block, cast(unsigned)type->Union.variants.count); - for_array(i, type->Union.variants) { + for (Type *v : type->Union.variants) { lbBlock *case_block = lb_create_block(p, "bcase"); lb_start_block(p, case_block); - Type *v = type->Union.variants[i]; lbValue case_tag = lb_const_union_tag(p->module, type, v); Type *vp = alloc_type_pointer(v); @@ -374,11 +373,10 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) { LLVMValueRef v_switch = LLVMBuildSwitch(p->builder, tag.value, end_block->block, cast(unsigned)type->Union.variants.count); - for_array(i, type->Union.variants) { + for (Type *v : type->Union.variants) { lbBlock *case_block = lb_create_block(p, "bcase"); lb_start_block(p, case_block); - Type *v = type->Union.variants[i]; lbValue case_tag = lb_const_union_tag(p->module, type, v); lbValue variant_hasher = lb_hasher_proc_for_type(m, v); @@ -2235,8 +2233,7 @@ gb_internal void lb_generate_code(lbGenerator *gen) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; - for_array(i, m->info->required_foreign_imports_through_force) { - Entity *e = m->info->required_foreign_imports_through_force[i]; + for (Entity *e : m->info->required_foreign_imports_through_force) { lb_add_foreign_library_path(m, e); } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index d574caf4c..c28e9fb2b 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -61,8 +61,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As GB_ASSERT(incoming_values.count > 0); LLVMTypeRef phi_type = nullptr; - for_array(i, incoming_values) { - LLVMValueRef incoming_value = incoming_values[i]; + for (LLVMValueRef incoming_value : incoming_values) { if (!LLVMIsConstant(incoming_value)) { phi_type = LLVMTypeOf(incoming_value); break; @@ -1921,8 +1920,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } if (is_type_union(dst)) { - for_array(i, dst->Union.variants) { - Type *vt = dst->Union.variants[i]; + for (Type *vt : dst->Union.variants) { if (are_types_identical(vt, src_type)) { lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); @@ -3596,8 +3594,7 @@ gb_internal void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice const &temp_data) { - for_array(i, temp_data) { - auto td = temp_data[i]; + for (auto const &td : temp_data) { if (td.value.value != nullptr) { if (td.elem_length > 0) { auto loop_data = lb_loop_start(p, cast(isize)td.elem_length, t_i32); @@ -4129,8 +4126,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); gb_unused(err); - for_array(field_index, cl->elems) { - Ast *elem = cl->elems[field_index]; + for (Ast *elem : cl->elems) { ast_node(fv, FieldValue, elem); lbValue key = lb_build_expr(p, fv->field); @@ -4304,8 +4300,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower)); - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; + for (Ast *elem : cl->elems) { GB_ASSERT(elem->kind != Ast_FieldValue); if (lb_is_elem_const(elem, et)) { @@ -4359,8 +4354,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector` // might be a better option - for_array(i, temp_data) { - auto td = temp_data[i]; + for (auto const &td : temp_data) { if (td.value.value != nullptr) { if (td.elem_length > 0) { for (i64 k = 0; k < td.elem_length; k++) { diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 2703c511a..c48115079 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -7,8 +7,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) static i32 global_guid = 0; - for_array(i, vd->names) { - Ast *ident = vd->names[i]; + for (Ast *ident : vd->names) { GB_ASSERT(ident->kind == Ast_Ident); Entity *e = entity_of_node(ident); GB_ASSERT(e != nullptr); @@ -106,8 +105,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) gb_internal void lb_build_stmt_list(lbProcedure *p, Slice const &stmts) { - for_array(i, stmts) { - Ast *stmt = stmts[i]; + for (Ast *stmt : stmts) { switch (stmt->kind) { case_ast_node(vd, ValueDecl, stmt); lb_build_constant_value_decl(p, vd); @@ -118,8 +116,8 @@ gb_internal void lb_build_stmt_list(lbProcedure *p, Slice const &stmts) { case_end; } } - for_array(i, stmts) { - lb_build_stmt(p, stmts[i]); + for (Ast *stmt : stmts) { + lb_build_stmt(p, stmt); } } @@ -129,10 +127,9 @@ gb_internal lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) { GB_ASSERT(ident->kind == Ast_Ident); Entity *e = entity_of_node(ident); GB_ASSERT(e->kind == Entity_Label); - for_array(i, p->branch_blocks) { - lbBranchBlocks *b = &p->branch_blocks[i]; - if (b->label == e->Label.node) { - return *b; + for (lbBranchBlocks const &b : p->branch_blocks) { + if (b.label == e->Label.node) { + return b; } } @@ -153,13 +150,12 @@ gb_internal lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBloc if (label != nullptr) { // Set label blocks GB_ASSERT(label->kind == Ast_Label); - for_array(i, p->branch_blocks) { - lbBranchBlocks *b = &p->branch_blocks[i]; - GB_ASSERT(b->label != nullptr && label != nullptr); - GB_ASSERT(b->label->kind == Ast_Label); - if (b->label == label) { - b->break_ = break_; - b->continue_ = continue_; + for (lbBranchBlocks &b : p->branch_blocks) { + GB_ASSERT(b.label != nullptr && label != nullptr); + GB_ASSERT(b.label->kind == Ast_Label); + if (b.label == label) { + b.break_ = break_; + b.continue_ = continue_; return tl; } } @@ -1095,8 +1091,7 @@ gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, boo } ast_node(body, BlockStmt, ss->body); - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; + for (Ast *clause : body->stmts) { ast_node(cc, CaseClause, clause); if (cc->list.count == 0) { @@ -1104,8 +1099,8 @@ gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, boo continue; } - for_array(j, cc->list) { - Ast *expr = unparen_expr(cc->list[j]); + for (Ast *expr : cc->list) { + expr = unparen_expr(expr); if (is_ast_range(expr)) { return false; } @@ -1166,8 +1161,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * LLVMValueRef switch_instr = nullptr; if (is_trivial) { isize num_cases = 0; - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; + for (Ast *clause : body->stmts) { ast_node(cc, CaseClause, clause); num_cases += cc->list.count; } @@ -1204,8 +1198,8 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * } lbBlock *next_cond = nullptr; - for_array(j, cc->list) { - Ast *expr = unparen_expr(cc->list[j]); + for (Ast *expr : cc->list) { + expr = unparen_expr(expr); if (switch_instr != nullptr) { lbValue on_val = {}; @@ -1384,8 +1378,7 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss lbBlock *default_block = nullptr; isize num_cases = 0; - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; + for (Ast *clause : body->stmts) { ast_node(cc, CaseClause, clause); num_cases += cc->list.count; if (cc->list.count == 0) { @@ -1405,8 +1398,7 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases); } - for_array(i, body->stmts) { - Ast *clause = body->stmts[i]; + for (Ast *clause : body->stmts) { ast_node(cc, CaseClause, clause); lb_open_scope(p, cc->scope); if (cc->list.count == 0) { @@ -1420,9 +1412,8 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss if (p->debug_info != nullptr) { LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, clause)); } - Type *case_type = nullptr; - for_array(type_index, cc->list) { - case_type = type_of_expr(cc->list[type_index]); + for (Ast *type_expr : cc->list) { + Type *case_type = type_of_expr(type_expr); lbValue on_val = {}; if (switch_kind == TypeSwitch_Union) { Type *ut = base_type(type_deref(parent.type)); @@ -1538,8 +1529,8 @@ gb_internal void lb_append_tuple_values(lbProcedure *p, Array *dst_valu if (t->kind == Type_Tuple) { lbTupleFix *tf = map_get(&p->tuple_fix_map, src_value.value); if (tf) { - for_array(j, tf->values) { - array_add(dst_values, tf->values[j]); + for (lbValue const &value : tf->values) { + array_add(dst_values, value); } } else { for_array(i, t->Tuple.variables) { @@ -1560,8 +1551,7 @@ gb_internal void lb_build_assignment(lbProcedure *p, Array &lvals, Slice auto inits = array_make(permanent_allocator(), 0, lvals.count); - for_array(i, values) { - Ast *rhs = values[i]; + for (Ast *rhs : values) { lbValue init = lb_build_expr(p, rhs); lb_append_tuple_values(p, &inits, init); } @@ -1971,8 +1961,7 @@ gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr auto indices_handled = slice_make(temporary_allocator(), bt->Array.count); auto indices = slice_make(temporary_allocator(), bt->Array.count); i32 index_count = 0; - for_array(i, lhs.swizzle_large.indices) { - i32 index = lhs.swizzle_large.indices[i]; + for (i32 index : lhs.swizzle_large.indices) { if (indices_handled[index]) { continue; } @@ -2049,8 +2038,7 @@ gb_internal void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) { if (as->op.kind == Token_Eq) { auto lvals = array_make(permanent_allocator(), 0, as->lhs.count); - for_array(i, as->lhs) { - Ast *lhs = as->lhs[i]; + for (Ast *lhs : as->lhs) { lbAddr lval = {}; if (!is_blank_ident(lhs)) { lval = lb_build_addr(p, lhs); @@ -2185,8 +2173,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { bool is_static = false; if (vd->names.count > 0) { - for_array(i, vd->names) { - Ast *name = vd->names[i]; + for (Ast *name : vd->names) { if (!is_blank_ident(name)) { GB_ASSERT(name->kind == Ast_Ident); Entity *e = entity_of_node(name); @@ -2208,8 +2195,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { auto lvals = array_make(permanent_allocator(), 0, vd->names.count); - for_array(i, vd->names) { - Ast *name = vd->names[i]; + for (Ast *name : vd->names) { lbAddr lval = {}; if (!is_blank_ident(name)) { Entity *e = entity_of_node(name); -- cgit v1.2.3 From 1517f1d7793c8985664600a820e3434dfdf83810 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 5 Jan 2023 11:54:21 +0000 Subject: Add uncomment `add_type_info_type` calls for type assertions --- src/check_decl.cpp | 60 ++++++++++++++++++++++++++++------------------------ src/check_expr.cpp | 8 +++---- src/checker.cpp | 38 +++++---------------------------- src/llvm_backend.cpp | 1 + src/ptr_map.cpp | 29 +++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 65 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 644771dcd..d4ae9c59d 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1411,6 +1411,37 @@ end:; } +gb_internal void add_deps_from_child_to_parent(DeclInfo *decl) { + if (decl && decl->parent) { + Scope *ps = decl->parent->scope; + if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) { + return; + } else { + // NOTE(bill): Add the dependencies from the procedure literal (lambda) + // But only at the procedure level + rw_mutex_shared_lock(&decl->deps_mutex); + rw_mutex_lock(&decl->parent->deps_mutex); + + for (Entity *e : decl->deps) { + ptr_set_add(&decl->parent->deps, e); + } + + rw_mutex_unlock(&decl->parent->deps_mutex); + rw_mutex_shared_unlock(&decl->deps_mutex); + + 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); + } + + rw_mutex_unlock(&decl->parent->type_info_deps_mutex); + rw_mutex_shared_unlock(&decl->type_info_deps_mutex); + } + } +} + struct ProcUsingVar { Entity *e; Entity *uvar; @@ -1576,34 +1607,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de check_scope_usage(ctx->checker, ctx->scope); - // if (decl->parent) { - // Scope *ps = decl->parent->scope; - // if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) { - // return true; - // } else { - // // NOTE(bill): Add the dependencies from the procedure literal (lambda) - // // But only at the procedure level - // rw_mutex_shared_lock(&decl->deps_mutex); - // rw_mutex_lock(&decl->parent->deps_mutex); - - // for (Entity *e : decl->deps) { - // ptr_set_add(&decl->parent->deps, e); - // } - - // rw_mutex_unlock(&decl->parent->deps_mutex); - // rw_mutex_shared_unlock(&decl->deps_mutex); - - // 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); - // } - - // rw_mutex_unlock(&decl->parent->type_info_deps_mutex); - // rw_mutex_shared_unlock(&decl->type_info_deps_mutex); - // } - // } + add_deps_from_child_to_parent(decl); return true; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e9e61486e..e0519d26b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8777,8 +8777,8 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no return kind; } - // add_type_info_type(c, o->type); - // add_type_info_type(c, bsrc->Union.variants[0]); + add_type_info_type(c, o->type); + add_type_info_type(c, bsrc->Union.variants[0]); o->type = bsrc->Union.variants[0]; o->mode = Addressing_OptionalOk; @@ -8810,8 +8810,8 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no return kind; } - // add_type_info_type(c, o->type); - // add_type_info_type(c, t); + add_type_info_type(c, o->type); + add_type_info_type(c, t); o->type = t; o->mode = Addressing_OptionalOk; diff --git a/src/checker.cpp b/src/checker.cpp index 8cb6ea99d..a2ed73119 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2026,14 +2026,13 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { ti_index = type_info_index(&c->info, t, false); } GB_ASSERT(ti_index >= 0); - if (map_get(set, ti_index)) { - // Type already exists; - return; - } // 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->entries.count; - map_set(set, ti_index, count); + if (map_set_if_not_previously_exists(set, ti_index, count)) { + // Type already exists; + return; + } // Add nested types if (t->kind == Type_Named) { @@ -5650,34 +5649,7 @@ gb_internal void check_walk_all_dependencies(DeclInfo *decl) { for (DeclInfo *child = decl->next_child; child != nullptr; child = child->next_sibling) { check_walk_all_dependencies(child); } - if (decl->parent && decl->parent->entity && decl->parent->entity->kind == Entity_Procedure) { - Scope *ps = decl->parent->scope; - if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) { - return; - } else { - // NOTE(bill): Add the dependencies from the procedure literal (lambda) - // But only at the procedure level - rw_mutex_shared_lock(&decl->deps_mutex); - rw_mutex_lock(&decl->parent->deps_mutex); - - for (Entity *e : decl->deps) { - ptr_set_add(&decl->parent->deps, e); - } - - rw_mutex_unlock(&decl->parent->deps_mutex); - rw_mutex_shared_unlock(&decl->deps_mutex); - - 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); - } - - rw_mutex_unlock(&decl->parent->type_info_deps_mutex); - rw_mutex_shared_unlock(&decl->type_info_deps_mutex); - } - } + add_deps_from_child_to_parent(decl); } gb_internal void check_update_dependency_tree_for_procedures(Checker *c) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 304e5ef36..192e5cc56 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1920,6 +1920,7 @@ gb_internal void lb_generate_code(lbGenerator *gen) { if (!ptr_set_exists(min_dep_set, e)) { continue; } + DeclInfo *decl = decl_info_of_entity(e); if (decl == nullptr) { continue; diff --git a/src/ptr_map.cpp b/src/ptr_map.cpp index c33bf9ffb..89d2cbf9d 100644 --- a/src/ptr_map.cpp +++ b/src/ptr_map.cpp @@ -52,6 +52,7 @@ template gb_internal void map_init (PtrMap< template gb_internal void map_destroy (PtrMap *h); template gb_internal V * map_get (PtrMap *h, K key); template gb_internal void map_set (PtrMap *h, K key, V const &value); +template gb_internal bool map_set_if_not_previously_exists(PtrMap *h, K key, V const &value); // returns true if it previously existed template gb_internal void map_remove (PtrMap *h, K key); template gb_internal void map_clear (PtrMap *h); template gb_internal void map_grow (PtrMap *h); @@ -240,6 +241,34 @@ gb_internal void map_set(PtrMap *h, K key, V const &value) { } } +// returns true if it previously existed +template +gb_internal bool map_set_if_not_previously_exists(PtrMap *h, K key, V const &value) { + MapIndex index; + MapFindResult fr; + if (h->hashes.count == 0) { + map_grow(h); + } + fr = map__find(h, key); + if (fr.entry_index != MAP_SENTINEL) { + return true; + } else { + index = map__add_entry(h, key); + if (fr.entry_prev != MAP_SENTINEL) { + h->entries.data[fr.entry_prev].next = index; + } else { + h->hashes.data[fr.hash_index] = index; + } + } + h->entries.data[index].value = value; + + if (map__full(h)) { + map_grow(h); + } + return false; +} + + template gb_internal void map__erase(PtrMap *h, MapFindResult const &fr) { MapFindResult last; -- cgit v1.2.3 From 213a0499a1964e0bc5d2c48cd3b4450b45f59314 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 5 Jan 2023 12:29:16 +0000 Subject: Begin multithreading the llvm backend when `-use-separate-modules` is enabled --- src/llvm_backend.cpp | 46 +++++++++++++++++++++++++++++--------------- src/llvm_backend.hpp | 3 +++ src/llvm_backend_general.cpp | 21 +++++++++++++++++--- src/llvm_backend_stmt.cpp | 2 +- 4 files changed, 53 insertions(+), 19 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 192e5cc56..f3c4dd50d 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -730,6 +730,8 @@ gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) { gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent) { + MUTEX_GUARD(&m->gen->anonymous_proc_lits_mutex); + lbProcedure **found = map_get(&m->gen->anonymous_proc_lits, expr); if (found) { return lb_find_procedure_value_from_entity(m, (*found)->entity); @@ -1526,6 +1528,10 @@ struct lbLLVMModulePassWorkerData { gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { auto wd = cast(lbLLVMModulePassWorkerData *)data; + + lb_run_remove_unused_function_pass(wd->m); + lb_run_remove_unused_globals_pass(wd->m); + LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager(); lb_populate_module_pass_manager(wd->target_machine, module_pass_manager, build_context.optimization_level); LLVMRunPassManager(module_pass_manager, wd->m->mod); @@ -2155,29 +2161,47 @@ gb_internal void lb_generate_code(lbGenerator *gen) { } } + isize non_empty_module_count = 0; + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + if (!lb_is_module_empty(m)) { + non_empty_module_count += 1; + } + } + if (non_empty_module_count <= 1) { + do_threading = false; + } TIME_SECTION("LLVM Function Pass"); for (auto const &entry : gen->modules) { lbModule *m = entry.value; - lb_llvm_function_pass_worker_proc(m); + // if (do_threading) { + // thread_pool_add_task(lb_llvm_function_pass_worker_proc, m); + // } else { + lb_llvm_function_pass_worker_proc(m); + // } } + thread_pool_wait(); TIME_SECTION("LLVM Module Pass"); - for (auto const &entry : gen->modules) { lbModule *m = entry.value; - lb_run_remove_unused_function_pass(m); - lb_run_remove_unused_globals_pass(m); - auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData); wd->m = m; wd->target_machine = m->target_machine; - lb_llvm_module_pass_worker_proc(wd); + if (do_threading) { + thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd); + } else { + lb_llvm_module_pass_worker_proc(wd); + } } + thread_pool_wait(); + TIME_SECTION("LLVM Module Verification"); + llvm_error = nullptr; defer (LLVMDisposeMessage(llvm_error)); @@ -2245,21 +2269,13 @@ gb_internal void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Object Generation"); - isize non_empty_module_count = 0; - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - if (!lb_is_module_empty(m)) { - non_empty_module_count += 1; - } - } - if (build_context.ignore_llvm_build) { gb_printf_err("LLVM SUCCESS!\n"); gb_exit(1); return; } - if (do_threading && non_empty_module_count > 1) { + if (do_threading) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; if (lb_is_module_empty(m)) { diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 9f7caa3bb..d824b99cf 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -132,6 +132,8 @@ struct lbModule { PtrMap struct_field_remapping; // Key: LLVMTypeRef or Type * i32 internal_type_level; + RecursiveMutex values_mutex; + PtrMap values; PtrMap soa_values; StringMap members; @@ -178,6 +180,7 @@ struct lbGenerator { PtrMap modules_through_ctx; lbModule default_module; + BlockingMutex anonymous_proc_lits_mutex; PtrMap anonymous_proc_lits; BlockingMutex foreign_mutex; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index a849929f0..c09648825 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -316,6 +316,7 @@ gb_internal bool lb_is_instr_terminating(LLVMValueRef instr) { gb_internal lbModule *lb_pkg_module(lbGenerator *gen, AstPackage *pkg) { + // NOTE(bill): no need for a mutex since it's immutable auto *found = map_get(&gen->modules, pkg); if (found) { return *found; @@ -1354,7 +1355,7 @@ gb_internal String lb_mangle_name(lbModule *m, Entity *e) { return mangled_name; } -gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p) { +gb_internal String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p, lbModule *module) { // NOTE(bill, 2020-03-08): A polymorphic procedure may take a nested type declaration // and as a result, the declaration does not have time to determine what it should be @@ -1421,7 +1422,7 @@ gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String default_nam } if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) { - return lb_set_nested_type_name_ir_mangled_name(e, nullptr); + return lb_set_nested_type_name_ir_mangled_name(e, nullptr, m); } String name = {}; @@ -2164,19 +2165,25 @@ gb_internal void lb_ensure_abi_function_type(lbModule *m, lbProcedure *p) { gb_internal void lb_add_entity(lbModule *m, Entity *e, lbValue val) { if (e != nullptr) { + mutex_lock(&m->values_mutex); map_set(&m->values, e, val); + mutex_unlock(&m->values_mutex); } } gb_internal void lb_add_member(lbModule *m, String const &name, lbValue val) { if (name.len > 0) { + mutex_lock(&m->values_mutex); string_map_set(&m->members, name, val); + mutex_unlock(&m->values_mutex); } } gb_internal void lb_add_procedure_value(lbModule *m, lbProcedure *p) { + mutex_lock(&m->values_mutex); if (p->entity != nullptr) { map_set(&m->procedure_values, p->value, p->entity); } string_map_set(&m->procedures, p->name, p); + mutex_unlock(&m->values_mutex); } @@ -2519,6 +2526,8 @@ gb_internal lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *e return *found; } } + mutex_lock(&m->values_mutex); + defer (mutex_unlock(&m->values_mutex)); auto *found = map_get(&m->values, e); if (found) { @@ -2538,7 +2547,6 @@ gb_internal lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *e if (USE_SEPARATE_MODULES) { lbModule *other_module = lb_pkg_module(m->gen, e->pkg); if (other_module != m) { - String name = lb_get_entity_name(other_module, e); lb_set_entity_from_other_modules_linkage_correctly(other_module, e, name); @@ -2569,6 +2577,9 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) e = strip_entity_wrapping(e); GB_ASSERT(e != nullptr); + mutex_lock(&m->values_mutex); + defer (mutex_unlock(&m->values_mutex)); + auto *found = map_get(&m->values, e); if (found) { return *found; @@ -2657,6 +2668,10 @@ gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e) { return lb_find_procedure_value_from_entity(m, e); } + mutex_lock(&m->values_mutex); + defer (mutex_unlock(&m->values_mutex)); + + auto *found = map_get(&m->values, e); if (found) { return *found; diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 0e6f75118..73b4e251f 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -32,7 +32,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) continue; } - lb_set_nested_type_name_ir_mangled_name(e, p); + lb_set_nested_type_name_ir_mangled_name(e, p, p->module); } for_array(i, vd->names) { -- cgit v1.2.3 From 025e87d97411da2782dc548ef4a49fc9e2de21f8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 5 Jan 2023 12:39:57 +0000 Subject: Multithread LLVM procedure generation --- src/llvm_backend.cpp | 39 +++++++++++++++++++++++++-------------- src/main.cpp | 22 +++++++++++----------- 2 files changed, 36 insertions(+), 25 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index f3c4dd50d..fd9d427ea 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1579,7 +1579,16 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) { } -gb_internal void lb_generate_code(lbGenerator *gen) { +gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) { + lbModule *m = cast(lbModule *)data; + for (isize i = 0; i < m->procedures_to_generate.count; i++) { + lbProcedure *p = m->procedures_to_generate[i]; + lb_generate_procedure(p->module, p); + } + return 0; +} + +gb_internal bool lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Initializtion"); isize thread_count = gb_max(build_context.thread_count, 1); @@ -2126,13 +2135,15 @@ gb_internal void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Procedure Generation"); for (auto const &entry : gen->modules) { lbModule *m = entry.value; - // NOTE(bill): procedures may be added during generation - for (isize i = 0; i < m->procedures_to_generate.count; i++) { - lbProcedure *p = m->procedures_to_generate[i]; - lb_generate_procedure(m, p); + if (do_threading) { + thread_pool_add_task(lb_generate_procedures_worker_proc, m); + } else { + lb_generate_procedures_worker_proc(m); } } + thread_pool_wait(); + if (build_context.command_kind == Command_test && !already_has_entry_point) { TIME_SECTION("LLVM main"); lb_create_main_procedure(default_module, startup_runtime); @@ -2221,11 +2232,11 @@ gb_internal void lb_generate_code(lbGenerator *gen) { if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) { gb_printf_err("LLVM Error: %s\n", llvm_error); gb_exit(1); - return; + return false; } } gb_exit(1); - return; + return false; } } llvm_error = nullptr; @@ -2243,14 +2254,13 @@ gb_internal void lb_generate_code(lbGenerator *gen) { if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) { gb_printf_err("LLVM Error: %s\n", llvm_error); gb_exit(1); - return; + return false; } array_add(&gen->output_temp_paths, filepath_ll); } if (build_context.build_mode == BuildMode_LLVM_IR) { - gb_exit(0); - return; + return true; } } @@ -2270,9 +2280,8 @@ gb_internal void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Object Generation"); if (build_context.ignore_llvm_build) { - gb_printf_err("LLVM SUCCESS!\n"); - gb_exit(1); - return; + gb_printf_err("LLVM object generation has been ignored!\n"); + return false; } if (do_threading) { @@ -2315,10 +2324,12 @@ gb_internal void lb_generate_code(lbGenerator *gen) { if (LLVMTargetMachineEmitToFile(m->target_machine, m->mod, cast(char *)filepath_obj.text, code_gen_file_type, &llvm_error)) { gb_printf_err("LLVM Error: %s\n", llvm_error); gb_exit(1); - return; + return false; } } } gb_sort_array(gen->foreign_libraries.data, gen->foreign_libraries.count, foreign_library_cmp); + + return true; } diff --git a/src/main.cpp b/src/main.cpp index c07d2c400..a7e5677e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2784,19 +2784,19 @@ int main(int arg_count, char const **arg_ptr) { if (!lb_init_generator(gen, checker)) { return 1; } - lb_generate_code(gen); - - switch (build_context.build_mode) { - case BuildMode_Executable: - case BuildMode_DynamicLibrary: - i32 result = linker_stage(gen); - if (result) { - if (build_context.show_timings) { - show_timings(checker, &global_timings); + if (lb_generate_code(gen)) { + switch (build_context.build_mode) { + case BuildMode_Executable: + case BuildMode_DynamicLibrary: + i32 result = linker_stage(gen); + if (result) { + if (build_context.show_timings) { + show_timings(checker, &global_timings); + } + return result; } - return result; + break; } - break; } remove_temp_files(gen); -- cgit v1.2.3 From 029cb6581b483f7db5b6bf35241b4b8a5cc544ff Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 5 Jan 2023 12:54:53 +0000 Subject: Unify function pass managers for auxiliary procedures (e.g. startup type info, runtime, objc names) --- src/llvm_backend.cpp | 57 +++++++++++++++++++++--------------------------- src/llvm_backend.hpp | 4 ++++ src/llvm_backend_opt.cpp | 3 +++ 3 files changed, 32 insertions(+), 32 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index fd9d427ea..f4e97aad7 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -990,10 +990,6 @@ gb_internal lbProcedure *lb_create_startup_type_info(lbModule *m) { if (build_context.disallow_rtti) { return nullptr; } - LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); - lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level); - LLVMFinalizeFunctionPassManager(default_function_pass_manager); - Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl); lbProcedure *p = lb_create_dummy_procedure(m, str_lit(LB_STARTUP_TYPE_INFO_PROC_NAME), proc_type); @@ -1014,9 +1010,6 @@ gb_internal lbProcedure *lb_create_startup_type_info(lbModule *m) { gb_printf_err("\n\n\n\n"); LLVMVerifyFunction(p->value, LLVMAbortProcessAction); } - - lb_run_function_pass_manager(default_function_pass_manager, p); - return p; } @@ -1037,11 +1030,6 @@ gb_internal void lb_finalize_objc_names(lbProcedure *p) { } lbModule *m = p->module; - LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); - lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level); - LLVMFinalizeFunctionPassManager(default_function_pass_manager); - - auto args = array_make(permanent_allocator(), 1); LLVMSetLinkage(p->value, LLVMInternalLinkage); @@ -1061,16 +1049,9 @@ gb_internal void lb_finalize_objc_names(lbProcedure *p) { } lb_end_procedure_body(p); - - lb_run_function_pass_manager(default_function_pass_manager, p); - } gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *startup_type_info, lbProcedure *objc_names, Array &global_variables) { // Startup Runtime - LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(main_module->mod); - lb_populate_function_pass_manager(main_module, default_function_pass_manager, false, build_context.optimization_level); - LLVMFinalizeFunctionPassManager(default_function_pass_manager); - Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); lbProcedure *p = lb_create_dummy_procedure(main_module, str_lit(LB_STARTUP_RUNTIME_PROC_NAME), proc_type); @@ -1175,8 +1156,6 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc LLVMVerifyFunction(p->value, LLVMAbortProcessAction); } - lb_run_function_pass_manager(default_function_pass_manager, p); - return p; } @@ -1466,6 +1445,12 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_worker_proc) { LLVMFinalizeFunctionPassManager(function_pass_manager_size); LLVMFinalizeFunctionPassManager(function_pass_manager_speed); + if (m == &m->gen->default_module) { + lb_run_function_pass_manager(default_function_pass_manager, m->gen->startup_type_info); + lb_run_function_pass_manager(default_function_pass_manager, m->gen->startup_runtime); + lb_finalize_objc_names(m->gen->objc_names); + } + LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(m->mod); LLVMInitializeFunctionPassManager(default_function_pass_manager_without_memcpy); @@ -1588,6 +1573,16 @@ gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) { return 0; } +gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) { + lbModule *m = cast(lbModule *)data; + for (isize i = 0; i < m->missing_procedures_to_check.count; i++) { + lbProcedure *p = m->missing_procedures_to_check[i]; + debugf("Generate missing procedure: %.*s\n", LIT(p->name)); + lb_generate_procedure(m, p); + } + return 0; +} + gb_internal bool lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Initializtion"); @@ -2055,13 +2050,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } TIME_SECTION("LLVM Runtime Type Information Creation"); - lbProcedure *startup_type_info = lb_create_startup_type_info(default_module); - - lbProcedure *objc_names = lb_create_objc_names(default_module); + gen->startup_type_info = lb_create_startup_type_info(default_module); + gen->objc_names = lb_create_objc_names(default_module); TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)"); - lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, objc_names, global_variables); - gb_unused(startup_runtime); + gen->startup_runtime = lb_create_startup_runtime(default_module, gen->startup_type_info, gen->objc_names, global_variables); if (build_context.ODIN_DEBUG) { for (auto const &entry : builtin_pkg->scope->elements) { @@ -2146,20 +2139,20 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { if (build_context.command_kind == Command_test && !already_has_entry_point) { TIME_SECTION("LLVM main"); - lb_create_main_procedure(default_module, startup_runtime); + lb_create_main_procedure(default_module, gen->startup_runtime); } for (auto const &entry : gen->modules) { lbModule *m = entry.value; // NOTE(bill): procedures may be added during generation - for (isize i = 0; i < m->missing_procedures_to_check.count; i++) { - lbProcedure *p = m->missing_procedures_to_check[i]; - debugf("Generate missing procedure: %.*s\n", LIT(p->name)); - lb_generate_procedure(m, p); + if (do_threading) { + thread_pool_add_task(lb_generate_missing_procedures_to_check_worker_proc, m); + } else { + lb_generate_missing_procedures_to_check_worker_proc(m); } } - lb_finalize_objc_names(objc_names); + thread_pool_wait(); if (build_context.ODIN_DEBUG) { TIME_SECTION("LLVM Debug Info Complete Types and Finalize"); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index d824b99cf..c4cc17782 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -189,6 +189,10 @@ struct lbGenerator { std::atomic global_array_index; std::atomic global_generated_index; + + lbProcedure *startup_type_info; + lbProcedure *startup_runtime; + lbProcedure *objc_names; }; diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index fd6d94361..d7a34d82a 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -359,6 +359,9 @@ gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) { gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) { + if (p == nullptr) { + return; + } LLVMRunFunctionPassManager(fpm, p->value); // NOTE(bill): LLVMAddDCEPass doesn't seem to be exported in the official DLL's for LLVM // which means we cannot rely upon it -- cgit v1.2.3 From 5eee8077ddea82610bf72a37c4032bb06b1c4ab0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 5 Jan 2023 15:56:45 +0000 Subject: enum-ifiy function pass managers for `lbModule` --- src/llvm_backend.cpp | 102 ++++++++++++++++++++++++--------------------- src/llvm_backend.hpp | 14 +++++++ src/llvm_backend_debug.cpp | 7 ++++ 3 files changed, 75 insertions(+), 48 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index f4e97aad7..54430246e 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1420,89 +1420,89 @@ gb_internal WORKER_TASK_PROC(lb_llvm_emit_worker_proc) { return 0; } -gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_worker_proc) { - GB_ASSERT(MULTITHREAD_OBJECT_GENERATION); - auto m = cast(lbModule *)data; +gb_internal void lb_llvm_function_pass_per_function_internal(lbModule *module, lbProcedure *p, lbFunctionPassManagerKind pass_manager_kind = lbFunctionPassManager_default) { + LLVMPassManagerRef pass_manager = module->function_pass_managers[pass_manager_kind]; + lb_run_function_pass_manager(pass_manager, p); +} - LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); - LLVMPassManagerRef function_pass_manager_minimal = LLVMCreateFunctionPassManagerForModule(m->mod); - LLVMPassManagerRef function_pass_manager_size = LLVMCreateFunctionPassManagerForModule(m->mod); - LLVMPassManagerRef function_pass_manager_speed = LLVMCreateFunctionPassManagerForModule(m->mod); +gb_internal void lb_llvm_function_pass_per_module(lbModule *m) { + { + GB_ASSERT(m->function_pass_managers[lbFunctionPassManager_default] == nullptr); - LLVMInitializeFunctionPassManager(default_function_pass_manager); - LLVMInitializeFunctionPassManager(function_pass_manager_minimal); - LLVMInitializeFunctionPassManager(function_pass_manager_size); - LLVMInitializeFunctionPassManager(function_pass_manager_speed); + m->function_pass_managers[lbFunctionPassManager_default] = LLVMCreateFunctionPassManagerForModule(m->mod); + m->function_pass_managers[lbFunctionPassManager_default_without_memcpy] = LLVMCreateFunctionPassManagerForModule(m->mod); + m->function_pass_managers[lbFunctionPassManager_minimal] = LLVMCreateFunctionPassManagerForModule(m->mod); + m->function_pass_managers[lbFunctionPassManager_size] = LLVMCreateFunctionPassManagerForModule(m->mod); + m->function_pass_managers[lbFunctionPassManager_speed] = LLVMCreateFunctionPassManagerForModule(m->mod); - lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level); - lb_populate_function_pass_manager_specific(m, function_pass_manager_minimal, 0); - lb_populate_function_pass_manager_specific(m, function_pass_manager_size, 1); - lb_populate_function_pass_manager_specific(m, function_pass_manager_speed, 2); + LLVMInitializeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_default]); + LLVMInitializeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_default_without_memcpy]); + LLVMInitializeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_minimal]); + LLVMInitializeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_size]); + LLVMInitializeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_speed]); - LLVMFinalizeFunctionPassManager(default_function_pass_manager); - LLVMFinalizeFunctionPassManager(function_pass_manager_minimal); - LLVMFinalizeFunctionPassManager(function_pass_manager_size); - LLVMFinalizeFunctionPassManager(function_pass_manager_speed); + lb_populate_function_pass_manager(m, m->function_pass_managers[lbFunctionPassManager_default], false, build_context.optimization_level); + lb_populate_function_pass_manager(m, m->function_pass_managers[lbFunctionPassManager_default_without_memcpy], true, build_context.optimization_level); + lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_minimal], 0); + lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_size], 1); + lb_populate_function_pass_manager_specific(m, m->function_pass_managers[lbFunctionPassManager_speed], 2); - if (m == &m->gen->default_module) { - lb_run_function_pass_manager(default_function_pass_manager, m->gen->startup_type_info); - lb_run_function_pass_manager(default_function_pass_manager, m->gen->startup_runtime); - lb_finalize_objc_names(m->gen->objc_names); + LLVMFinalizeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_default]); + LLVMFinalizeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_default_without_memcpy]); + LLVMFinalizeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_minimal]); + LLVMFinalizeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_size]); + LLVMFinalizeFunctionPassManager(m->function_pass_managers[lbFunctionPassManager_speed]); } - - LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(m->mod); - LLVMInitializeFunctionPassManager(default_function_pass_manager_without_memcpy); - lb_populate_function_pass_manager(m, default_function_pass_manager_without_memcpy, true, build_context.optimization_level); - LLVMFinalizeFunctionPassManager(default_function_pass_manager_without_memcpy); + if (m == &m->gen->default_module) { + lb_llvm_function_pass_per_function_internal(m, m->gen->startup_type_info); + lb_llvm_function_pass_per_function_internal(m, m->gen->startup_runtime); + lb_llvm_function_pass_per_function_internal(m, m->gen->objc_names); + } for (lbProcedure *p : m->procedures_to_generate) { if (p->body != nullptr) { // Build Procedure + lbFunctionPassManagerKind pass_manager_kind = lbFunctionPassManager_default; if (p->flags & lbProcedureFlag_WithoutMemcpyPass) { - lb_run_function_pass_manager(default_function_pass_manager_without_memcpy, p); + pass_manager_kind = lbFunctionPassManager_default_without_memcpy; } else { if (p->entity && p->entity->kind == Entity_Procedure) { switch (p->entity->Procedure.optimization_mode) { case ProcedureOptimizationMode_None: case ProcedureOptimizationMode_Minimal: - lb_run_function_pass_manager(function_pass_manager_minimal, p); + pass_manager_kind = lbFunctionPassManager_minimal; break; case ProcedureOptimizationMode_Size: - lb_run_function_pass_manager(function_pass_manager_size, p); + pass_manager_kind = lbFunctionPassManager_size; break; case ProcedureOptimizationMode_Speed: - lb_run_function_pass_manager(function_pass_manager_speed, p); - break; - default: - lb_run_function_pass_manager(default_function_pass_manager, p); + pass_manager_kind = lbFunctionPassManager_speed; break; } - } else { - lb_run_function_pass_manager(default_function_pass_manager, p); } } + + lb_llvm_function_pass_per_function_internal(m, p, pass_manager_kind); } } for (auto const &entry : m->equal_procs) { lbProcedure *p = entry.value; - lb_run_function_pass_manager(default_function_pass_manager, p); + lb_llvm_function_pass_per_function_internal(m, p); } for (auto const &entry : m->hasher_procs) { lbProcedure *p = entry.value; - lb_run_function_pass_manager(default_function_pass_manager, p); + lb_llvm_function_pass_per_function_internal(m, p); } for (auto const &entry : m->map_get_procs) { lbProcedure *p = entry.value; - lb_run_function_pass_manager(default_function_pass_manager, p); + lb_llvm_function_pass_per_function_internal(m, p); } for (auto const &entry : m->map_set_procs) { lbProcedure *p = entry.value; - lb_run_function_pass_manager(default_function_pass_manager, p); + lb_llvm_function_pass_per_function_internal(m, p); } - - return 0; } @@ -2125,6 +2125,10 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } } + if (gen->modules.entries.count <= 1) { + do_threading = false; + } + TIME_SECTION("LLVM Procedure Generation"); for (auto const &entry : gen->modules) { lbModule *m = entry.value; @@ -2142,6 +2146,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { lb_create_main_procedure(default_module, gen->startup_runtime); } + TIME_SECTION("LLVM Procedure Generation (missing)"); for (auto const &entry : gen->modules) { lbModule *m = entry.value; // NOTE(bill): procedures may be added during generation @@ -2154,6 +2159,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { thread_pool_wait(); + if (gen->objc_names) { + TIME_SECTION("Finalize objc names"); + lb_finalize_objc_names(gen->objc_names); + } + if (build_context.ODIN_DEBUG) { TIME_SECTION("LLVM Debug Info Complete Types and Finalize"); for (auto const &entry : gen->modules) { @@ -2180,11 +2190,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Function Pass"); for (auto const &entry : gen->modules) { lbModule *m = entry.value; - // if (do_threading) { - // thread_pool_add_task(lb_llvm_function_pass_worker_proc, m); - // } else { - lb_llvm_function_pass_worker_proc(m); - // } + lb_llvm_function_pass_per_module(m); } thread_pool_wait(); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index c4cc17782..0e3a38fd3 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -117,6 +117,16 @@ struct lbIncompleteDebugType { typedef Slice lbStructFieldRemapping; +enum lbFunctionPassManagerKind { + lbFunctionPassManager_default, + lbFunctionPassManager_default_without_memcpy, + lbFunctionPassManager_minimal, + lbFunctionPassManager_size, + lbFunctionPassManager_speed, + + lbFunctionPassManager_COUNT +}; + struct lbModule { LLVMModuleRef mod; LLVMContextRef ctx; @@ -158,6 +168,8 @@ struct lbModule { LLVMDIBuilderRef debug_builder; LLVMMetadataRef debug_compile_unit; + + RecursiveMutex debug_values_mutex; PtrMap debug_values; Array debug_incomplete_types; @@ -167,6 +179,8 @@ struct lbModule { PtrMap map_cell_info_map; // address of runtime.Map_Info PtrMap map_info_map; // address of runtime.Map_Cell_Info + + LLVMPassManagerRef function_pass_managers[lbFunctionPassManager_COUNT]; }; struct lbGenerator { diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 55c4370a2..9bf4063d6 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -2,7 +2,9 @@ gb_internal LLVMMetadataRef lb_get_llvm_metadata(lbModule *m, void *key) { if (key == nullptr) { return nullptr; } + mutex_lock(&m->debug_values_mutex); auto found = map_get(&m->debug_values, key); + mutex_unlock(&m->debug_values_mutex); if (found) { return *found; } @@ -10,7 +12,9 @@ gb_internal LLVMMetadataRef lb_get_llvm_metadata(lbModule *m, void *key) { } gb_internal void lb_set_llvm_metadata(lbModule *m, void *key, LLVMMetadataRef value) { if (key != nullptr) { + mutex_lock(&m->debug_values_mutex); map_set(&m->debug_values, key, value); + mutex_unlock(&m->debug_values_mutex); } } @@ -491,6 +495,9 @@ gb_internal LLVMMetadataRef lb_get_base_scope_metadata(lbModule *m, Scope *scope } gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) { + mutex_lock(&m->debug_values_mutex); + defer (mutex_unlock(&m->debug_values_mutex)); + GB_ASSERT(type != nullptr); LLVMMetadataRef found = lb_get_llvm_metadata(m, type); if (found != nullptr) { -- cgit v1.2.3 From 23d0c52bf466864c768129083d45a0f6ec59090e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 5 Jan 2023 16:42:02 +0000 Subject: Refactor llvm backend code into separate procedures to make it simpler to profile --- src/llvm_backend.cpp | 913 +++++++++++++++++++++++++++------------------------ src/llvm_backend.hpp | 2 +- 2 files changed, 484 insertions(+), 431 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 54430246e..6109ca247 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1159,222 +1159,73 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc return p; } +gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, CheckerInfo *info) { + auto *min_dep_set = &info->minimum_dependency_set; -gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) { - LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); - lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level); - LLVMFinalizeFunctionPassManager(default_function_pass_manager); - - Type *params = alloc_type_tuple(); - Type *results = alloc_type_tuple(); - - Type *t_ptr_cstring = alloc_type_pointer(t_cstring); - - bool call_cleanup = true; - - bool has_args = false; - bool is_dll_main = false; - String name = str_lit("main"); - if (build_context.metrics.os == TargetOs_windows && build_context.build_mode == BuildMode_DynamicLibrary) { - is_dll_main = true; - name = str_lit("DllMain"); - slice_init(¶ms->Tuple.variables, permanent_allocator(), 3); - params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("hinstDLL"), t_rawptr, false, true); - params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("fdwReason"), t_u32, false, true); - params->Tuple.variables[2] = alloc_entity_param(nullptr, make_token_ident("lpReserved"), t_rawptr, false, true); - call_cleanup = false; - } else if (build_context.metrics.os == TargetOs_windows && (build_context.metrics.arch == TargetArch_i386 || build_context.no_crt)) { - name = str_lit("mainCRTStartup"); - } else if (is_arch_wasm()) { - name = str_lit("_start"); - call_cleanup = false; - } else { - has_args = true; - slice_init(¶ms->Tuple.variables, permanent_allocator(), 2); - params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true); - params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), t_ptr_cstring, false, true); - } - - slice_init(&results->Tuple.variables, permanent_allocator(), 1); - results->Tuple.variables[0] = alloc_entity_param(nullptr, blank_token, t_i32, false, true); - - Type *proc_type = alloc_type_proc(nullptr, - params, params->Tuple.variables.count, - results, results->Tuple.variables.count, false, ProcCC_CDecl); - - - lbProcedure *p = lb_create_dummy_procedure(m, name, proc_type); - p->is_startup = true; - - lb_begin_procedure_body(p); - - if (has_args) { // initialize `runtime.args__` - lbValue argc = {LLVMGetParam(p->value, 0), t_i32}; - lbValue argv = {LLVMGetParam(p->value, 1), t_ptr_cstring}; - LLVMSetValueName2(argc.value, "argc", 4); - LLVMSetValueName2(argv.value, "argv", 4); - argc = lb_emit_conv(p, argc, t_int); - lbAddr args = lb_addr(lb_find_runtime_value(p->module, str_lit("args__"))); - lb_fill_slice(p, args, argv, argc); - } - - lbValue startup_runtime_value = {startup_runtime->value, startup_runtime->type}; - lb_emit_call(p, startup_runtime_value, {}, ProcInlining_none); + for (Entity *e : info->entities) { + String name = e->token.string; + Scope * scope = e->scope; - if (build_context.command_kind == Command_test) { - Type *t_Internal_Test = find_type_in_pkg(m->info, str_lit("testing"), str_lit("Internal_Test")); - Type *array_type = alloc_type_array(t_Internal_Test, m->info->testing_procedures.count); - Type *slice_type = alloc_type_slice(t_Internal_Test); - lbAddr all_tests_array_addr = lb_add_global_generated(p->module, array_type, {}); - lbValue all_tests_array = lb_addr_get_ptr(p, all_tests_array_addr); + if ((scope->flags & ScopeFlag_File) == 0) { + continue; + } - LLVMValueRef indices[2] = {}; - indices[0] = LLVMConstInt(lb_type(m, t_i32), 0, false); + Scope *package_scope = scope->parent; + GB_ASSERT(package_scope->flags & ScopeFlag_Pkg); - isize testing_proc_index = 0; - for (Entity *testing_proc : m->info->testing_procedures) { - String name = testing_proc->token.string; + switch (e->kind) { + case Entity_Variable: + // NOTE(bill): Handled above as it requires a specific load order + continue; + case Entity_ProcGroup: + continue; - String pkg_name = {}; - if (testing_proc->pkg != nullptr) { - pkg_name = testing_proc->pkg->name; + case Entity_TypeName: + case Entity_Procedure: + break; + case Entity_Constant: + if (build_context.ODIN_DEBUG) { + add_debug_info_for_global_constant_from_entity(gen, e); } - lbValue v_pkg = lb_find_or_add_entity_string(m, pkg_name); - lbValue v_name = lb_find_or_add_entity_string(m, name); - lbValue v_proc = lb_find_procedure_value_from_entity(m, testing_proc); - - indices[1] = LLVMConstInt(lb_type(m, t_int), testing_proc_index++, false); - - LLVMValueRef vals[3] = {}; - vals[0] = v_pkg.value; - vals[1] = v_name.value; - vals[2] = v_proc.value; - GB_ASSERT(LLVMIsConstant(vals[0])); - GB_ASSERT(LLVMIsConstant(vals[1])); - GB_ASSERT(LLVMIsConstant(vals[2])); - - LLVMValueRef dst = LLVMConstInBoundsGEP2(llvm_addr_type(m, all_tests_array), all_tests_array.value, indices, gb_count_of(indices)); - LLVMValueRef src = llvm_const_named_struct(m, t_Internal_Test, vals, gb_count_of(vals)); - - LLVMBuildStore(p->builder, src, dst); + break; } - lbAddr all_tests_slice = lb_add_local_generated(p, slice_type, true); - lb_fill_slice(p, all_tests_slice, - lb_array_elem(p, all_tests_array), - lb_const_int(m, t_int, m->info->testing_procedures.count)); - - - lbValue runner = lb_find_package_value(m, str_lit("testing"), str_lit("runner")); - - auto args = array_make(heap_allocator(), 1); - args[0] = lb_addr_load(p, all_tests_slice); - lb_emit_call(p, runner, args); - } else { - if (m->info->entry_point != nullptr) { - lbValue entry_point = lb_find_procedure_value_from_entity(m, m->info->entry_point); - lb_emit_call(p, entry_point, {}, ProcInlining_no_inline); + bool polymorphic_struct = false; + if (e->type != nullptr && e->kind == Entity_TypeName) { + Type *bt = base_type(e->type); + if (bt->kind == Type_Struct) { + polymorphic_struct = is_type_polymorphic(bt); + } } - } - - - if (call_cleanup) { - lbValue cleanup_runtime_value = lb_find_runtime_value(m, str_lit("_cleanup_runtime")); - lb_emit_call(p, cleanup_runtime_value, {}, ProcInlining_none); - } - - - if (is_dll_main) { - LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 1, false)); - } else { - LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false)); - } - - lb_end_procedure_body(p); - - - LLVMSetLinkage(p->value, LLVMExternalLinkage); - if (is_arch_wasm()) { - lb_set_wasm_export_attributes(p->value, p->name); - } - - - if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { - gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main"); - LLVMDumpValue(p->value); - gb_printf_err("\n\n\n\n"); - LLVMVerifyFunction(p->value, LLVMAbortProcessAction); - } - - lb_run_function_pass_manager(default_function_pass_manager, p); - return p; -} - -gb_internal String lb_filepath_ll_for_module(lbModule *m) { - String path = concatenate3_strings(permanent_allocator(), - build_context.build_paths[BuildPath_Output].basename, - STR_LIT("/"), - build_context.build_paths[BuildPath_Output].name - ); - - if (m->pkg) { - path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); - } else if (USE_SEPARATE_MODULES) { - path = concatenate_strings(permanent_allocator(), path, STR_LIT("-builtin")); - } - path = concatenate_strings(permanent_allocator(), path, STR_LIT(".ll")); - - return path; -} -gb_internal String lb_filepath_obj_for_module(lbModule *m) { - String path = concatenate3_strings(permanent_allocator(), - build_context.build_paths[BuildPath_Output].basename, - STR_LIT("/"), - build_context.build_paths[BuildPath_Output].name - ); - if (m->pkg) { - path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); - } + if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { + // NOTE(bill): Nothing depends upon it so doesn't need to be built + continue; + } - String ext = {}; + lbModule *m = &gen->default_module; + if (USE_SEPARATE_MODULES) { + m = lb_pkg_module(gen, e->pkg); + } - if (build_context.build_mode == BuildMode_Assembly) { - ext = STR_LIT(".S"); - } else { - if (is_arch_wasm()) { - ext = STR_LIT(".wasm.o"); - } else { - switch (build_context.metrics.os) { - case TargetOs_windows: - ext = STR_LIT(".obj"); - break; - default: - case TargetOs_darwin: - case TargetOs_linux: - case TargetOs_essence: - ext = STR_LIT(".o"); - break; + String mangled_name = lb_get_entity_name(m, e); - case TargetOs_freestanding: - switch (build_context.metrics.abi) { - default: - case TargetABI_Default: - case TargetABI_SysV: - ext = STR_LIT(".o"); - break; - case TargetABI_Win64: - ext = STR_LIT(".obj"); - break; - } - break; + switch (e->kind) { + case Entity_TypeName: + lb_type(m, e->type); + break; + case Entity_Procedure: + { + lbProcedure *p = lb_create_procedure(m, e); + array_add(&m->procedures_to_generate, p); } + break; } } - - return concatenate_strings(permanent_allocator(), path, ext); } +gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p); + gb_internal bool lb_is_module_empty(lbModule *m) { if (LLVMGetFirstFunction(m->mod) == nullptr && @@ -1487,42 +1338,428 @@ gb_internal void lb_llvm_function_pass_per_module(lbModule *m) { } } - for (auto const &entry : m->equal_procs) { - lbProcedure *p = entry.value; - lb_llvm_function_pass_per_function_internal(m, p); - } - for (auto const &entry : m->hasher_procs) { - lbProcedure *p = entry.value; - lb_llvm_function_pass_per_function_internal(m, p); - } - for (auto const &entry : m->map_get_procs) { - lbProcedure *p = entry.value; - lb_llvm_function_pass_per_function_internal(m, p); + for (auto const &entry : m->equal_procs) { + lbProcedure *p = entry.value; + lb_llvm_function_pass_per_function_internal(m, p); + } + for (auto const &entry : m->hasher_procs) { + lbProcedure *p = entry.value; + lb_llvm_function_pass_per_function_internal(m, p); + } + for (auto const &entry : m->map_get_procs) { + lbProcedure *p = entry.value; + lb_llvm_function_pass_per_function_internal(m, p); + } + for (auto const &entry : m->map_set_procs) { + lbProcedure *p = entry.value; + lb_llvm_function_pass_per_function_internal(m, p); + } +} + + +struct lbLLVMModulePassWorkerData { + lbModule *m; + LLVMTargetMachineRef target_machine; +}; + +gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { + auto wd = cast(lbLLVMModulePassWorkerData *)data; + + lb_run_remove_unused_function_pass(wd->m); + lb_run_remove_unused_globals_pass(wd->m); + + LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager(); + lb_populate_module_pass_manager(wd->target_machine, module_pass_manager, build_context.optimization_level); + LLVMRunPassManager(module_pass_manager, wd->m->mod); + return 0; +} + + + +gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) { + lbModule *m = cast(lbModule *)data; + for (isize i = 0; i < m->procedures_to_generate.count; i++) { + lbProcedure *p = m->procedures_to_generate[i]; + lb_generate_procedure(p->module, p); + } + return 0; +} + +gb_internal void lb_generate_procedures(lbGenerator *gen, bool do_threading) { + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + if (do_threading) { + thread_pool_add_task(lb_generate_procedures_worker_proc, m); + } else { + lb_generate_procedures_worker_proc(m); + } + } + + thread_pool_wait(); +} + +gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) { + lbModule *m = cast(lbModule *)data; + for (isize i = 0; i < m->missing_procedures_to_check.count; i++) { + lbProcedure *p = m->missing_procedures_to_check[i]; + debugf("Generate missing procedure: %.*s\n", LIT(p->name)); + lb_generate_procedure(m, p); + } + return 0; +} + +gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_threading) { + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + // NOTE(bill): procedures may be added during generation + if (do_threading) { + thread_pool_add_task(lb_generate_missing_procedures_to_check_worker_proc, m); + } else { + lb_generate_missing_procedures_to_check_worker_proc(m); + } + } + + thread_pool_wait(); +} + +gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) { + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + if (m->debug_builder != nullptr) { + lb_debug_complete_types(m); + LLVMDIBuilderFinalize(m->debug_builder); + } + } +} + +gb_internal void lb_llvm_function_passes(lbGenerator *gen) { + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + lb_llvm_function_pass_per_module(m); + } + thread_pool_wait(); +} + + +gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) { + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData); + wd->m = m; + wd->target_machine = m->target_machine; + + if (do_threading) { + thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd); + } else { + lb_llvm_module_pass_worker_proc(wd); + } + } + thread_pool_wait(); +} + + +gb_internal String lb_filepath_ll_for_module(lbModule *m) { + String path = concatenate3_strings(permanent_allocator(), + build_context.build_paths[BuildPath_Output].basename, + STR_LIT("/"), + build_context.build_paths[BuildPath_Output].name + ); + + if (m->pkg) { + path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); + } else if (USE_SEPARATE_MODULES) { + path = concatenate_strings(permanent_allocator(), path, STR_LIT("-builtin")); + } + path = concatenate_strings(permanent_allocator(), path, STR_LIT(".ll")); + + return path; +} +gb_internal String lb_filepath_obj_for_module(lbModule *m) { + String path = concatenate3_strings(permanent_allocator(), + build_context.build_paths[BuildPath_Output].basename, + STR_LIT("/"), + build_context.build_paths[BuildPath_Output].name + ); + + if (m->pkg) { + path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); + } + + String ext = {}; + + if (build_context.build_mode == BuildMode_Assembly) { + ext = STR_LIT(".S"); + } else { + if (is_arch_wasm()) { + ext = STR_LIT(".wasm.o"); + } else { + switch (build_context.metrics.os) { + case TargetOs_windows: + ext = STR_LIT(".obj"); + break; + default: + case TargetOs_darwin: + case TargetOs_linux: + case TargetOs_essence: + ext = STR_LIT(".o"); + break; + + case TargetOs_freestanding: + switch (build_context.metrics.abi) { + default: + case TargetABI_Default: + case TargetABI_SysV: + ext = STR_LIT(".o"); + break; + case TargetABI_Win64: + ext = STR_LIT(".obj"); + break; + } + break; + } + } + } + + return concatenate_strings(permanent_allocator(), path, ext); +} + +gb_internal bool lb_llvm_module_verification(lbGenerator *gen, char **llvm_error_ptr) { + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, llvm_error_ptr)) { + gb_printf_err("LLVM Error:\n%s\n", *llvm_error_ptr); + if (build_context.keep_temp_files) { + TIME_SECTION("LLVM Print Module to File"); + String filepath_ll = lb_filepath_ll_for_module(m); + if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, llvm_error_ptr)) { + gb_printf_err("LLVM Error: %s\n", *llvm_error_ptr); + gb_exit(1); + return false; + } + } + gb_exit(1); + return false; + } + } + *llvm_error_ptr = nullptr; + return true; +} + +gb_internal void lb_add_foreign_library_paths(lbGenerator *gen) { + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + for (Entity *e : m->info->required_foreign_imports_through_force) { + lb_add_foreign_library_path(m, e); + } + + if (lb_is_module_empty(m)) { + continue; + } + } +} + +gb_internal bool lb_llvm_object_generation(lbGenerator *gen, LLVMCodeGenFileType code_gen_file_type, bool do_threading) { + char *llvm_error = nullptr; + defer (LLVMDisposeMessage(llvm_error)); + + if (do_threading) { + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + if (lb_is_module_empty(m)) { + continue; + } + + String filepath_ll = lb_filepath_ll_for_module(m); + String filepath_obj = lb_filepath_obj_for_module(m); + array_add(&gen->output_object_paths, filepath_obj); + array_add(&gen->output_temp_paths, filepath_ll); + + auto *wd = gb_alloc_item(permanent_allocator(), lbLLVMEmitWorker); + wd->target_machine = m->target_machine; + wd->code_gen_file_type = code_gen_file_type; + wd->filepath_obj = filepath_obj; + wd->m = m; + thread_pool_add_task(lb_llvm_emit_worker_proc, wd); + } + + thread_pool_wait(&global_thread_pool); + } else { + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + if (lb_is_module_empty(m)) { + continue; + } + + String filepath_obj = lb_filepath_obj_for_module(m); + array_add(&gen->output_object_paths, filepath_obj); + + String short_name = remove_directory_from_path(filepath_obj); + gbString section_name = gb_string_make(heap_allocator(), "LLVM Generate Object: "); + section_name = gb_string_append_length(section_name, short_name.text, short_name.len); + + TIME_SECTION_WITH_LEN(section_name, gb_string_length(section_name)); + + if (LLVMTargetMachineEmitToFile(m->target_machine, m->mod, cast(char *)filepath_obj.text, code_gen_file_type, &llvm_error)) { + gb_printf_err("LLVM Error: %s\n", llvm_error); + gb_exit(1); + return false; + } + } + } + return true; +} + + + +gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) { + LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); + lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level); + LLVMFinalizeFunctionPassManager(default_function_pass_manager); + + Type *params = alloc_type_tuple(); + Type *results = alloc_type_tuple(); + + Type *t_ptr_cstring = alloc_type_pointer(t_cstring); + + bool call_cleanup = true; + + bool has_args = false; + bool is_dll_main = false; + String name = str_lit("main"); + if (build_context.metrics.os == TargetOs_windows && build_context.build_mode == BuildMode_DynamicLibrary) { + is_dll_main = true; + name = str_lit("DllMain"); + slice_init(¶ms->Tuple.variables, permanent_allocator(), 3); + params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("hinstDLL"), t_rawptr, false, true); + params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("fdwReason"), t_u32, false, true); + params->Tuple.variables[2] = alloc_entity_param(nullptr, make_token_ident("lpReserved"), t_rawptr, false, true); + call_cleanup = false; + } else if (build_context.metrics.os == TargetOs_windows && (build_context.metrics.arch == TargetArch_i386 || build_context.no_crt)) { + name = str_lit("mainCRTStartup"); + } else if (is_arch_wasm()) { + name = str_lit("_start"); + call_cleanup = false; + } else { + has_args = true; + slice_init(¶ms->Tuple.variables, permanent_allocator(), 2); + params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true); + params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), t_ptr_cstring, false, true); + } + + slice_init(&results->Tuple.variables, permanent_allocator(), 1); + results->Tuple.variables[0] = alloc_entity_param(nullptr, blank_token, t_i32, false, true); + + Type *proc_type = alloc_type_proc(nullptr, + params, params->Tuple.variables.count, + results, results->Tuple.variables.count, false, ProcCC_CDecl); + + + lbProcedure *p = lb_create_dummy_procedure(m, name, proc_type); + p->is_startup = true; + + lb_begin_procedure_body(p); + + if (has_args) { // initialize `runtime.args__` + lbValue argc = {LLVMGetParam(p->value, 0), t_i32}; + lbValue argv = {LLVMGetParam(p->value, 1), t_ptr_cstring}; + LLVMSetValueName2(argc.value, "argc", 4); + LLVMSetValueName2(argv.value, "argv", 4); + argc = lb_emit_conv(p, argc, t_int); + lbAddr args = lb_addr(lb_find_runtime_value(p->module, str_lit("args__"))); + lb_fill_slice(p, args, argv, argc); + } + + lbValue startup_runtime_value = {startup_runtime->value, startup_runtime->type}; + lb_emit_call(p, startup_runtime_value, {}, ProcInlining_none); + + if (build_context.command_kind == Command_test) { + Type *t_Internal_Test = find_type_in_pkg(m->info, str_lit("testing"), str_lit("Internal_Test")); + Type *array_type = alloc_type_array(t_Internal_Test, m->info->testing_procedures.count); + Type *slice_type = alloc_type_slice(t_Internal_Test); + lbAddr all_tests_array_addr = lb_add_global_generated(p->module, array_type, {}); + lbValue all_tests_array = lb_addr_get_ptr(p, all_tests_array_addr); + + LLVMValueRef indices[2] = {}; + indices[0] = LLVMConstInt(lb_type(m, t_i32), 0, false); + + isize testing_proc_index = 0; + for (Entity *testing_proc : m->info->testing_procedures) { + String name = testing_proc->token.string; + + String pkg_name = {}; + if (testing_proc->pkg != nullptr) { + pkg_name = testing_proc->pkg->name; + } + lbValue v_pkg = lb_find_or_add_entity_string(m, pkg_name); + lbValue v_name = lb_find_or_add_entity_string(m, name); + lbValue v_proc = lb_find_procedure_value_from_entity(m, testing_proc); + + indices[1] = LLVMConstInt(lb_type(m, t_int), testing_proc_index++, false); + + LLVMValueRef vals[3] = {}; + vals[0] = v_pkg.value; + vals[1] = v_name.value; + vals[2] = v_proc.value; + GB_ASSERT(LLVMIsConstant(vals[0])); + GB_ASSERT(LLVMIsConstant(vals[1])); + GB_ASSERT(LLVMIsConstant(vals[2])); + + LLVMValueRef dst = LLVMConstInBoundsGEP2(llvm_addr_type(m, all_tests_array), all_tests_array.value, indices, gb_count_of(indices)); + LLVMValueRef src = llvm_const_named_struct(m, t_Internal_Test, vals, gb_count_of(vals)); + + LLVMBuildStore(p->builder, src, dst); + } + + lbAddr all_tests_slice = lb_add_local_generated(p, slice_type, true); + lb_fill_slice(p, all_tests_slice, + lb_array_elem(p, all_tests_array), + lb_const_int(m, t_int, m->info->testing_procedures.count)); + + + lbValue runner = lb_find_package_value(m, str_lit("testing"), str_lit("runner")); + + auto args = array_make(heap_allocator(), 1); + args[0] = lb_addr_load(p, all_tests_slice); + lb_emit_call(p, runner, args); + } else { + if (m->info->entry_point != nullptr) { + lbValue entry_point = lb_find_procedure_value_from_entity(m, m->info->entry_point); + lb_emit_call(p, entry_point, {}, ProcInlining_no_inline); + } + } + + + if (call_cleanup) { + lbValue cleanup_runtime_value = lb_find_runtime_value(m, str_lit("_cleanup_runtime")); + lb_emit_call(p, cleanup_runtime_value, {}, ProcInlining_none); } - for (auto const &entry : m->map_set_procs) { - lbProcedure *p = entry.value; - lb_llvm_function_pass_per_function_internal(m, p); + + + if (is_dll_main) { + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 1, false)); + } else { + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false)); } -} + lb_end_procedure_body(p); -struct lbLLVMModulePassWorkerData { - lbModule *m; - LLVMTargetMachineRef target_machine; -}; -gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { - auto wd = cast(lbLLVMModulePassWorkerData *)data; + LLVMSetLinkage(p->value, LLVMExternalLinkage); + if (is_arch_wasm()) { + lb_set_wasm_export_attributes(p->value, p->name); + } - lb_run_remove_unused_function_pass(wd->m); - lb_run_remove_unused_globals_pass(wd->m); - LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager(); - lb_populate_module_pass_manager(wd->target_machine, module_pass_manager, build_context.optimization_level); - LLVMRunPassManager(module_pass_manager, wd->m->mod); - return 0; -} + if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { + gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main"); + LLVMDumpValue(p->value); + gb_printf_err("\n\n\n\n"); + LLVMVerifyFunction(p->value, LLVMAbortProcessAction); + } + lb_run_function_pass_manager(default_function_pass_manager, p); + return p; +} gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) { if (p->is_done) { @@ -1564,25 +1801,6 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) { } -gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) { - lbModule *m = cast(lbModule *)data; - for (isize i = 0; i < m->procedures_to_generate.count; i++) { - lbProcedure *p = m->procedures_to_generate[i]; - lb_generate_procedure(p->module, p); - } - return 0; -} - -gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) { - lbModule *m = cast(lbModule *)data; - for (isize i = 0; i < m->missing_procedures_to_check.count; i++) { - lbProcedure *p = m->missing_procedures_to_check[i]; - debugf("Generate missing procedure: %.*s\n", LIT(p->name)); - lb_generate_procedure(m, p); - } - return 0; -} - gb_internal bool lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Initializtion"); @@ -2064,82 +2282,14 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } TIME_SECTION("LLVM Global Procedures and Types"); - for (Entity *e : info->entities) { - String name = e->token.string; - Scope * scope = e->scope; - - if ((scope->flags & ScopeFlag_File) == 0) { - continue; - } - - Scope *package_scope = scope->parent; - GB_ASSERT(package_scope->flags & ScopeFlag_Pkg); - - switch (e->kind) { - case Entity_Variable: - // NOTE(bill): Handled above as it requires a specific load order - continue; - case Entity_ProcGroup: - continue; - - case Entity_TypeName: - case Entity_Procedure: - break; - case Entity_Constant: - if (build_context.ODIN_DEBUG) { - add_debug_info_for_global_constant_from_entity(gen, e); - } - break; - } - - bool polymorphic_struct = false; - if (e->type != nullptr && e->kind == Entity_TypeName) { - Type *bt = base_type(e->type); - if (bt->kind == Type_Struct) { - polymorphic_struct = is_type_polymorphic(bt); - } - } - - if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { - // NOTE(bill): Nothing depends upon it so doesn't need to be built - continue; - } - - lbModule *m = &gen->default_module; - if (USE_SEPARATE_MODULES) { - m = lb_pkg_module(gen, e->pkg); - } - - String mangled_name = lb_get_entity_name(m, e); - - switch (e->kind) { - case Entity_TypeName: - lb_type(m, e->type); - break; - case Entity_Procedure: - { - lbProcedure *p = lb_create_procedure(m, e); - array_add(&m->procedures_to_generate, p); - } - break; - } - } + lb_create_global_procedures_and_types(gen, info); if (gen->modules.entries.count <= 1) { do_threading = false; } TIME_SECTION("LLVM Procedure Generation"); - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - if (do_threading) { - thread_pool_add_task(lb_generate_procedures_worker_proc, m); - } else { - lb_generate_procedures_worker_proc(m); - } - } - - thread_pool_wait(); + lb_generate_procedures(gen, do_threading); if (build_context.command_kind == Command_test && !already_has_entry_point) { TIME_SECTION("LLVM main"); @@ -2147,17 +2297,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } TIME_SECTION("LLVM Procedure Generation (missing)"); - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - // NOTE(bill): procedures may be added during generation - if (do_threading) { - thread_pool_add_task(lb_generate_missing_procedures_to_check_worker_proc, m); - } else { - lb_generate_missing_procedures_to_check_worker_proc(m); - } - } - - thread_pool_wait(); + lb_generate_missing_procedures(gen, do_threading); if (gen->objc_names) { TIME_SECTION("Finalize objc names"); @@ -2166,48 +2306,28 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { if (build_context.ODIN_DEBUG) { TIME_SECTION("LLVM Debug Info Complete Types and Finalize"); + lb_debug_info_complete_types_and_finalize(gen); + } + + if (do_threading) { + isize non_empty_module_count = 0; for (auto const &entry : gen->modules) { lbModule *m = entry.value; - if (m->debug_builder != nullptr) { - lb_debug_complete_types(m); - LLVMDIBuilderFinalize(m->debug_builder); + if (!lb_is_module_empty(m)) { + non_empty_module_count += 1; } } - } - - isize non_empty_module_count = 0; - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - if (!lb_is_module_empty(m)) { - non_empty_module_count += 1; + if (non_empty_module_count <= 1) { + do_threading = false; } } - if (non_empty_module_count <= 1) { - do_threading = false; - } TIME_SECTION("LLVM Function Pass"); - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - lb_llvm_function_pass_per_module(m); - } - thread_pool_wait(); + lb_llvm_function_passes(gen); TIME_SECTION("LLVM Module Pass"); - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData); - wd->m = m; - wd->target_machine = m->target_machine; - - if (do_threading) { - thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd); - } else { - lb_llvm_module_pass_worker_proc(wd); - } - } - thread_pool_wait(); + lb_llvm_module_passes(gen, do_threading); TIME_SECTION("LLVM Module Verification"); @@ -2220,25 +2340,10 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { code_gen_file_type = LLVMAssemblyFile; } - - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) { - gb_printf_err("LLVM Error:\n%s\n", llvm_error); - if (build_context.keep_temp_files) { - TIME_SECTION("LLVM Print Module to File"); - String filepath_ll = lb_filepath_ll_for_module(m); - if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) { - gb_printf_err("LLVM Error: %s\n", llvm_error); - gb_exit(1); - return false; - } - } - gb_exit(1); - return false; - } + if (!lb_llvm_module_verification(gen, &llvm_error)) { + return false; } - llvm_error = nullptr; + if (build_context.keep_temp_files || build_context.build_mode == BuildMode_LLVM_IR) { TIME_SECTION("LLVM Print Module to File"); @@ -2264,17 +2369,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } TIME_SECTION("LLVM Add Foreign Library Paths"); - - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - for (Entity *e : m->info->required_foreign_imports_through_force) { - lb_add_foreign_library_path(m, e); - } - - if (lb_is_module_empty(m)) { - continue; - } - } + lb_add_foreign_library_paths(gen); TIME_SECTION("LLVM Object Generation"); @@ -2282,50 +2377,8 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { gb_printf_err("LLVM object generation has been ignored!\n"); return false; } - - if (do_threading) { - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - if (lb_is_module_empty(m)) { - continue; - } - - String filepath_ll = lb_filepath_ll_for_module(m); - String filepath_obj = lb_filepath_obj_for_module(m); - array_add(&gen->output_object_paths, filepath_obj); - array_add(&gen->output_temp_paths, filepath_ll); - - auto *wd = gb_alloc_item(permanent_allocator(), lbLLVMEmitWorker); - wd->target_machine = m->target_machine; - wd->code_gen_file_type = code_gen_file_type; - wd->filepath_obj = filepath_obj; - wd->m = m; - thread_pool_add_task(lb_llvm_emit_worker_proc, wd); - } - - thread_pool_wait(&global_thread_pool); - } else { - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - if (lb_is_module_empty(m)) { - continue; - } - - String filepath_obj = lb_filepath_obj_for_module(m); - array_add(&gen->output_object_paths, filepath_obj); - - String short_name = remove_directory_from_path(filepath_obj); - gbString section_name = gb_string_make(heap_allocator(), "LLVM Generate Object: "); - section_name = gb_string_append_length(section_name, short_name.text, short_name.len); - - TIME_SECTION_WITH_LEN(section_name, gb_string_length(section_name)); - - if (LLVMTargetMachineEmitToFile(m->target_machine, m->mod, cast(char *)filepath_obj.text, code_gen_file_type, &llvm_error)) { - gb_printf_err("LLVM Error: %s\n", llvm_error); - gb_exit(1); - return false; - } - } + if (!lb_llvm_object_generation(gen, code_gen_file_type, do_threading)) { + return false; } gb_sort_array(gen->foreign_libraries.data, gen->foreign_libraries.count, foreign_library_cmp); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 0e3a38fd3..98b657256 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -37,7 +37,7 @@ #endif #if LLVM_VERSION_MAJOR > 12 || (LLVM_VERSION_MAJOR == 12 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0) -#define ODIN_LLVM_MINIMUM_VERSION_12 1 +#define ODIN_LLVM_MINIMUM_VERSION_12 0 #else #define ODIN_LLVM_MINIMUM_VERSION_12 0 #endif -- cgit v1.2.3 From 8ef406324bd500cfd9f3d857e3a5d51adce33374 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 5 Jan 2023 17:26:51 +0000 Subject: Multi thread more of the backend where possible --- src/llvm_backend.cpp | 126 ++++++++++++++++++++++++++++--------------- src/llvm_backend.hpp | 1 + src/llvm_backend_general.cpp | 1 + 3 files changed, 85 insertions(+), 43 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 6109ca247..e959b4741 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1159,7 +1159,24 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc return p; } -gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, CheckerInfo *info) { +gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) { + lbModule *m = cast(lbModule *)data; + for (Entity *e : m->global_procedures_and_types_to_create) { + String mangled_name = lb_get_entity_name(m, e); + + switch (e->kind) { + case Entity_TypeName: + lb_type(m, e->type); + break; + case Entity_Procedure: + array_add(&m->procedures_to_generate, lb_create_procedure(m, e)); + break; + } + } + return 0; +} + +gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, CheckerInfo *info, bool do_threading) { auto *min_dep_set = &info->minimum_dependency_set; for (Entity *e : info->entities) { @@ -1208,20 +1225,19 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker m = lb_pkg_module(gen, e->pkg); } - String mangled_name = lb_get_entity_name(m, e); + array_add(&m->global_procedures_and_types_to_create, e); + } - switch (e->kind) { - case Entity_TypeName: - lb_type(m, e->type); - break; - case Entity_Procedure: - { - lbProcedure *p = lb_create_procedure(m, e); - array_add(&m->procedures_to_generate, p); - } - break; + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + if (do_threading) { + thread_pool_add_task(lb_generate_procedures_and_types_per_module, m); + } else { + lb_generate_procedures_and_types_per_module(m); } } + + thread_pool_wait(); } gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p); @@ -1277,7 +1293,8 @@ gb_internal void lb_llvm_function_pass_per_function_internal(lbModule *module, l lb_run_function_pass_manager(pass_manager, p); } -gb_internal void lb_llvm_function_pass_per_module(lbModule *m) { +gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) { + lbModule *m = cast(lbModule *)data; { GB_ASSERT(m->function_pass_managers[lbFunctionPassManager_default] == nullptr); @@ -1354,6 +1371,8 @@ gb_internal void lb_llvm_function_pass_per_module(lbModule *m) { lbProcedure *p = entry.value; lb_llvm_function_pass_per_function_internal(m, p); } + + return 0; } @@ -1432,10 +1451,14 @@ gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) { } } -gb_internal void lb_llvm_function_passes(lbGenerator *gen) { +gb_internal void lb_llvm_function_passes(lbGenerator *gen, bool do_threading) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; - lb_llvm_function_pass_per_module(m); + if (do_threading) { + thread_pool_add_task(lb_llvm_function_pass_per_module, m); + } else { + lb_llvm_function_pass_per_module(m); + } } thread_pool_wait(); } @@ -1523,25 +1546,41 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) { return concatenate_strings(permanent_allocator(), path, ext); } -gb_internal bool lb_llvm_module_verification(lbGenerator *gen, char **llvm_error_ptr) { +gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) { + char *llvm_error = nullptr; + defer (LLVMDisposeMessage(llvm_error)); + lbModule *m = cast(lbModule *)data; + if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) { + gb_printf_err("LLVM Error:\n%s\n", llvm_error); + if (build_context.keep_temp_files) { + TIME_SECTION("LLVM Print Module to File"); + String filepath_ll = lb_filepath_ll_for_module(m); + if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) { + gb_printf_err("LLVM Error: %s\n", llvm_error); + gb_exit(1); + return false; + } + } + gb_exit(1); + return 1; + } + return 0; +} + + +gb_internal bool lb_llvm_module_verification(lbGenerator *gen, bool do_threading) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; - if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, llvm_error_ptr)) { - gb_printf_err("LLVM Error:\n%s\n", *llvm_error_ptr); - if (build_context.keep_temp_files) { - TIME_SECTION("LLVM Print Module to File"); - String filepath_ll = lb_filepath_ll_for_module(m); - if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, llvm_error_ptr)) { - gb_printf_err("LLVM Error: %s\n", *llvm_error_ptr); - gb_exit(1); - return false; - } + if (do_threading) { + thread_pool_add_task(lb_llvm_module_verification_worker_proc, m); + } else { + if (lb_llvm_module_verification_worker_proc(m)) { + return false; } - gb_exit(1); - return false; } } - *llvm_error_ptr = nullptr; + thread_pool_wait(); + return true; } @@ -1558,7 +1597,12 @@ gb_internal void lb_add_foreign_library_paths(lbGenerator *gen) { } } -gb_internal bool lb_llvm_object_generation(lbGenerator *gen, LLVMCodeGenFileType code_gen_file_type, bool do_threading) { +gb_internal bool lb_llvm_object_generation(lbGenerator *gen, bool do_threading) { + LLVMCodeGenFileType code_gen_file_type = LLVMObjectFile; + if (build_context.build_mode == BuildMode_Assembly) { + code_gen_file_type = LLVMAssemblyFile; + } + char *llvm_error = nullptr; defer (LLVMDisposeMessage(llvm_error)); @@ -2281,13 +2325,13 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } } - TIME_SECTION("LLVM Global Procedures and Types"); - lb_create_global_procedures_and_types(gen, info); - if (gen->modules.entries.count <= 1) { do_threading = false; } + TIME_SECTION("LLVM Global Procedures and Types"); + lb_create_global_procedures_and_types(gen, info, do_threading); + TIME_SECTION("LLVM Procedure Generation"); lb_generate_procedures(gen, do_threading); @@ -2324,7 +2368,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Function Pass"); - lb_llvm_function_passes(gen); + lb_llvm_function_passes(gen, do_threading); TIME_SECTION("LLVM Module Pass"); lb_llvm_module_passes(gen, do_threading); @@ -2332,18 +2376,14 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Module Verification"); - llvm_error = nullptr; - defer (LLVMDisposeMessage(llvm_error)); - LLVMCodeGenFileType code_gen_file_type = LLVMObjectFile; - if (build_context.build_mode == BuildMode_Assembly) { - code_gen_file_type = LLVMAssemblyFile; - } - - if (!lb_llvm_module_verification(gen, &llvm_error)) { + if (!lb_llvm_module_verification(gen, do_threading)) { return false; } + llvm_error = nullptr; + defer (LLVMDisposeMessage(llvm_error)); + if (build_context.keep_temp_files || build_context.build_mode == BuildMode_LLVM_IR) { TIME_SECTION("LLVM Print Module to File"); @@ -2377,7 +2417,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { gb_printf_err("LLVM object generation has been ignored!\n"); return false; } - if (!lb_llvm_object_generation(gen, code_gen_file_type, do_threading)) { + if (!lb_llvm_object_generation(gen, do_threading)) { return false; } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 98b657256..90dfbc311 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -163,6 +163,7 @@ struct lbModule { u32 nested_type_name_guid; Array procedures_to_generate; + Array global_procedures_and_types_to_create; lbProcedure *curr_procedure; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index c09648825..dca8c829d 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -70,6 +70,7 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) { map_init(&m->map_get_procs); map_init(&m->map_set_procs); array_init(&m->procedures_to_generate, a, 0, 1024); + array_init(&m->global_procedures_and_types_to_create, a, 0, 1024); array_init(&m->missing_procedures_to_check, a, 0, 16); map_init(&m->debug_values); array_init(&m->debug_incomplete_types, a, 0, 1024); -- cgit v1.2.3 From 9b47a5eddba71989c37935eaafbec4bc1cd125c1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 11 Jan 2023 00:49:04 +0000 Subject: Fix macro issue --- src/llvm_backend.cpp | 2 +- src/llvm_backend.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/llvm_backend.cpp') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index e959b4741..fef222817 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1851,7 +1851,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { isize thread_count = gb_max(build_context.thread_count, 1); isize worker_count = thread_count-1; - LLVMBool do_threading = (LLVMIsMultithreaded() && USE_SEPARATE_MODULES && MULTITHREAD_OBJECT_GENERATION && worker_count > 0); + bool do_threading = !!(LLVMIsMultithreaded() && USE_SEPARATE_MODULES && MULTITHREAD_OBJECT_GENERATION && worker_count > 0); lbModule *default_module = &gen->default_module; CheckerInfo *info = gen->info; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 90dfbc311..de4deffd4 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -37,7 +37,7 @@ #endif #if LLVM_VERSION_MAJOR > 12 || (LLVM_VERSION_MAJOR == 12 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0) -#define ODIN_LLVM_MINIMUM_VERSION_12 0 +#define ODIN_LLVM_MINIMUM_VERSION_12 1 #else #define ODIN_LLVM_MINIMUM_VERSION_12 0 #endif -- cgit v1.2.3