@@ -31,7 +31,7 @@ use rustc_middle::mir::{
31
31
Location , MirPhase , NullOp , Operand , Place , ProjectionElem , Promoted , RuntimePhase , Rvalue ,
32
32
START_BLOCK , SourceInfo , Statement , StatementKind , TerminatorKind ,
33
33
} ;
34
- use rustc_middle:: ty:: { self , Instance , TyCtxt , TypeVisitableExt } ;
34
+ use rustc_middle:: ty:: { self , GenericParamDefKind , Instance , TyCtxt , TypeVisitableExt } ;
35
35
use rustc_middle:: util:: Providers ;
36
36
use rustc_middle:: { bug, query, span_bug} ;
37
37
use rustc_mir_build:: builder:: build_mir;
@@ -794,26 +794,47 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
794
794
795
795
run_optimization_passes ( tcx, & mut body) ;
796
796
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
+ }
799
802
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
+ }
811
816
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;
815
824
}
816
825
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
+
817
838
body
818
839
}
819
840
@@ -822,6 +843,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
822
843
// Currently, it looks for NullOp::UbChecks because that must be resolved at codegen.
823
844
struct MonoCompatVisitor {
824
845
contains_ubcheck : bool ,
846
+ contains_generic_const : bool ,
825
847
}
826
848
827
849
impl < ' tcx > Visitor < ' tcx > for MonoCompatVisitor {
@@ -831,25 +853,43 @@ impl<'tcx> Visitor<'tcx> for MonoCompatVisitor {
831
853
}
832
854
self . super_rvalue ( rvalue, location) ;
833
855
}
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
+ }
834
863
}
835
864
836
865
pub fn build_codegen_mir < ' tcx > ( tcx : TyCtxt < ' tcx > , instance : Instance < ' tcx > ) -> & ' tcx Body < ' tcx > {
837
866
let body = tcx. instance_mir ( instance. def ) ;
838
867
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) ;
841
876
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
- {
847
877
let mut body = instance. instantiate_mir_and_normalize_erasing_regions (
848
878
tcx,
849
879
ty:: TypingEnv :: fully_monomorphized ( ) ,
850
880
ty:: EarlyBinder :: bind ( body. clone ( ) ) ,
851
881
) ;
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 ;
853
893
tcx. arena . alloc ( body)
854
894
} else {
855
895
body
0 commit comments