2015-10-21 16:42:25 -05:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2016-09-19 15:50:00 -05:00
|
|
|
use rustc::mir;
|
2016-06-07 09:28:36 -05:00
|
|
|
|
2016-08-13 22:34:14 -05:00
|
|
|
use base;
|
2017-02-15 13:21:36 -06:00
|
|
|
use asm;
|
2016-12-31 17:00:24 -06:00
|
|
|
use common;
|
|
|
|
use builder::Builder;
|
2015-10-21 16:42:25 -05:00
|
|
|
|
|
|
|
use super::MirContext;
|
2016-06-20 15:55:14 -05:00
|
|
|
use super::LocalRef;
|
2015-10-21 16:42:25 -05:00
|
|
|
|
2016-12-17 20:54:32 -06:00
|
|
|
impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
2015-10-21 16:42:25 -05:00
|
|
|
pub fn trans_statement(&mut self,
|
2016-12-31 17:00:24 -06:00
|
|
|
bcx: Builder<'a, 'tcx>,
|
2015-10-21 16:42:25 -05:00
|
|
|
statement: &mir::Statement<'tcx>)
|
2016-12-31 17:00:24 -06:00
|
|
|
-> Builder<'a, 'tcx> {
|
2015-10-21 16:42:25 -05:00
|
|
|
debug!("trans_statement(statement={:?})", statement);
|
|
|
|
|
2016-12-19 15:38:16 -06:00
|
|
|
self.set_debug_loc(&bcx, statement.source_info);
|
2015-10-21 16:42:25 -05:00
|
|
|
match statement.kind {
|
|
|
|
mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
|
2016-09-24 18:38:27 -05:00
|
|
|
if let mir::Lvalue::Local(index) = *lvalue {
|
2016-06-20 15:55:14 -05:00
|
|
|
match self.locals[index] {
|
|
|
|
LocalRef::Lvalue(tr_dest) => {
|
2016-12-11 09:59:20 -06:00
|
|
|
self.trans_rvalue(bcx, tr_dest, rvalue)
|
2016-06-20 15:55:14 -05:00
|
|
|
}
|
|
|
|
LocalRef::Operand(None) => {
|
2016-12-11 09:59:20 -06:00
|
|
|
let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue);
|
2016-06-20 15:55:14 -05:00
|
|
|
self.locals[index] = LocalRef::Operand(Some(operand));
|
|
|
|
bcx
|
|
|
|
}
|
|
|
|
LocalRef::Operand(Some(_)) => {
|
2016-08-05 17:59:51 -05:00
|
|
|
let ty = self.monomorphized_lvalue_ty(lvalue);
|
Various improvements to MIR and LLVM IR Construction
Primarily affects the MIR construction, which indirectly improves LLVM
IR generation, but some LLVM IR changes have been made too.
* Handle "statement expressions" more intelligently. These are
expressions that always evaluate to `()`. Previously a temporary would
be generated as a destination to translate into, which is unnecessary.
This affects assignment, augmented assignment, `return`, `break` and
`continue`.
* Avoid inserting drops for non-drop types in more places. Scheduled
drops were already skipped for types that we knew wouldn't need
dropping at construction time. However manually-inserted drops like
those for `x` in `x = y;` were still generated. `build_drop` now takes
a type parameter like its `schedule_drop` counterpart and checks to
see if the type needs dropping.
* Avoid generating an extra temporary for an assignment where the types
involved don't need dropping. Previously an expression like
`a = b + 1;` would result in a temporary for `b + 1`. This is so the
RHS can be evaluated, then the LHS evaluated and dropped and have
everything work correctly. However, this isn't necessary if the `LHS`
doesn't need a drop, as we can just overwrite the existing value.
* Improves lvalue analysis to allow treating an `Rvalue::Use` as an
operand in certain conditions. The reason for it never being an
operand is so it can be zeroed/drop-filled, but this is only true for
types that need dropping.
The first two changes result in significantly fewer MIR blocks being
generated, as previously almost every statement would end up generating
a new block due to the drop of the `()` temporary being generated.
2016-04-14 19:36:16 -05:00
|
|
|
|
2016-12-19 17:25:00 -06:00
|
|
|
if !common::type_is_zero_size(bcx.ccx, ty) {
|
2016-06-20 15:55:14 -05:00
|
|
|
span_bug!(statement.source_info.span,
|
|
|
|
"operand {:?} already assigned",
|
|
|
|
rvalue);
|
|
|
|
} else {
|
|
|
|
// If the type is zero-sized, it's already been set here,
|
|
|
|
// but we still need to make sure we translate the operand
|
2016-12-11 09:59:20 -06:00
|
|
|
self.trans_rvalue_operand(bcx, rvalue).0
|
2015-11-02 08:39:59 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-06-20 15:55:14 -05:00
|
|
|
} else {
|
|
|
|
let tr_dest = self.trans_lvalue(&bcx, lvalue);
|
2016-12-11 09:59:20 -06:00
|
|
|
self.trans_rvalue(bcx, tr_dest, rvalue)
|
2015-11-02 08:39:59 -06:00
|
|
|
}
|
2015-10-21 16:42:25 -05:00
|
|
|
}
|
2016-08-04 18:14:33 -05:00
|
|
|
mir::StatementKind::SetDiscriminant{ref lvalue, variant_index} => {
|
2017-04-25 06:39:00 -05:00
|
|
|
self.trans_lvalue(&bcx, lvalue)
|
|
|
|
.trans_set_discr(&bcx, variant_index);
|
2016-08-04 18:14:33 -05:00
|
|
|
bcx
|
|
|
|
}
|
2017-09-04 00:01:46 -05:00
|
|
|
mir::StatementKind::StorageLive(local) => {
|
|
|
|
self.trans_storage_liveness(bcx, local, base::Lifetime::Start)
|
2016-08-13 22:34:14 -05:00
|
|
|
}
|
2017-09-04 00:01:46 -05:00
|
|
|
mir::StatementKind::StorageDead(local) => {
|
|
|
|
self.trans_storage_liveness(bcx, local, base::Lifetime::End)
|
2016-08-13 22:34:14 -05:00
|
|
|
}
|
2017-02-15 13:21:36 -06:00
|
|
|
mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
|
|
|
|
let outputs = outputs.iter().map(|output| {
|
|
|
|
let lvalue = self.trans_lvalue(&bcx, output);
|
|
|
|
(lvalue.llval, lvalue.ty.to_ty(bcx.tcx()))
|
|
|
|
}).collect();
|
|
|
|
|
|
|
|
let input_vals = inputs.iter().map(|input| {
|
|
|
|
self.trans_operand(&bcx, input).immediate()
|
|
|
|
}).collect();
|
|
|
|
|
|
|
|
asm::trans_inline_asm(&bcx, asm, outputs, input_vals);
|
|
|
|
bcx
|
|
|
|
}
|
Add `EndRegion` statement kind to MIR.
* Emit `EndRegion` for every code-extent for which we observe a
borrow. To do this, we needed to thread source info back through
to `fn in_scope`, which makes this commit a bit more painful than
one might have expected.
* There is `end_region` emission in `Builder::pop_scope` and in
`Builder::exit_scope`; the first handles falling out of a scope
normally, the second handles e.g. `break`.
* Remove `EndRegion` statements during the erase_regions mir
transformation.
* Preallocate the terminator block, and throw an `Unreachable` marker
on it from the outset. Then overwrite that Terminator as necessary
on demand.
* Instead of marking the scope as needs_cleanup after seeing a
borrow, just treat every scope in the chain as being part of the
diverge_block (after any *one* of them has separately signalled
that it needs cleanup, e.g. due to having a destructor to run).
* Allow for resume terminators to be patched when looking up drop flags.
(In particular, `MirPatch::new` has an explicit code path,
presumably previously unreachable, that patches up such resume
terminators.)
* Make `Scope` implement `Debug` trait.
* Expanded a stray comment: we do not emit StorageDead on diverging
paths, but that end behavior might not be desirable.
2017-02-17 06:38:42 -06:00
|
|
|
mir::StatementKind::EndRegion(_) |
|
2017-07-11 16:01:07 -05:00
|
|
|
mir::StatementKind::Validate(..) |
|
2016-09-15 20:17:58 -05:00
|
|
|
mir::StatementKind::Nop => bcx,
|
2016-08-13 22:34:14 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_storage_liveness(&self,
|
2016-12-31 17:00:24 -06:00
|
|
|
bcx: Builder<'a, 'tcx>,
|
2017-09-04 00:01:46 -05:00
|
|
|
index: mir::Local,
|
2016-08-13 22:34:14 -05:00
|
|
|
intrinsic: base::Lifetime)
|
2016-12-31 17:00:24 -06:00
|
|
|
-> Builder<'a, 'tcx> {
|
2017-09-04 00:01:46 -05:00
|
|
|
if let LocalRef::Lvalue(tr_lval) = self.locals[index] {
|
|
|
|
intrinsic.call(&bcx, tr_lval.llval);
|
2015-10-21 16:42:25 -05:00
|
|
|
}
|
2016-08-13 22:34:14 -05:00
|
|
|
bcx
|
2015-10-21 16:42:25 -05:00
|
|
|
}
|
|
|
|
}
|