22
33use rustc_attr as attr;
44use rustc_hir as hir;
5+ use rustc_hir:: def_id:: DefId ;
56use rustc_index:: bit_set:: BitSet ;
67use rustc_index:: vec:: Idx ;
78use rustc_middle:: middle:: codegen_fn_attrs:: { CodegenFnAttrFlags , CodegenFnAttrs } ;
@@ -37,10 +38,6 @@ struct CallSite<'tcx> {
3738
3839impl < ' tcx > MirPass < ' tcx > for Inline {
3940 fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
40- if tcx. sess . opts . debugging_opts . mir_opt_level < 2 {
41- return ;
42- }
43-
4441 if tcx. sess . opts . debugging_opts . instrument_coverage {
4542 // Since `Inline` happens after `InstrumentCoverage`, the function-specific coverage
4643 // counters can be invalidated, such as by merging coverage counter statements from
@@ -50,6 +47,13 @@ impl<'tcx> MirPass<'tcx> for Inline {
5047 return ;
5148 }
5249
50+ if body. generator_kind . is_some ( ) {
51+ // Avoid inlining into generators, since their `optimized_mir` is used for layout
52+ // computation, which can create a cycle, even when no attempt is made to inline
53+ // the function in the other direction.
54+ return ;
55+ }
56+
5357 if inline ( tcx, body) {
5458 debug ! ( "running simplify cfg on {:?}" , body. source) ;
5559 CfgSimplifier :: new ( body) . simplify ( ) ;
@@ -104,7 +108,7 @@ impl Inliner<'tcx> {
104108 Some ( it) => it,
105109 } ;
106110
107- if !self . is_mir_available ( & callsite. callee , caller_body ) {
111+ if !self . is_mir_available ( & callsite. callee ) {
108112 debug ! ( "MIR unavailable {}" , callsite. callee) ;
109113 continue ;
110114 }
@@ -137,11 +141,27 @@ impl Inliner<'tcx> {
137141 }
138142 }
139143
140- fn is_mir_available ( & self , callee : & Instance < ' tcx > , caller_body : & Body < ' tcx > ) -> bool {
141- if let InstanceDef :: Item ( _) = callee. def {
142- if !self . tcx . is_mir_available ( callee. def_id ( ) ) {
143- return false ;
144- }
144+ fn is_mir_available ( & self , callee : & Instance < ' tcx > ) -> bool {
145+ match callee. def {
146+ InstanceDef :: Virtual ( ..) | InstanceDef :: Intrinsic ( ..) => return false ,
147+
148+ InstanceDef :: VtableShim ( ..)
149+ | InstanceDef :: ReifyShim ( ..)
150+ | InstanceDef :: FnPtrShim ( ..)
151+ | InstanceDef :: ClosureOnceShim { .. }
152+ | InstanceDef :: DropGlue ( ..)
153+ | InstanceDef :: CloneShim ( ..) => return true ,
154+
155+ InstanceDef :: Item ( _) => { }
156+ } ;
157+
158+ if !self . tcx . is_mir_available ( callee. def_id ( ) ) {
159+ return false ;
160+ }
161+
162+ if self . tcx . sess . opts . debugging_opts . mir_opt_level <= 1 {
163+ // Only inline trivial functions by default.
164+ return self . tcx . is_trivial_mir ( callee. def_id ( ) ) ;
145165 }
146166
147167 if let Some ( callee_def_id) = callee. def_id ( ) . as_local ( ) {
@@ -153,9 +173,7 @@ impl Inliner<'tcx> {
153173 // since their `optimized_mir` is used for layout computation, which can
154174 // create a cycle, even when no attempt is made to inline the function
155175 // in the other direction.
156- !self . tcx . dep_graph . is_fully_enabled ( )
157- && self . hir_id < callee_hir_id
158- && caller_body. generator_kind . is_none ( )
176+ !self . tcx . dep_graph . is_fully_enabled ( ) && self . hir_id < callee_hir_id
159177 } else {
160178 // This cannot result in a cycle since the callee MIR is from another crate
161179 // and is already optimized.
@@ -885,3 +903,48 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
885903 }
886904 }
887905}
906+
907+ pub fn is_trivial_mir ( tcx : TyCtxt < ' tcx > , did : DefId ) -> bool {
908+ debug ! ( "is_trivial_mir({:?})" , did) ;
909+ if tcx. is_constructor ( did) {
910+ debug ! ( "is_trivial_mir = true (constructor)" ) ;
911+ return true ;
912+ }
913+
914+ use rustc_hir:: def:: DefKind ;
915+ if !matches ! ( tcx. def_kind( did) , DefKind :: Fn | DefKind :: AssocFn ) {
916+ debug ! ( "is_trivial_mir = false (not a function)" ) ;
917+ // Only inline functions, don't look at constants here.
918+ return false ;
919+ }
920+
921+ if !did. is_local ( ) {
922+ // This branch is only taken if no `optimized_mir` is available for
923+ // an extern crate, as `is_trivial_mir` has otherwise been encoded.
924+ debug ! ( "is_trivial_mir = false (no MIR available)" ) ;
925+ return false ;
926+ } ;
927+
928+ let body = tcx
929+ . mir_drops_elaborated_and_const_checked ( ty:: WithOptConstParam :: unknown ( did. expect_local ( ) ) )
930+ . borrow ( ) ;
931+
932+ for bb in body. basic_blocks ( ) {
933+ let terminator = bb. terminator ( ) ;
934+ if let TerminatorKind :: Call { func, .. } = & terminator. kind {
935+ let func_ty = func. ty ( body. local_decls ( ) , tcx) ;
936+ if let ty:: FnDef ( ..) = * func_ty. kind ( ) {
937+ let fn_sig = func_ty. fn_sig ( tcx) ;
938+ if fn_sig. abi ( ) == Abi :: RustIntrinsic || fn_sig. abi ( ) == Abi :: PlatformIntrinsic {
939+ continue ;
940+ }
941+ }
942+
943+ debug ! ( "is_trivial_mir = false (function call)" ) ;
944+ return false ;
945+ }
946+ }
947+
948+ debug ! ( "is_trivial_mir = true" ) ;
949+ true
950+ }
0 commit comments