Skip to content

Commit 741a7a7

Browse files
committed
(crudely) implement MIR-only rlibs
1 parent 75c68cf commit 741a7a7

File tree

8 files changed

+101
-15
lines changed

8 files changed

+101
-15
lines changed

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,14 @@ fn exported_symbols_provider_local(
227227
if allocator_kind_for_codegen(tcx).is_some() {
228228
for symbol_name in ALLOCATOR_METHODS
229229
.iter()
230-
.map(|method| format!("__rust_{}", method.name))
231-
.chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()])
230+
.flat_map(|method| {
231+
[format!("__rust_{}", method.name), format!("__rdl_{}", method.name)]
232+
})
233+
.chain([
234+
"__rust_alloc_error_handler".to_string(),
235+
OomStrategy::SYMBOL.to_string(),
236+
"__rg_oom".to_string(),
237+
])
232238
{
233239
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
234240

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,7 @@ fn test_unstable_options_tracking_hash() {
776776
tracked!(mir_emit_retag, true);
777777
tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
778778
tracked!(mir_keep_place_mention, true);
779+
tracked!(mir_only_libs, true);
779780
tracked!(mir_opt_level, Some(4));
780781
tracked!(move_size_limit, Some(4096));
781782
tracked!(mutable_noalias, false);

compiler/rustc_metadata/src/rmeta/encoder.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1037,12 +1037,13 @@ fn should_encode_mir(
10371037
reachable_set: &LocalDefIdSet,
10381038
def_id: LocalDefId,
10391039
) -> (bool, bool) {
1040+
let opts = &tcx.sess.opts;
1041+
let mir_required = opts.unstable_opts.always_encode_mir || opts.unstable_opts.mir_only_libs;
10401042
match tcx.def_kind(def_id) {
10411043
// Constructors
10421044
DefKind::Ctor(_, _) => {
1043-
let mir_opt_base = tcx.sess.opts.output_types.should_codegen()
1044-
|| tcx.sess.opts.unstable_opts.always_encode_mir;
1045-
(true, mir_opt_base)
1045+
let opt = mir_required || opts.output_types.should_codegen();
1046+
(true, opt)
10461047
}
10471048
// Constants
10481049
DefKind::AnonConst
@@ -1055,7 +1056,7 @@ fn should_encode_mir(
10551056
// Full-fledged functions + closures
10561057
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
10571058
let generics = tcx.generics_of(def_id);
1058-
let opt = tcx.sess.opts.unstable_opts.always_encode_mir
1059+
let opt = mir_required
10591060
|| (tcx.sess.opts.output_types.should_codegen()
10601061
&& reachable_set.contains(&def_id)
10611062
&& (generics.requires_monomorphization(tcx)

compiler/rustc_middle/src/mir/mono.rs

+15
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ impl<'tcx> MonoItem<'tcx> {
9898
}
9999

100100
pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
101+
// Always do LocalCopy codegen when building a MIR-only rlib
102+
if tcx.building_mir_only_lib() {
103+
return InstantiationMode::LocalCopy;
104+
}
101105
let generate_cgu_internal_copies = tcx
102106
.sess
103107
.opts
@@ -108,6 +112,17 @@ impl<'tcx> MonoItem<'tcx> {
108112

109113
match *self {
110114
MonoItem::Fn(ref instance) => {
115+
// See the check in MirUsedCollector for building_mir_only_bin for background.
116+
// Here, we need to give the symbols that the collector feeds to use GloballyShared
117+
// linkage so that CGU partitioning doesn't try to assign them lazily, then find no
118+
// uses of them. They might only be used by an upstream crate, so we need to force
119+
// codegen, which is what GloballyShared does.
120+
if tcx.building_mir_only_bin()
121+
&& tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
122+
{
123+
return InstantiationMode::GloballyShared { may_conflict: false };
124+
}
125+
111126
let entry_def_id = tcx.entry_fn(()).map(|(id, _)| id);
112127
// If this function isn't inlined or otherwise has an extern
113128
// indicator, then we'll be creating a globally shared version.

compiler/rustc_middle/src/ty/context.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,14 @@ impl<'tcx> TyCtxt<'tcx> {
10281028
pub fn dcx(self) -> &'tcx DiagCtxt {
10291029
self.sess.dcx()
10301030
}
1031+
1032+
pub fn building_mir_only_lib(self) -> bool {
1033+
self.sess.opts.unstable_opts.mir_only_libs && self.crate_types() == &[CrateType::Rlib]
1034+
}
1035+
1036+
pub fn building_mir_only_bin(self) -> bool {
1037+
self.sess.opts.unstable_opts.mir_only_libs && self.crate_types() == &[CrateType::Executable]
1038+
}
10311039
}
10321040

10331041
impl<'tcx> TyCtxtAt<'tcx> {

compiler/rustc_monomorphize/src/collector.rs

+49-7
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ use rustc_hir as hir;
170170
use rustc_hir::def::DefKind;
171171
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
172172
use rustc_hir::lang_items::LangItem;
173+
use rustc_middle::middle::exported_symbols::ExportedSymbol;
173174
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
174175
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
175176
use rustc_middle::mir::visit::Visitor as MirVisitor;
@@ -975,27 +976,36 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) ->
975976
};
976977

977978
if tcx.is_foreign_item(def_id) {
978-
// Foreign items are always linked against, there's no way of instantiating them.
979-
return false;
979+
if tcx.sess.opts.unstable_opts.mir_only_libs {
980+
return tcx.is_mir_available(instance.def_id());
981+
} else {
982+
// Foreign items are always linked against, there's no way of instantiating them.
983+
return false;
984+
}
985+
}
986+
987+
if tcx.sess.opts.unstable_opts.mir_only_libs {
988+
let has_mir = tcx.is_mir_available(instance.def_id());
989+
return has_mir || matches!(tcx.def_kind(instance.def_id()), DefKind::Static(_));
980990
}
981991

982992
if def_id.is_local() {
983993
// Local items cannot be referred to locally without monomorphizing them locally.
984994
return true;
985995
}
986996

997+
if let DefKind::Static(_) = tcx.def_kind(def_id) {
998+
// We cannot monomorphize statics from upstream crates.
999+
return false;
1000+
}
1001+
9871002
if tcx.is_reachable_non_generic(def_id)
9881003
|| instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some()
9891004
{
9901005
// We can link to the item in question, no instance needed in this crate.
9911006
return false;
9921007
}
9931008

994-
if let DefKind::Static(_) = tcx.def_kind(def_id) {
995-
// We cannot monomorphize statics from upstream crates.
996-
return false;
997-
}
998-
9991009
if !tcx.is_mir_available(def_id) {
10001010
tcx.dcx().emit_fatal(NoOptimizedMir {
10011011
span: tcx.def_span(def_id),
@@ -1295,6 +1305,38 @@ impl<'v> RootCollector<'_, 'v> {
12951305
.unwrap();
12961306

12971307
self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP));
1308+
1309+
// An upstream extern function may be used anywhere in the dependency tree, so we
1310+
// cannot do any reachability analysis on them. We blindly monomorphize every
1311+
// extern function declared anywhere in our dependency tree. We must give them
1312+
// GloballyShared codegen because we don't know if the only call to an upstream
1313+
// extern function is also upstream: We don't have reachability information. All we
1314+
// can do is codegen all extern functions and pray for the linker to delete the
1315+
// ones that are reachable.
1316+
if self.tcx.building_mir_only_bin() {
1317+
for (symbol, _info) in
1318+
self.tcx.crates(()).into_iter().flat_map(|krate| self.tcx.exported_symbols(*krate))
1319+
{
1320+
let def_id = match symbol {
1321+
ExportedSymbol::NonGeneric(def_id) => def_id,
1322+
_ => {
1323+
eprintln!("Not handling exported symbol {:?}", symbol);
1324+
continue;
1325+
}
1326+
};
1327+
if self.tcx.def_kind(def_id) != DefKind::Fn {
1328+
eprintln!("Not handling exported def {:?}", def_id);
1329+
continue;
1330+
}
1331+
let instance = Instance::mono(self.tcx, *def_id);
1332+
// FIXME: This is probably not the right span. What is?
1333+
let item = create_fn_mono_item(self.tcx, instance, DUMMY_SP);
1334+
// FIXME: Do we need this check?
1335+
if !self.output.iter().any(|out| out.node.def_id() == *def_id) {
1336+
self.output.push(item);
1337+
}
1338+
}
1339+
}
12981340
}
12991341
}
13001342

compiler/rustc_monomorphize/src/partitioning.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ fn partition<'tcx, I>(
141141
where
142142
I: Iterator<Item = MonoItem<'tcx>>,
143143
{
144+
if tcx.sess.opts.unstable_opts.mir_only_libs {
145+
assert!(tcx.building_mir_only_lib() || tcx.building_mir_only_bin());
146+
}
147+
144148
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");
145149

146150
let cx = &PartitioningCx { tcx, usage_map };
@@ -211,6 +215,9 @@ where
211215
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
212216
let cgu_name_cache = &mut FxHashMap::default();
213217

218+
let start_fn = cx.tcx.lang_items().start_fn();
219+
let entry_fn = cx.tcx.entry_fn(()).map(|(id, _)| id);
220+
214221
for mono_item in mono_items {
215222
// Handle only root (GloballyShared) items directly here. Inlined (LocalCopy) items
216223
// are handled at the bottom of the loop based on reachability, with one exception.
@@ -219,7 +226,8 @@ where
219226
match mono_item.instantiation_mode(cx.tcx) {
220227
InstantiationMode::GloballyShared { .. } => {}
221228
InstantiationMode::LocalCopy => {
222-
if Some(mono_item.def_id()) != cx.tcx.lang_items().start_fn() {
229+
let def_id = mono_item.def_id();
230+
if ![start_fn, entry_fn].contains(&Some(def_id)) {
223231
continue;
224232
}
225233
}
@@ -241,7 +249,7 @@ where
241249

242250
let cgu = codegen_units.entry(cgu_name).or_insert_with(|| CodegenUnit::new(cgu_name));
243251

244-
let mut can_be_internalized = true;
252+
let mut can_be_internalized = false;
245253
let (linkage, visibility) = mono_item_linkage_and_visibility(
246254
cx.tcx,
247255
&mono_item,
@@ -256,6 +264,9 @@ where
256264
cgu.items_mut()
257265
.insert(mono_item, MonoItemData { inlined: false, linkage, visibility, size_estimate });
258266

267+
if cx.tcx.building_mir_only_lib() {
268+
continue;
269+
}
259270
// Get all inlined items that are reachable from `mono_item` without
260271
// going via another root item. This includes drop-glue, functions from
261272
// external crates, and local functions the definition of which is

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,8 @@ options! {
17051705
mir_keep_place_mention: bool = (false, parse_bool, [TRACKED],
17061706
"keep place mention MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
17071707
(default: no)"),
1708+
mir_only_libs: bool = (false, parse_bool, [TRACKED],
1709+
"only generate MIR when building libraries (default: no)"),
17081710
#[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
17091711
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
17101712
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),

0 commit comments

Comments
 (0)