Skip to content

Commit

Permalink
Rollup merge of rust-lang#40133 - arielb1:operand-lifetimes, r=eddyb
Browse files Browse the repository at this point in the history
[MIR] improve operand lifetimes

r? @eddyb
  • Loading branch information
frewsxcv authored Mar 2, 2017
2 parents a68156c + e4458de commit 21d61ff
Show file tree
Hide file tree
Showing 15 changed files with 354 additions and 129 deletions.
1 change: 1 addition & 0 deletions src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
fn create_drop_flag(&mut self, index: MovePathIndex) {
let tcx = self.tcx;
let patch = &mut self.patch;
debug!("create_drop_flag({:?})", self.mir.span);
self.drop_flags.entry(index).or_insert_with(|| {
patch.new_temp(tcx.types.bool)
});
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_mir/build/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
this.expr_into_pattern(block, pattern, init)
}));
} else {
this.storage_live_for_bindings(block, &pattern);
this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
this.storage_live_binding(block, node, span);
this.schedule_drop_for_binding(node, span);
})
}

// Enter the visibility scope, after evaluating the initializer.
Expand Down
8 changes: 5 additions & 3 deletions src/librustc_mir/build/expr/as_lvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let (usize_ty, bool_ty) = (this.hir.usize_ty(), this.hir.bool_ty());

let slice = unpack!(block = this.as_lvalue(block, lhs));

let idx = unpack!(block = this.as_operand(block, index));
// extent=None so lvalue indexes live forever. They are scalars so they
// do not need storage annotations, and they are often copied between
// places.
let idx = unpack!(block = this.as_operand(block, None, index));

// bounds check:
let (len, lt) = (this.temp(usize_ty.clone()), this.temp(bool_ty));
Expand Down Expand Up @@ -121,7 +123,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Some(Category::Lvalue) => false,
_ => true,
});
this.as_temp(block, expr)
this.as_temp(block, expr.temp_lifetime, expr)
}
}
}
Expand Down
32 changes: 28 additions & 4 deletions src/librustc_mir/build/expr/as_operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,52 @@
use build::{BlockAnd, BlockAndExtension, Builder};
use build::expr::category::Category;
use hair::*;
use rustc::middle::region::CodeExtent;
use rustc::mir::*;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// Returns an operand suitable for use until the end of the current
/// scope expression.
///
/// The operand returned from this function will *not be valid* after
/// an ExprKind::Scope is passed, so please do *not* return it from
/// functions to avoid bad miscompiles.
pub fn as_local_operand<M>(&mut self, block: BasicBlock, expr: M)
-> BlockAnd<Operand<'tcx>>
where M: Mirror<'tcx, Output = Expr<'tcx>>
{
let topmost_scope = self.topmost_scope(); // FIXME(#6393)
self.as_operand(block, Some(topmost_scope), expr)
}

/// Compile `expr` into a value that can be used as an operand.
/// If `expr` is an lvalue like `x`, this will introduce a
/// temporary `tmp = x`, so that we capture the value of `x` at
/// this time.
pub fn as_operand<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Operand<'tcx>>
///
/// The operand is known to be live until the end of `scope`.
pub fn as_operand<M>(&mut self,
block: BasicBlock,
scope: Option<CodeExtent>,
expr: M) -> BlockAnd<Operand<'tcx>>
where M: Mirror<'tcx, Output = Expr<'tcx>>
{
let expr = self.hir.mirror(expr);
self.expr_as_operand(block, expr)
self.expr_as_operand(block, scope, expr)
}

fn expr_as_operand(&mut self,
mut block: BasicBlock,
scope: Option<CodeExtent>,
expr: Expr<'tcx>)
-> BlockAnd<Operand<'tcx>> {
debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
let this = self;

if let ExprKind::Scope { extent, value } = expr.kind {
return this.in_scope(extent, block, |this| this.as_operand(block, value));
return this.in_scope(extent, block, |this| {
this.as_operand(block, scope, value)
});
}

let category = Category::of(&expr.kind).unwrap();
Expand All @@ -47,7 +70,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
Category::Lvalue |
Category::Rvalue(..) => {
let operand = unpack!(block = this.as_temp(block, expr));
let operand =
unpack!(block = this.as_temp(block, scope, expr));
block.and(Operand::Consume(operand))
}
}
Expand Down
53 changes: 32 additions & 21 deletions src/librustc_mir/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,34 @@ use build::expr::category::{Category, RvalueFunc};
use hair::*;
use rustc_const_math::{ConstInt, ConstIsize};
use rustc::middle::const_val::ConstVal;
use rustc::middle::region::CodeExtent;
use rustc::ty;
use rustc::mir::*;
use syntax::ast;
use syntax_pos::Span;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// See comment on `as_local_operand`
pub fn as_local_rvalue<M>(&mut self, block: BasicBlock, expr: M)
-> BlockAnd<Rvalue<'tcx>>
where M: Mirror<'tcx, Output = Expr<'tcx>>
{
let topmost_scope = self.topmost_scope(); // FIXME(#6393)
self.as_rvalue(block, Some(topmost_scope), expr)
}

/// Compile `expr`, yielding an rvalue.
pub fn as_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
pub fn as_rvalue<M>(&mut self, block: BasicBlock, scope: Option<CodeExtent>, expr: M)
-> BlockAnd<Rvalue<'tcx>>
where M: Mirror<'tcx, Output = Expr<'tcx>>
{
let expr = self.hir.mirror(expr);
self.expr_as_rvalue(block, expr)
self.expr_as_rvalue(block, scope, expr)
}

fn expr_as_rvalue(&mut self,
mut block: BasicBlock,
scope: Option<CodeExtent>,
expr: Expr<'tcx>)
-> BlockAnd<Rvalue<'tcx>> {
debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr);
Expand All @@ -47,24 +59,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {

match expr.kind {
ExprKind::Scope { extent, value } => {
this.in_scope(extent, block, |this| this.as_rvalue(block, value))
this.in_scope(extent, block, |this| this.as_rvalue(block, scope, value))
}
ExprKind::Repeat { value, count } => {
let value_operand = unpack!(block = this.as_operand(block, value));
let value_operand = unpack!(block = this.as_operand(block, scope, value));
block.and(Rvalue::Repeat(value_operand, count))
}
ExprKind::Borrow { region, borrow_kind, arg } => {
let arg_lvalue = unpack!(block = this.as_lvalue(block, arg));
block.and(Rvalue::Ref(region, borrow_kind, arg_lvalue))
}
ExprKind::Binary { op, lhs, rhs } => {
let lhs = unpack!(block = this.as_operand(block, lhs));
let rhs = unpack!(block = this.as_operand(block, rhs));
let lhs = unpack!(block = this.as_operand(block, scope, lhs));
let rhs = unpack!(block = this.as_operand(block, scope, rhs));
this.build_binary_op(block, op, expr_span, expr.ty,
lhs, rhs)
}
ExprKind::Unary { op, arg } => {
let arg = unpack!(block = this.as_operand(block, arg));
let arg = unpack!(block = this.as_operand(block, scope, arg));
// Check for -MIN on signed integers
if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() {
let bool_ty = this.hir.bool_ty();
Expand Down Expand Up @@ -97,27 +109,27 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ExprKind::Cast { source } => {
let source = this.hir.mirror(source);

let source = unpack!(block = this.as_operand(block, source));
let source = unpack!(block = this.as_operand(block, scope, source));
block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
}
ExprKind::Use { source } => {
let source = unpack!(block = this.as_operand(block, source));
let source = unpack!(block = this.as_operand(block, scope, source));
block.and(Rvalue::Use(source))
}
ExprKind::ReifyFnPointer { source } => {
let source = unpack!(block = this.as_operand(block, source));
let source = unpack!(block = this.as_operand(block, scope, source));
block.and(Rvalue::Cast(CastKind::ReifyFnPointer, source, expr.ty))
}
ExprKind::UnsafeFnPointer { source } => {
let source = unpack!(block = this.as_operand(block, source));
let source = unpack!(block = this.as_operand(block, scope, source));
block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty))
}
ExprKind::ClosureFnPointer { source } => {
let source = unpack!(block = this.as_operand(block, source));
let source = unpack!(block = this.as_operand(block, scope, source));
block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty))
}
ExprKind::Unsize { source } => {
let source = unpack!(block = this.as_operand(block, source));
let source = unpack!(block = this.as_operand(block, scope, source));
block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty))
}
ExprKind::Array { fields } => {
Expand Down Expand Up @@ -151,7 +163,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let el_ty = expr.ty.sequence_element_type(this.hir.tcx());
let fields: Vec<_> =
fields.into_iter()
.map(|f| unpack!(block = this.as_operand(block, f)))
.map(|f| unpack!(block = this.as_operand(block, scope, f)))
.collect();

block.and(Rvalue::Aggregate(AggregateKind::Array(el_ty), fields))
Expand All @@ -160,15 +172,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// first process the set of fields
let fields: Vec<_> =
fields.into_iter()
.map(|f| unpack!(block = this.as_operand(block, f)))
.map(|f| unpack!(block = this.as_operand(block, scope, f)))
.collect();

block.and(Rvalue::Aggregate(AggregateKind::Tuple, fields))
}
ExprKind::Closure { closure_id, substs, upvars } => { // see (*) above
let upvars =
upvars.into_iter()
.map(|upvar| unpack!(block = this.as_operand(block, upvar)))
.map(|upvar| unpack!(block = this.as_operand(block, scope, upvar)))
.collect();
block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars))
}
Expand All @@ -180,10 +192,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {

// first process the set of fields that were provided
// (evaluating them in order given by user)
let fields_map: FxHashMap<_, _> =
fields.into_iter()
.map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr))))
.collect();
let fields_map: FxHashMap<_, _> = fields.into_iter()
.map(|f| (f.name, unpack!(block = this.as_operand(block, scope, f.expr))))
.collect();

let field_names = this.hir.all_fields(adt_def, variant_index);

Expand Down Expand Up @@ -236,7 +247,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
Some(Category::Rvalue(RvalueFunc::AsRvalue)) => false,
_ => true,
});
let operand = unpack!(block = this.as_operand(block, expr));
let operand = unpack!(block = this.as_operand(block, scope, expr));
block.and(Rvalue::Use(operand))
}
}
Expand Down
21 changes: 15 additions & 6 deletions src/librustc_mir/build/expr/as_temp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,38 @@
use build::{BlockAnd, BlockAndExtension, Builder};
use build::expr::category::Category;
use hair::*;
use rustc::middle::region::CodeExtent;
use rustc::mir::*;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// Compile `expr` into a fresh temporary. This is used when building
/// up rvalues so as to freeze the value that will be consumed.
pub fn as_temp<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Lvalue<'tcx>>
pub fn as_temp<M>(&mut self,
block: BasicBlock,
temp_lifetime: Option<CodeExtent>,
expr: M)
-> BlockAnd<Lvalue<'tcx>>
where M: Mirror<'tcx, Output = Expr<'tcx>>
{
let expr = self.hir.mirror(expr);
self.expr_as_temp(block, expr)
self.expr_as_temp(block, temp_lifetime, expr)
}

fn expr_as_temp(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<Lvalue<'tcx>> {
fn expr_as_temp(&mut self,
mut block: BasicBlock,
temp_lifetime: Option<CodeExtent>,
expr: Expr<'tcx>)
-> BlockAnd<Lvalue<'tcx>> {
debug!("expr_as_temp(block={:?}, expr={:?})", block, expr);
let this = self;

if let ExprKind::Scope { extent, value } = expr.kind {
return this.in_scope(extent, block, |this| this.as_temp(block, value));
if let ExprKind::Scope { .. } = expr.kind {
span_bug!(expr.span, "unexpected scope expression in as_temp: {:?}",
expr);
}

let expr_ty = expr.ty.clone();
let temp = this.temp(expr_ty.clone());
let temp_lifetime = expr.temp_lifetime;
let expr_span = expr.span;
let source_info = this.source_info(expr_span);

Expand Down
16 changes: 8 additions & 8 deletions src/librustc_mir/build/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
_ => false,
};

unpack!(block = this.as_rvalue(block, source));
unpack!(block = this.as_local_rvalue(block, source));

// This is an optimization. If the expression was a call then we already have an
// unreachable block. Don't bother to terminate it and create a new one.
Expand All @@ -65,7 +65,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}
ExprKind::If { condition: cond_expr, then: then_expr, otherwise: else_expr } => {
let operand = unpack!(block = this.as_operand(block, cond_expr));
let operand = unpack!(block = this.as_local_operand(block, cond_expr));

let mut then_block = this.cfg.start_new_block();
let mut else_block = this.cfg.start_new_block();
Expand Down Expand Up @@ -107,15 +107,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
(this.cfg.start_new_block(), this.cfg.start_new_block(),
this.cfg.start_new_block(), this.cfg.start_new_block());

let lhs = unpack!(block = this.as_operand(block, lhs));
let lhs = unpack!(block = this.as_local_operand(block, lhs));
let blocks = match op {
LogicalOp::And => (else_block, false_block),
LogicalOp::Or => (true_block, else_block),
};
let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
this.cfg.terminate(block, source_info, term);

let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
this.cfg.terminate(else_block, source_info, term);

Expand Down Expand Up @@ -173,7 +173,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
if let Some(cond_expr) = opt_cond_expr {
let loop_block_end;
let cond = unpack!(
loop_block_end = this.as_operand(loop_block, cond_expr));
loop_block_end = this.as_local_operand(loop_block, cond_expr));
body_block = this.cfg.start_new_block();
let term = TerminatorKind::if_(this.hir.tcx(), cond,
body_block, exit_block);
Expand Down Expand Up @@ -206,10 +206,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
_ => false
};
let fun = unpack!(block = this.as_operand(block, fun));
let fun = unpack!(block = this.as_local_operand(block, fun));
let args: Vec<_> =
args.into_iter()
.map(|arg| unpack!(block = this.as_operand(block, arg)))
.map(|arg| unpack!(block = this.as_local_operand(block, arg)))
.collect();

let success = this.cfg.start_new_block();
Expand Down Expand Up @@ -265,7 +265,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
_ => true,
});

let rvalue = unpack!(block = this.as_rvalue(block, expr));
let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
this.cfg.push_assign(block, source_info, destination, rvalue);
block.unit()
}
Expand Down
Loading

0 comments on commit 21d61ff

Please sign in to comment.