@@ -31,7 +31,7 @@ use rustc_middle::mir::{
3131 Location , MirPhase , NullOp , Operand , Place , ProjectionElem , Promoted , RuntimePhase , Rvalue ,
3232 START_BLOCK , SourceInfo , Statement , StatementKind , TerminatorKind ,
3333} ;
34- use rustc_middle:: ty:: { self , Instance , TyCtxt , TypeVisitableExt } ;
34+ use rustc_middle:: ty:: { self , GenericParamDefKind , Instance , TyCtxt , TypeVisitableExt } ;
3535use rustc_middle:: util:: Providers ;
3636use rustc_middle:: { bug, query, span_bug} ;
3737use rustc_mir_build:: builder:: build_mir;
@@ -794,26 +794,47 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
794794
795795 run_optimization_passes ( tcx, & mut body) ;
796796
797- let mut vis = MonoCompatVisitor { contains_ubcheck : false } ;
798- vis. visit_body ( & body) ;
797+ // If the body is polymorphic, we're done. Otherwise, we're going to turn the body into codegen
798+ // MIR ahead of time, as an optimization.
799+ if tcx. generics_of ( did) . requires_monomorphization ( tcx) {
800+ return body;
801+ }
799802
800- // If the MIR is already monomorphic, we can transform it to codegen MIR right away.
801- if !tcx. generics_of ( did) . requires_monomorphization ( tcx)
802- && !vis. contains_ubcheck
803- && !body. has_aliases ( )
804- {
805- let instance = Instance :: mono ( tcx, did. into ( ) ) ;
806- body = instance. instantiate_mir_and_normalize_erasing_regions (
807- tcx,
808- ty:: TypingEnv :: fully_monomorphized ( ) ,
809- ty:: EarlyBinder :: bind ( body) ,
810- ) ;
803+ // If the body has impossible predicates, the normalization we need to do to turn this into
804+ // post-mono MIR will fail. So we detect that case and return just optimized MIR.
805+ let args = ty:: GenericArgs :: for_item ( tcx, did. into ( ) , |param, _| match param. kind {
806+ GenericParamDefKind :: Lifetime => tcx. lifetimes . re_erased . into ( ) ,
807+ GenericParamDefKind :: Type { .. } | GenericParamDefKind :: Const { .. } => {
808+ unreachable ! (
809+ "`requires_monomorphization` check means that we should have no type/const params"
810+ )
811+ }
812+ } ) ;
813+ if tcx. instantiate_and_check_impossible_predicates ( ( did. to_def_id ( ) , args) ) {
814+ return body;
815+ }
811816
812- // Monomoprhizing this body didn't reveal any new information that is useful for
813- // optimizations, so we just run passes that make the MIR ready for codegen backends.
814- pm:: run_passes_no_validate ( tcx, & mut body, & [ & add_call_guards:: CriticalCallEdges ] , None ) ;
817+ // If the body contains the UB check intrinsic that is only to be monomorphized at codegen
818+ // time, we cannot generate codegen MIR early. We want post-mono optimizations to optimize on
819+ // whether UB checks are enabled or disabled at codegen time.
820+ let mut vis = MonoCompatVisitor { contains_ubcheck : false , contains_generic_const : false } ;
821+ vis. visit_body ( & body) ;
822+ if vis. contains_ubcheck {
823+ return body;
815824 }
816825
826+ let instance = Instance :: mono ( tcx, did. to_def_id ( ) ) ;
827+ body = instance. instantiate_mir_and_normalize_erasing_regions (
828+ tcx,
829+ ty:: TypingEnv :: fully_monomorphized ( ) ,
830+ ty:: EarlyBinder :: bind ( body) ,
831+ ) ;
832+
833+ // Monomoprhizing this body didn't reveal any new information that is useful for
834+ // optimizations, so we just run passes that make the MIR ready for codegen backends.
835+ pm:: run_passes_no_validate ( tcx, & mut body, & [ & add_call_guards:: CriticalCallEdges ] , None ) ;
836+ body. is_codegen_mir = true ;
837+
817838 body
818839}
819840
@@ -822,6 +843,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
822843// Currently, it looks for NullOp::UbChecks because that must be resolved at codegen.
823844struct MonoCompatVisitor {
824845 contains_ubcheck : bool ,
846+ contains_generic_const : bool ,
825847}
826848
827849impl < ' tcx > Visitor < ' tcx > for MonoCompatVisitor {
@@ -831,25 +853,43 @@ impl<'tcx> Visitor<'tcx> for MonoCompatVisitor {
831853 }
832854 self . super_rvalue ( rvalue, location) ;
833855 }
856+
857+ fn visit_const_operand ( & mut self , constant : & ConstOperand < ' tcx > , location : Location ) {
858+ if constant. has_non_region_param ( ) {
859+ self . contains_generic_const = true ;
860+ }
861+ self . super_const_operand ( constant, location) ;
862+ }
834863}
835864
836865pub fn build_codegen_mir < ' tcx > ( tcx : TyCtxt < ' tcx > , instance : Instance < ' tcx > ) -> & ' tcx Body < ' tcx > {
837866 let body = tcx. instance_mir ( instance. def ) ;
838867
839- let mut vis = MonoCompatVisitor { contains_ubcheck : false } ;
840- vis. visit_body ( & body) ;
868+ // If we have generic params, assert that we didn't get codegen MIR out of instance_mir
869+ if instance. args . non_erasable_generics ( ) . next ( ) . is_some ( ) {
870+ assert ! ( !body. is_codegen_mir) ;
871+ }
872+
873+ let body = if !body. is_codegen_mir {
874+ let mut vis = MonoCompatVisitor { contains_ubcheck : false , contains_generic_const : false } ;
875+ vis. visit_body ( & body) ;
841876
842- // MIR for monomorphic defs has already been fully optimized in optimized_mir.
843- let body = if instance. args . non_erasable_generics ( ) . next ( ) . is_some ( )
844- || vis. contains_ubcheck
845- || body. has_aliases ( )
846- {
847877 let mut body = instance. instantiate_mir_and_normalize_erasing_regions (
848878 tcx,
849879 ty:: TypingEnv :: fully_monomorphized ( ) ,
850880 ty:: EarlyBinder :: bind ( body. clone ( ) ) ,
851881 ) ;
852- transform_to_codegen_mir ( tcx, & mut body) ;
882+ if vis. contains_ubcheck || vis. contains_generic_const {
883+ transform_to_codegen_mir ( tcx, & mut body) ;
884+ } else {
885+ pm:: run_passes_no_validate (
886+ tcx,
887+ & mut body,
888+ & [ & add_call_guards:: CriticalCallEdges ] ,
889+ None ,
890+ ) ;
891+ }
892+ body. is_codegen_mir = true ;
853893 tcx. arena . alloc ( body)
854894 } else {
855895 body
0 commit comments