Skip to content

Commit 59e76cb

Browse files
committed
Auto merge of #53245 - michaelwoerister:thinlto-rust-llvm, r=<try>
[experimental]: Build LLVM with ThinLTO enabled (2nd attempt) This is #51207 revived. This time, I'd like to run actual performance tests to see if it improves compile times.
2 parents 147ca2d + 5807cc4 commit 59e76cb

File tree

10 files changed

+99
-9
lines changed

10 files changed

+99
-9
lines changed

config.toml.example

+10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121
# Indicates whether the LLVM build is a Release or Debug build
2222
#optimize = true
2323

24+
# Indicates whether LLVM should be built with ThinLTO. Note that this will
25+
# only succeed if you use clang, lld, llvm-ar, and llvm-ranlib in your C/C++
26+
# toolchain (see the `cc`, `cxx`, `linker`, `ar`, and `ranlib` options below).
27+
# More info at: https://clang.llvm.org/docs/ThinLTO.html#clang-bootstrap
28+
#thin-lto = false
29+
2430
# Indicates whether an LLVM Release build should include debug info
2531
#release-debuginfo = false
2632

@@ -384,6 +390,10 @@
384390
# Note: an absolute path should be used, otherwise LLVM build will break.
385391
#ar = "ar"
386392

393+
# Ranlib to be used to assemble static libraries compiled from C/C++ code.
394+
# Note: an absolute path should be used, otherwise LLVM build will break.
395+
#ranlib = "ranlib"
396+
387397
# Linker to be used to link Rust code. Note that the
388398
# default value is platform specific, and if not specified it may also depend on
389399
# what platform is crossing to what platform.

src/bootstrap/builder.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ impl<'a> Builder<'a> {
826826
if let Some(ref error_format) = self.config.rustc_error_format {
827827
cargo.env("RUSTC_ERROR_FORMAT", error_format);
828828
}
829-
if cmd != "build" && cmd != "check" && want_rustdoc {
829+
if cmd != "build" && cmd != "check" && cmd != "rustc" && want_rustdoc {
830830
cargo.env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.config.build));
831831
}
832832

@@ -987,7 +987,7 @@ impl<'a> Builder<'a> {
987987
}
988988
}
989989

990-
if cmd == "build"
990+
if (cmd == "build" || cmd == "rustc")
991991
&& mode == Mode::Std
992992
&& self.config.extended
993993
&& compiler.is_final_stage(self)

src/bootstrap/check.rs

+5
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ impl Step for Std {
5050
println!("Checking std artifacts ({} -> {})", &compiler.host, target);
5151
run_cargo(builder,
5252
&mut cargo,
53+
vec![],
5354
&libstd_stamp(builder, compiler, target),
5455
true);
5556

@@ -98,6 +99,7 @@ impl Step for Rustc {
9899
println!("Checking compiler artifacts ({} -> {})", &compiler.host, target);
99100
run_cargo(builder,
100101
&mut cargo,
102+
vec![],
101103
&librustc_stamp(builder, compiler, target),
102104
true);
103105

@@ -149,6 +151,7 @@ impl Step for CodegenBackend {
149151
let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage));
150152
run_cargo(builder,
151153
&mut cargo,
154+
vec![],
152155
&codegen_backend_stamp(builder, compiler, target, backend),
153156
true);
154157
}
@@ -187,6 +190,7 @@ impl Step for Test {
187190
println!("Checking test artifacts ({} -> {})", &compiler.host, target);
188191
run_cargo(builder,
189192
&mut cargo,
193+
vec![],
190194
&libtest_stamp(builder, compiler, target),
191195
true);
192196

@@ -236,6 +240,7 @@ impl Step for Rustdoc {
236240
println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target);
237241
run_cargo(builder,
238242
&mut cargo,
243+
vec![],
239244
&rustdoc_stamp(builder, compiler, target),
240245
true);
241246

src/bootstrap/compile.rs

+44-3
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ impl Step for Std {
117117
&compiler.host, target));
118118
run_cargo(builder,
119119
&mut cargo,
120+
vec![],
120121
&libstd_stamp(builder, compiler, target),
121122
false);
122123

@@ -396,6 +397,7 @@ impl Step for Test {
396397
&compiler.host, target));
397398
run_cargo(builder,
398399
&mut cargo,
400+
vec![],
399401
&libtest_stamp(builder, compiler, target),
400402
false);
401403

@@ -529,6 +531,7 @@ impl Step for Rustc {
529531
compiler.stage, &compiler.host, target));
530532
run_cargo(builder,
531533
&mut cargo,
534+
vec![],
532535
&librustc_stamp(builder, compiler, target),
533536
false);
534537

@@ -673,18 +676,47 @@ impl Step for CodegenBackend {
673676
let out_dir = builder.cargo_out(compiler, Mode::Codegen, target);
674677
builder.clear_if_dirty(&out_dir, &librustc_stamp(builder, compiler, target));
675678

676-
let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "build");
679+
let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "rustc");
677680
cargo.arg("--manifest-path")
678681
.arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
679682
rustc_cargo_env(builder, &mut cargo);
680683

681684
let features = build_codegen_backend(&builder, &mut cargo, &compiler, target, backend);
682685

686+
let mut cargo_tails_args = vec![];
687+
688+
if builder.config.llvm_thin_lto {
689+
cargo_tails_args.push("--".to_string());
690+
691+
let num_jobs = builder.jobs();
692+
693+
if !target.contains("msvc") {
694+
// Here we assume that the linker is clang. If it's not, there'll
695+
// be linker errors.
696+
cargo_tails_args.push("-Clink-arg=-fuse-ld=lld".to_string());
697+
cargo_tails_args.push("-Clink-arg=-flto=thin".to_string());
698+
699+
if builder.config.llvm_optimize {
700+
cargo_tails_args.push("-Clink-arg=-O2".to_string());
701+
}
702+
703+
// Let's make LLD respect the `-j` option.
704+
let num_jobs_arg = format!("-Clink-arg=-Wl,--thinlto-jobs={}", num_jobs);
705+
cargo_tails_args.push(num_jobs_arg);
706+
} else {
707+
// Here we assume that the linker is lld-link.exe. lld-link.exe
708+
// does not need the extra arguments except for num_jobs
709+
let num_jobs_arg = format!("-Clink-arg=/opt:lldltojobs={}", num_jobs);
710+
cargo_tails_args.push(num_jobs_arg);
711+
}
712+
}
713+
683714
let tmp_stamp = out_dir.join(".tmp.stamp");
684715

685716
let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage));
686717
let files = run_cargo(builder,
687718
cargo.arg("--features").arg(features),
719+
cargo_tails_args,
688720
&tmp_stamp,
689721
false);
690722
if builder.config.dry_run {
@@ -1045,7 +1077,11 @@ fn stderr_isatty() -> bool {
10451077
}
10461078
}
10471079

1048-
pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check: bool)
1080+
pub fn run_cargo(builder: &Builder,
1081+
cargo: &mut Command,
1082+
tail_args: Vec<String>,
1083+
stamp: &Path,
1084+
is_check: bool)
10491085
-> Vec<PathBuf>
10501086
{
10511087
if builder.config.dry_run {
@@ -1066,7 +1102,7 @@ pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check:
10661102
// files we need to probe for later.
10671103
let mut deps = Vec::new();
10681104
let mut toplevel = Vec::new();
1069-
let ok = stream_cargo(builder, cargo, &mut |msg| {
1105+
let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| {
10701106
let filenames = match msg {
10711107
CargoMessage::CompilerArtifact { filenames, .. } => filenames,
10721108
_ => return,
@@ -1191,6 +1227,7 @@ pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check:
11911227
pub fn stream_cargo(
11921228
builder: &Builder,
11931229
cargo: &mut Command,
1230+
tail_args: Vec<String>,
11941231
cb: &mut dyn FnMut(CargoMessage),
11951232
) -> bool {
11961233
if builder.config.dry_run {
@@ -1210,6 +1247,10 @@ pub fn stream_cargo(
12101247
cargo.env("RUSTC_COLOR", "1");
12111248
}
12121249

1250+
for arg in tail_args {
1251+
cargo.arg(arg);
1252+
}
1253+
12131254
builder.verbose(&format!("running: {:?}", cargo));
12141255
let mut child = match cargo.spawn() {
12151256
Ok(child) => child,

src/bootstrap/config.rs

+6
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ pub struct Config {
7777
pub llvm_enabled: bool,
7878
pub llvm_assertions: bool,
7979
pub llvm_optimize: bool,
80+
pub llvm_thin_lto: bool,
8081
pub llvm_release_debuginfo: bool,
8182
pub llvm_version_check: bool,
8283
pub llvm_static_stdcpp: bool,
@@ -162,6 +163,7 @@ pub struct Target {
162163
pub cc: Option<PathBuf>,
163164
pub cxx: Option<PathBuf>,
164165
pub ar: Option<PathBuf>,
166+
pub ranlib: Option<PathBuf>,
165167
pub linker: Option<PathBuf>,
166168
pub ndk: Option<PathBuf>,
167169
pub crt_static: Option<bool>,
@@ -245,6 +247,7 @@ struct Llvm {
245247
ninja: Option<bool>,
246248
assertions: Option<bool>,
247249
optimize: Option<bool>,
250+
thin_lto: Option<bool>,
248251
release_debuginfo: Option<bool>,
249252
version_check: Option<bool>,
250253
static_libstdcpp: Option<bool>,
@@ -325,6 +328,7 @@ struct TomlTarget {
325328
cc: Option<String>,
326329
cxx: Option<String>,
327330
ar: Option<String>,
331+
ranlib: Option<String>,
328332
linker: Option<String>,
329333
android_ndk: Option<String>,
330334
crt_static: Option<bool>,
@@ -501,6 +505,7 @@ impl Config {
501505
set(&mut config.llvm_enabled, llvm.enabled);
502506
llvm_assertions = llvm.assertions;
503507
set(&mut config.llvm_optimize, llvm.optimize);
508+
set(&mut config.llvm_thin_lto, llvm.thin_lto);
504509
set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
505510
set(&mut config.llvm_version_check, llvm.version_check);
506511
set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
@@ -578,6 +583,7 @@ impl Config {
578583
target.cc = cfg.cc.clone().map(PathBuf::from);
579584
target.cxx = cfg.cxx.clone().map(PathBuf::from);
580585
target.ar = cfg.ar.clone().map(PathBuf::from);
586+
target.ranlib = cfg.ranlib.clone().map(PathBuf::from);
581587
target.linker = cfg.linker.clone().map(PathBuf::from);
582588
target.crt_static = cfg.crt_static.clone();
583589
target.musl_root = cfg.musl_root.clone().map(PathBuf::from);

src/bootstrap/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ pub struct Build {
276276
cc: HashMap<Interned<String>, cc::Tool>,
277277
cxx: HashMap<Interned<String>, cc::Tool>,
278278
ar: HashMap<Interned<String>, PathBuf>,
279+
ranlib: HashMap<Interned<String>, PathBuf>,
279280
// Misc
280281
crates: HashMap<Interned<String>, Crate>,
281282
is_sudo: bool,
@@ -401,6 +402,7 @@ impl Build {
401402
cc: HashMap::new(),
402403
cxx: HashMap::new(),
403404
ar: HashMap::new(),
405+
ranlib: HashMap::new(),
404406
crates: HashMap::new(),
405407
lldb_version: None,
406408
lldb_python_dir: None,
@@ -767,6 +769,11 @@ impl Build {
767769
self.ar.get(&target).map(|p| &**p)
768770
}
769771

772+
/// Returns the path to the `ranlib` utility for the target specified.
773+
fn ranlib(&self, target: Interned<String>) -> Option<&Path> {
774+
self.ranlib.get(&target).map(|p| &**p)
775+
}
776+
770777
/// Returns the path to the C++ compiler for the target specified.
771778
fn cxx(&self, target: Interned<String>) -> Result<&Path, String> {
772779
match self.cxx.get(&target) {

src/bootstrap/native.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,11 @@ impl Step for Llvm {
154154
.define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
155155
.define("LLVM_DEFAULT_TARGET_TRIPLE", target);
156156

157+
if builder.config.llvm_thin_lto {
158+
cfg.define("LLVM_ENABLE_LTO", "Thin")
159+
.define("LLVM_ENABLE_LLD", "ON");
160+
}
161+
157162
// By default, LLVM will automatically find OCaml and, if it finds it,
158163
// install the LLVM bindings in LLVM_OCAML_INSTALL_PATH, which defaults
159164
// to /usr/bin/ocaml.
@@ -169,8 +174,7 @@ impl Step for Llvm {
169174
// just a local concern. However, it doesn't work well everywhere.
170175
//
171176
// If we are shipping llvm tools then we statically link them LLVM
172-
if (target.contains("linux-gnu") || target.contains("apple-darwin")) &&
173-
!builder.config.llvm_tools_enabled {
177+
if target.contains("linux-gnu") || target.contains("apple-darwin") {
174178
cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
175179
}
176180

@@ -366,6 +370,14 @@ fn configure_cmake(builder: &Builder,
366370
}
367371
}
368372

373+
if let Some(ranlib) = builder.ranlib(target) {
374+
if ranlib.is_absolute() {
375+
// LLVM build breaks if `CMAKE_RANLIB` is a relative path, for some reason it
376+
// tries to resolve this path in the LLVM build directory.
377+
cfg.define("CMAKE_RANLIB", sanitize_cc(ranlib));
378+
}
379+
}
380+
369381
if env::var_os("SCCACHE_ERROR_LOG").is_some() {
370382
cfg.env("RUST_LOG", "sccache=warn");
371383
}

src/bootstrap/tool.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ impl Step for ToolBuild {
136136
let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
137137
builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
138138
let mut duplicates = Vec::new();
139-
let is_expected = compile::stream_cargo(builder, &mut cargo, &mut |msg| {
139+
let is_expected = compile::stream_cargo(builder, &mut cargo, vec![], &mut |msg| {
140140
// Only care about big things like the RLS/Cargo for now
141141
match tool {
142142
| "rls"

src/ci/docker/dist-x86_64-linux/Dockerfile

+4-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ ENV RUST_CONFIGURE_ARGS \
9393
--enable-sanitizers \
9494
--enable-profiler \
9595
--enable-compiler-docs \
96-
--set target.x86_64-unknown-linux-gnu.linker=clang
96+
--set target.x86_64-unknown-linux-gnu.linker=clang \
97+
--set target.x86_64-unknown-linux-gnu.ar=/rustroot/bin/llvm-ar \
98+
--set target.x86_64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \
99+
--set llvm.thin-lto=true
97100
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
98101
ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
99102

src/ci/docker/dist-x86_64-linux/build-clang.sh

+6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ curl https://releases.llvm.org/$LLVM/cfe-$LLVM.src.tar.xz | \
3030
xz -d | \
3131
tar xf - -C tools/clang --strip-components=1
3232

33+
mkdir -p tools/lld
34+
35+
curl https://releases.llvm.org/$LLVM/lld-$LLVM.src.tar.xz | \
36+
xz -d | \
37+
tar xf - -C tools/lld --strip-components=1
38+
3339
mkdir ../clang-build
3440
cd ../clang-build
3541

0 commit comments

Comments
 (0)