]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/inline.rs
move projection mode into parameter environment
[rust.git] / src / librustc_mir / transform / inline.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Inlining pass for MIR functions
12
13 use rustc::hir::def_id::DefId;
14
15 use rustc_data_structures::bitvec::BitVector;
16 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
17
18 use rustc::mir::*;
19 use rustc::mir::transform::{MirPass, MirSource};
20 use rustc::mir::visit::*;
21 use rustc::ty::{self, Ty, TyCtxt};
22 use rustc::ty::subst::{Subst,Substs};
23
24 use std::collections::VecDeque;
25 use super::simplify::{remove_dead_blocks, CfgSimplifier};
26
27 use syntax::{attr};
28 use syntax::abi::Abi;
29
30 const DEFAULT_THRESHOLD: usize = 50;
31 const HINT_THRESHOLD: usize = 100;
32
33 const INSTR_COST: usize = 5;
34 const CALL_PENALTY: usize = 25;
35
36 const UNKNOWN_SIZE_COST: usize = 10;
37
38 pub struct Inline;
39
40 #[derive(Copy, Clone)]
41 struct CallSite<'tcx> {
42     callee: DefId,
43     substs: &'tcx Substs<'tcx>,
44     bb: BasicBlock,
45     location: SourceInfo,
46 }
47
48 impl MirPass for Inline {
49     fn run_pass<'a, 'tcx>(&self,
50                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
51                           source: MirSource,
52                           mir: &mut Mir<'tcx>) {
53         if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
54             Inliner { tcx, source }.run_pass(mir);
55         }
56     }
57 }
58
59 struct Inliner<'a, 'tcx: 'a> {
60     tcx: TyCtxt<'a, 'tcx, 'tcx>,
61     source: MirSource,
62 }
63
64 impl<'a, 'tcx> Inliner<'a, 'tcx> {
65     fn run_pass(&self, caller_mir: &mut Mir<'tcx>) {
66         // Keep a queue of callsites to try inlining on. We take
67         // advantage of the fact that queries detect cycles here to
68         // allow us to try and fetch the fully optimized MIR of a
69         // call; if it succeeds, we can inline it and we know that
70         // they do not call us.  Otherwise, we just don't try to
71         // inline.
72         //
73         // We use a queue so that we inline "broadly" before we inline
74         // in depth. It is unclear if this is the best heuristic,
75         // really, but that's true of all the heuristics in this
76         // file. =)
77
78         let mut callsites = VecDeque::new();
79
80         // Only do inlining into fn bodies.
81         if let MirSource::Fn(_) = self.source {
82             for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated() {
83                 // Don't inline calls that are in cleanup blocks.
84                 if bb_data.is_cleanup { continue; }
85
86                 // Only consider direct calls to functions
87                 let terminator = bb_data.terminator();
88                 if let TerminatorKind::Call {
89                     func: Operand::Constant(ref f), .. } = terminator.kind {
90                     if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty {
91                         callsites.push_back(CallSite {
92                             callee: callee_def_id,
93                             substs: substs,
94                             bb: bb,
95                             location: terminator.source_info
96                         });
97                     }
98                 }
99             }
100         }
101
102         let mut local_change;
103         let mut changed = false;
104
105         loop {
106             local_change = false;
107             while let Some(callsite) = callsites.pop_front() {
108                 if !self.tcx.is_mir_available(callsite.callee) {
109                     continue;
110                 }
111
112                 let callee_mir = match ty::queries::optimized_mir::try_get(self.tcx,
113                                                                            callsite.location.span,
114                                                                            callsite.callee) {
115                     Ok(ref callee_mir) if self.should_inline(callsite, callee_mir) => {
116                         callee_mir.subst(self.tcx, callsite.substs)
117                     }
118
119                     _ => continue,
120                 };
121
122                 let start = caller_mir.basic_blocks().len();
123
124                 if !self.inline_call(callsite, caller_mir, callee_mir) {
125                     continue;
126                 }
127
128                 // Add callsites from inlined function
129                 for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated().skip(start) {
130                     // Only consider direct calls to functions
131                     let terminator = bb_data.terminator();
132                     if let TerminatorKind::Call {
133                         func: Operand::Constant(ref f), .. } = terminator.kind {
134                         if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty {
135                             // Don't inline the same function multiple times.
136                             if callsite.callee != callee_def_id {
137                                 callsites.push_back(CallSite {
138                                     callee: callee_def_id,
139                                     substs: substs,
140                                     bb: bb,
141                                     location: terminator.source_info
142                                 });
143                             }
144                         }
145                     }
146                 }
147
148                 local_change = true;
149                 changed = true;
150             }
151
152             if !local_change {
153                 break;
154             }
155         }
156
157         // Simplify if we inlined anything.
158         if changed {
159             debug!("Running simplify cfg on {:?}", self.source);
160             CfgSimplifier::new(caller_mir).simplify();
161             remove_dead_blocks(caller_mir);
162         }
163     }
164
165     fn should_inline(&self,
166                      callsite: CallSite<'tcx>,
167                      callee_mir: &Mir<'tcx>)
168                      -> bool
169     {
170         let tcx = self.tcx;
171
172         // Don't inline closures that have captures
173         // FIXME: Handle closures better
174         if callee_mir.upvar_decls.len() > 0 {
175             return false;
176         }
177
178
179         let attrs = tcx.get_attrs(callsite.callee);
180         let hint = attr::find_inline_attr(None, &attrs[..]);
181
182         let hinted = match hint {
183             // Just treat inline(always) as a hint for now,
184             // there are cases that prevent inlining that we
185             // need to check for first.
186             attr::InlineAttr::Always => true,
187             attr::InlineAttr::Never => return false,
188             attr::InlineAttr::Hint => true,
189             attr::InlineAttr::None => false,
190         };
191
192         // Only inline local functions if they would be eligible for cross-crate
193         // inlining. This is to ensure that the final crate doesn't have MIR that
194         // reference unexported symbols
195         if callsite.callee.is_local() {
196             if callsite.substs.types().count() == 0 && !hinted {
197                 return false;
198             }
199         }
200
201         let mut threshold = if hinted {
202             HINT_THRESHOLD
203         } else {
204             DEFAULT_THRESHOLD
205         };
206
207         // Significantly lower the threshold for inlining cold functions
208         if attr::contains_name(&attrs[..], "cold") {
209             threshold /= 5;
210         }
211
212         // Give a bonus functions with a small number of blocks,
213         // We normally have two or three blocks for even
214         // very small functions.
215         if callee_mir.basic_blocks().len() <= 3 {
216             threshold += threshold / 4;
217         }
218
219         // FIXME: Give a bonus to functions with only a single caller
220
221         let def_id = tcx.hir.local_def_id(self.source.item_id());
222         let param_env = tcx.param_env(def_id);
223
224         let mut first_block = true;
225         let mut cost = 0;
226
227         // Traverse the MIR manually so we can account for the effects of
228         // inlining on the CFG.
229         let mut work_list = vec![START_BLOCK];
230         let mut visited = BitVector::new(callee_mir.basic_blocks().len());
231         while let Some(bb) = work_list.pop() {
232             if !visited.insert(bb.index()) { continue; }
233             let blk = &callee_mir.basic_blocks()[bb];
234
235             for stmt in &blk.statements {
236                 // Don't count StorageLive/StorageDead in the inlining cost.
237                 match stmt.kind {
238                     StatementKind::StorageLive(_) |
239                     StatementKind::StorageDead(_) |
240                     StatementKind::Nop => {}
241                     _ => cost += INSTR_COST
242                 }
243             }
244             let term = blk.terminator();
245             let mut is_drop = false;
246             match term.kind {
247                 TerminatorKind::Drop { ref location, target, unwind } |
248                 TerminatorKind::DropAndReplace { ref location, target, unwind, .. } => {
249                     is_drop = true;
250                     work_list.push(target);
251                     // If the location doesn't actually need dropping, treat it like
252                     // a regular goto.
253                     let ty = location.ty(&callee_mir, tcx).subst(tcx, callsite.substs);
254                     let ty = ty.to_ty(tcx);
255                     if ty.needs_drop(tcx, param_env) {
256                         cost += CALL_PENALTY;
257                         if let Some(unwind) = unwind {
258                             work_list.push(unwind);
259                         }
260                     } else {
261                         cost += INSTR_COST;
262                     }
263                 }
264
265                 TerminatorKind::Unreachable |
266                 TerminatorKind::Call { destination: None, .. } if first_block => {
267                     // If the function always diverges, don't inline
268                     // unless the cost is zero
269                     threshold = 0;
270                 }
271
272                 TerminatorKind::Call {func: Operand::Constant(ref f), .. } => {
273                     if let ty::TyFnDef(.., f) = f.ty.sty {
274                         // Don't give intrinsics the extra penalty for calls
275                         if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
276                             cost += INSTR_COST;
277                         } else {
278                             cost += CALL_PENALTY;
279                         }
280                     }
281                 }
282                 TerminatorKind::Assert { .. } => cost += CALL_PENALTY,
283                 _ => cost += INSTR_COST
284             }
285
286             if !is_drop {
287                 for &succ in &term.successors()[..] {
288                     work_list.push(succ);
289                 }
290             }
291
292             first_block = false;
293         }
294
295         // Count up the cost of local variables and temps, if we know the size
296         // use that, otherwise we use a moderately-large dummy cost.
297
298         let ptr_size = tcx.data_layout.pointer_size.bytes();
299
300         for v in callee_mir.vars_and_temps_iter() {
301             let v = &callee_mir.local_decls[v];
302             let ty = v.ty.subst(tcx, callsite.substs);
303             // Cost of the var is the size in machine-words, if we know
304             // it.
305             if let Some(size) = type_size_of(tcx, param_env.clone(), ty) {
306                 cost += (size / ptr_size) as usize;
307             } else {
308                 cost += UNKNOWN_SIZE_COST;
309             }
310         }
311
312         debug!("Inline cost for {:?} is {}", callsite.callee, cost);
313
314         if let attr::InlineAttr::Always = hint {
315             true
316         } else {
317             cost <= threshold
318         }
319     }
320
321     fn inline_call(&self,
322                    callsite: CallSite<'tcx>,
323                    caller_mir: &mut Mir<'tcx>,
324                    mut callee_mir: Mir<'tcx>) -> bool {
325         let terminator = caller_mir[callsite.bb].terminator.take().unwrap();
326         match terminator.kind {
327             // FIXME: Handle inlining of diverging calls
328             TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => {
329                 debug!("Inlined {:?} into {:?}", callsite.callee, self.source);
330
331                 let is_box_free = Some(callsite.callee) == self.tcx.lang_items.box_free_fn();
332
333                 let mut local_map = IndexVec::with_capacity(callee_mir.local_decls.len());
334                 let mut scope_map = IndexVec::with_capacity(callee_mir.visibility_scopes.len());
335                 let mut promoted_map = IndexVec::with_capacity(callee_mir.promoted.len());
336
337                 for mut scope in callee_mir.visibility_scopes.iter().cloned() {
338                     if scope.parent_scope.is_none() {
339                         scope.parent_scope = Some(callsite.location.scope);
340                         scope.span = callee_mir.span;
341                     }
342
343                     scope.span = callsite.location.span;
344
345                     let idx = caller_mir.visibility_scopes.push(scope);
346                     scope_map.push(idx);
347                 }
348
349                 for loc in callee_mir.vars_and_temps_iter() {
350                     let mut local = callee_mir.local_decls[loc].clone();
351
352                     local.source_info.scope = scope_map[local.source_info.scope];
353                     local.source_info.span = callsite.location.span;
354
355                     let idx = caller_mir.local_decls.push(local);
356                     local_map.push(idx);
357                 }
358
359                 for p in callee_mir.promoted.iter().cloned() {
360                     let idx = caller_mir.promoted.push(p);
361                     promoted_map.push(idx);
362                 }
363
364                 // If the call is something like `a[*i] = f(i)`, where
365                 // `i : &mut usize`, then just duplicating the `a[*i]`
366                 // Lvalue could result in two different locations if `f`
367                 // writes to `i`. To prevent this we need to create a temporary
368                 // borrow of the lvalue and pass the destination as `*temp` instead.
369                 fn dest_needs_borrow(lval: &Lvalue) -> bool {
370                     match *lval {
371                         Lvalue::Projection(ref p) => {
372                             match p.elem {
373                                 ProjectionElem::Deref |
374                                 ProjectionElem::Index(_) => true,
375                                 _ => dest_needs_borrow(&p.base)
376                             }
377                         }
378                         // Static variables need a borrow because the callee
379                         // might modify the same static.
380                         Lvalue::Static(_) => true,
381                         _ => false
382                     }
383                 }
384
385                 let dest = if dest_needs_borrow(&destination.0) {
386                     debug!("Creating temp for return destination");
387                     let dest = Rvalue::Ref(
388                         self.tcx.types.re_erased,
389                         BorrowKind::Mut,
390                         destination.0);
391
392                     let ty = dest.ty(caller_mir, self.tcx);
393
394                     let temp = LocalDecl::new_temp(ty, callsite.location.span);
395
396                     let tmp = caller_mir.local_decls.push(temp);
397                     let tmp = Lvalue::Local(tmp);
398
399                     let stmt = Statement {
400                         source_info: callsite.location,
401                         kind: StatementKind::Assign(tmp.clone(), dest)
402                     };
403                     caller_mir[callsite.bb]
404                         .statements.push(stmt);
405                     tmp.deref()
406                 } else {
407                     destination.0
408                 };
409
410                 let return_block = destination.1;
411
412                 let args : Vec<_> = if is_box_free {
413                     assert!(args.len() == 1);
414                     // box_free takes a Box, but is defined with a *mut T, inlining
415                     // needs to generate the cast.
416                     // FIXME: we should probably just generate correct MIR in the first place...
417
418                     let arg = if let Operand::Consume(ref lval) = args[0] {
419                         lval.clone()
420                     } else {
421                         bug!("Constant arg to \"box_free\"");
422                     };
423
424                     let ptr_ty = args[0].ty(caller_mir, self.tcx);
425                     vec![self.cast_box_free_arg(arg, ptr_ty, &callsite, caller_mir)]
426                 } else {
427                     // Copy the arguments if needed.
428                     self.make_call_args(args, &callsite, caller_mir)
429                 };
430
431                 let bb_len = caller_mir.basic_blocks().len();
432                 let mut integrator = Integrator {
433                     block_idx: bb_len,
434                     args: &args,
435                     local_map: local_map,
436                     scope_map: scope_map,
437                     promoted_map: promoted_map,
438                     _callsite: callsite,
439                     destination: dest,
440                     return_block: return_block,
441                     cleanup_block: cleanup,
442                     in_cleanup_block: false
443                 };
444
445
446                 for (bb, mut block) in callee_mir.basic_blocks_mut().drain_enumerated(..) {
447                     integrator.visit_basic_block_data(bb, &mut block);
448                     caller_mir.basic_blocks_mut().push(block);
449                 }
450
451                 let terminator = Terminator {
452                     source_info: callsite.location,
453                     kind: TerminatorKind::Goto { target: BasicBlock::new(bb_len) }
454                 };
455
456                 caller_mir[callsite.bb].terminator = Some(terminator);
457
458                 true
459             }
460             kind => {
461                 caller_mir[callsite.bb].terminator = Some(Terminator {
462                     source_info: terminator.source_info,
463                     kind: kind
464                 });
465                 false
466             }
467         }
468     }
469
470     fn cast_box_free_arg(&self, arg: Lvalue<'tcx>, ptr_ty: Ty<'tcx>,
471                          callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Operand<'tcx> {
472         let arg = Rvalue::Ref(
473             self.tcx.types.re_erased,
474             BorrowKind::Mut,
475             arg.deref());
476
477         let ty = arg.ty(caller_mir, self.tcx);
478         let ref_tmp = LocalDecl::new_temp(ty, callsite.location.span);
479         let ref_tmp = caller_mir.local_decls.push(ref_tmp);
480         let ref_tmp = Lvalue::Local(ref_tmp);
481
482         let ref_stmt = Statement {
483             source_info: callsite.location,
484             kind: StatementKind::Assign(ref_tmp.clone(), arg)
485         };
486
487         caller_mir[callsite.bb]
488             .statements.push(ref_stmt);
489
490         let pointee_ty = match ptr_ty.sty {
491             ty::TyRawPtr(tm) | ty::TyRef(_, tm) => tm.ty,
492             _ if ptr_ty.is_box() => ptr_ty.boxed_ty(),
493             _ => bug!("Invalid type `{:?}` for call to box_free", ptr_ty)
494         };
495         let ptr_ty = self.tcx.mk_mut_ptr(pointee_ty);
496
497         let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Consume(ref_tmp), ptr_ty);
498
499         let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span);
500         let cast_tmp = caller_mir.local_decls.push(cast_tmp);
501         let cast_tmp = Lvalue::Local(cast_tmp);
502
503         let cast_stmt = Statement {
504             source_info: callsite.location,
505             kind: StatementKind::Assign(cast_tmp.clone(), raw_ptr)
506         };
507
508         caller_mir[callsite.bb]
509             .statements.push(cast_stmt);
510
511         Operand::Consume(cast_tmp)
512     }
513
514     fn make_call_args(&self, args: Vec<Operand<'tcx>>,
515                       callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Vec<Operand<'tcx>> {
516         let tcx = self.tcx;
517         // FIXME: Analysis of the usage of the arguments to avoid
518         // unnecessary temporaries.
519         args.into_iter().map(|a| {
520             if let Operand::Consume(Lvalue::Local(local)) = a {
521                 if caller_mir.local_kind(local) == LocalKind::Temp {
522                     // Reuse the operand if it's a temporary already
523                     return a;
524                 }
525             }
526
527             debug!("Creating temp for argument");
528             // Otherwise, create a temporary for the arg
529             let arg = Rvalue::Use(a);
530
531             let ty = arg.ty(caller_mir, tcx);
532
533             let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span);
534             let arg_tmp = caller_mir.local_decls.push(arg_tmp);
535             let arg_tmp = Lvalue::Local(arg_tmp);
536
537             let stmt = Statement {
538                 source_info: callsite.location,
539                 kind: StatementKind::Assign(arg_tmp.clone(), arg)
540             };
541             caller_mir[callsite.bb].statements.push(stmt);
542             Operand::Consume(arg_tmp)
543         }).collect()
544     }
545 }
546
547 fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
548                           param_env: ty::ParamEnv<'tcx>,
549                           ty: Ty<'tcx>) -> Option<u64> {
550     tcx.infer_ctxt(param_env.reveal_all()).enter(|infcx| {
551         ty.layout(&infcx).ok().map(|layout| {
552             layout.size(&tcx.data_layout).bytes()
553         })
554     })
555 }
556
557 /**
558  * Integrator.
559  *
560  * Integrates blocks from the callee function into the calling function.
561  * Updates block indices, references to locals and other control flow
562  * stuff.
563  */
564 struct Integrator<'a, 'tcx: 'a> {
565     block_idx: usize,
566     args: &'a [Operand<'tcx>],
567     local_map: IndexVec<Local, Local>,
568     scope_map: IndexVec<VisibilityScope, VisibilityScope>,
569     promoted_map: IndexVec<Promoted, Promoted>,
570     _callsite: CallSite<'tcx>,
571     destination: Lvalue<'tcx>,
572     return_block: BasicBlock,
573     cleanup_block: Option<BasicBlock>,
574     in_cleanup_block: bool,
575 }
576
577 impl<'a, 'tcx> Integrator<'a, 'tcx> {
578     fn update_target(&self, tgt: BasicBlock) -> BasicBlock {
579         let new = BasicBlock::new(tgt.index() + self.block_idx);
580         debug!("Updating target `{:?}`, new: `{:?}`", tgt, new);
581         new
582     }
583
584     fn update_local(&self, local: Local) -> Option<Local> {
585         let idx = local.index();
586         if idx < (self.args.len() + 1) {
587             return None;
588         }
589         let idx = idx - (self.args.len() + 1);
590         let local = Local::new(idx);
591         self.local_map.get(local).cloned()
592     }
593
594     fn arg_index(&self, arg: Local) -> Option<usize> {
595         let idx = arg.index();
596         if idx > 0 && idx <= self.args.len() {
597             Some(idx - 1)
598         } else {
599             None
600         }
601     }
602 }
603
604 impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
605     fn visit_lvalue(&mut self,
606                     lvalue: &mut Lvalue<'tcx>,
607                     _ctxt: LvalueContext<'tcx>,
608                     _location: Location) {
609         if let Lvalue::Local(ref mut local) = *lvalue {
610             if let Some(l) = self.update_local(*local) {
611                 // Temp or Var; update the local reference
612                 *local = l;
613                 return;
614             }
615         }
616         if let Lvalue::Local(local) = *lvalue {
617             if local == RETURN_POINTER {
618                 // Return pointer; update the lvalue itself
619                 *lvalue = self.destination.clone();
620             } else if local.index() < (self.args.len() + 1) {
621                 // Argument, once again update the the lvalue itself
622                 let idx = local.index() - 1;
623                 if let Operand::Consume(ref lval) = self.args[idx] {
624                     *lvalue = lval.clone();
625                 } else {
626                     bug!("Arg operand `{:?}` is not an Lvalue use.", idx)
627                 }
628             }
629         } else {
630             self.super_lvalue(lvalue, _ctxt, _location)
631         }
632     }
633
634     fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
635         if let Operand::Consume(Lvalue::Local(arg)) = *operand {
636             if let Some(idx) = self.arg_index(arg) {
637                 let new_arg = self.args[idx].clone();
638                 *operand = new_arg;
639                 return;
640             }
641         }
642         self.super_operand(operand, location);
643     }
644
645     fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
646         self.in_cleanup_block = data.is_cleanup;
647         self.super_basic_block_data(block, data);
648         self.in_cleanup_block = false;
649     }
650
651     fn visit_terminator_kind(&mut self, block: BasicBlock,
652                              kind: &mut TerminatorKind<'tcx>, loc: Location) {
653         self.super_terminator_kind(block, kind, loc);
654
655         match *kind {
656             TerminatorKind::Goto { ref mut target} => {
657                 *target = self.update_target(*target);
658             }
659             TerminatorKind::SwitchInt { ref mut targets, .. } => {
660                 for tgt in targets {
661                     *tgt = self.update_target(*tgt);
662                 }
663             }
664             TerminatorKind::Drop { ref mut target, ref mut unwind, .. } |
665             TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => {
666                 *target = self.update_target(*target);
667                 if let Some(tgt) = *unwind {
668                     *unwind = Some(self.update_target(tgt));
669                 } else if !self.in_cleanup_block {
670                     // Unless this drop is in a cleanup block, add an unwind edge to
671                     // the orignal call's cleanup block
672                     *unwind = self.cleanup_block;
673                 }
674             }
675             TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => {
676                 if let Some((_, ref mut tgt)) = *destination {
677                     *tgt = self.update_target(*tgt);
678                 }
679                 if let Some(tgt) = *cleanup {
680                     *cleanup = Some(self.update_target(tgt));
681                 } else if !self.in_cleanup_block {
682                     // Unless this call is in a cleanup block, add an unwind edge to
683                     // the orignal call's cleanup block
684                     *cleanup = self.cleanup_block;
685                 }
686             }
687             TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => {
688                 *target = self.update_target(*target);
689                 if let Some(tgt) = *cleanup {
690                     *cleanup = Some(self.update_target(tgt));
691                 } else if !self.in_cleanup_block {
692                     // Unless this assert is in a cleanup block, add an unwind edge to
693                     // the orignal call's cleanup block
694                     *cleanup = self.cleanup_block;
695                 }
696             }
697             TerminatorKind::Return => {
698                 *kind = TerminatorKind::Goto { target: self.return_block };
699             }
700             TerminatorKind::Resume => {
701                 if let Some(tgt) = self.cleanup_block {
702                     *kind = TerminatorKind::Goto { target: tgt }
703                 }
704             }
705             TerminatorKind::Unreachable => { }
706         }
707     }
708
709     fn visit_visibility_scope(&mut self, scope: &mut VisibilityScope) {
710         *scope = self.scope_map[*scope];
711     }
712
713     fn visit_literal(&mut self, literal: &mut Literal<'tcx>, loc: Location) {
714         if let Literal::Promoted { ref mut index } = *literal {
715             if let Some(p) = self.promoted_map.get(*index).cloned() {
716                 *index = p;
717             }
718         } else {
719             self.super_literal(literal, loc);
720         }
721     }
722 }