From c5c86806c859048f9bfdbb92b30401ef4f3a3346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 29 Sep 2022 16:31:03 +0200 Subject: [PATCH] Introduce dedicated `-Zdylib-lto` flag for enabling LTO on `dylib`s --- compiler/rustc_codegen_llvm/src/back/lto.rs | 16 +++++++++++++- compiler/rustc_codegen_ssa/src/back/link.rs | 13 +++++++---- compiler/rustc_codegen_ssa/src/errors.rs | 3 +++ .../locales/en-US/codegen_ssa.ftl | 2 ++ compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 2 ++ config.toml.example | 8 +++---- src/bootstrap/compile.rs | 22 +++++++++++++++++++ src/bootstrap/config.rs | 7 +++--- .../src/compiler-flags/dylib-lto.md | 4 ++++ src/test/rustdoc-ui/z-help.stdout | 1 + 11 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/dylib-lto.md diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index fb58d5f7df2..a49cc7f8d66 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -82,10 +82,24 @@ fn prepare_lto( ); return Err(e); } else if *crate_type == CrateType::Dylib { - diag_handler.warn("LTO with dylibs may not be as effective"); + if !cgcx.opts.unstable_opts.dylib_lto { + return Err(diag_handler + .fatal("lto cannot be used for `dylib` crate type without `-Zdylib-lto`")); + } } } + if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto { + diag_handler + .struct_err("cannot prefer dynamic linking when performing LTO") + .note( + "only 'staticlib', 'bin', and 'cdylib' outputs are \ + supported with LTO", + ) + .emit(); + return Err(FatalError); + } + for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { let exported_symbols = cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO"); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 1adaf9bd6cf..a0b5e3b6daf 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -39,6 +39,7 @@ use cc::windows_registry; use regex::Regex; use tempfile::Builder as TempFileBuilder; +use itertools::Itertools; use std::borrow::Borrow; use std::cell::OnceCell; use std::collections::BTreeSet; @@ -49,7 +50,6 @@ use std::ops::Deref; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; use std::{env, fmt, fs, io, mem, str}; -use itertools::Itertools; pub fn ensure_removed(diag_handler: &Handler, path: &Path) { if let Err(e) = fs::remove_file(path) { @@ -219,10 +219,15 @@ pub fn each_linked_rlib( let lto_active = matches!(sess.lto(), Lto::Fat | Lto::Thin); if lto_active { for combination in info.dependency_formats.iter().combinations(2) { - let (ty1, list1) = combination[0]; - let (ty2, list2) = combination[1]; + let (ty1, list1) = &combination[0]; + let (ty2, list2) = &combination[1]; if list1 != list2 { - return Err(format!("{ty1:?} and {ty2:?} do not have equivalent dependency formats (`{list1:?}` vs `{list2:?}`)")); + return Err(errors::LinkRlibError::IncompatibleDependencyFormats { + ty1: format!("{ty1:?}"), + ty2: format!("{ty2:?}"), + list1: format!("{list1:?}"), + list2: format!("{list2:?}"), + }); } } } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 6059e9f24ba..ebb531f1c43 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -127,6 +127,9 @@ pub enum LinkRlibError { #[diag(codegen_ssa_rlib_not_found)] NotFound { crate_name: Symbol }, + + #[diag(codegen_ssa_rlib_incompatible_dependency_formats)] + IncompatibleDependencyFormats { ty1: String, ty2: String, list1: String, list2: String }, } pub struct ThorinErrorWrapper(pub thorin::Error); diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl index 0d0388a039e..966a421bcf0 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl @@ -34,6 +34,8 @@ codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, fo codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}` +codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`) + codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status} codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index da3102ba7b0..eb8e65a6d59 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -648,6 +648,7 @@ fn test_unstable_options_tracking_hash() { untracked!(dump_mir_dir, String::from("abc")); untracked!(dump_mir_exclude_pass_number, true); untracked!(dump_mir_graphviz, true); + untracked!(dylib_lto, true); untracked!(emit_stack_sizes, true); untracked!(future_incompat_test, true); untracked!(hir_stats, true); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a8be318dea8..3f234a47a3d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1295,6 +1295,8 @@ options! { an additional `.html` file showing the computed coverage spans."), dwarf_version: Option = (None, parse_opt_number, [TRACKED], "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), + dylib_lto: bool = (false, parse_bool, [UNTRACKED], + "enables LTO for dylib crate type"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), emit_thin_lto: bool = (true, parse_bool, [TRACKED], diff --git a/config.toml.example b/config.toml.example index 35b07924b8e..a46813e4d7a 100644 --- a/config.toml.example +++ b/config.toml.example @@ -638,10 +638,10 @@ changelog-seen = 2 # If an explicit setting is given, it will be used for all parts of the codebase. #new-symbol-mangling = true|false (see comment) -# Select LTO mode that will be used for compiling rustc. By default, thin local LTO (LTO within a -# single crate) is used. You can also select "thin" or "fat" to apply Thin/Fat LTO on the -# `rustc_driver` dylib. -#lto = thin-local +# Select LTO mode that will be used for compiling rustc. By default, thin local LTO +# (LTO within a single crate) is used (like for any Rust crate). You can also select +# "thin" or "fat" to apply Thin/Fat LTO to the `rustc_driver` dylib. +#lto = "thin-local" # ============================================================================= # Options for specific targets diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index f59f2021484..9cc119d3301 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -701,6 +701,28 @@ impl Step for Rustc { )); } + // cfg(bootstrap): remove if condition once the bootstrap compiler supports dylib LTO + if compiler.stage != 0 { + match builder.config.rust_lto { + RustcLto::Thin | RustcLto::Fat => { + // Since using LTO for optimizing dylibs is currently experimental, + // we need to pass -Zdylib-lto. + cargo.rustflag("-Zdylib-lto"); + // Cargo by default passes `-Cembed-bitcode=no` and doesn't pass `-Clto` when + // compiling dylibs (and their dependencies), even when LTO is enabled for the + // crate. Therefore, we need to override `-Clto` and `-Cembed-bitcode` here. + let lto_type = match builder.config.rust_lto { + RustcLto::Thin => "thin", + RustcLto::Fat => "fat", + _ => unreachable!(), + }; + cargo.rustflag(&format!("-Clto={}", lto_type)); + cargo.rustflag("-Cembed-bitcode=yes"); + } + RustcLto::ThinLocal => { /* Do nothing, this is the default */ } + } + } + builder.info(&format!( "Building stage{} compiler artifacts ({} -> {})", compiler.stage, &compiler.host, target diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 4025697dabe..a8c403675d8 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -321,12 +321,12 @@ impl SplitDebuginfo { } /// LTO mode used for compiling rustc itself. -#[derive(Default)] +#[derive(Default, Clone)] pub enum RustcLto { #[default] ThinLocal, Thin, - Fat + Fat, } impl std::str::FromStr for RustcLto { @@ -1201,8 +1201,7 @@ impl Config { config.rust_lto = rust .lto .as_deref() - .map(RustcLto::from_str) - .map(|v| v.expect("invalid value for rust.lto")) + .map(|value| RustcLto::from_str(value).unwrap()) .unwrap_or_default(); } else { config.rust_profile_use = flags.rust_profile_use; diff --git a/src/doc/unstable-book/src/compiler-flags/dylib-lto.md b/src/doc/unstable-book/src/compiler-flags/dylib-lto.md new file mode 100644 index 00000000000..f69ea334f5a --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/dylib-lto.md @@ -0,0 +1,4 @@ +## `dylib-lto` + +This option enables using LTO for the `dylib` crate type. This is currently only used for compiling +`rustc` itself (more specifically, the `librustc_driver` dylib). diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout index dbf3a8f00ee..46f11d2e5d1 100644 --- a/src/test/rustdoc-ui/z-help.stdout +++ b/src/test/rustdoc-ui/z-help.stdout @@ -36,6 +36,7 @@ -Z dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no) -Z dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans. -Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform) + -Z dylib-lto=val -- enables LTO for dylib crate type -Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no) -Z emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes) -Z export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries