Skip to content

Commit

Permalink
Auto merge of #46321 - eddyb:even-mirer-3, r=<try>
Browse files Browse the repository at this point in the history
 rustc_mir: implement an "lvalue reuse" optimization (aka destination propagation aka NRVO).

Replaces a chain of moves, such as `a = ...; ... b = move a; ... f(&mut b) ... c = move b`, with the final destination, i.e. only `c = ...; ... f(&mut c); ...` remains (note that borrowing is allowed).

**DO NOT MERGE** only for testing atm. Based on #46142.
  • Loading branch information
bors committed Nov 28, 2017
2 parents 3e9a7f7 + 69b5139 commit cf73ed6
Show file tree
Hide file tree
Showing 76 changed files with 730 additions and 449 deletions.
5 changes: 4 additions & 1 deletion src/librustc/ich/impls_mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Operand<'gcx> {
mem::discriminant(self).hash_stable(hcx, hasher);

match *self {
mir::Operand::Consume(ref lvalue) => {
mir::Operand::Copy(ref lvalue) => {
lvalue.hash_stable(hcx, hasher);
}
mir::Operand::Move(ref lvalue) => {
lvalue.hash_stable(hcx, hasher);
}
mir::Operand::Constant(ref constant) => {
Expand Down
21 changes: 17 additions & 4 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1283,7 +1283,17 @@ pub struct VisibilityScopeData {
/// being nested in one another.
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Operand<'tcx> {
Consume(Lvalue<'tcx>),
/// Copy: The value must be available for use afterwards.
///
/// This implies that the type of the lvalue must be `Copy`; this is true
/// by construction during build, but also checked by the MIR type checker.
Copy(Lvalue<'tcx>),
/// Move: The value (including old borrows of it) will not be used again.
///
/// Safe for values of all types (modulo future developments towards `?Move`).
/// Correct usage patterns are enforced by the borrow checker for safe code.
/// `Copy` may be converted to `Move` to enable "last-use" optimizations.
Move(Lvalue<'tcx>),
Constant(Box<Constant<'tcx>>),
}

Expand All @@ -1292,7 +1302,8 @@ impl<'tcx> Debug for Operand<'tcx> {
use self::Operand::*;
match *self {
Constant(ref a) => write!(fmt, "{:?}", a),
Consume(ref lv) => write!(fmt, "{:?}", lv),
Copy(ref lv) => write!(fmt, "{:?}", lv),
Move(ref lv) => write!(fmt, "move {:?}", lv),
}
}
}
Expand Down Expand Up @@ -2089,14 +2100,16 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
Operand::Consume(ref lval) => Operand::Consume(lval.fold_with(folder)),
Operand::Copy(ref lval) => Operand::Copy(lval.fold_with(folder)),
Operand::Move(ref lval) => Operand::Move(lval.fold_with(folder)),
Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)),
}
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
Operand::Consume(ref lval) => lval.visit_with(visitor),
Operand::Copy(ref lval) |
Operand::Move(ref lval) => lval.visit_with(visitor),
Operand::Constant(ref c) => c.visit_with(visitor)
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ impl<'tcx> Operand<'tcx> {
where D: HasLocalDecls<'tcx>
{
match self {
&Operand::Consume(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
&Operand::Copy(ref l) |
&Operand::Move(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
&Operand::Constant(ref c) => c.ty,
}
}
Expand Down
18 changes: 12 additions & 6 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,8 +611,11 @@ macro_rules! make_mir_visitor {
operand: & $($mutability)* Operand<'tcx>,
location: Location) {
match *operand {
Operand::Consume(ref $($mutability)* lvalue) => {
self.visit_lvalue(lvalue, LvalueContext::Consume, location);
Operand::Copy(ref $($mutability)* lvalue) => {
self.visit_lvalue(lvalue, LvalueContext::Copy, location);
}
Operand::Move(ref $($mutability)* lvalue) => {
self.visit_lvalue(lvalue, LvalueContext::Move, location);
}
Operand::Constant(ref $($mutability)* constant) => {
self.visit_constant(constant, location);
Expand Down Expand Up @@ -679,7 +682,7 @@ macro_rules! make_mir_visitor {
self.visit_ty(ty, TyContext::Location(location));
}
ProjectionElem::Index(ref $($mutability)* local) => {
self.visit_local(local, LvalueContext::Consume, location);
self.visit_local(local, LvalueContext::Copy, location);
}
ProjectionElem::ConstantIndex { offset: _,
min_length: _,
Expand Down Expand Up @@ -860,7 +863,8 @@ pub enum LvalueContext<'tcx> {
Projection(Mutability),

// Consumed as part of an operand
Consume,
Copy,
Move,

// Starting and ending a storage live range
StorageLive,
Expand Down Expand Up @@ -913,7 +917,8 @@ impl<'tcx> LvalueContext<'tcx> {
LvalueContext::Inspect |
LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume |
LvalueContext::Projection(Mutability::Not) |
LvalueContext::Copy | LvalueContext::Move |
LvalueContext::StorageLive | LvalueContext::StorageDead |
LvalueContext::Validate => false,
}
Expand All @@ -924,7 +929,8 @@ impl<'tcx> LvalueContext<'tcx> {
match *self {
LvalueContext::Inspect | LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume => true,
LvalueContext::Projection(Mutability::Not) |
LvalueContext::Copy | LvalueContext::Move => true,
LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | LvalueContext::Store |
LvalueContext::Call | LvalueContext::Projection(Mutability::Mut) |
LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead |
Expand Down
Loading

0 comments on commit cf73ed6

Please sign in to comment.