Skip to content

Commit 2986d31

Browse files
committed
(crudely) implement MIR-only rlibs
1 parent 3ed6e3c commit 2986d31

File tree

11 files changed

+165
-18
lines changed

11 files changed

+165
-18
lines changed

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,14 @@ fn exported_symbols_provider_local(
209209
if allocator_kind_for_codegen(tcx).is_some() {
210210
for symbol_name in ALLOCATOR_METHODS
211211
.iter()
212-
.map(|method| format!("__rust_{}", method.name))
213-
.chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()])
212+
.flat_map(|method| {
213+
[format!("__rust_{}", method.name), format!("__rdl_{}", method.name)]
214+
})
215+
.chain([
216+
"__rust_alloc_error_handler".to_string(),
217+
OomStrategy::SYMBOL.to_string(),
218+
"__rg_oom".to_string(),
219+
])
214220
{
215221
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
216222

@@ -355,6 +361,27 @@ fn exported_symbols_provider_local(
355361
}
356362
}
357363

364+
if tcx.building_mir_only_rlib() {
365+
for def_id in tcx.mir_keys(()) {
366+
if !matches!(tcx.def_kind(def_id.to_def_id()), DefKind::Static { .. }) {
367+
continue;
368+
}
369+
if tcx.is_reachable_non_generic(def_id.to_def_id()) {
370+
continue;
371+
}
372+
let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id());
373+
symbols.push((ExportedSymbol::NonGeneric(def_id.to_def_id()), SymbolExportInfo {
374+
level: symbol_export_level(tcx, def_id.to_def_id()),
375+
kind: if codegen_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
376+
SymbolExportKind::Tls
377+
} else {
378+
SymbolExportKind::Data
379+
},
380+
used: true,
381+
}));
382+
}
383+
}
384+
358385
// Sort so we get a stable incr. comp. hash.
359386
symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx));
360387

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,7 @@ fn test_unstable_options_tracking_hash() {
807807
tracked!(mir_emit_retag, true);
808808
tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
809809
tracked!(mir_keep_place_mention, true);
810+
tracked!(mir_only_rlibs, true);
810811
tracked!(mir_opt_level, Some(4));
811812
tracked!(move_size_limit, Some(4096));
812813
tracked!(mutable_noalias, false);

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

+8
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,14 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
578578
.filter_map(|(cnum, data)| data.used().then_some(cnum)),
579579
)
580580
},
581+
mir_only_crates: |tcx, ()| {
582+
tcx.untracked().cstore.freeze();
583+
let store = CStore::from_tcx(tcx);
584+
let crates = store
585+
.iter_crate_data()
586+
.filter_map(|(cnum, data)| if data.root.is_mir_only { Some(cnum) } else { None });
587+
tcx.arena.alloc_from_iter(crates)
588+
},
581589
..providers.queries
582590
};
583591
provide_extern(&mut providers.extern_queries);

compiler/rustc_metadata/src/rmeta/encoder.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
736736
impls,
737737
incoherent_impls,
738738
exported_symbols,
739+
is_mir_only: tcx.building_mir_only_rlib(),
739740
interpret_alloc_index,
740741
tables,
741742
syntax_contexts,
@@ -1058,12 +1059,13 @@ fn should_encode_mir(
10581059
reachable_set: &LocalDefIdSet,
10591060
def_id: LocalDefId,
10601061
) -> (bool, bool) {
1062+
let opts = &tcx.sess.opts;
1063+
let mir_required = opts.unstable_opts.always_encode_mir || tcx.building_mir_only_rlib();
10611064
match tcx.def_kind(def_id) {
10621065
// Constructors
10631066
DefKind::Ctor(_, _) => {
1064-
let mir_opt_base = tcx.sess.opts.output_types.should_codegen()
1065-
|| tcx.sess.opts.unstable_opts.always_encode_mir;
1066-
(true, mir_opt_base)
1067+
let opt = mir_required || opts.output_types.should_codegen();
1068+
(true, opt)
10671069
}
10681070
// Constants
10691071
DefKind::AnonConst | DefKind::InlineConst | DefKind::AssocConst | DefKind::Const => {
@@ -1075,7 +1077,7 @@ fn should_encode_mir(
10751077
// Full-fledged functions + closures
10761078
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
10771079
let generics = tcx.generics_of(def_id);
1078-
let opt = tcx.sess.opts.unstable_opts.always_encode_mir
1080+
let opt = mir_required
10791081
|| (tcx.sess.opts.output_types.should_codegen()
10801082
&& reachable_set.contains(&def_id)
10811083
&& (generics.requires_monomorphization(tcx)

compiler/rustc_metadata/src/rmeta/mod.rs

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

277277
exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
278+
is_mir_only: bool,
278279

279280
syntax_contexts: SyntaxContextTable,
280281
expn_data: ExpnDataTable,

compiler/rustc_middle/src/mir/mono.rs

+11
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,17 @@ impl<'tcx> MonoItem<'tcx> {
106106
}
107107

108108
pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
109+
// Always do LocalCopy codegen when building a MIR-only rlib
110+
if tcx.building_mir_only_rlib() {
111+
return InstantiationMode::LocalCopy;
112+
}
113+
// If this is a monomorphization from a MIR-only rlib and we are building another lib, do
114+
// local codegen.
115+
if tcx.mir_only_crates(()).iter().any(|c| *c == self.def_id().krate)
116+
&& tcx.crate_types() == &[rustc_session::config::CrateType::Rlib]
117+
{
118+
return InstantiationMode::LocalCopy;
119+
}
109120
let generate_cgu_internal_copies = tcx
110121
.sess
111122
.opts

compiler/rustc_middle/src/query/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -2281,6 +2281,15 @@ rustc_queries! {
22812281
desc { "whether the item should be made inlinable across crates" }
22822282
separate_provide_extern
22832283
}
2284+
2285+
query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option<rustc_target::abi::FieldIdx> {
2286+
desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) }
2287+
}
2288+
2289+
query mir_only_crates(_: ()) -> &'tcx [CrateNum] {
2290+
eval_always
2291+
desc { "fetching all foreign crates built in mir-only mode" }
2292+
}
22842293
}
22852294

22862295
rustc_query_append! { define_callbacks! }

compiler/rustc_middle/src/ty/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,10 @@ impl<'tcx> TyCtxt<'tcx> {
17581758
pub fn dcx(self) -> DiagCtxtHandle<'tcx> {
17591759
self.sess.dcx()
17601760
}
1761+
1762+
pub fn building_mir_only_rlib(self) -> bool {
1763+
self.sess.opts.unstable_opts.mir_only_rlibs && self.crate_types() == &[CrateType::Rlib]
1764+
}
17611765
}
17621766

17631767
impl<'tcx> TyCtxtAt<'tcx> {

compiler/rustc_monomorphize/src/collector.rs

+71-8
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ use rustc_hir::def::DefKind;
217217
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
218218
use rustc_hir::lang_items::LangItem;
219219
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
220+
use rustc_middle::middle::exported_symbols::ExportedSymbol;
220221
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
221222
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
222223
use rustc_middle::mir::visit::Visitor as MirVisitor;
@@ -232,7 +233,7 @@ use rustc_middle::ty::{
232233
use rustc_middle::util::Providers;
233234
use rustc_middle::{bug, span_bug};
234235
use rustc_session::Limit;
235-
use rustc_session::config::EntryFnType;
236+
use rustc_session::config::{CrateType, EntryFnType};
236237
use rustc_span::source_map::{Spanned, dummy_spanned, respan};
237238
use rustc_span::symbol::{Ident, sym};
238239
use rustc_span::{DUMMY_SP, Span};
@@ -940,28 +941,45 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -
940941
return true;
941942
};
942943

944+
let def_is_for_mir_only_rlib = if def_id.krate == rustc_hir::def_id::LOCAL_CRATE {
945+
tcx.building_mir_only_rlib()
946+
} else {
947+
tcx.mir_only_crates(()).iter().any(|c| *c == def_id.krate)
948+
};
949+
943950
if tcx.is_foreign_item(def_id) {
944-
// Foreign items are always linked against, there's no way of instantiating them.
945-
return false;
951+
if def_is_for_mir_only_rlib {
952+
return tcx.is_mir_available(instance.def_id());
953+
} else {
954+
// Foreign items are always linked against, there's no way of instantiating them.
955+
return false;
956+
}
957+
}
958+
959+
if def_is_for_mir_only_rlib {
960+
let has_mir = tcx.is_mir_available(instance.def_id());
961+
return has_mir || matches!(tcx.def_kind(instance.def_id()), DefKind::Static { .. });
946962
}
947963

948964
if def_id.is_local() {
949965
// Local items cannot be referred to locally without monomorphizing them locally.
950966
return true;
951967
}
952968

969+
if !def_is_for_mir_only_rlib {
970+
if let DefKind::Static { .. } = tcx.def_kind(def_id) {
971+
// We cannot monomorphize statics from upstream crates.
972+
return false;
973+
}
974+
}
975+
953976
if tcx.is_reachable_non_generic(def_id)
954977
|| instance.polymorphize(*tcx).upstream_monomorphization(*tcx).is_some()
955978
{
956979
// We can link to the item in question, no instance needed in this crate.
957980
return false;
958981
}
959982

960-
if let DefKind::Static { .. } = tcx.def_kind(def_id) {
961-
// We cannot monomorphize statics from upstream crates.
962-
return false;
963-
}
964-
965983
if !tcx.is_mir_available(def_id) {
966984
tcx.dcx().emit_fatal(NoOptimizedMir {
967985
span: tcx.def_span(def_id),
@@ -1351,6 +1369,7 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionStrategy) -> Vec<MonoI
13511369
}
13521370

13531371
collector.push_extra_entry_roots();
1372+
collector.push_extra_roots_from_mir_only_rlibs();
13541373
}
13551374

13561375
// We can only codegen items that are instantiable - items all of
@@ -1495,6 +1514,50 @@ impl<'v> RootCollector<'_, 'v> {
14951514

14961515
self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP));
14971516
}
1517+
1518+
fn push_extra_roots_from_mir_only_rlibs(&mut self) {
1519+
// An upstream extern function may be used anywhere in the dependency tree, so we
1520+
// cannot do any reachability analysis on them. We blindly monomorphize every
1521+
// extern function declared anywhere in our dependency tree. We must give them
1522+
// GloballyShared codegen because we don't know if the only call to an upstream
1523+
// extern function is also upstream: We don't have reachability information. All we
1524+
// can do is codegen all extern functions and pray for the linker to delete the
1525+
// ones that are reachable.
1526+
if !self.tcx.crate_types().iter().any(|c| !matches!(c, CrateType::Rlib)) {
1527+
return;
1528+
}
1529+
1530+
for (symbol, _info) in self
1531+
.tcx
1532+
.mir_only_crates(())
1533+
.into_iter()
1534+
.flat_map(|krate| self.tcx.exported_symbols(*krate))
1535+
{
1536+
let def_id = match symbol {
1537+
ExportedSymbol::NonGeneric(def_id) => def_id,
1538+
ExportedSymbol::ThreadLocalShim(def_id) => {
1539+
let item = MonoItem::Fn(Instance {
1540+
def: InstanceKind::ThreadLocalShim(*def_id),
1541+
args: GenericArgs::empty(),
1542+
});
1543+
self.output.push(dummy_spanned(item));
1544+
continue;
1545+
}
1546+
_ => continue,
1547+
};
1548+
match self.tcx.def_kind(def_id) {
1549+
DefKind::Fn | DefKind::AssocFn => {
1550+
let instance = Instance::mono(self.tcx, *def_id);
1551+
let item = create_fn_mono_item(self.tcx, instance, DUMMY_SP);
1552+
self.output.push(item);
1553+
}
1554+
DefKind::Static { .. } => {
1555+
self.output.push(dummy_spanned(MonoItem::Static(*def_id)));
1556+
}
1557+
_ => {}
1558+
}
1559+
}
1560+
}
14981561
}
14991562

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

compiler/rustc_monomorphize/src/partitioning.rs

+23-4
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ fn partition<'tcx, I>(
146146
where
147147
I: Iterator<Item = MonoItem<'tcx>>,
148148
{
149+
if tcx.building_mir_only_rlib() {
150+
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
151+
let cgu_name = fallback_cgu_name(cgu_name_builder);
152+
return vec![CodegenUnit::new(cgu_name)];
153+
}
154+
149155
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");
150156

151157
let cx = &PartitioningCx { tcx, usage_map };
@@ -170,6 +176,10 @@ where
170176
debug_dump(tcx, "MERGE", &codegen_units);
171177
}
172178

179+
if !codegen_units.is_sorted_by(|a, b| a.name().as_str() < b.name().as_str()) {
180+
bug!("unsorted CGUs");
181+
}
182+
173183
// Make as many symbols "internal" as possible, so LLVM has more freedom to
174184
// optimize.
175185
if !tcx.sess.link_dead_code() {
@@ -190,7 +200,12 @@ where
190200
for cgu in codegen_units.iter() {
191201
names += &format!("- {}\n", cgu.name());
192202
}
193-
bug!("unsorted CGUs:\n{names}");
203+
codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str()));
204+
let mut sorted_names = String::new();
205+
for cgu in codegen_units.iter() {
206+
sorted_names += &format!("- {}\n", cgu.name());
207+
}
208+
bug!("unsorted CGUs:\n{names}\n{sorted_names}");
194209
}
195210

196211
codegen_units
@@ -214,6 +229,9 @@ where
214229
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
215230
let cgu_name_cache = &mut UnordMap::default();
216231

232+
let start_fn = cx.tcx.lang_items().start_fn();
233+
let entry_fn = cx.tcx.entry_fn(()).map(|(id, _)| id);
234+
217235
for mono_item in mono_items {
218236
// Handle only root (GloballyShared) items directly here. Inlined (LocalCopy) items
219237
// are handled at the bottom of the loop based on reachability, with one exception.
@@ -222,7 +240,8 @@ where
222240
match mono_item.instantiation_mode(cx.tcx) {
223241
InstantiationMode::GloballyShared { .. } => {}
224242
InstantiationMode::LocalCopy => {
225-
if Some(mono_item.def_id()) != cx.tcx.lang_items().start_fn() {
243+
let def_id = mono_item.def_id();
244+
if ![start_fn, entry_fn].contains(&Some(def_id)) {
226245
continue;
227246
}
228247
}
@@ -244,7 +263,7 @@ where
244263

245264
let cgu = codegen_units.entry(cgu_name).or_insert_with(|| CodegenUnit::new(cgu_name));
246265

247-
let mut can_be_internalized = true;
266+
let mut can_be_internalized = false;
248267
let (linkage, visibility) = mono_item_linkage_and_visibility(
249268
cx.tcx,
250269
&mono_item,
@@ -486,7 +505,7 @@ fn merge_codegen_units<'tcx>(
486505
// If we didn't zero-pad the sorted-by-name order would be `XYZ-cgu.0`,
487506
// `XYZ-cgu.1`, `XYZ-cgu.10`, `XYZ-cgu.11`, ..., `XYZ-cgu.2`, etc.
488507
codegen_units.sort_by_key(|cgu| cmp::Reverse(cgu.size_estimate()));
489-
let num_digits = codegen_units.len().ilog10() as usize + 1;
508+
let num_digits = std::hint::black_box(codegen_units.len().ilog10() as usize + 1);
490509
for (index, cgu) in codegen_units.iter_mut().enumerate() {
491510
// Note: `WorkItem::short_description` depends on this name ending
492511
// 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
@@ -1896,6 +1896,8 @@ options! {
18961896
mir_keep_place_mention: bool = (false, parse_bool, [TRACKED],
18971897
"keep place mention MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
18981898
(default: no)"),
1899+
mir_only_rlibs: bool = (false, parse_bool, [TRACKED],
1900+
"only generate MIR when building rlibs (default: no)"),
18991901
#[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
19001902
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
19011903
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),

0 commit comments

Comments
 (0)