Skip to content

Commit

Permalink
(crudely) implement MIR-only rlibs
Browse files Browse the repository at this point in the history
  • Loading branch information
saethlin committed Jan 10, 2024
1 parent 75c68cf commit 741a7a7
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 15 deletions.
10 changes: 8 additions & 2 deletions compiler/rustc_codegen_ssa/src/back/symbol_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,14 @@ fn exported_symbols_provider_local(
if allocator_kind_for_codegen(tcx).is_some() {
for symbol_name in ALLOCATOR_METHODS
.iter()
.map(|method| format!("__rust_{}", method.name))
.chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()])
.flat_map(|method| {
[format!("__rust_{}", method.name), format!("__rdl_{}", method.name)]
})
.chain([
"__rust_alloc_error_handler".to_string(),
OomStrategy::SYMBOL.to_string(),
"__rg_oom".to_string(),
])
{
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(mir_emit_retag, true);
tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
tracked!(mir_keep_place_mention, true);
tracked!(mir_only_libs, true);
tracked!(mir_opt_level, Some(4));
tracked!(move_size_limit, Some(4096));
tracked!(mutable_noalias, false);
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1037,12 +1037,13 @@ fn should_encode_mir(
reachable_set: &LocalDefIdSet,
def_id: LocalDefId,
) -> (bool, bool) {
let opts = &tcx.sess.opts;
let mir_required = opts.unstable_opts.always_encode_mir || opts.unstable_opts.mir_only_libs;
match tcx.def_kind(def_id) {
// Constructors
DefKind::Ctor(_, _) => {
let mir_opt_base = tcx.sess.opts.output_types.should_codegen()
|| tcx.sess.opts.unstable_opts.always_encode_mir;
(true, mir_opt_base)
let opt = mir_required || opts.output_types.should_codegen();
(true, opt)
}
// Constants
DefKind::AnonConst
Expand All @@ -1055,7 +1056,7 @@ fn should_encode_mir(
// Full-fledged functions + closures
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
let generics = tcx.generics_of(def_id);
let opt = tcx.sess.opts.unstable_opts.always_encode_mir
let opt = mir_required
|| (tcx.sess.opts.output_types.should_codegen()
&& reachable_set.contains(&def_id)
&& (generics.requires_monomorphization(tcx)
Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_middle/src/mir/mono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ impl<'tcx> MonoItem<'tcx> {
}

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

match *self {
MonoItem::Fn(ref instance) => {
// See the check in MirUsedCollector for building_mir_only_bin for background.
// Here, we need to give the symbols that the collector feeds to use GloballyShared
// linkage so that CGU partitioning doesn't try to assign them lazily, then find no
// uses of them. They might only be used by an upstream crate, so we need to force
// codegen, which is what GloballyShared does.
if tcx.building_mir_only_bin()
&& tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
{
return InstantiationMode::GloballyShared { may_conflict: false };
}

let entry_def_id = tcx.entry_fn(()).map(|(id, _)| id);
// If this function isn't inlined or otherwise has an extern
// indicator, then we'll be creating a globally shared version.
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,14 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn dcx(self) -> &'tcx DiagCtxt {
self.sess.dcx()
}

pub fn building_mir_only_lib(self) -> bool {
self.sess.opts.unstable_opts.mir_only_libs && self.crate_types() == &[CrateType::Rlib]
}

pub fn building_mir_only_bin(self) -> bool {
self.sess.opts.unstable_opts.mir_only_libs && self.crate_types() == &[CrateType::Executable]
}
}

impl<'tcx> TyCtxtAt<'tcx> {
Expand Down
56 changes: 49 additions & 7 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
use rustc_middle::mir::visit::Visitor as MirVisitor;
Expand Down Expand Up @@ -975,27 +976,36 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) ->
};

if tcx.is_foreign_item(def_id) {
// Foreign items are always linked against, there's no way of instantiating them.
return false;
if tcx.sess.opts.unstable_opts.mir_only_libs {
return tcx.is_mir_available(instance.def_id());
} else {
// Foreign items are always linked against, there's no way of instantiating them.
return false;
}
}

if tcx.sess.opts.unstable_opts.mir_only_libs {
let has_mir = tcx.is_mir_available(instance.def_id());
return has_mir || matches!(tcx.def_kind(instance.def_id()), DefKind::Static(_));
}

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

if let DefKind::Static(_) = tcx.def_kind(def_id) {
// We cannot monomorphize statics from upstream crates.
return false;
}

if tcx.is_reachable_non_generic(def_id)
|| instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some()
{
// We can link to the item in question, no instance needed in this crate.
return false;
}

if let DefKind::Static(_) = tcx.def_kind(def_id) {
// We cannot monomorphize statics from upstream crates.
return false;
}

if !tcx.is_mir_available(def_id) {
tcx.dcx().emit_fatal(NoOptimizedMir {
span: tcx.def_span(def_id),
Expand Down Expand Up @@ -1295,6 +1305,38 @@ impl<'v> RootCollector<'_, 'v> {
.unwrap();

self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP));

// An upstream extern function may be used anywhere in the dependency tree, so we
// cannot do any reachability analysis on them. We blindly monomorphize every
// extern function declared anywhere in our dependency tree. We must give them
// GloballyShared codegen because we don't know if the only call to an upstream
// extern function is also upstream: We don't have reachability information. All we
// can do is codegen all extern functions and pray for the linker to delete the
// ones that are reachable.
if self.tcx.building_mir_only_bin() {
for (symbol, _info) in
self.tcx.crates(()).into_iter().flat_map(|krate| self.tcx.exported_symbols(*krate))
{
let def_id = match symbol {
ExportedSymbol::NonGeneric(def_id) => def_id,
_ => {
eprintln!("Not handling exported symbol {:?}", symbol);
continue;
}
};
if self.tcx.def_kind(def_id) != DefKind::Fn {
eprintln!("Not handling exported def {:?}", def_id);
continue;
}
let instance = Instance::mono(self.tcx, *def_id);
// FIXME: This is probably not the right span. What is?
let item = create_fn_mono_item(self.tcx, instance, DUMMY_SP);
// FIXME: Do we need this check?
if !self.output.iter().any(|out| out.node.def_id() == *def_id) {
self.output.push(item);
}
}
}
}
}

Expand Down
15 changes: 13 additions & 2 deletions compiler/rustc_monomorphize/src/partitioning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ fn partition<'tcx, I>(
where
I: Iterator<Item = MonoItem<'tcx>>,
{
if tcx.sess.opts.unstable_opts.mir_only_libs {
assert!(tcx.building_mir_only_lib() || tcx.building_mir_only_bin());
}

let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");

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

let start_fn = cx.tcx.lang_items().start_fn();
let entry_fn = cx.tcx.entry_fn(()).map(|(id, _)| id);

for mono_item in mono_items {
// Handle only root (GloballyShared) items directly here. Inlined (LocalCopy) items
// are handled at the bottom of the loop based on reachability, with one exception.
Expand All @@ -219,7 +226,8 @@ where
match mono_item.instantiation_mode(cx.tcx) {
InstantiationMode::GloballyShared { .. } => {}
InstantiationMode::LocalCopy => {
if Some(mono_item.def_id()) != cx.tcx.lang_items().start_fn() {
let def_id = mono_item.def_id();
if ![start_fn, entry_fn].contains(&Some(def_id)) {
continue;
}
}
Expand All @@ -241,7 +249,7 @@ where

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

let mut can_be_internalized = true;
let mut can_be_internalized = false;
let (linkage, visibility) = mono_item_linkage_and_visibility(
cx.tcx,
&mono_item,
Expand All @@ -256,6 +264,9 @@ where
cgu.items_mut()
.insert(mono_item, MonoItemData { inlined: false, linkage, visibility, size_estimate });

if cx.tcx.building_mir_only_lib() {
continue;
}
// Get all inlined items that are reachable from `mono_item` without
// going via another root item. This includes drop-glue, functions from
// external crates, and local functions the definition of which is
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1705,6 +1705,8 @@ options! {
mir_keep_place_mention: bool = (false, parse_bool, [TRACKED],
"keep place mention MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
(default: no)"),
mir_only_libs: bool = (false, parse_bool, [TRACKED],
"only generate MIR when building libraries (default: no)"),
#[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
Expand Down

0 comments on commit 741a7a7

Please sign in to comment.