Skip to content

Commit d53f0b1

Browse files
committed
Auto merge of rust-lang#123244 - Mark-Simulacrum:share-inline-never-generics, r=saethlin
Enable -Zshare-generics for inline(never) functions This avoids inlining cross-crate generic items when possible that are already marked inline(never), implying that the author is not intending for the function to be inlined by callers. As such, having a local copy may make it easier for LLVM to optimize but mostly just adds to binary bloat and codegen time. In practice our benchmarks indicate this is indeed a win for larger compilations, where the extra cost in dynamic linking to these symbols is diminished compared to the advantages in fewer copies that need optimizing in each binary. It might also make sense it expand this with other heuristics (e.g., `#[cold]`) in the future, but this seems like a good starting point. FWIW, I expect that doing cleanup in where we make the decision what should/shouldn't be shared is also a good idea. Way too much code needed to be tweaked to check this. But I'm hoping to leave that for a follow-up PR rather than blocking this on it.
2 parents a2545fd + 4a216a2 commit d53f0b1

26 files changed

+127
-52
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4137,6 +4137,7 @@ name = "rustc_monomorphize"
41374137
version = "0.0.0"
41384138
dependencies = [
41394139
"rustc_abi",
4140+
"rustc_attr",
41404141
"rustc_data_structures",
41414142
"rustc_errors",
41424143
"rustc_fluent_macro",

compiler/rustc_codegen_llvm/src/callee.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
104104

105105
let is_hidden = if is_generic {
106106
// This is a monomorphization of a generic function.
107-
if !cx.tcx.sess.opts.share_generics() {
107+
if !(cx.tcx.sess.opts.share_generics()
108+
|| tcx.codegen_fn_attrs(instance_def_id).inline
109+
== rustc_attr::InlineAttr::Never)
110+
{
108111
// When not sharing generics, all instances are in the same
109112
// crate and have hidden visibility.
110113
true

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ fn exported_symbols_provider_local(
282282
}));
283283
}
284284

285-
if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() {
285+
if tcx.local_crate_exports_generics() {
286286
use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility};
287287
use rustc_middle::ty::InstanceKind;
288288

@@ -310,6 +310,16 @@ fn exported_symbols_provider_local(
310310
continue;
311311
}
312312

313+
if !tcx.sess.opts.share_generics() {
314+
if tcx.codegen_fn_attrs(mono_item.def_id()).inline == rustc_attr::InlineAttr::Never
315+
{
316+
// this is OK, we explicitly allow sharing inline(never) across crates even
317+
// without share-generics.
318+
} else {
319+
continue;
320+
}
321+
}
322+
313323
match *mono_item {
314324
MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => {
315325
if args.non_erasable_generics().next().is_some() {

compiler/rustc_middle/src/mir/mono.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ impl<'tcx> MonoItem<'tcx> {
111111
return InstantiationMode::GloballyShared { may_conflict: false };
112112
}
113113

114+
if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline
115+
&& self.is_generic_fn()
116+
{
117+
// Upgrade inline(never) to a globally shared instance.
118+
return InstantiationMode::GloballyShared { may_conflict: true };
119+
}
120+
114121
// At this point we don't have explicit linkage and we're an
115122
// inlined function. If we're inlining into all CGUs then we'll
116123
// be creating a local copy per CGU.

compiler/rustc_middle/src/ty/context.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,8 +1955,6 @@ impl<'tcx> TyCtxt<'tcx> {
19551955

19561956
#[inline]
19571957
pub fn local_crate_exports_generics(self) -> bool {
1958-
debug_assert!(self.sess.opts.share_generics());
1959-
19601958
self.crate_types().iter().any(|crate_type| {
19611959
match crate_type {
19621960
CrateType::Executable

compiler/rustc_middle/src/ty/instance.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -190,19 +190,23 @@ impl<'tcx> Instance<'tcx> {
190190
/// This method already takes into account the global `-Zshare-generics`
191191
/// setting, always returning `None` if `share-generics` is off.
192192
pub fn upstream_monomorphization(&self, tcx: TyCtxt<'tcx>) -> Option<CrateNum> {
193-
// If we are not in share generics mode, we don't link to upstream
194-
// monomorphizations but always instantiate our own internal versions
195-
// instead.
196-
if !tcx.sess.opts.share_generics() {
197-
return None;
198-
}
199-
200193
// If this is an item that is defined in the local crate, no upstream
201194
// crate can know about it/provide a monomorphization.
202195
if self.def_id().is_local() {
203196
return None;
204197
}
205198

199+
// If we are not in share generics mode, we don't link to upstream
200+
// monomorphizations but always instantiate our own internal versions
201+
// instead.
202+
if !tcx.sess.opts.share_generics()
203+
// However, if the def_id is marked inline(never), then it's fine to just reuse the
204+
// upstream monomorphization.
205+
&& tcx.codegen_fn_attrs(self.def_id()).inline != rustc_attr::InlineAttr::Never
206+
{
207+
return None;
208+
}
209+
206210
// If this a non-generic instance, it cannot be a shared monomorphization.
207211
self.args.non_erasable_generics().next()?;
208212

compiler/rustc_monomorphize/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2021"
66
[dependencies]
77
# tidy-alphabetical-start
88
rustc_abi = { path = "../rustc_abi" }
9+
rustc_attr = { path = "../rustc_attr" }
910
rustc_data_structures = { path = "../rustc_data_structures" }
1011
rustc_errors = { path = "../rustc_errors" }
1112
rustc_fluent_macro = { path = "../rustc_fluent_macro" }

compiler/rustc_monomorphize/src/partitioning.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,8 @@ where
208208
// available to downstream crates. This depends on whether we are in
209209
// share-generics mode and whether the current crate can even have
210210
// downstream crates.
211-
let export_generics =
212-
cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics();
211+
let can_export_generics = cx.tcx.local_crate_exports_generics();
212+
let always_export_generics = can_export_generics && cx.tcx.sess.opts.share_generics();
213213

214214
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
215215
let cgu_name_cache = &mut UnordMap::default();
@@ -249,7 +249,8 @@ where
249249
cx.tcx,
250250
&mono_item,
251251
&mut can_be_internalized,
252-
export_generics,
252+
can_export_generics,
253+
always_export_generics,
253254
);
254255
if visibility == Visibility::Hidden && can_be_internalized {
255256
internalization_candidates.insert(mono_item);
@@ -739,12 +740,19 @@ fn mono_item_linkage_and_visibility<'tcx>(
739740
tcx: TyCtxt<'tcx>,
740741
mono_item: &MonoItem<'tcx>,
741742
can_be_internalized: &mut bool,
742-
export_generics: bool,
743+
can_export_generics: bool,
744+
always_export_generics: bool,
743745
) -> (Linkage, Visibility) {
744746
if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) {
745747
return (explicit_linkage, Visibility::Default);
746748
}
747-
let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, export_generics);
749+
let vis = mono_item_visibility(
750+
tcx,
751+
mono_item,
752+
can_be_internalized,
753+
can_export_generics,
754+
always_export_generics,
755+
);
748756
(Linkage::External, vis)
749757
}
750758

@@ -767,7 +775,8 @@ fn mono_item_visibility<'tcx>(
767775
tcx: TyCtxt<'tcx>,
768776
mono_item: &MonoItem<'tcx>,
769777
can_be_internalized: &mut bool,
770-
export_generics: bool,
778+
can_export_generics: bool,
779+
always_export_generics: bool,
771780
) -> Visibility {
772781
let instance = match mono_item {
773782
// This is pretty complicated; see below.
@@ -826,7 +835,11 @@ fn mono_item_visibility<'tcx>(
826835

827836
// Upstream `DefId` instances get different handling than local ones.
828837
let Some(def_id) = def_id.as_local() else {
829-
return if export_generics && is_generic {
838+
return if is_generic
839+
&& (always_export_generics
840+
|| (can_export_generics
841+
&& tcx.codegen_fn_attrs(def_id).inline == rustc_attr::InlineAttr::Never))
842+
{
830843
// If it is an upstream monomorphization and we export generics, we must make
831844
// it available to downstream crates.
832845
*can_be_internalized = false;
@@ -837,7 +850,10 @@ fn mono_item_visibility<'tcx>(
837850
};
838851

839852
if is_generic {
840-
if export_generics {
853+
if always_export_generics
854+
|| (can_export_generics
855+
&& tcx.codegen_fn_attrs(def_id).inline == rustc_attr::InlineAttr::Never)
856+
{
841857
if tcx.is_unreachable_local_definition(def_id) {
842858
// This instance cannot be used from another crate.
843859
Visibility::Hidden

library/alloc/src/raw_vec.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,9 @@ impl<A: Allocator> RawVecInner<A> {
757757
}
758758
}
759759

760-
#[inline(never)]
760+
// not marked inline(never) since we want optimizers to be able to observe the specifics of this
761+
// function, see tests/codegen/vec-reserve-extend.rs.
762+
#[cold]
761763
fn finish_grow<A>(
762764
new_layout: Layout,
763765
current_memory: Option<(NonNull<u8>, Layout)>,

library/std/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@
362362
#![feature(strict_provenance_atomic_ptr)]
363363
#![feature(sync_unsafe_cell)]
364364
#![feature(ub_checks)]
365+
#![feature(used_with_arg)]
365366
// tidy-alphabetical-end
366367
//
367368
// Library features (alloc):

0 commit comments

Comments
 (0)