[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