mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Refactor llvm backend code into separate procedures to make it simpler to profile
This commit is contained in:
+473
-420
@@ -1159,6 +1159,457 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, CheckerInfo *info) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 void lb_llvm_function_pass_per_module(lbModule *m) {
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) {
|
||||||
LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod);
|
LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod);
|
||||||
@@ -1310,220 +1761,6 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
|
|||||||
return 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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 void lb_llvm_function_pass_per_module(lbModule *m) {
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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 void lb_generate_procedure(lbModule *m, lbProcedure *p) {
|
gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) {
|
||||||
if (p->is_done) {
|
if (p->is_done) {
|
||||||
return;
|
return;
|
||||||
@@ -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) {
|
gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||||
TIME_SECTION("LLVM Initializtion");
|
TIME_SECTION("LLVM Initializtion");
|
||||||
|
|
||||||
@@ -2064,82 +2282,14 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TIME_SECTION("LLVM Global Procedures and Types");
|
TIME_SECTION("LLVM Global Procedures and Types");
|
||||||
for (Entity *e : info->entities) {
|
lb_create_global_procedures_and_types(gen, info);
|
||||||
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) {
|
if (gen->modules.entries.count <= 1) {
|
||||||
do_threading = false;
|
do_threading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TIME_SECTION("LLVM Procedure Generation");
|
TIME_SECTION("LLVM Procedure Generation");
|
||||||
for (auto const &entry : gen->modules) {
|
lb_generate_procedures(gen, do_threading);
|
||||||
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();
|
|
||||||
|
|
||||||
if (build_context.command_kind == Command_test && !already_has_entry_point) {
|
if (build_context.command_kind == Command_test && !already_has_entry_point) {
|
||||||
TIME_SECTION("LLVM main");
|
TIME_SECTION("LLVM main");
|
||||||
@@ -2147,17 +2297,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TIME_SECTION("LLVM Procedure Generation (missing)");
|
TIME_SECTION("LLVM Procedure Generation (missing)");
|
||||||
for (auto const &entry : gen->modules) {
|
lb_generate_missing_procedures(gen, do_threading);
|
||||||
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();
|
|
||||||
|
|
||||||
if (gen->objc_names) {
|
if (gen->objc_names) {
|
||||||
TIME_SECTION("Finalize objc names");
|
TIME_SECTION("Finalize objc names");
|
||||||
@@ -2166,48 +2306,28 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
|||||||
|
|
||||||
if (build_context.ODIN_DEBUG) {
|
if (build_context.ODIN_DEBUG) {
|
||||||
TIME_SECTION("LLVM Debug Info Complete Types and Finalize");
|
TIME_SECTION("LLVM Debug Info Complete Types and Finalize");
|
||||||
for (auto const &entry : gen->modules) {
|
lb_debug_info_complete_types_and_finalize(gen);
|
||||||
lbModule *m = entry.value;
|
|
||||||
if (m->debug_builder != nullptr) {
|
|
||||||
lb_debug_complete_types(m);
|
|
||||||
LLVMDIBuilderFinalize(m->debug_builder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isize non_empty_module_count = 0;
|
if (do_threading) {
|
||||||
for (auto const &entry : gen->modules) {
|
isize non_empty_module_count = 0;
|
||||||
lbModule *m = entry.value;
|
for (auto const &entry : gen->modules) {
|
||||||
if (!lb_is_module_empty(m)) {
|
lbModule *m = entry.value;
|
||||||
non_empty_module_count += 1;
|
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");
|
TIME_SECTION("LLVM Function Pass");
|
||||||
for (auto const &entry : gen->modules) {
|
lb_llvm_function_passes(gen);
|
||||||
lbModule *m = entry.value;
|
|
||||||
lb_llvm_function_pass_per_module(m);
|
|
||||||
}
|
|
||||||
thread_pool_wait();
|
|
||||||
|
|
||||||
TIME_SECTION("LLVM Module Pass");
|
TIME_SECTION("LLVM Module Pass");
|
||||||
for (auto const &entry : gen->modules) {
|
lb_llvm_module_passes(gen, do_threading);
|
||||||
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();
|
|
||||||
|
|
||||||
|
|
||||||
TIME_SECTION("LLVM Module Verification");
|
TIME_SECTION("LLVM Module Verification");
|
||||||
@@ -2220,25 +2340,10 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
|||||||
code_gen_file_type = LLVMAssemblyFile;
|
code_gen_file_type = LLVMAssemblyFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!lb_llvm_module_verification(gen, &llvm_error)) {
|
||||||
for (auto const &entry : gen->modules) {
|
return false;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
llvm_error = nullptr;
|
|
||||||
if (build_context.keep_temp_files ||
|
if (build_context.keep_temp_files ||
|
||||||
build_context.build_mode == BuildMode_LLVM_IR) {
|
build_context.build_mode == BuildMode_LLVM_IR) {
|
||||||
TIME_SECTION("LLVM Print Module to File");
|
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");
|
TIME_SECTION("LLVM Add Foreign Library Paths");
|
||||||
|
lb_add_foreign_library_paths(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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TIME_SECTION("LLVM Object Generation");
|
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");
|
gb_printf_err("LLVM object generation has been ignored!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!lb_llvm_object_generation(gen, code_gen_file_type, do_threading)) {
|
||||||
if (do_threading) {
|
return false;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_sort_array(gen->foreign_libraries.data, gen->foreign_libraries.count, foreign_library_cmp);
|
gb_sort_array(gen->foreign_libraries.data, gen->foreign_libraries.count, foreign_library_cmp);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LLVM_VERSION_MAJOR > 12 || (LLVM_VERSION_MAJOR == 12 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0)
|
#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
|
#else
|
||||||
#define ODIN_LLVM_MINIMUM_VERSION_12 0
|
#define ODIN_LLVM_MINIMUM_VERSION_12 0
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user