aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm_backend.cpp')
-rw-r--r--src/llvm_backend.cpp198
1 files changed, 170 insertions, 28 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index 304effb7f..cf7389ec1 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -29,29 +29,53 @@ void lb_add_foreign_library_path(lbModule *m, Entity *e) {
GB_ASSERT(e->kind == Entity_LibraryName);
GB_ASSERT(e->flags & EntityFlag_Used);
- for_array(i, e->LibraryName.paths) {
- String library_path = e->LibraryName.paths[i];
- if (library_path.len == 0) {
- continue;
- }
+ mutex_lock(&m->gen->foreign_mutex);
+ if (!ptr_set_update(&m->gen->foreign_libraries_set, e)) {
+ array_add(&m->gen->foreign_libraries, e);
+ }
+ mutex_unlock(&m->gen->foreign_mutex);
+}
- bool ok = true;
- for_array(path_index, m->foreign_library_paths) {
- String path = m->foreign_library_paths[path_index];
- #if defined(GB_SYSTEM_WINDOWS)
- if (str_eq_ignore_case(path, library_path)) {
- #else
- if (str_eq(path, library_path)) {
- #endif
- ok = false;
- break;
- }
+GB_COMPARE_PROC(foreign_library_cmp) {
+ int cmp = 0;
+ Entity *x = *(Entity **)a;
+ Entity *y = *(Entity **)b;
+ if (x == y) {
+ return 0;
+ }
+ GB_ASSERT(x->kind == Entity_LibraryName);
+ GB_ASSERT(y->kind == Entity_LibraryName);
+
+ cmp = i64_cmp(x->LibraryName.priority_index, y->LibraryName.priority_index);
+ if (cmp) {
+ return cmp;
+ }
+
+ if (x->pkg != y->pkg) {
+ isize order_x = x->pkg ? x->pkg->order : 0;
+ isize order_y = y->pkg ? y->pkg->order : 0;
+ cmp = isize_cmp(order_x, order_y);
+ if (cmp) {
+ return cmp;
}
+ }
+ if (x->file != y->file) {
+ String fullpath_x = x->file ? x->file->fullpath : (String{});
+ String fullpath_y = y->file ? y->file->fullpath : (String{});
+ String file_x = filename_from_path(fullpath_x);
+ String file_y = filename_from_path(fullpath_y);
- if (ok) {
- array_add(&m->foreign_library_paths, library_path);
+ cmp = string_compare(file_x, file_y);
+ if (cmp) {
+ return cmp;
}
}
+
+ cmp = u64_cmp(x->order_in_src, y->order_in_src);
+ if (cmp) {
+ return cmp;
+ }
+ return i32_cmp(x->token.pos.offset, y->token.pos.offset);
}
void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name) {
@@ -624,6 +648,9 @@ struct lbGlobalVariable {
};
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);
@@ -652,7 +679,54 @@ lbProcedure *lb_create_startup_type_info(lbModule *m) {
return p;
}
-lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *startup_type_info, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
+lbProcedure *lb_create_objc_names(lbModule *main_module) {
+ if (build_context.metrics.os != TargetOs_darwin) {
+ return nullptr;
+ }
+ Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl);
+ lbProcedure *p = lb_create_dummy_procedure(main_module, str_lit("__$init_objc_names"), proc_type);
+ p->is_startup = true;
+ return p;
+}
+
+void lb_finalize_objc_names(lbProcedure *p) {
+ if (p == nullptr) {
+ return;
+ }
+ 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);
+ lb_begin_procedure_body(p);
+ for_array(i, m->objc_classes.entries) {
+ auto const &entry = m->objc_classes.entries[i];
+ String name = entry.key.string;
+ args[0] = lb_const_value(m, t_cstring, exact_value_string(name));
+ lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args);
+ lb_addr_store(p, entry.value, ptr);
+ }
+
+ for_array(i, m->objc_selectors.entries) {
+ auto const &entry = m->objc_selectors.entries[i];
+ String name = entry.key.string;
+ args[0] = lb_const_value(m, t_cstring, exact_value_string(name));
+ lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args);
+ lb_addr_store(p, entry.value, ptr);
+ }
+
+ lb_end_procedure_body(p);
+
+ lb_run_function_pass_manager(default_function_pass_manager, p);
+
+}
+
+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);
@@ -664,7 +738,13 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
lb_begin_procedure_body(p);
- LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, "");
+ if (startup_type_info) {
+ LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, "");
+ }
+
+ if (objc_names) {
+ LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, "");
+ }
for_array(i, global_variables) {
auto *var = &global_variables[i];
@@ -911,7 +991,12 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime)
}
String lb_filepath_ll_for_module(lbModule *m) {
- String path = m->gen->output_base;
+ 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) {
@@ -922,7 +1007,12 @@ String lb_filepath_ll_for_module(lbModule *m) {
return path;
}
String lb_filepath_obj_for_module(lbModule *m) {
- String path = m->gen->output_base;
+ 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);
}
@@ -945,6 +1035,19 @@ String lb_filepath_obj_for_module(lbModule *m) {
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;
}
}
}
@@ -1197,6 +1300,8 @@ void lb_generate_code(lbGenerator *gen) {
LLVMCodeModel code_mode = LLVMCodeModelDefault;
if (is_arch_wasm()) {
code_mode = LLVMCodeModelJITDefault;
+ } else if (build_context.metrics.os == TargetOs_freestanding) {
+ code_mode = LLVMCodeModelKernel;
}
char const *host_cpu_name = LLVMGetHostCPUName();
@@ -1219,10 +1324,18 @@ void lb_generate_code(lbGenerator *gen) {
// x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE
// x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
if (ODIN_LLVM_MINIMUM_VERSION_12) {
- llvm_cpu = "x86-64-v2";
+ if (build_context.metrics.os == TargetOs_freestanding) {
+ llvm_cpu = "x86-64";
+ } else {
+ llvm_cpu = "x86-64-v2";
+ }
}
}
+ if (build_context.target_features_set.entries.count != 0) {
+ llvm_features = target_features_set_to_cstring(permanent_allocator(), false);
+ }
+
// GB_ASSERT_MSG(LLVMTargetHasAsmBackend(target));
LLVMCodeGenOptLevel code_gen_level = LLVMCodeGenLevelNone;
@@ -1244,6 +1357,24 @@ void lb_generate_code(lbGenerator *gen) {
reloc_mode = LLVMRelocPIC;
}
+ switch (build_context.reloc_mode) {
+ case RelocMode_Default:
+ if (build_context.metrics.os == TargetOs_openbsd) {
+ // Always use PIC for OpenBSD: it defaults to PIE
+ reloc_mode = LLVMRelocPIC;
+ }
+ break;
+ case RelocMode_Static:
+ reloc_mode = LLVMRelocStatic;
+ break;
+ case RelocMode_PIC:
+ reloc_mode = LLVMRelocPIC;
+ break;
+ case RelocMode_DynamicNoPIC:
+ reloc_mode = LLVMRelocDynamicNoPic;
+ break;
+ }
+
for_array(i, gen->modules.entries) {
target_machines[i] = LLVMCreateTargetMachine(
target, target_triple, llvm_cpu,
@@ -1310,7 +1441,7 @@ void lb_generate_code(lbGenerator *gen) {
TIME_SECTION("LLVM Global Variables");
- {
+ if (!build_context.disallow_rtti) {
lbModule *m = default_module;
{ // Add type info data
@@ -1417,9 +1548,8 @@ void lb_generate_code(lbGenerator *gen) {
if ((e->scope->flags&ScopeFlag_Init) && name == "main") {
GB_ASSERT(e == info->entry_point);
}
- if (e->Procedure.is_export ||
- (e->Procedure.link_name.len > 0) ||
- ((e->scope->flags&ScopeFlag_File) && e->Procedure.link_name.len > 0)) {
+ if (build_context.command_kind == Command_test &&
+ (e->Procedure.is_export || e->Procedure.link_name.len > 0)) {
String link_name = e->Procedure.link_name;
if (e->pkg->kind == Package_Runtime) {
if (link_name == "main" ||
@@ -1570,8 +1700,10 @@ 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);
+
TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)");
- lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, global_variables);
+ lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, objc_names, global_variables);
gb_unused(startup_runtime);
TIME_SECTION("LLVM Global Procedures and Types");
@@ -1641,6 +1773,11 @@ void 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);
+ }
+
for_array(j, gen->modules.entries) {
lbModule *m = gen->modules.entries[j].value;
for_array(i, m->missing_procedures_to_check) {
@@ -1650,6 +1787,8 @@ void lb_generate_code(lbGenerator *gen) {
}
}
+ lb_finalize_objc_names(objc_names);
+
if (build_context.ODIN_DEBUG) {
TIME_SECTION("LLVM Debug Info Complete Types and Finalize");
for_array(j, gen->modules.entries) {
@@ -1662,6 +1801,7 @@ void lb_generate_code(lbGenerator *gen) {
}
+
TIME_SECTION("LLVM Function Pass");
for_array(i, gen->modules.entries) {
lbModule *m = gen->modules.entries[i].value;
@@ -1806,4 +1946,6 @@ void lb_generate_code(lbGenerator *gen) {
}
}
}
+
+ gb_sort_array(gen->foreign_libraries.data, gen->foreign_libraries.count, foreign_library_cmp);
}