X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=compiler%2Frustc_mir%2Fsrc%2Ftransform%2Fmod.rs;h=717479b999076c1d5c16e610608999da80ce78cd;hb=3af7989a7ce0ef0d6bc9b8a6950f90abbf63ac76;hp=e86d11e248fceb3562eae8fa3e88970fd003d0b1;hpb=8fde4be7d042a348387a82832a44076cfbf334ca;p=rust.git diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index e86d11e248f..717479b9990 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -21,6 +21,7 @@ pub mod check_packed_ref; pub mod check_unsafety; pub mod cleanup_post_borrowck; +pub mod const_debuginfo; pub mod const_prop; pub mod coverage; pub mod deaggregator; @@ -70,9 +71,11 @@ pub(crate) fn provide(providers: &mut Providers) { }, mir_promoted, mir_drops_elaborated_and_const_checked, + mir_for_ctfe, + mir_for_ctfe_of_const_arg, optimized_mir, - optimized_mir_of_const_arg, is_mir_available, + is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did), promoted_mir: |tcx, def_id| { let def_id = def_id.expect_local(); if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { @@ -277,6 +280,7 @@ fn mir_const<'tcx>( tcx.alloc_steal_mir(body) } +/// Compute the main MIR body and the list of MIR bodies of the promoteds. fn mir_promoted( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, @@ -318,6 +322,72 @@ fn mir_promoted( (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted)) } +/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it) +fn mir_for_ctfe<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> { + let did = def_id.expect_local(); + if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) { + tcx.mir_for_ctfe_of_const_arg(def) + } else { + tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(did))) + } +} + +/// Same as `mir_for_ctfe`, but used to get the MIR of a const generic parameter. +/// The docs on `WithOptConstParam` explain this a bit more, but the TLDR is that +/// we'd get cycle errors with `mir_for_ctfe`, because typeck would need to typeck +/// the const parameter while type checking the main body, which in turn would try +/// to type check the main body again. +fn mir_for_ctfe_of_const_arg<'tcx>( + tcx: TyCtxt<'tcx>, + (did, param_did): (LocalDefId, DefId), +) -> &'tcx Body<'tcx> { + tcx.arena.alloc(inner_mir_for_ctfe( + tcx, + ty::WithOptConstParam { did, const_param_did: Some(param_did) }, + )) +} + +fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_> { + // FIXME: don't duplicate this between the optimized_mir/mir_for_ctfe queries + if tcx.is_constructor(def.did.to_def_id()) { + // There's no reason to run all of the MIR passes on constructors when + // we can just output the MIR we want directly. This also saves const + // qualification and borrow checking the trouble of special casing + // constructors. + return shim::build_adt_ctor(tcx, def.did.to_def_id()); + } + + assert_ne!( + tcx.hir().body_const_context(def.did), + None, + "mir_for_ctfe should not be used for runtime functions" + ); + + let mut body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone(); + + #[rustfmt::skip] + let optimizations: &[&dyn MirPass<'_>] = &[ + &const_prop::ConstProp, + ]; + + #[rustfmt::skip] + run_passes( + tcx, + &mut body, + MirPhase::Optimization, + &[ + optimizations, + ], + ); + + debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE"); + + body +} + +/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs +/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't +/// end up missing the source MIR due to stealing happening. fn mir_drops_elaborated_and_const_checked<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, @@ -363,6 +433,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tc // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late, // but before optimizations begin. &add_retag::AddRetag, + &lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops"), // `Deaggregator` is conceptually part of MIR building, some backends rely on it happening // and it can help optimizations. @@ -391,7 +462,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // The main optimizations that we do on MIR. let optimizations: &[&dyn MirPass<'tcx>] = &[ - &lower_intrinsics::LowerIntrinsics, &remove_unneeded_drops::RemoveUnneededDrops, &match_branches::MatchBranchSimplification, // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) @@ -408,6 +478,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::new("final"), &nrvo::RenameReturnPlace, + &const_debuginfo::ConstDebugInfo, &simplify::SimplifyLocals, &multiple_return_terminators::MultipleReturnTerminators, ]; @@ -454,35 +525,32 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { ); } +/// Optimize the MIR and prepare it for codegen. fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> { let did = did.expect_local(); - if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) { - tcx.optimized_mir_of_const_arg(def) - } else { - tcx.arena.alloc(inner_optimized_mir(tcx, ty::WithOptConstParam::unknown(did))) - } -} - -fn optimized_mir_of_const_arg<'tcx>( - tcx: TyCtxt<'tcx>, - (did, param_did): (LocalDefId, DefId), -) -> &'tcx Body<'tcx> { - tcx.arena.alloc(inner_optimized_mir( - tcx, - ty::WithOptConstParam { did, const_param_did: Some(param_did) }, - )) + assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None); + tcx.arena.alloc(inner_optimized_mir(tcx, did)) } -fn inner_optimized_mir(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_> { - if tcx.is_constructor(def.did.to_def_id()) { +fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { + if tcx.is_constructor(did.to_def_id()) { // There's no reason to run all of the MIR passes on constructors when // we can just output the MIR we want directly. This also saves const // qualification and borrow checking the trouble of special casing // constructors. - return shim::build_adt_ctor(tcx, def.did.to_def_id()); + return shim::build_adt_ctor(tcx, did.to_def_id()); } - let mut body = tcx.mir_drops_elaborated_and_const_checked(def).steal(); + match tcx.hir().body_const_context(did) { + // Run the `mir_for_ctfe` query, which depends on `mir_drops_elaborated_and_const_checked` + // which we are going to steal below. Thus we need to run `mir_for_ctfe` first, so it + // computes and caches its result. + Some(hir::ConstContext::ConstFn) => tcx.ensure().mir_for_ctfe(did), + None => {} + Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other), + } + let mut body = + tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal(); run_optimization_passes(tcx, &mut body); debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR"); @@ -490,6 +558,8 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) body } +/// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for +/// constant evaluation once all substitutions become known. fn promoted_mir<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, @@ -508,7 +578,6 @@ fn promoted_mir<'tcx>( for body in &mut promoted { run_post_borrowck_cleanup_passes(tcx, body); - run_optimization_passes(tcx, body); } debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");