Skip to content

Commit

Permalink
[lld] Support --lto-emit-asm and --plugin-opt=emit-asm
Browse files Browse the repository at this point in the history
Summary: The switch --plugin-opt=emit-asm can be used with the gold linker to dump the final assembly code generated by LTO in a user-friendly way. Unfortunately it doesn't work with lld. I'm hooking it up with lld. With that switch, lld emits assembly code into the output file (specified by -o) and if there are multiple input files, each of their assembly code will be emitted into a separate file named by suffixing the output file name with a unique number, respectively. The linking then stops after generating those assembly files.

Reviewers: espindola, wenlei, tejohnson, MaskRay, grimar

Reviewed By: tejohnson, MaskRay, grimar

Subscribers: pcc, emaste, inglorion, arichardson, hiraditya, MaskRay, steven_wu, dexonsmith, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D77231
  • Loading branch information
htyu committed Apr 27, 2020
1 parent 5cfdd82 commit 964ef8e
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 7 deletions.
1 change: 1 addition & 0 deletions lld/ELF/Config.h
Expand Up @@ -166,6 +166,7 @@ struct Configuration {
bool ignoreFunctionAddressEquality;
bool ltoCSProfileGenerate;
bool ltoDebugPassManager;
bool ltoEmitAsm;
bool ltoNewPassManager;
bool ltoUniqueBBSectionNames;
bool ltoWholeProgramVisibility;
Expand Down
12 changes: 5 additions & 7 deletions lld/ELF/Driver.cpp
Expand Up @@ -917,6 +917,7 @@ static void readConfigs(opt::InputArgList &args) {
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 =
Expand Down Expand Up @@ -1949,13 +1950,10 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// 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.
Expand Down
10 changes: 10 additions & 0 deletions lld/ELF/LTO.cpp
Expand Up @@ -153,6 +153,9 @@ static lto::Config createConfig() {
};
}

if (config->ltoEmitAsm)
c.CGFileType = CGFT_AssemblyFile;

if (config->saveTemps)
checkError(c.addSaveTemps(config->outputFile.str() + ".",
/*UseInputModulePath*/ true));
Expand Down Expand Up @@ -329,6 +332,13 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
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<InputFile *> ret;
for (unsigned i = 0; i != maxTasks; ++i)
if (!buf[i].empty())
Expand Down
4 changes: 4 additions & 0 deletions lld/ELF/Options.td
Expand Up @@ -483,6 +483,8 @@ def lto_aa_pipeline: J<"lto-aa-pipeline=">,
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=">,
Expand Down Expand Up @@ -535,6 +537,8 @@ def: F<"plugin-opt=debug-pass-manager">,
def: F<"plugin-opt=disable-verify">, Alias<disable_verify>, 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<lto_emit_asm>, HelpText<"Alias for --lto-emit-asm">;
def plugin_opt_emit_llvm: F<"plugin-opt=emit-llvm">;
def: J<"plugin-opt=jobs=">, Alias<thinlto_jobs>, HelpText<"Alias for --thinlto-jobs">;
def: J<"plugin-opt=lto-partitions=">, Alias<lto_partitions>, HelpText<"Alias for --lto-partitions">;
Expand Down
24 changes: 24 additions & 0 deletions 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
}

0 comments on commit 964ef8e

Please sign in to comment.