From 45497e32ccade5671f564ea6df69db1423fe090c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 10 Aug 2018 12:23:48 +0200 Subject: [PATCH] bootstrap: Allow for building LLVM with ThinLTO. --- config.toml.example | 6 +++++ src/bootstrap/check.rs | 5 +++++ src/bootstrap/compile.rs | 47 +++++++++++++++++++++++++++++++++++++--- src/bootstrap/config.rs | 3 +++ src/bootstrap/native.rs | 5 +++++ src/bootstrap/tool.rs | 2 +- 6 files changed, 64 insertions(+), 4 deletions(-) diff --git a/config.toml.example b/config.toml.example index e7a530ba4c2af..35f69cd05b607 100644 --- a/config.toml.example +++ b/config.toml.example @@ -21,6 +21,12 @@ # Indicates whether the LLVM build is a Release or Debug build #optimize = true +# Indicates whether LLVM should be built with ThinLTO. Note that this will +# only succeed if you use clang, lld, llvm-ar, and llvm-ranlib in your C/C++ +# toolchain (see the `cc`, `cxx`, `linker`, `ar`, and `ranlib` options below). +# More info at: https://clang.llvm.org/docs/ThinLTO.html#clang-bootstrap +#thin-lto = false + # Indicates whether an LLVM Release build should include debug info #release-debuginfo = false diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 133e5aa37a7db..20cdfcb3d2981 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -50,6 +50,7 @@ impl Step for Std { println!("Checking std artifacts ({} -> {})", &compiler.host, target); run_cargo(builder, &mut cargo, + vec![], &libstd_stamp(builder, compiler, target), true); @@ -98,6 +99,7 @@ impl Step for Rustc { println!("Checking compiler artifacts ({} -> {})", &compiler.host, target); run_cargo(builder, &mut cargo, + vec![], &librustc_stamp(builder, compiler, target), true); @@ -149,6 +151,7 @@ impl Step for CodegenBackend { let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage)); run_cargo(builder, &mut cargo, + vec![], &codegen_backend_stamp(builder, compiler, target, backend), true); } @@ -187,6 +190,7 @@ impl Step for Test { println!("Checking test artifacts ({} -> {})", &compiler.host, target); run_cargo(builder, &mut cargo, + vec![], &libtest_stamp(builder, compiler, target), true); @@ -236,6 +240,7 @@ impl Step for Rustdoc { println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target); run_cargo(builder, &mut cargo, + vec![], &rustdoc_stamp(builder, compiler, target), true); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 2f8816d111a9d..da0ccf5e1773d 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -117,6 +117,7 @@ impl Step for Std { &compiler.host, target)); run_cargo(builder, &mut cargo, + vec![], &libstd_stamp(builder, compiler, target), false); @@ -396,6 +397,7 @@ impl Step for Test { &compiler.host, target)); run_cargo(builder, &mut cargo, + vec![], &libtest_stamp(builder, compiler, target), false); @@ -529,6 +531,7 @@ impl Step for Rustc { compiler.stage, &compiler.host, target)); run_cargo(builder, &mut cargo, + vec![], &librustc_stamp(builder, compiler, target), false); @@ -673,18 +676,47 @@ impl Step for CodegenBackend { let out_dir = builder.cargo_out(compiler, Mode::Codegen, target); builder.clear_if_dirty(&out_dir, &librustc_stamp(builder, compiler, target)); - let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "build"); + let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "rustc"); cargo.arg("--manifest-path") .arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml")); rustc_cargo_env(builder, &mut cargo); let features = build_codegen_backend(&builder, &mut cargo, &compiler, target, backend); + let mut cargo_tails_args = vec![]; + + if builder.config.llvm_thin_lto { + cargo_tails_args.push("--".to_string()); + + let num_jobs = builder.jobs(); + + if !target.contains("msvc") { + // Here we assume that the linker is clang. If it's not, there'll + // be linker errors. + cargo_tails_args.push("-Clink-arg=-fuse-ld=lld".to_string()); + cargo_tails_args.push("-Clink-arg=-flto=thin".to_string()); + + if builder.config.llvm_optimize { + cargo_tails_args.push("-Clink-arg=-O2".to_string()); + } + + // Let's make LLD respect the `-j` option. + let num_jobs_arg = format!("-Clink-arg=-Wl,--thinlto-jobs={}", num_jobs); + cargo_tails_args.push(num_jobs_arg); + } else { + // Here we assume that the linker is lld-link.exe. lld-link.exe + // does not need the extra arguments except for num_jobs + let num_jobs_arg = format!("-Clink-arg=/opt:lldltojobs={}", num_jobs); + cargo_tails_args.push(num_jobs_arg); + } + } + let tmp_stamp = out_dir.join(".tmp.stamp"); let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage)); let files = run_cargo(builder, cargo.arg("--features").arg(features), + cargo_tails_args, &tmp_stamp, false); if builder.config.dry_run { @@ -1045,7 +1077,11 @@ fn stderr_isatty() -> bool { } } -pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check: bool) +pub fn run_cargo(builder: &Builder, + cargo: &mut Command, + tail_args: Vec, + stamp: &Path, + is_check: bool) -> Vec { if builder.config.dry_run { @@ -1066,7 +1102,7 @@ pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check: // files we need to probe for later. let mut deps = Vec::new(); let mut toplevel = Vec::new(); - let ok = stream_cargo(builder, cargo, &mut |msg| { + let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| { let filenames = match msg { CargoMessage::CompilerArtifact { filenames, .. } => filenames, _ => return, @@ -1191,6 +1227,7 @@ pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check: pub fn stream_cargo( builder: &Builder, cargo: &mut Command, + tail_args: Vec, cb: &mut dyn FnMut(CargoMessage), ) -> bool { if builder.config.dry_run { @@ -1210,6 +1247,10 @@ pub fn stream_cargo( cargo.env("RUSTC_COLOR", "1"); } + for arg in tail_args { + cargo.arg(arg); + } + builder.verbose(&format!("running: {:?}", cargo)); let mut child = match cargo.spawn() { Ok(child) => child, diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index aef97204a4abc..bf4d39c4947e5 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -77,6 +77,7 @@ pub struct Config { pub llvm_enabled: bool, pub llvm_assertions: bool, pub llvm_optimize: bool, + pub llvm_thin_lto: bool, pub llvm_release_debuginfo: bool, pub llvm_version_check: bool, pub llvm_static_stdcpp: bool, @@ -247,6 +248,7 @@ struct Llvm { ninja: Option, assertions: Option, optimize: Option, + thin_lto: Option, release_debuginfo: Option, version_check: Option, static_libstdcpp: Option, @@ -505,6 +507,7 @@ impl Config { set(&mut config.llvm_enabled, llvm.enabled); llvm_assertions = llvm.assertions; set(&mut config.llvm_optimize, llvm.optimize); + set(&mut config.llvm_thin_lto, llvm.thin_lto); set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo); set(&mut config.llvm_version_check, llvm.version_check); set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp); diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 0e8605750dc64..966673d7d2c14 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -153,6 +153,11 @@ impl Step for Llvm { .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); + if builder.config.llvm_thin_lto { + cfg.define("LLVM_ENABLE_LTO", "Thin") + .define("LLVM_ENABLE_LLD", "ON"); + } + // By default, LLVM will automatically find OCaml and, if it finds it, // install the LLVM bindings in LLVM_OCAML_INSTALL_PATH, which defaults // to /usr/bin/ocaml. diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 23ef031dcb703..04aaa97065473 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -136,7 +136,7 @@ impl Step for ToolBuild { let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool)); builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target)); let mut duplicates = Vec::new(); - let is_expected = compile::stream_cargo(builder, &mut cargo, &mut |msg| { + let is_expected = compile::stream_cargo(builder, &mut cargo, vec![], &mut |msg| { // Only care about big things like the RLS/Cargo for now match tool { | "rls"