Skip to content

Commit 4b0f58c

Browse files
committed
(crudely) implement MIR-only rlibs
1 parent 2627e9f commit 4b0f58c

File tree

13 files changed

+169
-21
lines changed

13 files changed

+169
-21
lines changed

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,14 @@ fn exported_symbols_provider_local(
218218
if allocator_kind_for_codegen(tcx).is_some() {
219219
for symbol_name in ALLOCATOR_METHODS
220220
.iter()
221-
.map(|method| format!("__rust_{}", method.name))
222-
.chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()])
221+
.flat_map(|method| {
222+
[format!("__rust_{}", method.name), format!("__rdl_{}", method.name)]
223+
})
224+
.chain([
225+
"__rust_alloc_error_handler".to_string(),
226+
OomStrategy::SYMBOL.to_string(),
227+
"__rg_oom".to_string(),
228+
])
223229
{
224230
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
225231

@@ -370,6 +376,30 @@ fn exported_symbols_provider_local(
370376
}
371377
}
372378

379+
if tcx.building_mir_only_rlib() {
380+
for def_id in tcx.mir_keys(()) {
381+
if !matches!(tcx.def_kind(def_id.to_def_id()), DefKind::Static { .. }) {
382+
continue;
383+
}
384+
if tcx.is_reachable_non_generic(def_id.to_def_id()) {
385+
continue;
386+
}
387+
let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id());
388+
symbols.push((
389+
ExportedSymbol::NonGeneric(def_id.to_def_id()),
390+
SymbolExportInfo {
391+
level: symbol_export_level(tcx, def_id.to_def_id()),
392+
kind: if codegen_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
393+
SymbolExportKind::Tls
394+
} else {
395+
SymbolExportKind::Data
396+
},
397+
used: true,
398+
},
399+
));
400+
}
401+
}
402+
373403
// Sort so we get a stable incr. comp. hash.
374404
symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx));
375405

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,7 @@ fn test_unstable_options_tracking_hash() {
787787
tracked!(mir_emit_retag, true);
788788
tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
789789
tracked!(mir_keep_place_mention, true);
790+
tracked!(mir_only_rlibs, true);
790791
tracked!(mir_opt_level, Some(4));
791792
tracked!(move_size_limit, Some(4096));
792793
tracked!(mutable_noalias, false);

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+8
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,14 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
530530
.filter_map(|(cnum, data)| data.used().then_some(cnum)),
531531
)
532532
},
533+
mir_only_crates: |tcx, ()| {
534+
tcx.untracked().cstore.freeze();
535+
let store = CStore::from_tcx(tcx);
536+
let crates = store
537+
.iter_crate_data()
538+
.filter_map(|(cnum, data)| if data.root.is_mir_only { Some(cnum) } else { None });
539+
tcx.arena.alloc_from_iter(crates)
540+
},
533541
..providers.queries
534542
};
535543
provide_extern(&mut providers.extern_queries);

compiler/rustc_metadata/src/rmeta/encoder.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
739739
impls,
740740
incoherent_impls,
741741
exported_symbols,
742+
is_mir_only: tcx.building_mir_only_rlib(),
742743
interpret_alloc_index,
743744
tables,
744745
syntax_contexts,
@@ -1051,12 +1052,13 @@ fn should_encode_mir(
10511052
reachable_set: &LocalDefIdSet,
10521053
def_id: LocalDefId,
10531054
) -> (bool, bool) {
1055+
let opts = &tcx.sess.opts;
1056+
let mir_required = opts.unstable_opts.always_encode_mir || tcx.building_mir_only_rlib();
10541057
match tcx.def_kind(def_id) {
10551058
// Constructors
10561059
DefKind::Ctor(_, _) => {
1057-
let mir_opt_base = tcx.sess.opts.output_types.should_codegen()
1058-
|| tcx.sess.opts.unstable_opts.always_encode_mir;
1059-
(true, mir_opt_base)
1060+
let opt = mir_required || opts.output_types.should_codegen();
1061+
(true, opt)
10601062
}
10611063
// Constants
10621064
DefKind::AnonConst | DefKind::InlineConst | DefKind::AssocConst | DefKind::Const => {
@@ -1067,7 +1069,7 @@ fn should_encode_mir(
10671069
// Full-fledged functions + closures
10681070
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
10691071
let generics = tcx.generics_of(def_id);
1070-
let opt = tcx.sess.opts.unstable_opts.always_encode_mir
1072+
let opt = mir_required
10711073
|| (tcx.sess.opts.output_types.should_codegen()
10721074
&& reachable_set.contains(&def_id)
10731075
&& (generics.requires_monomorphization(tcx)

compiler/rustc_metadata/src/rmeta/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ pub(crate) struct CrateRoot {
276276
debugger_visualizers: LazyArray<DebuggerVisualizerFile>,
277277

278278
exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
279+
is_mir_only: bool,
279280

280281
syntax_contexts: SyntaxContextTable,
281282
expn_data: ExpnDataTable,

compiler/rustc_middle/src/mir/mono.rs

+11
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,17 @@ impl<'tcx> MonoItem<'tcx> {
9999
}
100100

101101
pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
102+
// Always do LocalCopy codegen when building a MIR-only rlib
103+
if tcx.building_mir_only_rlib() {
104+
return InstantiationMode::LocalCopy;
105+
}
106+
// If this is a monomorphization from a MIR-only rlib and we are building another lib, do
107+
// local codegen.
108+
if tcx.mir_only_crates(()).iter().any(|c| *c == self.def_id().krate)
109+
&& tcx.crate_types() == &[rustc_session::config::CrateType::Rlib]
110+
{
111+
return InstantiationMode::LocalCopy;
112+
}
102113
let generate_cgu_internal_copies = tcx
103114
.sess
104115
.opts

compiler/rustc_middle/src/query/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -2250,6 +2250,11 @@ rustc_queries! {
22502250
query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option<rustc_target::abi::FieldIdx> {
22512251
desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) }
22522252
}
2253+
2254+
query mir_only_crates(_: ()) -> &'tcx [CrateNum] {
2255+
eval_always
2256+
desc { "fetching all foreign crates built in mir-only mode" }
2257+
}
22532258
}
22542259

22552260
rustc_query_append! { define_callbacks! }

compiler/rustc_middle/src/ty/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,10 @@ impl<'tcx> TyCtxt<'tcx> {
11061106
pub fn dcx(self) -> &'tcx DiagCtxt {
11071107
self.sess.dcx()
11081108
}
1109+
1110+
pub fn building_mir_only_rlib(self) -> bool {
1111+
self.sess.opts.unstable_opts.mir_only_rlibs && self.crate_types() == &[CrateType::Rlib]
1112+
}
11091113
}
11101114

11111115
impl<'tcx> TyCtxtAt<'tcx> {

compiler/rustc_monomorphize/src/collector.rs

+72-8
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ use rustc_hir as hir;
211211
use rustc_hir::def::DefKind;
212212
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
213213
use rustc_hir::lang_items::LangItem;
214-
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
214+
use rustc_middle::middle::exported_symbols::ExportedSymbol;
215215
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
216216
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
217217
use rustc_middle::mir::visit::Visitor as MirVisitor;
@@ -225,6 +225,8 @@ use rustc_middle::ty::{
225225
TypeVisitableExt, VtblEntry,
226226
};
227227
use rustc_middle::ty::{GenericArgKind, GenericArgs};
228+
use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags};
229+
use rustc_session::config::CrateType;
228230
use rustc_session::config::EntryFnType;
229231
use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
230232
use rustc_session::Limit;
@@ -1112,28 +1114,45 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) ->
11121114
return true;
11131115
};
11141116

1117+
let def_is_for_mir_only_rlib = if def_id.krate == rustc_hir::def_id::LOCAL_CRATE {
1118+
tcx.building_mir_only_rlib()
1119+
} else {
1120+
tcx.mir_only_crates(()).iter().any(|c| *c == def_id.krate)
1121+
};
1122+
11151123
if tcx.is_foreign_item(def_id) {
1116-
// Foreign items are always linked against, there's no way of instantiating them.
1117-
return false;
1124+
if def_is_for_mir_only_rlib {
1125+
return tcx.is_mir_available(instance.def_id());
1126+
} else {
1127+
// Foreign items are always linked against, there's no way of instantiating them.
1128+
return false;
1129+
}
1130+
}
1131+
1132+
if def_is_for_mir_only_rlib {
1133+
let has_mir = tcx.is_mir_available(instance.def_id());
1134+
return has_mir || matches!(tcx.def_kind(instance.def_id()), DefKind::Static { .. });
11181135
}
11191136

11201137
if def_id.is_local() {
11211138
// Local items cannot be referred to locally without monomorphizing them locally.
11221139
return true;
11231140
}
11241141

1142+
if !def_is_for_mir_only_rlib {
1143+
if let DefKind::Static { .. } = tcx.def_kind(def_id) {
1144+
// We cannot monomorphize statics from upstream crates.
1145+
return false;
1146+
}
1147+
}
1148+
11251149
if tcx.is_reachable_non_generic(def_id)
11261150
|| instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some()
11271151
{
11281152
// We can link to the item in question, no instance needed in this crate.
11291153
return false;
11301154
}
11311155

1132-
if let DefKind::Static { .. } = tcx.def_kind(def_id) {
1133-
// We cannot monomorphize statics from upstream crates.
1134-
return false;
1135-
}
1136-
11371156
if !tcx.is_mir_available(def_id) {
11381157
tcx.dcx().emit_fatal(NoOptimizedMir {
11391158
span: tcx.def_span(def_id),
@@ -1535,6 +1554,7 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionStrategy) -> Vec<MonoI
15351554
}
15361555

15371556
collector.push_extra_entry_roots();
1557+
collector.push_extra_roots_from_mir_only_rlibs();
15381558
}
15391559

15401560
// We can only codegen items that are instantiable - items all of
@@ -1669,6 +1689,50 @@ impl<'v> RootCollector<'_, 'v> {
16691689

16701690
self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP));
16711691
}
1692+
1693+
fn push_extra_roots_from_mir_only_rlibs(&mut self) {
1694+
// An upstream extern function may be used anywhere in the dependency tree, so we
1695+
// cannot do any reachability analysis on them. We blindly monomorphize every
1696+
// extern function declared anywhere in our dependency tree. We must give them
1697+
// GloballyShared codegen because we don't know if the only call to an upstream
1698+
// extern function is also upstream: We don't have reachability information. All we
1699+
// can do is codegen all extern functions and pray for the linker to delete the
1700+
// ones that are reachable.
1701+
if !self.tcx.crate_types().iter().any(|c| !matches!(c, CrateType::Rlib)) {
1702+
return;
1703+
}
1704+
1705+
for (symbol, _info) in self
1706+
.tcx
1707+
.mir_only_crates(())
1708+
.into_iter()
1709+
.flat_map(|krate| self.tcx.exported_symbols(*krate))
1710+
{
1711+
let def_id = match symbol {
1712+
ExportedSymbol::NonGeneric(def_id) => def_id,
1713+
ExportedSymbol::ThreadLocalShim(def_id) => {
1714+
let item = MonoItem::Fn(Instance {
1715+
def: InstanceDef::ThreadLocalShim(*def_id),
1716+
args: GenericArgs::empty(),
1717+
});
1718+
self.output.push(dummy_spanned(item));
1719+
continue;
1720+
}
1721+
_ => continue,
1722+
};
1723+
match self.tcx.def_kind(def_id) {
1724+
DefKind::Fn | DefKind::AssocFn => {
1725+
let instance = Instance::mono(self.tcx, *def_id);
1726+
let item = create_fn_mono_item(self.tcx, instance, DUMMY_SP);
1727+
self.output.push(item);
1728+
}
1729+
DefKind::Static { .. } => {
1730+
self.output.push(dummy_spanned(MonoItem::Static(*def_id)));
1731+
}
1732+
_ => {}
1733+
}
1734+
}
1735+
}
16721736
}
16731737

16741738
#[instrument(level = "debug", skip(tcx, output))]

compiler/rustc_monomorphize/src/partitioning.rs

+23-4
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ fn partition<'tcx, I>(
141141
where
142142
I: Iterator<Item = MonoItem<'tcx>>,
143143
{
144+
if tcx.building_mir_only_rlib() {
145+
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
146+
let cgu_name = fallback_cgu_name(cgu_name_builder);
147+
return vec![CodegenUnit::new(cgu_name)];
148+
}
149+
144150
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");
145151

146152
let cx = &PartitioningCx { tcx, usage_map };
@@ -165,6 +171,10 @@ where
165171
debug_dump(tcx, "MERGE", &codegen_units);
166172
}
167173

174+
if !codegen_units.is_sorted_by(|a, b| a.name().as_str() < b.name().as_str()) {
175+
bug!("unsorted CGUs");
176+
}
177+
168178
// Make as many symbols "internal" as possible, so LLVM has more freedom to
169179
// optimize.
170180
if !tcx.sess.link_dead_code() {
@@ -185,7 +195,12 @@ where
185195
for cgu in codegen_units.iter() {
186196
names += &format!("- {}\n", cgu.name());
187197
}
188-
bug!("unsorted CGUs:\n{names}");
198+
codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str()));
199+
let mut sorted_names = String::new();
200+
for cgu in codegen_units.iter() {
201+
sorted_names += &format!("- {}\n", cgu.name());
202+
}
203+
bug!("unsorted CGUs:\n{names}\n{sorted_names}");
189204
}
190205

191206
codegen_units
@@ -209,6 +224,9 @@ where
209224
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
210225
let cgu_name_cache = &mut FxHashMap::default();
211226

227+
let start_fn = cx.tcx.lang_items().start_fn();
228+
let entry_fn = cx.tcx.entry_fn(()).map(|(id, _)| id);
229+
212230
for mono_item in mono_items {
213231
// Handle only root (GloballyShared) items directly here. Inlined (LocalCopy) items
214232
// are handled at the bottom of the loop based on reachability, with one exception.
@@ -217,7 +235,8 @@ where
217235
match mono_item.instantiation_mode(cx.tcx) {
218236
InstantiationMode::GloballyShared { .. } => {}
219237
InstantiationMode::LocalCopy => {
220-
if Some(mono_item.def_id()) != cx.tcx.lang_items().start_fn() {
238+
let def_id = mono_item.def_id();
239+
if ![start_fn, entry_fn].contains(&Some(def_id)) {
221240
continue;
222241
}
223242
}
@@ -239,7 +258,7 @@ where
239258

240259
let cgu = codegen_units.entry(cgu_name).or_insert_with(|| CodegenUnit::new(cgu_name));
241260

242-
let mut can_be_internalized = true;
261+
let mut can_be_internalized = false;
243262
let (linkage, visibility) = mono_item_linkage_and_visibility(
244263
cx.tcx,
245264
&mono_item,
@@ -474,7 +493,7 @@ fn merge_codegen_units<'tcx>(
474493
// If we didn't zero-pad the sorted-by-name order would be `XYZ-cgu.0`,
475494
// `XYZ-cgu.1`, `XYZ-cgu.10`, `XYZ-cgu.11`, ..., `XYZ-cgu.2`, etc.
476495
codegen_units.sort_by_key(|cgu| cmp::Reverse(cgu.size_estimate()));
477-
let num_digits = codegen_units.len().ilog10() as usize + 1;
496+
let num_digits = std::hint::black_box(codegen_units.len().ilog10() as usize + 1);
478497
for (index, cgu) in codegen_units.iter_mut().enumerate() {
479498
// Note: `WorkItem::short_description` depends on this name ending
480499
// with `-cgu.` followed by a numeric suffix. Please keep it in

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1760,6 +1760,8 @@ options! {
17601760
mir_keep_place_mention: bool = (false, parse_bool, [TRACKED],
17611761
"keep place mention MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
17621762
(default: no)"),
1763+
mir_only_rlibs: bool = (false, parse_bool, [TRACKED],
1764+
"only generate MIR when building rlibs (default: no)"),
17631765
#[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
17641766
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
17651767
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),

library/std/Cargo.toml

-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ repository = "https://github.com/rust-lang/rust.git"
88
description = "The Rust Standard Library"
99
edition = "2021"
1010

11-
[lib]
12-
crate-type = ["dylib", "rlib"]
13-
1411
[dependencies]
1512
alloc = { path = "../alloc", public = true }
1613
cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }

src/bootstrap/src/core/builder.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,10 @@ impl<'a> Builder<'a> {
14541454
rustflags.arg("--cfg=bootstrap");
14551455
}
14561456

1457+
if stage != 0 && mode == Mode::Std {
1458+
rustflags.arg("-Zmir-only-rlibs");
1459+
}
1460+
14571461
if cmd == "clippy" {
14581462
// clippy overwrites sysroot if we pass it to cargo.
14591463
// Pass it directly to clippy instead.

0 commit comments

Comments
 (0)