diff options
| author | bors <bors@rust-lang.org> | 2022-07-02 11:24:17 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-07-02 11:24:17 +0000 |
| commit | 0075bb4fad68e64b6d1be06bf2db366c30bc75e1 (patch) | |
| tree | a5160fdc5cce917dc6bae3cb99277dab7b37e279 /compiler | |
| parent | aedf78e56b2279cc869962feac5153b6ba7001ed (diff) | |
| parent | cbbf06b0cd39dc93033568f1e65f5363cbbdebcd (diff) | |
| download | rust-0075bb4fad68e64b6d1be06bf2db366c30bc75e1.tar.gz rust-0075bb4fad68e64b6d1be06bf2db366c30bc75e1.zip | |
Auto merge of #91743 - cjgillot:enable_mir_inlining_inline_all, r=oli-obk
Enable MIR inlining Continuation of https://github.com/rust-lang/rust/pull/82280 by `@wesleywiser.` #82280 has shown nice compile time wins could be obtained by enabling MIR inlining. Most of the issues in https://github.com/rust-lang/rust/issues/81567 are now fixed, except the interaction with polymorphization which is worked around specifically. I believe we can proceed with enabling MIR inlining in the near future (preferably just after beta branching, in case we discover new issues). Steps before merging: - [x] figure out the interaction with polymorphization; - [x] figure out how miri should deal with extern types; - [x] silence the extra arithmetic overflow warnings; - [x] remove the codegen fulfilment ICE; - [x] remove the type normalization ICEs while compiling nalgebra; - [ ] tweak the inlining threshold.
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_codegen_cranelift/src/base.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/cast.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/util.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/instance.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/normalize_erasing_regions.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/inline.rs | 100 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/inline/cycle.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_monomorphize/src/collector.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_ty_utils/src/instance.rs | 4 |
10 files changed, 107 insertions, 58 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index fbe830b2b10..fa4ea426385 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -686,6 +686,7 @@ fn codegen_stmt<'tcx>( substs, ty::ClosureKind::FnOnce, ) + .expect("failed to normalize and resolve closure during codegen") .polymorphize(fx.tcx); let func_ref = fx.get_function_ref(instance); let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 81c1897694c..a5806d64d43 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -213,6 +213,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { substs, ty::ClosureKind::FnOnce, ) + .expect("failed to normalize and resolve closure during codegen") .polymorphize(bx.cx().tcx()); OperandValue::Immediate(bx.cx().get_fn_addr(instance)) } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 2e6c7f47ac1..d09ab5fa3e8 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -100,7 +100,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { def_id, substs, ty::ClosureKind::FnOnce, - ); + ) + .ok_or_else(|| err_inval!(TooGeneric))?; let fn_ptr = self.create_fn_alloc_ptr(FnVal::Instance(instance)); self.write_pointer(fn_ptr, dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index b9866995e9f..9d7905ed9a8 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -44,22 +44,10 @@ where let is_used = unused_params.contains(index).map_or(true, |unused| !unused); // Only recurse when generic parameters in fns, closures and generators // are used and require substitution. - match (is_used, subst.needs_subst()) { - // Just in case there are closures or generators within this subst, - // recurse. - (true, true) => return subst.visit_with(self), - // Confirm that polymorphization replaced the parameter with - // `ty::Param`/`ty::ConstKind::Param`. - (false, true) if cfg!(debug_assertions) => match subst.unpack() { - ty::subst::GenericArgKind::Type(ty) => { - assert!(matches!(ty.kind(), ty::Param(_))) - } - ty::subst::GenericArgKind::Const(ct) => { - assert!(matches!(ct.kind(), ty::ConstKind::Param(_))) - } - ty::subst::GenericArgKind::Lifetime(..) => (), - }, - _ => {} + // Just in case there are closures or generators within this subst, + // recurse. + if is_used && subst.needs_subst() { + return subst.visit_with(self); } } ControlFlow::CONTINUE diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index e8dd179eac1..0e10fe25c10 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -496,12 +496,12 @@ impl<'tcx> Instance<'tcx> { def_id: DefId, substs: ty::SubstsRef<'tcx>, requested_kind: ty::ClosureKind, - ) -> Instance<'tcx> { + ) -> Option<Instance<'tcx>> { let actual_kind = substs.as_closure().kind(); match needs_fn_once_adapter_shim(actual_kind, requested_kind) { Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, substs), - _ => Instance::new(def_id, substs), + _ => Some(Instance::new(def_id, substs)), } } @@ -515,7 +515,7 @@ impl<'tcx> Instance<'tcx> { tcx: TyCtxt<'tcx>, closure_did: DefId, substs: ty::SubstsRef<'tcx>, - ) -> Instance<'tcx> { + ) -> Option<Instance<'tcx>> { debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, substs); let fn_once = tcx.require_lang_item(LangItem::FnOnce, None); let call_once = tcx @@ -531,12 +531,13 @@ impl<'tcx> Instance<'tcx> { let self_ty = tcx.mk_closure(closure_did, substs); let sig = substs.as_closure().sig(); - let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); + let sig = + tcx.try_normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig).ok()?; assert_eq!(sig.inputs().len(), 1); let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]); debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); - Instance { def, substs } + Some(Instance { def, substs }) } /// Depending on the kind of `InstanceDef`, the MIR body associated with an diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 66a0a192a87..9d8a8116594 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -112,6 +112,26 @@ impl<'tcx> TyCtxt<'tcx> { self.normalize_erasing_regions(param_env, value) } + /// If you have a `Binder<'tcx, T>`, you can do this to strip out the + /// late-bound regions and then normalize the result, yielding up + /// a `T` (with regions erased). This is appropriate when the + /// binder is being instantiated at the call site. + /// + /// N.B., currently, higher-ranked type bounds inhibit + /// normalization. Therefore, each time we erase them in + /// codegen, we need to normalize the contents. + pub fn try_normalize_erasing_late_bound_regions<T>( + self, + param_env: ty::ParamEnv<'tcx>, + value: ty::Binder<'tcx, T>, + ) -> Result<T, NormalizationError<'tcx>> + where + T: TypeFoldable<'tcx>, + { + let value = self.erase_late_bound_regions(value); + self.try_normalize_erasing_regions(param_env, value) + } + /// Monomorphizes a type from the AST by first applying the /// in-scope substitutions and then normalizing any associated /// types. diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 49403ba03a4..ce387cb4453 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1,14 +1,15 @@ //! Inlining pass for MIR functions use crate::deref_separator::deref_finder; use rustc_attr::InlineAttr; +use rustc_const_eval::transform::validate::equal_up_to_regions; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::traits::ObligationCause; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; +use rustc_session::config::OptLevel; use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span}; use rustc_target::spec::abi::Abi; @@ -43,7 +44,15 @@ impl<'tcx> MirPass<'tcx> for Inline { return enabled; } - sess.opts.mir_opt_level() >= 3 + match sess.mir_opt_level() { + 0 | 1 => false, + 2 => { + (sess.opts.optimize == OptLevel::Default + || sess.opts.optimize == OptLevel::Aggressive) + && sess.opts.incremental == None + } + _ => true, + } } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -76,13 +85,6 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { } let param_env = tcx.param_env_reveal_all_normalized(def_id); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let param_env = rustc_trait_selection::traits::normalize_param_env_or_error( - tcx, - def_id.to_def_id(), - param_env, - ObligationCause::misc(body.span, hir_id), - ); let mut this = Inliner { tcx, @@ -166,6 +168,45 @@ impl<'tcx> Inliner<'tcx> { return Err("failed to normalize callee body"); }; + // Check call signature compatibility. + // Normally, this shouldn't be required, but trait normalization failure can create a + // validation ICE. + let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); + let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; + let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty; + let output_type = callee_body.return_ty(); + if !equal_up_to_regions(self.tcx, self.param_env, output_type, destination_ty) { + trace!(?output_type, ?destination_ty); + return Err("failed to normalize return type"); + } + if callsite.fn_sig.abi() == Abi::RustCall { + let mut args = args.into_iter(); + let _ = args.next(); // Skip `self` argument. + let arg_tuple_ty = args.next().unwrap().ty(&caller_body.local_decls, self.tcx); + assert!(args.next().is_none()); + + let ty::Tuple(arg_tuple_tys) = arg_tuple_ty.kind() else { + bug!("Closure arguments are not passed as a tuple"); + }; + + for (arg_ty, input) in arg_tuple_tys.iter().zip(callee_body.args_iter().skip(1)) { + let input_type = callee_body.local_decls[input].ty; + if !equal_up_to_regions(self.tcx, self.param_env, arg_ty, input_type) { + trace!(?arg_ty, ?input_type); + return Err("failed to normalize tuple argument type"); + } + } + } else { + for (arg, input) in args.iter().zip(callee_body.args_iter()) { + let input_type = callee_body.local_decls[input].ty; + let arg_ty = arg.ty(&caller_body.local_decls, self.tcx); + if !equal_up_to_regions(self.tcx, self.param_env, arg_ty, input_type) { + trace!(?arg_ty, ?input_type); + return Err("failed to normalize argument type"); + } + } + } + let old_blocks = caller_body.basic_blocks().next_index(); self.inline_call(caller_body, &callsite, callee_body); let new_blocks = old_blocks..caller_body.basic_blocks().next_index(); @@ -263,6 +304,10 @@ impl<'tcx> Inliner<'tcx> { return None; } + if self.history.contains(&callee) { + return None; + } + let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs); return Some(CallSite { @@ -285,8 +330,14 @@ impl<'tcx> Inliner<'tcx> { callsite: &CallSite<'tcx>, callee_attrs: &CodegenFnAttrs, ) -> Result<(), &'static str> { - if let InlineAttr::Never = callee_attrs.inline { - return Err("never inline hint"); + match callee_attrs.inline { + InlineAttr::Never => return Err("never inline hint"), + InlineAttr::Always | InlineAttr::Hint => {} + InlineAttr::None => { + if self.tcx.sess.mir_opt_level() <= 2 { + return Err("at mir-opt-level=2, only #[inline] is inlined"); + } + } } // Only inline local functions if they would be eligible for cross-crate @@ -407,22 +458,9 @@ impl<'tcx> Inliner<'tcx> { } TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => { - if let ty::FnDef(def_id, substs) = + if let ty::FnDef(def_id, _) = *callsite.callee.subst_mir(self.tcx, &f.literal.ty()).kind() { - if let Ok(substs) = - self.tcx.try_normalize_erasing_regions(self.param_env, substs) - { - if let Ok(Some(instance)) = - Instance::resolve(self.tcx, self.param_env, def_id, substs) - { - if callsite.callee.def_id() == instance.def_id() { - return Err("self-recursion"); - } else if self.history.contains(&instance) { - return Err("already inlined"); - } - } - } // Don't give intrinsics the extra penalty for calls if tcx.is_intrinsic(def_id) { cost += INSTR_COST; @@ -482,14 +520,12 @@ impl<'tcx> Inliner<'tcx> { if let InlineAttr::Always = callee_attrs.inline { debug!("INLINING {:?} because inline(always) [cost={}]", callsite, cost); Ok(()) + } else if cost <= threshold { + debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold); + Ok(()) } else { - if cost <= threshold { - debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold); - Ok(()) - } else { - debug!("NOT inlining {:?} [cost={} > threshold={}]", callsite, cost, threshold); - Err("cost above threshold") - } + debug!("NOT inlining {:?} [cost={} > threshold={}]", callsite, cost, threshold); + Err("cost above threshold") } } diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index fd7de2bd1dc..ee4a6bfba0e 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -48,7 +48,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping"); continue; }; - let Some(callee) = ty::Instance::resolve(tcx, param_env, callee, substs).unwrap() else { + let Ok(Some(callee)) = ty::Instance::resolve(tcx, param_env, callee, substs) else { trace!(?callee, "cannot resolve, skipping"); continue; }; diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 3f082896ccf..b9936e35b77 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -730,7 +730,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { def_id, substs, ty::ClosureKind::FnOnce, - ); + ) + .expect("failed to normalize and resolve closure during codegen"); if should_codegen_locally(self.tcx, &instance) { self.output.push(create_fn_mono_item(self.tcx, instance, span)); } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 552db5406df..d08fe6dada1 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -332,12 +332,12 @@ fn resolve_associated_item<'tcx>( }), traits::ImplSource::Closure(closure_data) => { let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap(); - Some(Instance::resolve_closure( + Instance::resolve_closure( tcx, closure_data.closure_def_id, closure_data.substs, trait_closure_kind, - )) + ) } traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() { ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { |
