about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJakub Beránek <berykubik@gmail.com>2022-09-29 16:31:03 +0200
committerJakub Beránek <berykubik@gmail.com>2022-10-23 13:48:03 +0200
commitc5c86806c859048f9bfdbb92b30401ef4f3a3346 (patch)
tree80bd0586eb361e26c5f7f826ecc4f39f3eec9ef7
parentcba16819a1aa2f99c861eba907847db39fea06c5 (diff)
downloadrust-c5c86806c859048f9bfdbb92b30401ef4f3a3346.tar.gz
rust-c5c86806c859048f9bfdbb92b30401ef4f3a3346.zip
Introduce dedicated `-Zdylib-lto` flag for enabling LTO on `dylib`s
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs3
-rw-r--r--compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl2
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--config.toml.example8
-rw-r--r--src/bootstrap/compile.rs22
-rw-r--r--src/bootstrap/config.rs7
-rw-r--r--src/doc/unstable-book/src/compiler-flags/dylib-lto.md4
-rw-r--r--src/test/rustdoc-ui/z-help.stdout1
11 files changed, 66 insertions, 13 deletions
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<u32> = (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