[lld] d4e9355 - [lld][MachO] Add --lto-emit-llvm command line option

via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 16 06:30:57 PST 2025


Author: Tarun Prabhu
Date: 2025-12-16T07:30:53-07:00
New Revision: d4e93550a0e6ae0278e93ebe235e7afd3db72c2d

URL: https://github.com/llvm/llvm-project/commit/d4e93550a0e6ae0278e93ebe235e7afd3db72c2d
DIFF: https://github.com/llvm/llvm-project/commit/d4e93550a0e6ae0278e93ebe235e7afd3db72c2d.diff

LOG: [lld][MachO] Add --lto-emit-llvm command line option

This option will cause the linker to emit LLVM bitcode instead of an
object file. The implementation is similar to that of the corresponding
option in the ELF backend. This only works with LLD and will not work
the gold plugin.

Added: 
    lld/test/MachO/lto-emit-llvm.ll

Modified: 
    lld/MachO/Config.h
    lld/MachO/Driver.cpp
    lld/MachO/LTO.cpp
    lld/MachO/Options.td

Removed: 
    


################################################################################
diff  --git a/lld/MachO/Config.h b/lld/MachO/Config.h
index 759a8cbe3d353..814ba1016849f 100644
--- a/lld/MachO/Config.h
+++ b/lld/MachO/Config.h
@@ -216,6 +216,7 @@ struct Configuration {
   std::vector<SectionAlign> sectionAlignments;
   std::vector<SegmentProtection> segmentProtections;
   bool ltoDebugPassManager = false;
+  bool emitLLVM = false;
   llvm::StringRef codegenDataGeneratePath;
   bool csProfileGenerate = false;
   llvm::StringRef csProfilePath;

diff  --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index f4f3aba55e643..973b3f5535cb4 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -1999,6 +1999,7 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
     config->ignoreAutoLinkOptions.insert(arg->getValue());
   config->strictAutoLink = args.hasArg(OPT_strict_auto_link);
   config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager);
+  config->emitLLVM = args.hasArg(OPT_lto_emit_llvm);
   config->codegenDataGeneratePath =
       args.getLastArgValue(OPT_codegen_data_generate_path);
   config->csProfileGenerate = args.hasArg(OPT_cs_profile_generate);
@@ -2352,10 +2353,10 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
 
     resolveLCLinkerOptions();
 
-    // If --thinlto-index-only is given, we should create only "index
-    // files" and not object files. Index file creation is already done
-    // in compileBitcodeFiles, so we are done if that's the case.
-    if (config->thinLTOIndexOnly)
+    // If either --thinlto-index-only or --lto-emit-llvm is given, we should
+    // not create object files. Index file creation is already done in
+    // compileBitcodeFiles, so we are done if that's the case.
+    if (config->thinLTOIndexOnly || config->emitLLVM)
       return errorCount() == 0;
 
     // LTO may emit a non-hidden (extern) object file symbol even if the

diff  --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp
index 4695b639dcc96..2c360374ef3cc 100644
--- a/lld/MachO/LTO.cpp
+++ b/lld/MachO/LTO.cpp
@@ -64,6 +64,16 @@ static lto::Config createConfig() {
   if (config->saveTemps)
     checkError(c.addSaveTemps(config->outputFile.str() + ".",
                               /*UseInputModulePath=*/true));
+
+  if (config->emitLLVM) {
+    llvm::StringRef outputFile = config->outputFile;
+    c.PreCodeGenModuleHook = [outputFile](size_t task, const Module &m) {
+      if (std::unique_ptr<raw_fd_ostream> os = openLTOOutputFile(outputFile))
+        WriteBitcodeToFile(m, *os, false);
+      return false;
+    };
+  }
+
   return c;
 }
 

diff  --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index f5f75490e5293..5bd220b3c196a 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -188,6 +188,8 @@ def lto_debug_pass_manager: Flag<["--"], "lto-debug-pass-manager">,
     HelpText<"Debug new pass manager">, Group<grp_lld>;
 def lto_newpm_passes: Joined<["--"], "lto-newpm-passes=">,
     HelpText<"Passes to run during LTO">, Group<grp_lld>;
+def lto_emit_llvm: Flag<["--"], "lto-emit-llvm">,
+    HelpText<"Emit LLVM-IR bitcode">, Group<grp_lld>;
 def load_pass_plugins : Separate<["--"], "load-pass-plugin">, Group<grp_lld>;
 def load_pass_plugins_eq : Joined<["--"], "load-pass-plugin=">,
     Alias<!cast<Separate>(load_pass_plugins)>,

diff  --git a/lld/test/MachO/lto-emit-llvm.ll b/lld/test/MachO/lto-emit-llvm.ll
new file mode 100644
index 0000000000000..77bf700837dfb
--- /dev/null
+++ b/lld/test/MachO/lto-emit-llvm.ll
@@ -0,0 +1,18 @@
+; REQUIRES: x86
+;
+; Check that the --lto-emit-llvm option is handled correctly.
+;
+; RUN: opt %s -o %t.o
+; RUN: ld.lld --lto-emit-llvm %t.o -o %t.out.o
+; RUN: llvm-dis < %t.out.o -o - | FileCheck %s
+;
+; CHECK: define hidden void @main()
+
+target triple = "x86_64-apple-darwin"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @main], section "llvm.metadata"
+
+define hidden void @main() {
+  ret void
+}


        


More information about the llvm-commits mailing list