diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -96,6 +96,9 @@ // For -z *stack enum class GnuStackKind { None, Exec, NoExec }; +// For --lto= +enum LtoKind : uint8_t {UnifiedThin, UnifiedRegular, Default}; + struct SymbolVersion { llvm::StringRef name; bool isExternCpp; @@ -415,6 +418,9 @@ // not supported on Android 11 & 12. bool androidMemtagStack; + // When using a unified pre-link LTO pipeline, specify the backend LTO mode. + LtoKind ltoKind = LtoKind::Default; + unsigned threadCount; // If an input file equals a key, remap it to the value. diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1489,6 +1489,19 @@ config->mllvmOpts.emplace_back(arg->getValue()); } + config->ltoKind = LtoKind::Default; + if (auto *arg = args.getLastArg(OPT_lto)) { + StringRef s = arg->getValue(); + if (s == "thin") + config->ltoKind = LtoKind::UnifiedThin; + else if (s == "full") + config->ltoKind = LtoKind::UnifiedRegular; + else if (s == "default") + config->ltoKind = LtoKind::Default; + else + error("unknown LTO mode: " + s); + } + // --threads= takes a positive integer and provides the default value for // --thinlto-jobs=. If unspecified, cap the number of threads since // overhead outweighs optimization for used parallel algorithms for the diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -206,8 +206,13 @@ config->thinLTOEmitImportsFiles); } - ltoObj = std::make_unique(createConfig(), backend, - config->ltoPartitions); + constexpr llvm::lto::LTO::LTOKind ltoModes[3] = + {llvm::lto::LTO::LTOKind::LTOK_UnifiedThin, + llvm::lto::LTO::LTOKind::LTOK_UnifiedRegular, + llvm::lto::LTO::LTOKind::LTOK_Default}; + ltoObj = std::make_unique( + createConfig(), backend, config->ltoPartitions, + ltoModes[config->ltoKind]); // Initialize usedStartStop. if (ctx.bitcodeFiles.empty()) diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -577,6 +577,9 @@ def: Flag<["-"], "V">, Alias, HelpText<"Alias for -v">; // LTO-related options. + +def lto: JJ<"lto=">, HelpText<"Set LTO backend">, + MetaVarName<"[full,thin]">; def lto_aa_pipeline: JJ<"lto-aa-pipeline=">, HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">; def lto_debug_pass_manager: FF<"lto-debug-pass-manager">, diff --git a/lld/test/ELF/lto/unified-lto.ll b/lld/test/ELF/lto/unified-lto.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/lto/unified-lto.ll @@ -0,0 +1,35 @@ +; REQUIRES: x86 +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -unified-lto %s -o %t0.o +; RUN: opt -thinlto-bc -thinlto-split-lto-unit %s -o %t1.o +; RUN: ld.lld --lto=full %t0.o -o %t0 +; RUN: llvm-readelf -s %t0 | FileCheck %s --check-prefix=FULL +; RUN: ld.lld --lto=thin %t0.o -o %t0 +; RUN: llvm-readelf -s %t0 | FileCheck %s --check-prefix=THIN +; RUN: ld.lld --lto=default %t0.o -o %t0 +; RUN: llvm-readelf -s %t0 | FileCheck %s --check-prefix=THIN +; RUN: ld.lld --lto=default %t1.o -o %t1 +; RUN: llvm-readelf -s %t1 | FileCheck %s --check-prefix=THIN +; RUN: ld.lld %t0.o -o %t0 2>&1 | count 0 +; RUN: llvm-readelf -s %t0 | FileCheck %s --check-prefix=THIN +; RUN: not ld.lld --lto=unknown %t1.o -o /dev/null 2>&1 | \ +; RUN: FileCheck --implicit-check-not=error: --check-prefix=ERR %s +; ERR: error: unknown LTO mode: unknown + +; FULL: Symbol table '.symtab' contains 3 entries: +; FULL-NEXT: Num: Value Size Type Bind Vis Ndx Name +; FULL-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +; FULL-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS ld-temp.o +; FULL-NEXT: 2: 0000000000201120 1 FUNC GLOBAL DEFAULT 1 _start + +; THIN: Symbol table '.symtab' contains 3 entries: +; THIN-NEXT: Num: Value Size Type Bind Vis Ndx Name +; THIN-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +; THIN-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS unified-lto.ll +; THIN-NEXT: 2: 0000000000201120 1 FUNC GLOBAL DEFAULT 1 _start + +target triple = "x86_64-unknown-linux-gnu" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + +define void @_start() { + ret void +}