diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h index a2ca5770bf952..bacfaa241f69b 100644 --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -216,6 +216,7 @@ struct Configuration { std::vector sectionAlignments; std::vector 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 28c817c54c85d..94dbbf04a56f1 100644 --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1999,6 +1999,7 @@ bool link(ArrayRef 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); @@ -2344,10 +2345,10 @@ bool link(ArrayRef 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 os = openLTOOutputFile(outputFile)) + WriteBitcodeToFile(m, *os, false); + return false; + }; + } + return c; } diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td index be1a1cc2963d9..4954903e2548e 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; def lto_newpm_passes: Joined<["--"], "lto-newpm-passes=">, HelpText<"Passes to run during LTO">, Group; +def lto_emit_llvm: Flag<["--"], "lto-emit-llvm">, + HelpText<"Emit LLVM-IR bitcode">, Group; def load_pass_plugins : Separate<["--"], "load-pass-plugin">, Group; def load_pass_plugins_eq : Joined<["--"], "load-pass-plugin=">, Alias(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" + +@llvm.compiler.used = appending global [1 x ptr] [ptr @main], section "llvm.metadata" + +define hidden void @main() { + ret void +}