about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUrgau <3616612+Urgau@users.noreply.github.com>2025-06-18 19:40:30 +0200
committerGitHub <noreply@github.com>2025-06-18 19:40:30 +0200
commit33185d3fd9a60a9c285e021c97537d9f8808cbcf (patch)
treec691873fc0eb4d2bc3ae76292c4fde25a3f77d3a
parent6f935a044d1ddeb6160494a6320d008d7c311aef (diff)
parent1b23b64be4bf9e827cbc9d7c4012da77e8f05a85 (diff)
downloadrust-33185d3fd9a60a9c285e021c97537d9f8808cbcf.tar.gz
rust-33185d3fd9a60a9c285e021c97537d9f8808cbcf.zip
Rollup merge of #135656 - joshtriplett:hint-mostly-unused, r=saethlin
Add `-Z hint-mostly-unused` to tell rustc that most of a crate will go unused

This hint allows the compiler to optimize its operation based on this assumption, in order to compile faster. This is a hint, and does not guarantee any particular behavior.

This option can substantially speed up compilation if applied to a large dependency where the majority of the dependency does not get used. This flag may slow down compilation in other cases.

Currently, this option makes the compiler defer as much code generation as possible from functions in the crate, until later crates invoke those functions. Functions that never get invoked will never have code generated for them. For instance, if a crate provides thousands of functions, but only a few of them will get called, this flag will result in the compiler only doing code generation for the called functions. (This uses the same mechanisms as cross-crate inlining of functions.) This does not affect `extern` functions, or functions marked as `#[inline(never)]`.

This option has already existed in nightly as `-Zcross-crate-inline-threshold=always` for some time, and has gotten testing in that form. However, this option is still unstable, to give an opportunity for wider testing in this form.

Some performance numbers, based on a crate with many dependencies having just *one* large dependency set to `-Z hint-mostly-unused` (using Cargo's `profile-rustflags` option):

A release build went from 4m07s to 2m04s.

A non-release build went from 2m26s to 1m28s.
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_mir_transform/src/cross_crate_inline.rs7
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--src/doc/unstable-book/src/compiler-flags/hint-mostly-unused.md33
4 files changed, 43 insertions, 0 deletions
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 82823581c12..a0012b04c4f 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -802,6 +802,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(force_unstable_if_unmarked, true);
     tracked!(function_return, FunctionReturn::ThunkExtern);
     tracked!(function_sections, Some(false));
+    tracked!(hint_mostly_unused, true);
     tracked!(human_readable_cgu_names, true);
     tracked!(incremental_ignore_spans, true);
     tracked!(inline_mir, Some(true));
diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
index 727d4a126d2..6d7b7e10ef6 100644
--- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs
+++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
@@ -50,6 +50,13 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
         _ => {}
     }
 
+    // If the crate is likely to be mostly unused, use cross-crate inlining to defer codegen until
+    // the function is referenced, in order to skip codegen for unused functions. This is
+    // intentionally after the check for `inline(never)`, so that `inline(never)` wins.
+    if tcx.sess.opts.unstable_opts.hint_mostly_unused {
+        return true;
+    }
+
     let sig = tcx.fn_sig(def_id).instantiate_identity();
     for ty in sig.inputs().skip_binder().iter().chain(std::iter::once(&sig.output().skip_binder()))
     {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 9ca405333f4..0ac2702cac5 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -2235,6 +2235,8 @@ options! {
         environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"),
     has_thread_local: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "explicitly enable the `cfg(target_thread_local)` directive"),
+    hint_mostly_unused: bool = (false, parse_bool, [TRACKED],
+        "hint that most of this crate will go unused, to minimize work for uncalled functions"),
     human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
         "generate human-readable, predictable names for codegen units (default: no)"),
     identify_regions: bool = (false, parse_bool, [UNTRACKED],
diff --git a/src/doc/unstable-book/src/compiler-flags/hint-mostly-unused.md b/src/doc/unstable-book/src/compiler-flags/hint-mostly-unused.md
new file mode 100644
index 00000000000..80f5b1c4450
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/hint-mostly-unused.md
@@ -0,0 +1,33 @@
+# `hint-mostly-unused`
+
+This flag hints to the compiler that most of the crate will probably go unused.
+The compiler can optimize its operation based on this assumption, in order to
+compile faster. This is a hint, and does not guarantee any particular behavior.
+
+This option can substantially speed up compilation if applied to a large
+dependency where the majority of the dependency does not get used. This flag
+may slow down compilation in other cases.
+
+Currently, this option makes the compiler defer as much code generation as
+possible from functions in the crate, until later crates invoke those
+functions. Functions that never get invoked will never have code generated for
+them. For instance, if a crate provides thousands of functions, but only a few
+of them will get called, this flag will result in the compiler only doing code
+generation for the called functions. (This uses the same mechanisms as
+cross-crate inlining of functions.) This does not affect `extern` functions, or
+functions marked as `#[inline(never)]`.
+
+To try applying this flag to one dependency out of a dependency tree, use the
+[`profile-rustflags`](https://doc.rust-lang.org/cargo/reference/unstable.html#profile-rustflags-option)
+feature of nightly cargo:
+
+```toml
+cargo-features = ["profile-rustflags"]
+
+# ...
+[dependencies]
+mostly-unused-dependency = "1.2.3"
+
+[profile.release.package.mostly-unused-dependency]
+rustflags = ["-Zhint-mostly-unused"]
+```