11//! Inlining pass for MIR functions
22
3- use rustc_hir:: def_id:: DefId ;
4-
53use rustc_index:: bit_set:: BitSet ;
64use rustc_index:: vec:: { Idx , IndexVec } ;
75
86use rustc:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
97use rustc:: mir:: visit:: * ;
108use rustc:: mir:: * ;
119use rustc:: session:: config:: Sanitizer ;
12- use rustc:: ty:: subst:: { InternalSubsts , Subst , SubstsRef } ;
10+ use rustc:: ty:: subst:: { InternalSubsts , Subst } ;
1311use rustc:: ty:: { self , Instance , InstanceDef , ParamEnv , Ty , TyCtxt , TypeFoldable } ;
1412
1513use super :: simplify:: { remove_dead_blocks, CfgSimplifier } ;
@@ -32,8 +30,7 @@ pub struct Inline;
3230
3331#[ derive( Copy , Clone , Debug ) ]
3432struct CallSite < ' tcx > {
35- callee : DefId ,
36- substs : SubstsRef < ' tcx > ,
33+ callee : Instance < ' tcx > ,
3734 bb : BasicBlock ,
3835 source_info : SourceInfo ,
3936}
@@ -97,13 +94,19 @@ impl Inliner<'tcx> {
9794 local_change = false ;
9895 while let Some ( callsite) = callsites. pop_front ( ) {
9996 debug ! ( "checking whether to inline callsite {:?}" , callsite) ;
100- if !self . tcx . is_mir_available ( callsite. callee ) {
101- debug ! ( "checking whether to inline callsite {:?} - MIR unavailable" , callsite) ;
102- continue ;
97+
98+ if let InstanceDef :: Item ( callee_def_id) = callsite. callee . def {
99+ if !self . tcx . is_mir_available ( callee_def_id) {
100+ debug ! (
101+ "checking whether to inline callsite {:?} - MIR unavailable" ,
102+ callsite,
103+ ) ;
104+ continue ;
105+ }
103106 }
104107
105108 let self_node_id = self . tcx . hir ( ) . as_local_node_id ( self . source . def_id ( ) ) . unwrap ( ) ;
106- let callee_node_id = self . tcx . hir ( ) . as_local_node_id ( callsite. callee ) ;
109+ let callee_node_id = self . tcx . hir ( ) . as_local_node_id ( callsite. callee . def_id ( ) ) ;
107110
108111 let callee_body = if let Some ( callee_node_id) = callee_node_id {
109112 // Avoid a cycle here by only using `optimized_mir` only if we have
@@ -113,19 +116,21 @@ impl Inliner<'tcx> {
113116 if !self . tcx . dep_graph . is_fully_enabled ( )
114117 && self_node_id. as_u32 ( ) < callee_node_id. as_u32 ( )
115118 {
116- self . tcx . optimized_mir ( callsite. callee )
119+ self . tcx . instance_mir ( callsite. callee . def )
117120 } else {
118121 continue ;
119122 }
120123 } else {
121124 // This cannot result in a cycle since the callee MIR is from another crate
122125 // and is already optimized.
123- self . tcx . optimized_mir ( callsite. callee )
126+ self . tcx . instance_mir ( callsite. callee . def )
124127 } ;
125128
129+ let callee_body: & Body < ' tcx > = & * callee_body;
130+
126131 let callee_body = if self . consider_optimizing ( callsite, callee_body) {
127132 self . tcx . subst_and_normalize_erasing_regions (
128- & callsite. substs ,
133+ & callsite. callee . substs ,
129134 param_env,
130135 callee_body,
131136 )
@@ -186,18 +191,13 @@ impl Inliner<'tcx> {
186191 let terminator = bb_data. terminator ( ) ;
187192 if let TerminatorKind :: Call { func : ref op, .. } = terminator. kind {
188193 if let ty:: FnDef ( callee_def_id, substs) = op. ty ( caller_body, self . tcx ) . kind {
189- let instance = Instance :: resolve ( self . tcx , param_env, callee_def_id, substs) ?;
194+ let callee = Instance :: resolve ( self . tcx , param_env, callee_def_id, substs) ?;
190195
191- if let InstanceDef :: Virtual ( ..) = instance . def {
196+ if let InstanceDef :: Virtual ( ..) | InstanceDef :: Intrinsic ( _ ) = callee . def {
192197 return None ;
193198 }
194199
195- return Some ( CallSite {
196- callee : instance. def_id ( ) ,
197- substs : instance. substs ,
198- bb,
199- source_info : terminator. source_info ,
200- } ) ;
200+ return Some ( CallSite { callee, bb, source_info : terminator. source_info } ) ;
201201 }
202202 }
203203
@@ -222,7 +222,7 @@ impl Inliner<'tcx> {
222222 return false ;
223223 }
224224
225- let codegen_fn_attrs = tcx. codegen_fn_attrs ( callsite. callee ) ;
225+ let codegen_fn_attrs = tcx. codegen_fn_attrs ( callsite. callee . def_id ( ) ) ;
226226
227227 if codegen_fn_attrs. flags . contains ( CodegenFnAttrFlags :: TRACK_CALLER ) {
228228 debug ! ( "`#[track_caller]` present - not inlining" ) ;
@@ -267,8 +267,8 @@ impl Inliner<'tcx> {
267267 // Only inline local functions if they would be eligible for cross-crate
268268 // inlining. This is to ensure that the final crate doesn't have MIR that
269269 // reference unexported symbols
270- if callsite. callee . is_local ( ) {
271- if callsite. substs . non_erasable_generics ( ) . count ( ) == 0 && !hinted {
270+ if callsite. callee . def_id ( ) . is_local ( ) {
271+ if callsite. callee . substs . non_erasable_generics ( ) . count ( ) == 0 && !hinted {
272272 debug ! ( " callee is an exported function - not inlining" ) ;
273273 return false ;
274274 }
@@ -324,7 +324,7 @@ impl Inliner<'tcx> {
324324 work_list. push ( target) ;
325325 // If the location doesn't actually need dropping, treat it like
326326 // a regular goto.
327- let ty = location. ty ( callee_body, tcx) . subst ( tcx, callsite. substs ) . ty ;
327+ let ty = location. ty ( callee_body, tcx) . subst ( tcx, callsite. callee . substs ) . ty ;
328328 if ty. needs_drop ( tcx, param_env) {
329329 cost += CALL_PENALTY ;
330330 if let Some ( unwind) = unwind {
@@ -374,7 +374,7 @@ impl Inliner<'tcx> {
374374
375375 for v in callee_body. vars_and_temps_iter ( ) {
376376 let v = & callee_body. local_decls [ v] ;
377- let ty = v. ty . subst ( tcx, callsite. substs ) ;
377+ let ty = v. ty . subst ( tcx, callsite. callee . substs ) ;
378378 // Cost of the var is the size in machine-words, if we know
379379 // it.
380380 if let Some ( size) = type_size_of ( tcx, param_env, ty) {
@@ -402,7 +402,7 @@ impl Inliner<'tcx> {
402402 & self ,
403403 callsite : CallSite < ' tcx > ,
404404 caller_body : & mut BodyAndCache < ' tcx > ,
405- mut callee_body : BodyAndCache < ' tcx > ,
405+ mut callee_body : Body < ' tcx > ,
406406 ) -> bool {
407407 let terminator = caller_body[ callsite. bb ] . terminator . take ( ) . unwrap ( ) ;
408408 match terminator. kind {
@@ -504,6 +504,13 @@ impl Inliner<'tcx> {
504504 caller_body. var_debug_info . push ( var_debug_info) ;
505505 }
506506
507+ // HACK(eddyb) work around the `basic_blocks` field of `mir::Body`
508+ // being private, due to `BodyAndCache` implementing `DerefMut`
509+ // to `mir::Body` (which would allow bypassing `basic_blocks_mut`).
510+ // The only way to make `basic_blocks` public again would be to
511+ // remove that `DerefMut` impl and add more `*_mut` accessors.
512+ let mut callee_body = BodyAndCache :: new ( callee_body) ;
513+
507514 for ( bb, mut block) in callee_body. basic_blocks_mut ( ) . drain_enumerated ( ..) {
508515 integrator. visit_basic_block_data ( bb, & mut block) ;
509516 caller_body. basic_blocks_mut ( ) . push ( block) ;
@@ -557,7 +564,9 @@ impl Inliner<'tcx> {
557564 // tmp2 = tuple_tmp.2
558565 //
559566 // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
560- if tcx. is_closure ( callsite. callee ) {
567+ // FIXME(eddyb) make this check for `"rust-call"` ABI combined with
568+ // `callee_body.spread_arg == None`, instead of special-casing closures.
569+ if tcx. is_closure ( callsite. callee . def_id ( ) ) {
561570 let mut args = args. into_iter ( ) ;
562571 let self_ = self . create_temp_if_necessary ( args. next ( ) . unwrap ( ) , callsite, caller_body) ;
563572 let tuple = self . create_temp_if_necessary ( args. next ( ) . unwrap ( ) , callsite, caller_body) ;
0 commit comments