aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend.cpp
diff options
context:
space:
mode:
authorJesse Meyer <jesse.r.meyer@me.com>2026-02-01 09:04:53 -0500
committerJesse Meyer <jesse.r.meyer@me.com>2026-02-03 20:16:20 -0500
commit43ad4a1d9f18a89822e1b9f554adef1a228136db (patch)
treeca7a569d1e5adc6fa3f1d7eb6c1a5fe36b175715 /src/llvm_backend.cpp
parentf7901cffc9f4983259586241d5b336cdb6377b9c (diff)
Add ThinLTO support via -lto:thin and -lto:thin-files flags
- Add -lto:thin and -lto:thin-files CLI flags with validation - Emit LLVM bitcode (.bc) instead of object files when LTO is enabled - Pass -flto=thin and -flto-jobs to clang/lld linkers - Guard linkage corrections to skip declarations without definitions (required for LTO where declarations appear across modules) - Allow module-per-file with LTO even at higher optimization levels Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/llvm_backend.cpp')
-rw-r--r--src/llvm_backend.cpp23
1 files changed, 18 insertions, 5 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index c15f326f8..43f6f8f03 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -171,7 +171,7 @@ gb_internal void lb_correct_entity_linkage(lbGenerator *gen) {
LLVMValueRef other_global = nullptr;
if (ec.e->kind == Entity_Variable) {
other_global = LLVMGetNamedGlobal(ec.other_module->mod, ec.cname);
- if (other_global) {
+ if (other_global && (LLVMGetInitializer(other_global) != nullptr || LLVMIsExternallyInitialized(other_global))) {
LLVM_SET_INTERNAL_WEAK_LINKAGE(other_global);
if (!ec.e->Variable.is_export && !ec.e->Variable.is_foreign) {
LLVMSetVisibility(other_global, LLVMHiddenVisibility);
@@ -179,7 +179,7 @@ gb_internal void lb_correct_entity_linkage(lbGenerator *gen) {
}
} else if (ec.e->kind == Entity_Procedure) {
other_global = LLVMGetNamedFunction(ec.other_module->mod, ec.cname);
- if (other_global) {
+ if (other_global && LLVMCountBasicBlocks(other_global) != 0) {
LLVM_SET_INTERNAL_WEAK_LINKAGE(other_global);
if (!ec.e->Procedure.is_export && !ec.e->Procedure.is_foreign) {
LLVMSetVisibility(other_global, LLVMHiddenVisibility);
@@ -2332,7 +2332,12 @@ gb_internal WORKER_TASK_PROC(lb_llvm_emit_worker_proc) {
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)) {
+ if (build_context.lto_kind != LTO_None) {
+ if (LLVMWriteBitcodeToFile(wd->m->mod, cast(char *)wd->filepath_obj.text)) {
+ gb_printf_err("Failed to write bitcode file: %.*s\n", LIT(wd->filepath_obj));
+ exit_with_errors();
+ }
+ } else 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);
exit_with_errors();
}
@@ -2701,7 +2706,9 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
String ext = {};
- if (build_context.build_mode == BuildMode_Assembly) {
+ if (build_context.lto_kind != LTO_None) {
+ ext = STR_LIT("bc");
+ } else if (build_context.build_mode == BuildMode_Assembly) {
ext = STR_LIT("S");
} else if (build_context.build_mode == BuildMode_Object) {
// Allow a user override for the object extension.
@@ -2776,7 +2783,13 @@ gb_internal bool lb_llvm_object_generation(lbGenerator *gen, bool do_threading)
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)) {
+ if (build_context.lto_kind != LTO_None) {
+ if (LLVMWriteBitcodeToFile(m->mod, cast(char *)filepath_obj.text)) {
+ gb_printf_err("Failed to write bitcode file: %.*s\n", LIT(filepath_obj));
+ exit_with_errors();
+ return false;
+ }
+ } else 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);
exit_with_errors();
return false;