diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -166,6 +166,7 @@ bool ignoreFunctionAddressEquality; bool ltoCSProfileGenerate; bool ltoDebugPassManager; + bool ltoEmitAsm; bool ltoNewPassManager; bool ltoUniqueBBSectionNames; bool ltoWholeProgramVisibility; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -917,6 +917,7 @@ config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate); config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file); config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager); + config->ltoEmitAsm = args.hasArg(OPT_lto_emit_asm); config->ltoNewPassManager = args.hasArg(OPT_lto_new_pass_manager); config->ltoNewPmPasses = args.getLastArgValue(OPT_lto_newpm_passes); config->ltoWholeProgramVisibility = @@ -1949,13 +1950,10 @@ // 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) - return; - - // Likewise, --plugin-opt=emit-llvm is an option to make LTO create - // an output file in bitcode and exit, so that you can just get a - // combined bitcode file. - if (config->emitLLVM) + // Likewise, --plugin-opt=emit-llvm and --plugin-opt=emit-asm are the + // options to create output files in bitcode or assembly code + // repsectively. No object files are generated. + if (config->thinLTOIndexOnly || config->emitLLVM || config->ltoEmitAsm) return; // Apply symbol renames for -wrap. diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -153,6 +153,9 @@ }; } + if (config->ltoEmitAsm) + c.CGFileType = CGFT_AssemblyFile; + if (config->saveTemps) checkError(c.addSaveTemps(config->outputFile.str() + ".", /*UseInputModulePath*/ true)); @@ -329,6 +332,13 @@ saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o"); } + if (config->ltoEmitAsm) { + saveBuffer(buf[0], config->outputFile); + for (unsigned i = 1; i != maxTasks; ++i) + saveBuffer(buf[i], config->outputFile + Twine(i)); + return {}; + } + std::vector ret; for (unsigned i = 0; i != maxTasks; ++i) if (!buf[i].empty()) diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -483,6 +483,8 @@ HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">; def lto_debug_pass_manager: F<"lto-debug-pass-manager">, HelpText<"Debug new pass manager">; +def lto_emit_asm: F<"lto-emit-asm">, + HelpText<"Emit assembly code">; def lto_new_pass_manager: F<"lto-new-pass-manager">, HelpText<"Use new pass manager">; def lto_newpm_passes: J<"lto-newpm-passes=">, @@ -535,6 +537,8 @@ def: F<"plugin-opt=disable-verify">, Alias, HelpText<"Alias for --disable-verify">; def plugin_opt_dwo_dir_eq: J<"plugin-opt=dwo_dir=">, HelpText<"Directory to store .dwo files when LTO and debug fission are used">; +def plugin_opt_emit_asm: F<"plugin-opt=emit-asm">, + Alias, HelpText<"Alias for --lto-emit-asm">; def plugin_opt_emit_llvm: F<"plugin-opt=emit-llvm">; def: J<"plugin-opt=jobs=">, Alias, HelpText<"Alias for --thinlto-jobs">; def: J<"plugin-opt=lto-partitions=">, Alias, HelpText<"Alias for --lto-partitions">; diff --git a/lld/test/ELF/lto/emit-asm.ll b/lld/test/ELF/lto/emit-asm.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/lto/emit-asm.ll @@ -0,0 +1,24 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: ld.lld --lto-emit-asm -shared %t.o -o - | FileCheck %s +; RUN: ld.lld --plugin-opt=emit-asm --plugin-opt=lto-partitions=2 -shared %t.o -o %t2.s +; RUN: cat %t2.s %t2.s1 | FileCheck %s + +; RUN: ld.lld --lto-emit-asm --save-temps -shared %t.o -o %t3.s +; RUN: FileCheck --input-file %t3.s %s +; RUN: llvm-dis %t3.s.0.4.opt.bc -o - | FileCheck --check-prefix=OPT %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; CHECK-DAG: f1: +; OPT-DAG: define void @f1() +define void @f1() { + ret void +} + +; CHECK-DAG: f2: +; OPT-DAG: define void @f2() +define void @f2() { + ret void +}