Skip to content

Commit

Permalink
[lld] A Unified LTO Bitcode Frontend
Browse files Browse the repository at this point in the history
The unified LTO pipeline creates a single LTO bitcode structure that can
be used by Thin or Full LTO. This means that the LTO mode can be chosen
at link time and that all LTO bitcode produced by the pipeline is
compatible, from an optimization perspective. This makes the behavior of
LTO a bit more predictable by normalizing the set of LTO features
supported by each LTO bitcode file.

Example usage:

clang -flto -funified-lto -fuse-ld=lld foo.c

clang -flto=thin -funified-lto -fuse-ld=lld foo.c

clang -c -flto -funified-lto foo.c  # -flto={full,thin} are identical in
terms of compilation actions
clang -flto=thin -fuse-ld=lld foo.o # pass --lto=thin to ld.lld

clang -c -flto -funified-lto foo.c clang -flto -fuse-ld=lld foo.o

The RFC discussing the details and rational for this change is here:
https://discourse.llvm.org/t/rfc-a-unified-lto-bitcode-frontend/61774

Differential Revision: https://reviews.llvm.org/D123805
  • Loading branch information
ormris committed Jul 18, 2023
1 parent 1e62587 commit ab9b3c8
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 2 deletions.
6 changes: 6 additions & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ enum class SeparateSegmentKind { None, Code, Loadable };
// 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;
Expand Down Expand Up @@ -415,6 +418,9 @@ struct Config {
// 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.
Expand Down
13 changes: 13 additions & 0 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,19 @@ static void readConfigs(opt::InputArgList &args) {
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
Expand Down
9 changes: 7 additions & 2 deletions lld/ELF/LTO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,13 @@ BitcodeCompiler::BitcodeCompiler() {
config->thinLTOEmitImportsFiles);
}

ltoObj = std::make_unique<lto::LTO>(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<lto::LTO>(
createConfig(), backend, config->ltoPartitions,
ltoModes[config->ltoKind]);

// Initialize usedStartStop.
if (ctx.bitcodeFiles.empty())
Expand Down
3 changes: 3 additions & 0 deletions lld/ELF/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,9 @@ def: JoinedOrSeparate<["-"], "u">, Alias<undefined>, HelpText<"Alias for --undef
def: Flag<["-"], "V">, Alias<v>, 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">,
Expand Down
35 changes: 35 additions & 0 deletions lld/test/ELF/lto/unified-lto.ll
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit ab9b3c8

Please sign in to comment.