25
25
use rustc:: mir:: * ;
26
26
use rustc:: mir:: visit:: { PlaceContext , MutVisitor , Visitor } ;
27
27
use rustc:: mir:: traversal:: ReversePostorder ;
28
- use rustc:: ty:: TyCtxt ;
28
+ use rustc:: ty:: { self , TyCtxt } ;
29
29
use syntax_pos:: Span ;
30
30
31
31
use rustc_data_structures:: indexed_vec:: { IndexVec , Idx } ;
32
32
33
- use std:: iter;
34
- use std:: mem;
35
- use std:: usize;
33
+ use std:: { cmp, iter, mem, usize} ;
36
34
37
35
/// State of a temporary during collection and promotion.
38
36
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
@@ -150,9 +148,11 @@ pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Local, T
150
148
}
151
149
152
150
struct Promoter < ' a , ' tcx : ' a > {
151
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
153
152
source : & ' a mut Mir < ' tcx > ,
154
153
promoted : Mir < ' tcx > ,
155
154
temps : & ' a mut IndexVec < Local , TempState > ,
155
+ extra_statements : & ' a mut Vec < ( Location , Statement < ' tcx > ) > ,
156
156
157
157
/// If true, all nested temps are also kept in the
158
158
/// source MIR, not moved to the promoted MIR.
@@ -288,38 +288,78 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
288
288
}
289
289
290
290
fn promote_candidate ( mut self , candidate : Candidate ) {
291
- let span = self . promoted . span ;
292
- let new_operand = Operand :: Constant ( box Constant {
293
- span,
294
- ty : self . promoted . return_ty ( ) ,
295
- literal : Literal :: Promoted {
291
+ let mut rvalue = {
292
+ let promoted = & mut self . promoted ;
293
+ let literal = Literal :: Promoted {
296
294
index : Promoted :: new ( self . source . promoted . len ( ) )
297
- }
298
- } ) ;
299
- let mut rvalue = match candidate {
300
- Candidate :: Ref ( Location { block : bb, statement_index : stmt_idx } ) => {
301
- let ref mut statement = self . source [ bb] . statements [ stmt_idx] ;
302
- match statement. kind {
303
- StatementKind :: Assign ( _, ref mut rvalue) => {
304
- mem:: replace ( rvalue, Rvalue :: Use ( new_operand) )
295
+ } ;
296
+ let operand = |ty, span| {
297
+ promoted. span = span;
298
+ promoted. local_decls [ RETURN_PLACE ] =
299
+ LocalDecl :: new_return_place ( ty, span) ;
300
+ Operand :: Constant ( box Constant {
301
+ span,
302
+ ty,
303
+ literal
304
+ } )
305
+ } ;
306
+ let ( blocks, local_decls) = self . source . basic_blocks_and_local_decls_mut ( ) ;
307
+ match candidate {
308
+ Candidate :: Ref ( loc) => {
309
+ let ref mut statement = blocks[ loc. block ] . statements [ loc. statement_index ] ;
310
+ match statement. kind {
311
+ StatementKind :: Assign ( _, Rvalue :: Ref ( r, bk, ref mut place) ) => {
312
+ let ty = place. ty ( local_decls, self . tcx ) . to_ty ( self . tcx ) ;
313
+ let ref_ty = self . tcx . mk_ref ( r,
314
+ ty:: TypeAndMut {
315
+ ty,
316
+ mutbl : bk. to_mutbl_lossy ( )
317
+ }
318
+ ) ;
319
+ let span = statement. source_info . span ;
320
+
321
+ // Create a temp to hold the promoted reference.
322
+ // This is because `*r` requires `r` to be a local,
323
+ // otherwise we would use the `promoted` directly.
324
+ let mut promoted_ref = LocalDecl :: new_temp ( ref_ty, span) ;
325
+ promoted_ref. source_info = statement. source_info ;
326
+ let promoted_ref = local_decls. push ( promoted_ref) ;
327
+ assert_eq ! ( self . temps. push( TempState :: Unpromotable ) , promoted_ref) ;
328
+ self . extra_statements . push ( ( loc, Statement {
329
+ source_info : statement. source_info ,
330
+ kind : StatementKind :: Assign (
331
+ Place :: Local ( promoted_ref) ,
332
+ Rvalue :: Use ( operand ( ref_ty, span) ) ,
333
+ )
334
+ } ) ) ;
335
+ let promoted_place = Place :: Local ( promoted_ref) . deref ( ) ;
336
+
337
+ Rvalue :: Ref ( r, bk, mem:: replace ( place, promoted_place) )
338
+ }
339
+ _ => bug ! ( )
305
340
}
306
- _ => bug ! ( )
307
341
}
308
- }
309
- Candidate :: Argument { bb, index } => {
310
- match self . source [ bb] . terminator_mut ( ) . kind {
311
- TerminatorKind :: Call { ref mut args, .. } => {
312
- Rvalue :: Use ( mem:: replace ( & mut args[ index] , new_operand) )
342
+ Candidate :: Argument { bb, index } => {
343
+ let terminator = blocks[ bb] . terminator_mut ( ) ;
344
+ match terminator. kind {
345
+ TerminatorKind :: Call { ref mut args, .. } => {
346
+ let ty = args[ index] . ty ( local_decls, self . tcx ) ;
347
+ let span = terminator. source_info . span ;
348
+ Rvalue :: Use ( mem:: replace ( & mut args[ index] , operand ( ty, span) ) )
349
+ }
350
+ _ => bug ! ( )
313
351
}
314
- _ => bug ! ( )
315
352
}
316
353
}
317
354
} ;
355
+
356
+ assert_eq ! ( self . new_block( ) , START_BLOCK ) ;
318
357
self . visit_rvalue ( & mut rvalue, Location {
319
358
block : BasicBlock :: new ( 0 ) ,
320
359
statement_index : usize:: MAX
321
360
} ) ;
322
361
362
+ let span = self . promoted . span ;
323
363
self . assign ( RETURN_PLACE , rvalue, span) ;
324
364
self . source . promoted . push ( self . promoted ) ;
325
365
}
@@ -343,43 +383,29 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
343
383
candidates : Vec < Candidate > ) {
344
384
// Visit candidates in reverse, in case they're nested.
345
385
debug ! ( "promote_candidates({:?})" , candidates) ;
386
+
387
+ let mut extra_statements = vec ! [ ] ;
346
388
for candidate in candidates. into_iter ( ) . rev ( ) {
347
- let ( span, ty) = match candidate {
348
- Candidate :: Ref ( Location { block : bb, statement_index : stmt_idx } ) => {
349
- let statement = & mir[ bb] . statements [ stmt_idx] ;
350
- let dest = match statement. kind {
351
- StatementKind :: Assign ( ref dest, _) => dest,
352
- _ => {
353
- span_bug ! ( statement. source_info. span,
354
- "expected assignment to promote" ) ;
355
- }
356
- } ;
357
- if let Place :: Local ( index) = * dest {
358
- if temps[ index] == TempState :: PromotedOut {
359
- // Already promoted.
360
- continue ;
389
+ match candidate {
390
+ Candidate :: Ref ( Location { block, statement_index } ) => {
391
+ match mir[ block] . statements [ statement_index] . kind {
392
+ StatementKind :: Assign ( Place :: Local ( local) , _) => {
393
+ if temps[ local] == TempState :: PromotedOut {
394
+ // Already promoted.
395
+ continue ;
396
+ }
361
397
}
398
+ _ => { }
362
399
}
363
- ( statement. source_info . span , dest. ty ( mir, tcx) . to_ty ( tcx) )
364
- }
365
- Candidate :: Argument { bb, index } => {
366
- let terminator = mir[ bb] . terminator ( ) ;
367
- let ty = match terminator. kind {
368
- TerminatorKind :: Call { ref args, .. } => {
369
- args[ index] . ty ( mir, tcx)
370
- }
371
- _ => {
372
- span_bug ! ( terminator. source_info. span,
373
- "expected call argument to promote" ) ;
374
- }
375
- } ;
376
- ( terminator. source_info . span , ty)
377
400
}
378
- } ;
401
+ Candidate :: Argument { .. } => { }
402
+ }
403
+
379
404
380
- // Declare return place local
381
- let initial_locals = iter:: once ( LocalDecl :: new_return_place ( ty, span) )
382
- . collect ( ) ;
405
+ // Declare return place local so that `Mir::new` doesn't complain.
406
+ let initial_locals = iter:: once (
407
+ LocalDecl :: new_return_place ( tcx. types . never , mir. span )
408
+ ) . collect ( ) ;
383
409
384
410
let mut promoter = Promoter {
385
411
promoted : Mir :: new (
@@ -393,16 +419,24 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
393
419
initial_locals,
394
420
0 ,
395
421
vec ! [ ] ,
396
- span
422
+ mir . span
397
423
) ,
424
+ tcx,
398
425
source : mir,
399
426
temps : & mut temps,
427
+ extra_statements : & mut extra_statements,
400
428
keep_original : false
401
429
} ;
402
- assert_eq ! ( promoter. new_block( ) , START_BLOCK ) ;
403
430
promoter. promote_candidate ( candidate) ;
404
431
}
405
432
433
+ // Insert each of `extra_statements` before its indicated location, which
434
+ // has to be done in reverse location order, to not invalidate the rest.
435
+ extra_statements. sort_by_key ( |& ( loc, _) | cmp:: Reverse ( loc) ) ;
436
+ for ( loc, statement) in extra_statements {
437
+ mir[ loc. block ] . statements . insert ( loc. statement_index , statement) ;
438
+ }
439
+
406
440
// Eliminate assignments to, and drops of promoted temps.
407
441
let promoted = |index : Local | temps[ index] == TempState :: PromotedOut ;
408
442
for block in mir. basic_blocks_mut ( ) {
0 commit comments