Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a hook for should_codegen_locally #127779

Merged
merged 3 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ use std::mem;
use cranelift_codegen::ir::{ArgumentPurpose, SigRef};
use cranelift_codegen::isa::CallConv;
use cranelift_module::ModuleError;
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::TypeVisitableExt;
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_target::abi::call::{Conv, FnAbi, PassMode};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use cranelift_codegen::CodegenError;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use cranelift_module::ModuleError;
use rustc_ast::InlineAsmOptions;
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
use rustc_index::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::TypeVisitableExt;
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;

use crate::constant::ConstantCx;
use crate::debuginfo::{FunctionDebugContext, TypeDebugContext};
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_codegen_cranelift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ extern crate rustc_hir;
extern crate rustc_incremental;
extern crate rustc_index;
extern crate rustc_metadata;
extern crate rustc_monomorphize;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
Expand Down
28 changes: 28 additions & 0 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,34 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
ongoing_codegen
}

/// Returns whether a call from the current crate to the [`Instance`] would produce a call
/// from `compiler_builtins` to a symbol the linker must resolve.
///
/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some
/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
/// unlinkable calls.
///
/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker.
pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
) -> bool {
fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name {
name.as_str().starts_with("llvm.")
} else {
false
}
}

let def_id = instance.def_id();
!def_id.is_local()
&& tcx.is_compiler_builtins(LOCAL_CRATE)
&& !is_llvm_intrinsic(tcx, def_id)
&& !tcx.should_codegen_locally(instance)
}

impl CrateInfo {
pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
let crate_types = tcx.crate_types().to_vec();
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::operand::OperandValue::{Immediate, Pair, Ref, ZeroSized};
use super::place::{PlaceRef, PlaceValue};
use super::{CachedLlbb, FunctionCx, LocalRef};

use crate::base;
use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization};
use crate::common::{self, IntPredicate};
use crate::errors::CompilerBuiltinsCannotCall;
use crate::meth;
Expand All @@ -18,7 +18,6 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, span_bug};
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
use rustc_session::config::OptLevel;
use rustc_span::{source_map::Spanned, sym, Span};
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/hooks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ declare_hooks! {

/// Create a list-like THIR representation for debugging.
hook thir_flat(key: LocalDefId) -> String;

/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
/// can just link to the upstream crate and therefore don't need a mono item.
hook should_codegen_locally(instance: crate::ty::Instance<'tcx>) -> bool;
}

#[cold]
Expand Down
39 changes: 22 additions & 17 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ use rustc_middle::ty::{
self, AssocKind, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable,
TypeVisitableExt, VtblEntry,
};
use rustc_middle::util::Providers;
use rustc_middle::{bug, span_bug};
use rustc_session::config::EntryFnType;
use rustc_session::Limit;
Expand Down Expand Up @@ -399,7 +400,7 @@ fn collect_items_rec<'tcx>(
let instance = Instance::mono(tcx, def_id);

// Sanity check whether this ended up being collected accidentally
debug_assert!(should_codegen_locally(tcx, instance));
debug_assert!(tcx.should_codegen_locally(instance));

let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() };
// Nested statics have no type.
Expand Down Expand Up @@ -431,7 +432,7 @@ fn collect_items_rec<'tcx>(
}
MonoItem::Fn(instance) => {
// Sanity check whether this ended up being collected accidentally
debug_assert!(should_codegen_locally(tcx, instance));
debug_assert!(tcx.should_codegen_locally(instance));

// Keep track of the monomorphization recursion depth
recursion_depth_reset = Some(check_recursion_limit(
Expand Down Expand Up @@ -475,7 +476,7 @@ fn collect_items_rec<'tcx>(
}
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
let instance = Instance::mono(tcx, *def_id);
if should_codegen_locally(tcx, instance) {
if tcx.should_codegen_locally(instance) {
trace!("collecting static {:?}", def_id);
used_items.push(dummy_spanned(MonoItem::Static(*def_id)));
}
Expand Down Expand Up @@ -712,7 +713,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
if let ty::Closure(def_id, args) = *source_ty.kind() {
let instance =
Instance::resolve_closure(self.tcx, def_id, args, ty::ClosureKind::FnOnce);
if should_codegen_locally(self.tcx, instance) {
if self.tcx.should_codegen_locally(instance) {
self.used_items.push(create_fn_mono_item(self.tcx, instance, span));
}
} else {
Expand All @@ -722,7 +723,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
mir::Rvalue::ThreadLocalRef(def_id) => {
assert!(self.tcx.is_thread_local_static(def_id));
let instance = Instance::mono(self.tcx, def_id);
if should_codegen_locally(self.tcx, instance) {
if self.tcx.should_codegen_locally(instance) {
trace!("collecting thread-local static {:?}", def_id);
self.used_items.push(respan(span, MonoItem::Static(def_id)));
}
Expand All @@ -749,7 +750,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
let tcx = self.tcx;
let push_mono_lang_item = |this: &mut Self, lang_item: LangItem| {
let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source)));
if should_codegen_locally(tcx, instance) {
if tcx.should_codegen_locally(instance) {
this.used_items.push(create_fn_mono_item(tcx, instance, source));
}
};
Expand Down Expand Up @@ -783,7 +784,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
}
mir::InlineAsmOperand::SymStatic { def_id } => {
let instance = Instance::mono(self.tcx, def_id);
if should_codegen_locally(self.tcx, instance) {
if self.tcx.should_codegen_locally(instance) {
trace!("collecting asm sym static {:?}", def_id);
self.used_items.push(respan(source, MonoItem::Static(def_id)));
}
Expand Down Expand Up @@ -873,7 +874,7 @@ fn visit_instance_use<'tcx>(
output: &mut MonoItems<'tcx>,
) {
debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call);
if !should_codegen_locally(tcx, instance) {
if !tcx.should_codegen_locally(instance) {
return;
}
if let ty::InstanceKind::Intrinsic(def_id) = instance.def {
Expand All @@ -885,13 +886,13 @@ fn visit_instance_use<'tcx>(
// codegen a call to that function without generating code for the function itself.
let def_id = tcx.require_lang_item(LangItem::PanicNounwind, None);
let panic_instance = Instance::mono(tcx, def_id);
if should_codegen_locally(tcx, panic_instance) {
if tcx.should_codegen_locally(panic_instance) {
output.push(create_fn_mono_item(tcx, panic_instance, source));
}
} else if tcx.has_attr(def_id, sym::rustc_intrinsic) {
// Codegen the fallback body of intrinsics with fallback bodies
let instance = ty::Instance::new(def_id, instance.args);
if should_codegen_locally(tcx, instance) {
if tcx.should_codegen_locally(instance) {
output.push(create_fn_mono_item(tcx, instance, source));
}
}
Expand Down Expand Up @@ -930,7 +931,7 @@ fn visit_instance_use<'tcx>(

/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
/// can just link to the upstream crate and therefore don't need a mono item.
pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool {
fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -> bool {
let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else {
return true;
};
Expand All @@ -946,7 +947,7 @@ pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance
}

if tcx.is_reachable_non_generic(def_id)
|| instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some()
|| instance.polymorphize(*tcx).upstream_monomorphization(*tcx).is_some()
{
// We can link to the item in question, no instance needed in this crate.
return false;
Expand Down Expand Up @@ -1127,7 +1128,7 @@ fn create_mono_items_for_vtable_methods<'tcx>(
None
}
VtblEntry::Method(instance) => {
Some(*instance).filter(|instance| should_codegen_locally(tcx, *instance))
Some(*instance).filter(|instance| tcx.should_codegen_locally(*instance))
}
})
.map(|item| create_fn_mono_item(tcx, item, source));
Expand All @@ -1144,7 +1145,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
GlobalAlloc::Static(def_id) => {
assert!(!tcx.is_thread_local_static(def_id));
let instance = Instance::mono(tcx, def_id);
if should_codegen_locally(tcx, instance) {
if tcx.should_codegen_locally(instance) {
trace!("collecting static {:?}", def_id);
output.push(dummy_spanned(MonoItem::Static(def_id)));
}
Expand All @@ -1162,7 +1163,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
}
}
GlobalAlloc::Function { instance, .. } => {
if should_codegen_locally(tcx, instance) {
if tcx.should_codegen_locally(instance) {
trace!("collecting {:?} with {:#?}", alloc_id, instance);
output.push(create_fn_mono_item(tcx, instance, DUMMY_SP));
}
Expand Down Expand Up @@ -1284,7 +1285,7 @@ fn visit_mentioned_item<'tcx>(
if let ty::Closure(def_id, args) = *source_ty.kind() {
let instance =
Instance::resolve_closure(tcx, def_id, args, ty::ClosureKind::FnOnce);
if should_codegen_locally(tcx, instance) {
if tcx.should_codegen_locally(instance) {
output.push(create_fn_mono_item(tcx, instance, span));
}
} else {
Expand Down Expand Up @@ -1557,7 +1558,7 @@ fn create_mono_items_for_default_impls<'tcx>(
let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, DUMMY_SP);

let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) {
if mono_item.node.is_instantiable(tcx) && tcx.should_codegen_locally(instance) {
output.push(mono_item);
}
}
Expand Down Expand Up @@ -1613,3 +1614,7 @@ pub(crate) fn collect_crate_mono_items<'tcx>(

(mono_items, state.usage_map.into_inner())
}

pub fn provide(providers: &mut Providers) {
providers.hooks.should_codegen_locally = should_codegen_locally;
}
37 changes: 2 additions & 35 deletions compiler/rustc_monomorphize/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@

use rustc_hir::lang_items::LangItem;
use rustc_middle::bug;
use rustc_middle::query::{Providers, TyCtxtAt};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::traits;
use rustc_middle::ty::adjustment::CustomCoerceUnsized;
use rustc_middle::ty::Instance;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, Ty};
use rustc_span::def_id::DefId;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_middle::util::Providers;
use rustc_span::ErrorGuaranteed;

mod collector;
Expand All @@ -21,8 +18,6 @@ mod partitioning;
mod polymorphize;
mod util;

use collector::should_codegen_locally;

rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

fn custom_coerce_unsize_info<'tcx>(
Expand All @@ -47,34 +42,6 @@ fn custom_coerce_unsize_info<'tcx>(
}
}

/// Returns whether a call from the current crate to the [`Instance`] would produce a call
/// from `compiler_builtins` to a symbol the linker must resolve.
///
/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some
/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
/// unlinkable calls.
///
/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker.
pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
) -> bool {
fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name {
name.as_str().starts_with("llvm.")
} else {
false
}
}

let def_id = instance.def_id();
!def_id.is_local()
&& tcx.is_compiler_builtins(LOCAL_CRATE)
&& !is_llvm_intrinsic(tcx, def_id)
&& !should_codegen_locally(tcx, instance)
}

pub fn provide(providers: &mut Providers) {
partitioning::provide(providers);
polymorphize::provide(providers);
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_monomorphize/src/partitioning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ use rustc_middle::mir::mono::{
CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, Linkage, MonoItem, MonoItemData,
Visibility,
};
use rustc_middle::query::Providers;
use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths};
use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceKind, TyCtxt};
use rustc_middle::util::Providers;
use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath};
use rustc_session::CodegenUnits;
use rustc_span::symbol::Symbol;
Expand Down Expand Up @@ -1314,4 +1314,6 @@ pub fn provide(providers: &mut Providers) {
.find(|cgu| cgu.name() == name)
.unwrap_or_else(|| panic!("failed to find cgu with name {name:?}"))
};

collector::provide(providers);
}
Loading