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) + ".",
c.DwoDir = std::string(config->dwoDir);
c.HasWholeProgramVisibility = config->ltoWholeProgramVisibility;
+ c.AlwaysEmitRegularLTOObj = !config->ltoObjPath.empty();
c.TimeTraceEnabled = config->timeTraceEnabled;
c.TimeTraceGranularity = config->timeTraceGranularity;
}
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");
}
; 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
; 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 *`:
; 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
; 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"
/// 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.
std::vector<GlobalValue *> Keep;
};
std::vector<AddedModule> ModsWithSummaries;
+ bool EmptyCombinedModule = true;
} RegularLTO;
struct ThinLTOState {
if (LTOInfo->IsThinLTO)
return addThinLTO(BM, ModSyms, ResI, ResE);
+ RegularLTO.EmptyCombinedModule = false;
Expected<RegularLTOState::AddedModule> ModOrErr =
addRegularLTO(BM, ModSyms, ResI, ResE);
if (!ModOrErr)
!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));
}
; 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"
; 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 \
; 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 \
; 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
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;