[lld] ad5fad0 - [LTO] Suppress emission of empty combined module by default
Zakk Chen via llvm-commits
llvm-commits at lists.llvm.org
Mon May 4 18:33:52 PDT 2020
Author: Zakk Chen
Date: 2020-05-04T18:31:09-07:00
New Revision: ad5fad0ac56b78a692a052f2da397b4bc7fd6150
URL: https://github.com/llvm/llvm-project/commit/ad5fad0ac56b78a692a052f2da397b4bc7fd6150
DIFF: https://github.com/llvm/llvm-project/commit/ad5fad0ac56b78a692a052f2da397b4bc7fd6150.diff
LOG: [LTO] Suppress emission of empty combined module by default
Summary:
That unless the user requested an output object (--lto-obj-path), the an
unused empty combined module is not emitted.
This changed is helpful for some target (ex. RISCV-V) which encoded the
ABI info in IR module flags (target-abi). Empty unused module has no ABI
info so the linker would get the linking error during merging
incompatible ABIs.
Reviewers: tejohnson, espindola, MaskRay
Subscribers: emaste, inglorion, arichardson, hiraditya, simoncook, MaskRay, steven_wu, dexonsmith, PkmX, dang, lenary, s.egerton, luismarques, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78988
Added:
Modified:
lld/COFF/LTO.cpp
lld/ELF/LTO.cpp
lld/test/COFF/lto-obj-path.ll
lld/test/COFF/pdb-thinlto.ll
lld/test/ELF/lto/linker-script-symbols-assign.ll
lld/test/ELF/lto/thinlto-obj-path.ll
llvm/include/llvm/LTO/Config.h
llvm/include/llvm/LTO/LTO.h
llvm/lib/LTO/LTO.cpp
llvm/test/ThinLTO/X86/empty-module.ll
llvm/test/tools/gold/X86/thinlto.ll
llvm/tools/gold/gold-plugin.cpp
Removed:
################################################################################
diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp
index c88ce0ee95a9..bb44819e60f8 100644
--- a/lld/COFF/LTO.cpp
+++ b/lld/COFF/LTO.cpp
@@ -81,6 +81,7 @@ static lto::Config createConfig() {
c.CPU = getCPUStr();
c.MAttrs = getMAttrs();
c.CGOptLevel = args::getCGOptLevel(config->ltoo);
+ c.AlwaysEmitRegularLTOObj = !config->ltoObjPath.empty();
if (config->saveTemps)
checkError(c.addSaveTemps(std::string(config->outputFile) + ".",
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index 7f3aca5e90f0..503a9c4f20f8 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -138,6 +138,7 @@ static lto::Config createConfig() {
c.DwoDir = std::string(config->dwoDir);
c.HasWholeProgramVisibility = config->ltoWholeProgramVisibility;
+ c.AlwaysEmitRegularLTOObj = !config->ltoObjPath.empty();
c.TimeTraceEnabled = config->timeTraceEnabled;
c.TimeTraceGranularity = config->timeTraceGranularity;
@@ -327,7 +328,8 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
}
if (config->saveTemps) {
- saveBuffer(buf[0], config->outputFile + ".lto.o");
+ if (!buf[0].empty())
+ saveBuffer(buf[0], config->outputFile + ".lto.o");
for (unsigned i = 1; i != maxTasks; ++i)
saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o");
}
diff --git a/lld/test/COFF/lto-obj-path.ll b/lld/test/COFF/lto-obj-path.ll
index 987e2bd77896..ab0c82e9b170 100644
--- a/lld/test/COFF/lto-obj-path.ll
+++ b/lld/test/COFF/lto-obj-path.ll
@@ -11,6 +11,18 @@
; RUN: llvm-nm %t4.obj 2>&1 | FileCheck %s -check-prefix=SYMBOLS
; RUN: llvm-nm %t4.obj 2>&1 | count 1
+;; Ensure lld emits empty combined module if specific obj-path.
+; RUN: rm -fr %t.dir/objpath && mkdir -p %t.dir/objpath
+; RUN: lld-link /out:%t.dir/objpath/a.exe -lto-obj-path:%t4.obj \
+; RUN: -entry:main %t1.obj %t2.obj -lldsavetemps
+; RUN: ls %t.dir/objpath/a.exe.lto.* | count 3
+
+;; Ensure lld does not emit empty combined module in default.
+; RUN: rm -fr %t.dir/objpath && mkdir -p %t.dir/objpath
+; RUN: lld-link /out:%t.dir/objpath/a.exe \
+; RUN: -entry:main %t1.obj %t2.obj -lldsavetemps
+; RUN: ls %t.dir/objpath/a.exe.lto.* | count 2
+
; CHECK: Format: COFF-x86-64
; SYMBOLS: @feat.00
diff --git a/lld/test/COFF/pdb-thinlto.ll b/lld/test/COFF/pdb-thinlto.ll
index de0eef2b67da..4954f841e21d 100644
--- a/lld/test/COFF/pdb-thinlto.ll
+++ b/lld/test/COFF/pdb-thinlto.ll
@@ -29,10 +29,8 @@ declare void @foo()
; CHECK: Modules
; CHECK: ============================================================
-; CHECK: Mod 0000 | `{{.*}}main.exe.lto.obj`:
-; CHECK: Obj: `{{.*}}main.exe.lto.obj`:
-; CHECK: Mod 0001 | `{{.*}}main.exe.lto.1.obj`:
+; CHECK: Mod 0000 | `{{.*}}main.exe.lto.1.obj`:
; CHECK: Obj: `{{.*}}main.exe.lto.1.obj`:
-; CHECK: Mod 0002 | `{{.*}}main.exe.lto.2.obj`:
+; CHECK: Mod 0001 | `{{.*}}main.exe.lto.2.obj`:
; CHECK: Obj: `{{.*}}main.exe.lto.2.obj`:
-; CHECK: Mod 0003 | `* Linker *`:
+; CHECK: Mod 0002 | `* Linker *`:
diff --git a/lld/test/ELF/lto/linker-script-symbols-assign.ll b/lld/test/ELF/lto/linker-script-symbols-assign.ll
index 079113e1fcfd..c66bd1dda015 100644
--- a/lld/test/ELF/lto/linker-script-symbols-assign.ll
+++ b/lld/test/ELF/lto/linker-script-symbols-assign.ll
@@ -1,13 +1,13 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
+; RUN: rm -f %t2.*
; RUN: echo "foo = 1;" > %t.script
; RUN: ld.lld %t.o -o %t2 --script %t.script -save-temps
+;; Combined module is not empty, but it will be empty after optimization.
+;; Ensure lld still emits empty combined obj in this case.
; RUN: llvm-nm %t2.lto.o | count 0
-; CHECK-NOT: bar
-; CHECK-NOT: foo
-
; RUN: llvm-readobj --symbols %t2 | FileCheck %s --check-prefix=VAL
; VAL: Symbol {
; VAL: Name: foo
diff --git a/lld/test/ELF/lto/thinlto-obj-path.ll b/lld/test/ELF/lto/thinlto-obj-path.ll
index 787c1c03b665..5d22360fc282 100644
--- a/lld/test/ELF/lto/thinlto-obj-path.ll
+++ b/lld/test/ELF/lto/thinlto-obj-path.ll
@@ -14,6 +14,16 @@
; RUN: ld.lld -thinlto-index-only -lto-obj-path=%t4.o -shared %t1.o %t2.o -o /dev/null
; RUN: llvm-readobj -h %t4.o | FileCheck %s
+;; Ensure lld emits empty combined module if specific obj-path.
+; RUN: rm -fr %t.dir/objpath && mkdir -p %t.dir/objpath
+; RUN: ld.lld --plugin-opt=obj-path=%t4.o -shared %t1.o %t2.o -o %t.dir/objpath/a.out --save-temps
+; RUN: ls %t.dir/objpath/a.out*.lto.* | count 3
+
+;; Ensure lld does not emit empty combined module in default.
+; RUN: rm -fr %t.dir/objpath && mkdir -p %t.dir/objpath
+; RUN: ld.lld %t1.o %t2.o -o %t.dir/objpath/a.out --save-temps
+; RUN: ls %t.dir/objpath/a.out*.lto.* | count 2
+
; CHECK: Format: elf64-x86-64
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/llvm/include/llvm/LTO/Config.h b/llvm/include/llvm/LTO/Config.h
index a6b116f6bc86..20fed3488f29 100644
--- a/llvm/include/llvm/LTO/Config.h
+++ b/llvm/include/llvm/LTO/Config.h
@@ -66,6 +66,11 @@ struct Config {
/// link.
bool HasWholeProgramVisibility = false;
+ /// Always emit a Regular LTO object even when it is empty because no Regular
+ /// LTO modules were linked. This option is useful for some build system which
+ /// want to know a priori all possible output files.
+ bool AlwaysEmitRegularLTOObj = false;
+
/// If this field is set, the set of passes run in the middle-end optimizer
/// will be the one specified by the string. Only works with the new pass
/// manager as the old one doesn't have this ability.
diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h
index e93439819415..0a635b45e5a2 100644
--- a/llvm/include/llvm/LTO/LTO.h
+++ b/llvm/include/llvm/LTO/LTO.h
@@ -331,6 +331,7 @@ class LTO {
std::vector<GlobalValue *> Keep;
};
std::vector<AddedModule> ModsWithSummaries;
+ bool EmptyCombinedModule = true;
} RegularLTO;
struct ThinLTOState {
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index e9eb1d136e75..ab39a0819250 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -603,6 +603,7 @@ Error LTO::addModule(InputFile &Input, unsigned ModI,
if (LTOInfo->IsThinLTO)
return addThinLTO(BM, ModSyms, ResI, ResE);
+ RegularLTO.EmptyCombinedModule = false;
Expected<RegularLTOState::AddedModule> ModOrErr =
addRegularLTO(BM, ModSyms, ResI, ResE);
if (!ModOrErr)
@@ -1026,10 +1027,13 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
!Conf.PostInternalizeModuleHook(0, *RegularLTO.CombinedModule))
return Error::success();
}
- if (Error Err =
- backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
- std::move(RegularLTO.CombinedModule), ThinLTO.CombinedIndex))
- return Err;
+
+ if (!RegularLTO.EmptyCombinedModule || Conf.AlwaysEmitRegularLTOObj) {
+ if (Error Err = backend(
+ Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
+ std::move(RegularLTO.CombinedModule), ThinLTO.CombinedIndex))
+ return Err;
+ }
return finalizeOptimizationRemarks(std::move(*DiagFileOrErr));
}
diff --git a/llvm/test/ThinLTO/X86/empty-module.ll b/llvm/test/ThinLTO/X86/empty-module.ll
index 550be4df6657..3a63a65259da 100644
--- a/llvm/test/ThinLTO/X86/empty-module.ll
+++ b/llvm/test/ThinLTO/X86/empty-module.ll
@@ -1,11 +1,11 @@
; RUN: opt -module-summary -o %t.bc %s
-; RUN: rm -f %t2.0
-; RUN: llvm-lto2 run %t.bc -r %t.bc,foo,pl -o %t2 -thinlto-distributed-indexes
-; RUN: llvm-readobj -h %t2.0 | FileCheck %s
-; RUN: llvm-nm %t2.0 2>&1 | count 0
-
-; CHECK: Format: elf64-x86-64
+; RUN: rm -f %t2.*
+; RUN: llvm-lto2 run %t.bc -r %t.bc,foo,pl -o %t2 -thinlto-distributed-indexes -save-temps
+; Ensure lto does not emit empty combined module.
+; RUN: test ! -e %t2.0
+; Ensure empty combined module has only 2 temp files.
+; RUN: ls %t2.0.*.bc | count 2
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
diff --git a/llvm/test/tools/gold/X86/thinlto.ll b/llvm/test/tools/gold/X86/thinlto.ll
index ebe9b56a2f85..51609ebb7918 100644
--- a/llvm/test/tools/gold/X86/thinlto.ll
+++ b/llvm/test/tools/gold/X86/thinlto.ll
@@ -32,6 +32,7 @@
; Ensure gold generates an index as well as a binary with save-temps in ThinLTO mode.
; First force single-threaded mode
+; RUN: rm -f %t4*
; RUN: %gold -plugin %llvmshlibdir/LLVMgold%shlibext \
; RUN: -m elf_x86_64 \
; RUN: --plugin-opt=save-temps \
@@ -40,6 +41,8 @@
; RUN: -shared %t.o %t2.o -o %t4
; RUN: llvm-bcanalyzer -dump %t4.index.bc | FileCheck %s --check-prefix=COMBINED
; RUN: llvm-nm %t4 | FileCheck %s --check-prefix=NM
+; Ensure ld does not emit empty combined module in default.
+; RUN: ls %t4.o* | count 2
; Check with --no-map-whole-files
; RUN: %gold -plugin %llvmshlibdir/LLVMgold%shlibext \
@@ -72,6 +75,8 @@
; RUN: -shared %t.o %t2.o -o %t4
; RUN: llvm-nm %t5.o1 | FileCheck %s --check-prefix=NM2
; RUN: llvm-nm %t5.o2 | FileCheck %s --check-prefix=NM2
+; Ensure ld emits empty combined module if specific obj-path.
+; RUN: ls %t5.o* | count 3
; Test to ensure that thinlto-index-only with obj-path creates the file.
; RUN: rm -f %t5.o %t5.o1
diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp
index 0b249d222063..50b017345c0c 100644
--- a/llvm/tools/gold/gold-plugin.cpp
+++ b/llvm/tools/gold/gold-plugin.cpp
@@ -871,6 +871,7 @@ static std::unique_ptr<LTO> createLTO(IndexWriteCallback OnIndexWrite,
Conf.OptLevel = options::OptLevel;
Conf.PTO.LoopVectorization = options::OptLevel > 1;
Conf.PTO.SLPVectorization = options::OptLevel > 1;
+ Conf.AlwaysEmitRegularLTOObj = !options::obj_path.empty();
if (options::thinlto_index_only) {
std::string OldPrefix, NewPrefix;
More information about the llvm-commits
mailing list