diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 4ade2c953c73e..e66ab3a32c567 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -48,6 +48,8 @@ enum class ExportSource { ModuleDefinition, }; +enum class EmitKind { Obj, LLVM }; + // Represents an /export option. struct Export { StringRef name; // N in /export:N or /export:E=N @@ -311,6 +313,7 @@ struct Configuration { bool pseudoRelocs = false; bool stdcallFixup = false; bool writeCheckSum = false; + EmitKind emit = EmitKind::Obj; }; } // namespace lld::coff diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index e2f414f78ecb7..75ac6d965eba6 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1852,6 +1852,17 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { if (args.hasArg(OPT_lldsavetemps)) config->saveTemps = true; + // Handle /lldemit + if (auto *arg = args.getLastArg(OPT_lldemit)) { + StringRef s = arg->getValue(); + if (s == "obj") + config->emit = EmitKind::Obj; + else if (s == "llvm") + config->emit = EmitKind::LLVM; + else + error("/lldemit: unknown option: " + s); + } + // Handle /kill-at if (args.hasArg(OPT_kill_at)) config->killAt = true; @@ -2395,7 +2406,8 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { // If -thinlto-index-only is given, we should create only "index // files" and not object files. Index file creation is already done // in addCombinedLTOObject, so we are done if that's the case. - if (config->thinLTOIndexOnly) + // Likewise, don't emit object files for other /lldemit options. + if (config->emit != EmitKind::Obj || config->thinLTOIndexOnly) return; // If we generated native object files from bitcode files, this resolves diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp index 6ca000b466a12..6e835d055479c 100644 --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -87,6 +87,15 @@ lto::Config BitcodeCompiler::createConfig() { c.RunCSIRInstr = ctx.config.ltoCSProfileGenerate; c.PGOWarnMismatch = ctx.config.ltoPGOWarnMismatch; + if (ctx.config.emit == EmitKind::LLVM) { + c.PostInternalizeModuleHook = [this](size_t task, const Module &m) { + if (std::unique_ptr os = + openLTOOutputFile(ctx.config.outputFile)) + WriteBitcodeToFile(m, *os, false); + return false; + }; + } + if (ctx.config.saveTemps) checkError(c.addSaveTemps(std::string(ctx.config.outputFile) + ".", /*UseInputModulePath*/ true)); diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td index ea4ddb2d84953..22add8ff72b95 100644 --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -232,6 +232,7 @@ defm demangle : B<"demangle", def include_optional : Joined<["/", "-", "/?", "-?"], "includeoptional:">, HelpText<"Add symbol as undefined, but allow it to remain undefined">; def kill_at : F<"kill-at">; +def lldemit : P<"lldemit", "Specify output type">; def lldmingw : F<"lldmingw">; def noseh : F<"noseh">; def osversion : P_priv<"osversion">; diff --git a/lld/test/COFF/lto-emit-llvm.ll b/lld/test/COFF/lto-emit-llvm.ll new file mode 100644 index 0000000000000..985058de10a48 --- /dev/null +++ b/lld/test/COFF/lto-emit-llvm.ll @@ -0,0 +1,14 @@ +; REQUIRES: x86 +; RUN: llvm-as -o %T/lto.obj %s + +; RUN: lld-link /lldemit:llvm /out:%T/lto.bc /entry:main /subsystem:console %T/lto.obj +; RUN: llvm-dis %T/lto.bc -o - | FileCheck %s + +; CHECK: define void @main() + +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +define void @main() { + ret void +}