diff options
| author | gingerBill <gingerBill@users.noreply.github.com> | 2023-01-11 22:14:53 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-11 22:14:53 +0000 |
| commit | 320062157f06d979db926fcbf407bbbdcc3028c1 (patch) | |
| tree | 770bb60802ff24cc66c8e5e5837819969dc84cd6 /src/llvm_backend.cpp | |
| parent | 86511d44e46b6271b01df2cd1ebb83b5496e143c (diff) | |
| parent | d7d6608142c8e169a7856c9e5965619809653903 (diff) | |
Merge pull request #2288 from odin-lang/compiler-improvements-2023-01
Multithreading Compiler Improvements 2023-01
Diffstat (limited to 'src/llvm_backend.cpp')
| -rw-r--r-- | src/llvm_backend.cpp | 977 |
1 files changed, 550 insertions, 427 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 146cb2944..fef222817 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); @@ -732,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); @@ -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<lbValue>(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<lbGlobalVariable> &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,11 +1156,504 @@ 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; } +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) { + 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); + } + + array_add(&m->global_procedures_and_types_to_create, e); + } + + 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); + + +gb_internal bool lb_is_module_empty(lbModule *m) { + if (LLVMGetFirstFunction(m->mod) == nullptr && + LLVMGetFirstGlobal(m->mod) == nullptr) { + return true; + } + for (auto fn = LLVMGetFirstFunction(m->mod); fn != nullptr; fn = LLVMGetNextFunction(fn)) { + if (LLVMGetFirstBasicBlock(fn) != nullptr) { + return false; + } + } + + for (auto g = LLVMGetFirstGlobal(m->mod); g != nullptr; g = LLVMGetNextGlobal(g)) { + if (LLVMGetLinkage(g) == LLVMExternalLinkage) { + continue; + } + if (!LLVMIsExternallyInitialized(g)) { + return false; + } + } + return true; +} + +struct lbLLVMEmitWorker { + LLVMTargetMachineRef target_machine; + LLVMCodeGenFileType code_gen_file_type; + String filepath_obj; + lbModule *m; +}; + +gb_internal WORKER_TASK_PROC(lb_llvm_emit_worker_proc) { + GB_ASSERT(MULTITHREAD_OBJECT_GENERATION); + + char *llvm_error = nullptr; + + auto wd = cast(lbLLVMEmitWorker *)data; + + if (LLVMTargetMachineEmitToFile(wd->target_machine, wd->m->mod, cast(char *)wd->filepath_obj.text, wd->code_gen_file_type, &llvm_error)) { + gb_printf_err("LLVM Error: %s\n", llvm_error); + gb_exit(1); + } + + return 0; +} + + +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); +} + +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); + + 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); + + 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]); + + 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); + + 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]); + } + + 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) { + 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: + pass_manager_kind = lbFunctionPassManager_minimal; + break; + case ProcedureOptimizationMode_Size: + pass_manager_kind = lbFunctionPassManager_size; + break; + case ProcedureOptimizationMode_Speed: + pass_manager_kind = lbFunctionPassManager_speed; + break; + } + } + } + + lb_llvm_function_pass_per_function_internal(m, p, pass_manager_kind); + } + } + + 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); + } + + return 0; +} + + +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, bool do_threading) { + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + 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(); +} + + +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 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 (do_threading) { + thread_pool_add_task(lb_llvm_module_verification_worker_proc, m); + } else { + if (lb_llvm_module_verification_worker_proc(m)) { + return false; + } + } + } + thread_pool_wait(); + + 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, 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)); + + 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); @@ -1190,7 +1664,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star Type *results = alloc_type_tuple(); Type *t_ptr_cstring = alloc_type_pointer(t_cstring); - + bool call_cleanup = true; bool has_args = false; @@ -1238,7 +1712,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star 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); @@ -1298,12 +1772,12 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star } } - + 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)); @@ -1312,13 +1786,13 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star } 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"); @@ -1331,210 +1805,6 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star 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); - } - - 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_is_module_empty(lbModule *m) { - if (LLVMGetFirstFunction(m->mod) == nullptr && - LLVMGetFirstGlobal(m->mod) == nullptr) { - return true; - } - for (auto fn = LLVMGetFirstFunction(m->mod); fn != nullptr; fn = LLVMGetNextFunction(fn)) { - if (LLVMGetFirstBasicBlock(fn) != nullptr) { - return false; - } - } - - for (auto g = LLVMGetFirstGlobal(m->mod); g != nullptr; g = LLVMGetNextGlobal(g)) { - if (LLVMGetLinkage(g) == LLVMExternalLinkage) { - continue; - } - if (!LLVMIsExternallyInitialized(g)) { - return false; - } - } - return true; -} - -struct lbLLVMEmitWorker { - LLVMTargetMachineRef target_machine; - LLVMCodeGenFileType code_gen_file_type; - String filepath_obj; - lbModule *m; -}; - -gb_internal WORKER_TASK_PROC(lb_llvm_emit_worker_proc) { - GB_ASSERT(MULTITHREAD_OBJECT_GENERATION); - - char *llvm_error = nullptr; - - auto wd = cast(lbLLVMEmitWorker *)data; - - if (LLVMTargetMachineEmitToFile(wd->target_machine, wd->m->mod, cast(char *)wd->filepath_obj.text, wd->code_gen_file_type, &llvm_error)) { - gb_printf_err("LLVM Error: %s\n", llvm_error); - gb_exit(1); - } - - return 0; -} - -gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_worker_proc) { - GB_ASSERT(MULTITHREAD_OBJECT_GENERATION); - - auto m = cast(lbModule *)data; - - 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); - - LLVMInitializeFunctionPassManager(default_function_pass_manager); - LLVMInitializeFunctionPassManager(function_pass_manager_minimal); - LLVMInitializeFunctionPassManager(function_pass_manager_size); - LLVMInitializeFunctionPassManager(function_pass_manager_speed); - - 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); - - LLVMFinalizeFunctionPassManager(default_function_pass_manager); - LLVMFinalizeFunctionPassManager(function_pass_manager_minimal); - LLVMFinalizeFunctionPassManager(function_pass_manager_size); - LLVMFinalizeFunctionPassManager(function_pass_manager_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); - - for (lbProcedure *p : m->procedures_to_generate) { - if (p->body != nullptr) { // Build Procedure - if (p->flags & lbProcedureFlag_WithoutMemcpyPass) { - lb_run_function_pass_manager(default_function_pass_manager_without_memcpy, p); - } 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); - break; - case ProcedureOptimizationMode_Size: - lb_run_function_pass_manager(function_pass_manager_size, p); - 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); - break; - } - } else { - lb_run_function_pass_manager(default_function_pass_manager, p); - } - } - } - } - - for (auto const &entry : m->equal_procs) { - lbProcedure *p = entry.value; - lb_run_function_pass_manager(default_function_pass_manager, p); - } - for (auto const &entry : m->hasher_procs) { - lbProcedure *p = entry.value; - lb_run_function_pass_manager(default_function_pass_manager, p); - } - for (auto const &entry : m->map_get_procs) { - lbProcedure *p = entry.value; - lb_run_function_pass_manager(default_function_pass_manager, p); - } - for (auto const &entry : m->map_set_procs) { - lbProcedure *p = entry.value; - lb_run_function_pass_manager(default_function_pass_manager, p); - } - - return 0; -} - - -struct lbLLVMModulePassWorkerData { - lbModule *m; - LLVMTargetMachineRef target_machine; -}; - -gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { - auto wd = cast(lbLLVMModulePassWorkerData *)data; - 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 void lb_generate_procedure(lbModule *m, lbProcedure *p) { if (p->is_done) { return; @@ -1575,13 +1845,13 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) { } -gb_internal void lb_generate_code(lbGenerator *gen) { +gb_internal bool lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Initializtion"); 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; @@ -1922,6 +2192,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; @@ -2041,13 +2312,11 @@ gb_internal void 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) { @@ -2056,156 +2325,65 @@ gb_internal void 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; - } + 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"); - 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); - } - } + lb_generate_procedures(gen, do_threading); 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); - } - } + TIME_SECTION("LLVM Procedure Generation (missing)"); + lb_generate_missing_procedures(gen, do_threading); - lb_finalize_objc_names(objc_names); + 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"); + 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; } } + 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); - } + lb_llvm_function_passes(gen, do_threading); TIME_SECTION("LLVM Module Pass"); + lb_llvm_module_passes(gen, do_threading); - 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; + TIME_SECTION("LLVM Module Verification"); - lb_llvm_module_pass_worker_proc(wd); - } + if (!lb_llvm_module_verification(gen, do_threading)) { + return false; + } 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; - } - - - 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; - } - } - gb_exit(1); - return; - } - } - llvm_error = nullptr; if (build_context.keep_temp_files || build_context.build_mode == BuildMode_LLVM_IR) { TIME_SECTION("LLVM Print Module to File"); @@ -2220,85 +2398,30 @@ 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; } } TIME_SECTION("LLVM Add Foreign Library Paths"); - - 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]; - 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"); - 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 object generation has been ignored!\n"); + return false; } - - if (do_threading && non_empty_module_count > 1) { - 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; - global_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; - } - } + if (!lb_llvm_object_generation(gen, do_threading)) { + return false; } gb_sort_array(gen->foreign_libraries.data, gen->foreign_libraries.count, foreign_library_cmp); + + return true; } |