1
Fork 0

[WIP] Move MIR towards a single kind of local

This commit is contained in:
Jonas Schievink 2016-09-25 01:38:27 +02:00
parent 205dac9355
commit 393db2d830
33 changed files with 628 additions and 661 deletions

View file

@ -70,24 +70,26 @@ pub struct Mir<'tcx> {
/// Rvalues promoted from this function, such as borrows of constants.
/// Each of them is the Mir of a constant with the fn's type parameters
/// in scope, but no vars or args and a separate set of temps.
/// in scope, but a separate set of locals.
pub promoted: IndexVec<Promoted, Mir<'tcx>>,
/// Return type of the function.
pub return_ty: Ty<'tcx>,
/// Variables: these are stack slots corresponding to user variables. They may be
/// assigned many times.
pub var_decls: IndexVec<Var, VarDecl<'tcx>>,
/// Declarations of locals.
///
/// The first local is the return value pointer, followed by `arg_count`
/// locals for the function arguments, followed by any user-declared
/// variables and temporaries.
pub local_decls: IndexVec<Local, LocalDecl<'tcx>>,
/// Args: these are stack slots corresponding to the input arguments.
pub arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
/// Temp declarations: stack slots that for temporaries created by
/// the compiler. These are assigned once, but they are not SSA
/// values in that it is possible to borrow them and mutate them
/// through the resulting reference.
pub temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
/// Number of arguments this function takes.
///
/// Starting at local1, `arg_count` locals will be provided by the caller
/// and can be assumed to be initialized.
///
/// If this MIR was built for a constant, this will be 0.
pub arg_count: usize,
/// Names and capture modes of all the closure upvars, assuming
/// the first argument is either the closure or a reference to it.
@ -114,20 +116,23 @@ impl<'tcx> Mir<'tcx> {
visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
promoted: IndexVec<Promoted, Mir<'tcx>>,
return_ty: Ty<'tcx>,
var_decls: IndexVec<Var, VarDecl<'tcx>>,
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
arg_count: usize,
upvar_decls: Vec<UpvarDecl>,
span: Span) -> Self
{
// We need `arg_count` locals, and one for the return pointer
assert!(local_decls.len() >= arg_count + 1,
"expected at least {} locals, got {}", arg_count + 1, local_decls.len());
assert_eq!(local_decls[RETURN_POINTER].ty, return_ty);
Mir {
basic_blocks: basic_blocks,
visibility_scopes: visibility_scopes,
promoted: promoted,
return_ty: return_ty,
var_decls: var_decls,
arg_decls: arg_decls,
temp_decls: temp_decls,
local_decls: local_decls,
arg_count: arg_count,
upvar_decls: upvar_decls,
spread_last_arg: false,
span: span,
@ -161,56 +166,63 @@ impl<'tcx> Mir<'tcx> {
dominators(self)
}
/// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order)
/// to their index in the whole list of locals. This is useful if you
/// want to treat all locals the same instead of repeating yourself.
pub fn local_index(&self, lvalue: &Lvalue<'tcx>) -> Option<Local> {
let idx = match *lvalue {
Lvalue::Arg(arg) => arg.index(),
Lvalue::Var(var) => {
self.arg_decls.len() +
var.index()
}
Lvalue::Temp(temp) => {
self.arg_decls.len() +
self.var_decls.len() +
temp.index()
}
Lvalue::ReturnPointer => {
self.arg_decls.len() +
self.var_decls.len() +
self.temp_decls.len()
}
Lvalue::Static(_) |
Lvalue::Projection(_) => return None
};
Some(Local::new(idx))
#[inline]
pub fn local_kind(&self, local: Local) -> LocalKind {
let index = local.0 as usize;
if index == 0 {
debug_assert!(self.local_decls[local].mutability == Mutability::Mut,
"return pointer should be mutable");
LocalKind::ReturnPointer
} else if index < self.arg_count + 1 {
LocalKind::Arg
} else if self.local_decls[local].name.is_some() {
LocalKind::Var
} else {
debug_assert!(self.local_decls[local].mutability == Mutability::Mut,
"temp should be mutable");
LocalKind::Temp
}
}
/// Counts the number of locals, such that local_index
/// will always return an index smaller than this count.
pub fn count_locals(&self) -> usize {
self.arg_decls.len() +
self.var_decls.len() +
self.temp_decls.len() + 1
/// Returns an iterator over all temporaries.
#[inline]
pub fn temp_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
(self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
let local = Local::new(index);
if self.local_decls[local].source_info.is_none() {
Some(local)
} else {
None
}
})
}
pub fn format_local(&self, local: Local) -> String {
let mut index = local.index();
index = match index.checked_sub(self.arg_decls.len()) {
None => return format!("{:?}", Arg::new(index)),
Some(index) => index,
};
index = match index.checked_sub(self.var_decls.len()) {
None => return format!("{:?}", Var::new(index)),
Some(index) => index,
};
index = match index.checked_sub(self.temp_decls.len()) {
None => return format!("{:?}", Temp::new(index)),
Some(index) => index,
};
debug_assert!(index == 0);
return "ReturnPointer".to_string()
/// Returns an iterator over all user-declared locals.
#[inline]
pub fn var_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
(self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
let local = Local::new(index);
if self.local_decls[local].source_info.is_none() {
None
} else {
Some(local)
}
})
}
/// Returns an iterator over all function arguments.
#[inline]
pub fn arg_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
(1..self.arg_count+1).map(Local::new)
}
/// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
/// locals that are neither arguments nor the return pointer).
#[inline]
pub fn var_and_temp_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
(self.arg_count+1..self.local_decls.len()).map(Local::new)
}
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@ -308,49 +320,76 @@ pub enum BorrowKind {
///////////////////////////////////////////////////////////////////////////
// Variables and temps
/// A "variable" is a binding declared by the user as part of the fn
/// decl, a let, etc.
newtype_index!(Local, "local");
pub const RETURN_POINTER: Local = Local(0);
/// Classifies locals into categories. See `Mir::local_kind`.
#[derive(PartialEq, Eq, Debug)]
pub enum LocalKind {
/// User-declared variable binding
Var,
/// Compiler-introduced temporary
Temp,
/// Function argument
Arg,
/// Location of function's return value
ReturnPointer,
}
/// A MIR local.
///
/// This can be a binding declared by the user, a temporary inserted by the compiler, a function
/// argument, or the return pointer.
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct VarDecl<'tcx> {
/// `let mut x` vs `let x`
pub struct LocalDecl<'tcx> {
/// `let mut x` vs `let x`.
///
/// Temporaries and the return pointer are always mutable.
pub mutability: Mutability,
/// name that user gave the variable; not that, internally,
/// mir references variables by index
pub name: Name,
/// type inferred for this variable (`let x: ty = ...`)
/// Type of this local.
pub ty: Ty<'tcx>,
/// source information (span, scope, etc.) for the declaration
pub source_info: SourceInfo,
/// Name of the local, used in debuginfo and pretty-printing.
///
/// Note that function arguments can also have this set to `Some(_)`
/// to generate better debuginfo.
pub name: Option<Name>,
/// For user-declared variables, stores their source information.
///
/// For temporaries, this is `None`.
///
/// This is the primary way to differentiate between user-declared
/// variables and compiler-generated temporaries.
pub source_info: Option<SourceInfo>,
}
/// A "temp" is a temporary that we place on the stack. They are
/// anonymous, always mutable, and have only a type.
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct TempDecl<'tcx> {
pub ty: Ty<'tcx>,
}
impl<'tcx> LocalDecl<'tcx> {
/// Create a new `LocalDecl` for a temporary.
#[inline]
pub fn new_temp(ty: Ty<'tcx>) -> Self {
LocalDecl {
mutability: Mutability::Mut,
ty: ty,
name: None,
source_info: None,
}
}
/// A "arg" is one of the function's formal arguments. These are
/// anonymous and distinct from the bindings that the user declares.
///
/// For example, in this function:
///
/// ```
/// fn foo((x, y): (i32, u32)) { ... }
/// ```
///
/// there is only one argument, of type `(i32, u32)`, but two bindings
/// (`x` and `y`).
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ArgDecl<'tcx> {
pub ty: Ty<'tcx>,
/// Either keywords::Invalid or the name of a single-binding
/// pattern associated with this argument. Useful for debuginfo.
pub debug_name: Name
/// Builds a `LocalDecl` for the return pointer.
///
/// This must be inserted into the `local_decls` list as the first local.
#[inline]
pub fn new_return_pointer(return_ty: Ty) -> LocalDecl {
LocalDecl {
mutability: Mutability::Mut,
ty: return_ty,
source_info: None,
name: None, // FIXME maybe we do want some name here?
}
}
}
/// A closure capture, with its name and mode.
@ -442,7 +481,7 @@ pub enum TerminatorKind<'tcx> {
/// continue. Emitted by build::scope::diverge_cleanup.
Resume,
/// Indicates a normal return. The ReturnPointer lvalue should
/// Indicates a normal return. The return pointer lvalue should
/// have been filled in by now. This should occur at most once.
Return,
@ -759,31 +798,16 @@ impl<'tcx> Debug for Statement<'tcx> {
///////////////////////////////////////////////////////////////////////////
// Lvalues
newtype_index!(Var, "var");
newtype_index!(Temp, "tmp");
newtype_index!(Arg, "arg");
newtype_index!(Local, "local");
/// A path to a value; something that can be evaluated without
/// changing or disturbing program state.
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Lvalue<'tcx> {
/// local variable declared by the user
Var(Var),
/// temporary introduced during lowering into MIR
Temp(Temp),
/// formal parameter of the function; note that these are NOT the
/// bindings that the user declares, which are vars
Arg(Arg),
/// local variable
Local(Local),
/// static or static mut variable
Static(DefId),
/// the return pointer of the fn
ReturnPointer,
/// projection out of an lvalue (access a field, deref a pointer, etc)
Projection(Box<LvalueProjection<'tcx>>),
}
@ -865,24 +889,6 @@ impl<'tcx> Lvalue<'tcx> {
elem: elem,
}))
}
pub fn from_local(mir: &Mir<'tcx>, local: Local) -> Lvalue<'tcx> {
let mut index = local.index();
index = match index.checked_sub(mir.arg_decls.len()) {
None => return Lvalue::Arg(Arg(index as u32)),
Some(index) => index,
};
index = match index.checked_sub(mir.var_decls.len()) {
None => return Lvalue::Var(Var(index as u32)),
Some(index) => index,
};
index = match index.checked_sub(mir.temp_decls.len()) {
None => return Lvalue::Temp(Temp(index as u32)),
Some(index) => index,
};
debug_assert!(index == 0);
Lvalue::ReturnPointer
}
}
impl<'tcx> Debug for Lvalue<'tcx> {
@ -890,13 +896,9 @@ impl<'tcx> Debug for Lvalue<'tcx> {
use self::Lvalue::*;
match *self {
Var(id) => write!(fmt, "{:?}", id),
Arg(id) => write!(fmt, "{:?}", id),
Temp(id) => write!(fmt, "{:?}", id),
Local(id) => write!(fmt, "{:?}", id),
Static(def_id) =>
write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))),
ReturnPointer =>
write!(fmt, "return"),
Projection(ref data) =>
match data.elem {
ProjectionElem::Downcast(ref adt_def, index) =>

View file

@ -49,12 +49,17 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
-> LvalueTy<'tcx>
{
match *elem {
ProjectionElem::Deref =>
ProjectionElem::Deref => {
let ty = self.to_ty(tcx)
.builtin_deref(true, ty::LvaluePreference::NoPreference)
.unwrap_or_else(|| {
bug!("deref projection of non-dereferencable ty {:?}", self)
})
.ty;
LvalueTy::Ty {
ty: self.to_ty(tcx).builtin_deref(true, ty::LvaluePreference::NoPreference)
.unwrap()
.ty
},
ty: ty,
}
}
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
LvalueTy::Ty {
ty: self.to_ty(tcx).builtin_index().unwrap()
@ -116,18 +121,12 @@ impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> {
impl<'tcx> Lvalue<'tcx> {
pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> LvalueTy<'tcx> {
match self {
&Lvalue::Var(index) =>
LvalueTy::Ty { ty: mir.var_decls[index].ty },
&Lvalue::Temp(index) =>
LvalueTy::Ty { ty: mir.temp_decls[index].ty },
&Lvalue::Arg(index) =>
LvalueTy::Ty { ty: mir.arg_decls[index].ty },
&Lvalue::Static(def_id) =>
match *self {
Lvalue::Local(index) =>
LvalueTy::Ty { ty: mir.local_decls[index].ty },
Lvalue::Static(def_id) =>
LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty },
&Lvalue::ReturnPointer =>
LvalueTy::Ty { ty: mir.return_ty },
&Lvalue::Projection(ref proj) =>
Lvalue::Projection(ref proj) =>
proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem),
}
}

View file

@ -236,19 +236,9 @@ macro_rules! make_mir_visitor {
self.super_typed_const_val(val, location);
}
fn visit_var_decl(&mut self,
var_decl: & $($mutability)* VarDecl<'tcx>) {
self.super_var_decl(var_decl);
}
fn visit_temp_decl(&mut self,
temp_decl: & $($mutability)* TempDecl<'tcx>) {
self.super_temp_decl(temp_decl);
}
fn visit_arg_decl(&mut self,
arg_decl: & $($mutability)* ArgDecl<'tcx>) {
self.super_arg_decl(arg_decl);
fn visit_local_decl(&mut self,
local_decl: & $($mutability)* LocalDecl<'tcx>) {
self.super_local_decl(local_decl);
}
fn visit_visibility_scope(&mut self,
@ -272,16 +262,8 @@ macro_rules! make_mir_visitor {
self.visit_ty(&$($mutability)* mir.return_ty);
for var_decl in &$($mutability)* mir.var_decls {
self.visit_var_decl(var_decl);
}
for arg_decl in &$($mutability)* mir.arg_decls {
self.visit_arg_decl(arg_decl);
}
for temp_decl in &$($mutability)* mir.temp_decls {
self.visit_temp_decl(temp_decl);
for local_decl in &$($mutability)* mir.local_decls {
self.visit_local_decl(local_decl);
}
self.visit_span(&$($mutability)* mir.span);
@ -584,10 +566,7 @@ macro_rules! make_mir_visitor {
context: LvalueContext<'tcx>,
location: Location) {
match *lvalue {
Lvalue::Var(_) |
Lvalue::Temp(_) |
Lvalue::Arg(_) |
Lvalue::ReturnPointer => {
Lvalue::Local(_) => {
}
Lvalue::Static(ref $($mutability)* def_id) => {
self.visit_def_id(def_id, location);
@ -639,36 +618,19 @@ macro_rules! make_mir_visitor {
}
}
fn super_var_decl(&mut self,
var_decl: & $($mutability)* VarDecl<'tcx>) {
let VarDecl {
fn super_local_decl(&mut self,
local_decl: & $($mutability)* LocalDecl<'tcx>) {
let LocalDecl {
mutability: _,
ref $($mutability)* ty,
name: _,
ref $($mutability)* ty,
ref $($mutability)* source_info,
} = *var_decl;
self.visit_ty(ty);
self.visit_source_info(source_info);
}
fn super_temp_decl(&mut self,
temp_decl: & $($mutability)* TempDecl<'tcx>) {
let TempDecl {
ref $($mutability)* ty,
} = *temp_decl;
self.visit_ty(ty);
}
fn super_arg_decl(&mut self,
arg_decl: & $($mutability)* ArgDecl<'tcx>) {
let ArgDecl {
ref $($mutability)* ty,
debug_name: _
} = *arg_decl;
} = *local_decl;
self.visit_ty(ty);
if let Some(ref $($mutability)* info) = *source_info {
self.visit_source_info(info);
}
}
fn super_visibility_scope(&mut self,

View file

@ -13,7 +13,7 @@ use syntax::ast;
use syntax_pos::Span;
use rustc::ty::{self, TyCtxt};
use rustc::mir::repr::{self, Mir};
use rustc::mir::repr::{self, Mir, LocalKind};
use rustc_data_structures::indexed_vec::Idx;
use super::super::gather_moves::{MovePathIndex, LookupResult};
@ -73,11 +73,20 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
};
assert!(args.len() == 1);
let peek_arg_lval = match args[0] {
repr::Operand::Consume(ref lval @ repr::Lvalue::Temp(_)) => {
lval
}
repr::Operand::Consume(_) |
repr::Operand::Consume(ref lval) => match *lval {
repr::Lvalue::Local(local) if mir.local_kind(local) == LocalKind::Temp => {
Some(lval)
}
_ => None
},
repr::Operand::Constant(_) => {
None
}
};
let peek_arg_lval = match peek_arg_lval {
Some(arg) => arg,
None => {
tcx.sess.diagnostic().span_err(
span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
return;

View file

@ -118,7 +118,7 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> {
env: &'a MoveDataParamEnv<'tcx>,
flow_inits: DataflowResults<MaybeInitializedLvals<'a, 'tcx>>,
flow_uninits: DataflowResults<MaybeUninitializedLvals<'a, 'tcx>>,
drop_flags: FnvHashMap<MovePathIndex, Temp>,
drop_flags: FnvHashMap<MovePathIndex, Local>,
patch: MirPatch<'tcx>,
}
@ -164,7 +164,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
}
fn drop_flag(&mut self, index: MovePathIndex) -> Option<Lvalue<'tcx>> {
self.drop_flags.get(&index).map(|t| Lvalue::Temp(*t))
self.drop_flags.get(&index).map(|t| Lvalue::Local(*t))
}
/// create a patch that elaborates all drops in the input
@ -847,14 +847,14 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
statements.push(Statement {
source_info: c.source_info,
kind: StatementKind::Assign(
Lvalue::Temp(flag),
Lvalue::Local(flag),
self.constant_bool(c.source_info.span, false)
)
});
}
let tcx = self.tcx;
let unit_temp = Lvalue::Temp(self.patch.new_temp(tcx.mk_nil()));
let unit_temp = Lvalue::Local(self.patch.new_temp(tcx.mk_nil()));
let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
.unwrap_or_else(|e| tcx.sess.fatal(&e));
let substs = Substs::new(tcx, iter::once(Kind::from(ty)));
@ -917,7 +917,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
if let Some(&flag) = self.drop_flags.get(&path) {
let span = self.patch.source_info_for_location(self.mir, loc).span;
let val = self.constant_bool(span, val.value());
self.patch.add_assign(loc, Lvalue::Temp(flag), val);
self.patch.add_assign(loc, Lvalue::Local(flag), val);
}
}
@ -926,7 +926,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let span = self.patch.source_info_for_location(self.mir, loc).span;
let false_ = self.constant_bool(span, false);
for flag in self.drop_flags.values() {
self.patch.add_assign(loc, Lvalue::Temp(*flag), false_.clone());
self.patch.add_assign(loc, Lvalue::Local(*flag), false_.clone());
}
}

View file

@ -173,13 +173,7 @@ impl fmt::Debug for MoveOut {
/// Tables mapping from an l-value to its MovePathIndex.
#[derive(Debug)]
pub struct MovePathLookup<'tcx> {
vars: IndexVec<Var, MovePathIndex>,
temps: IndexVec<Temp, MovePathIndex>,
args: IndexVec<Arg, MovePathIndex>,
/// The move path representing the return value is constructed
/// lazily when we first encounter it in the input MIR.
return_ptr: Option<MovePathIndex>,
locals: IndexVec<Local, MovePathIndex>,
/// projections are made from a base-lvalue and a projection
/// elem. The base-lvalue will have a unique MovePathIndex; we use
@ -218,16 +212,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
moves: IndexVec::new(),
loc_map: LocationMap::new(mir),
rev_lookup: MovePathLookup {
vars: mir.var_decls.indices().map(Lvalue::Var).map(|v| {
locals: mir.local_decls.indices().map(Lvalue::Local).map(|v| {
Self::new_move_path(&mut move_paths, &mut path_map, None, v)
}).collect(),
temps: mir.temp_decls.indices().map(Lvalue::Temp).map(|t| {
Self::new_move_path(&mut move_paths, &mut path_map, None, t)
}).collect(),
args: mir.arg_decls.indices().map(Lvalue::Arg).map(|a| {
Self::new_move_path(&mut move_paths, &mut path_map, None, a)
}).collect(),
return_ptr: None,
projections: FnvHashMap(),
},
move_paths: move_paths,
@ -272,23 +259,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
{
debug!("lookup({:?})", lval);
match *lval {
Lvalue::Var(var) => Ok(self.data.rev_lookup.vars[var]),
Lvalue::Arg(arg) => Ok(self.data.rev_lookup.args[arg]),
Lvalue::Temp(temp) => Ok(self.data.rev_lookup.temps[temp]),
Lvalue::Local(local) => Ok(self.data.rev_lookup.locals[local]),
// error: can't move out of a static
Lvalue::Static(..) => Err(MovePathError::IllegalMove),
Lvalue::ReturnPointer => match self.data.rev_lookup.return_ptr {
Some(ptr) => Ok(ptr),
ref mut ptr @ None => {
let path = Self::new_move_path(
&mut self.data.move_paths,
&mut self.data.path_map,
None,
lval.clone());
*ptr = Some(path);
Ok(path)
}
},
Lvalue::Projection(ref proj) => {
self.move_path_for_projection(lval, proj)
}
@ -373,11 +346,8 @@ impl<'tcx> MovePathLookup<'tcx> {
// parent.
pub fn find(&self, lval: &Lvalue<'tcx>) -> LookupResult {
match *lval {
Lvalue::Var(var) => LookupResult::Exact(self.vars[var]),
Lvalue::Temp(temp) => LookupResult::Exact(self.temps[temp]),
Lvalue::Arg(arg) => LookupResult::Exact(self.args[arg]),
Lvalue::Local(local) => LookupResult::Exact(self.locals[local]),
Lvalue::Static(..) => LookupResult::Parent(None),
Lvalue::ReturnPointer => LookupResult::Exact(self.return_ptr.unwrap()),
Lvalue::Projection(ref proj) => {
match self.find(&proj.base) {
LookupResult::Exact(base_path) => {
@ -486,7 +456,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
TerminatorKind::Unreachable => { }
TerminatorKind::Return => {
self.gather_move(loc, &Lvalue::ReturnPointer);
self.gather_move(loc, &Lvalue::Local(RETURN_POINTER));
}
TerminatorKind::If { .. } |

View file

@ -338,8 +338,8 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>(
where F: FnMut(MovePathIndex, DropFlagState)
{
let move_data = &ctxt.move_data;
for (arg, _) in mir.arg_decls.iter_enumerated() {
let lvalue = repr::Lvalue::Arg(arg);
for arg in mir.arg_iter() {
let lvalue = repr::Lvalue::Local(arg);
let lookup_result = move_data.rev_lookup.find(&lvalue);
on_lookup_result_bits(tcx, mir, move_data,
lookup_result,

View file

@ -19,9 +19,9 @@ pub struct MirPatch<'tcx> {
patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>,
new_blocks: Vec<BasicBlockData<'tcx>>,
new_statements: Vec<(Location, StatementKind<'tcx>)>,
new_temps: Vec<TempDecl<'tcx>>,
new_locals: Vec<LocalDecl<'tcx>>,
resume_block: BasicBlock,
next_temp: usize,
next_local: usize,
}
impl<'tcx> MirPatch<'tcx> {
@ -29,9 +29,9 @@ impl<'tcx> MirPatch<'tcx> {
let mut result = MirPatch {
patch_map: IndexVec::from_elem(None, mir.basic_blocks()),
new_blocks: vec![],
new_temps: vec![],
new_statements: vec![],
next_temp: mir.temp_decls.len(),
new_locals: vec![],
next_local: mir.local_decls.len(),
resume_block: START_BLOCK
};
@ -92,11 +92,11 @@ impl<'tcx> MirPatch<'tcx> {
}
}
pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Temp {
let index = self.next_temp;
self.next_temp += 1;
self.new_temps.push(TempDecl { ty: ty });
Temp::new(index as usize)
pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Local {
let index = self.next_local;
self.next_local += 1;
self.new_locals.push(LocalDecl::new_temp(ty));
Local::new(index as usize)
}
pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
@ -124,11 +124,11 @@ impl<'tcx> MirPatch<'tcx> {
pub fn apply(self, mir: &mut Mir<'tcx>) {
debug!("MirPatch: {:?} new temps, starting from index {}: {:?}",
self.new_temps.len(), mir.temp_decls.len(), self.new_temps);
self.new_locals.len(), mir.local_decls.len(), self.new_locals);
debug!("MirPatch: {} new blocks, starting from index {}",
self.new_blocks.len(), mir.basic_blocks().len());
mir.basic_blocks_mut().extend(self.new_blocks);
mir.temp_decls.extend(self.new_temps);
mir.local_decls.extend(self.new_locals);
for (src, patch) in self.patch_map.into_iter_enumerated() {
if let Some(patch) = patch {
debug!("MirPatch: patching block {:?}", src);

View file

@ -77,11 +77,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
success.and(slice.index(idx))
}
ExprKind::SelfRef => {
block.and(Lvalue::Arg(Arg::new(0)))
block.and(Lvalue::Local(Local::new(1)))
}
ExprKind::VarRef { id } => {
let index = this.var_indices[&id];
block.and(Lvalue::Var(index))
block.and(Lvalue::Local(index))
}
ExprKind::StaticRef { id } => {
block.and(Lvalue::Static(id))

View file

@ -90,9 +90,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
ExprKind::Return { value } => {
block = match value {
Some(value) => unpack!(this.into(&Lvalue::ReturnPointer, block, value)),
Some(value) => {
unpack!(this.into(&Lvalue::Local(RETURN_POINTER), block, value))
}
None => {
this.cfg.push_assign_unit(block, source_info, &Lvalue::ReturnPointer);
this.cfg.push_assign_unit(block,
source_info,
&Lvalue::Local(RETURN_POINTER));
block
}
};

View file

@ -123,7 +123,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
var,
subpattern: None, .. } => {
self.storage_live_for_bindings(block, &irrefutable_pat);
let lvalue = Lvalue::Var(self.var_indices[&var]);
let lvalue = Lvalue::Local(self.var_indices[&var]);
return self.into(&lvalue, block, initializer);
}
_ => {}
@ -214,7 +214,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
pattern: &Pattern<'tcx>) {
match *pattern.kind {
PatternKind::Binding { var, ref subpattern, .. } => {
let lvalue = Lvalue::Var(self.var_indices[&var]);
let lvalue = Lvalue::Local(self.var_indices[&var]);
let source_info = self.source_info(pattern.span);
self.cfg.push(block, Statement {
source_info: source_info,
@ -705,10 +705,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let source_info = self.source_info(binding.span);
self.cfg.push(block, Statement {
source_info: source_info,
kind: StatementKind::StorageLive(Lvalue::Var(var_index))
kind: StatementKind::StorageLive(Lvalue::Local(var_index))
});
self.cfg.push_assign(block, source_info,
&Lvalue::Var(var_index), rvalue);
&Lvalue::Local(var_index), rvalue);
}
}
@ -718,19 +718,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
name: Name,
var_id: NodeId,
var_ty: Ty<'tcx>)
-> Var
-> Local
{
debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, source_info={:?})",
var_id, name, var_ty, source_info);
let var = self.var_decls.push(VarDecl::<'tcx> {
source_info: source_info,
let var = self.local_decls.push(LocalDecl::<'tcx> {
mutability: mutability,
name: name,
ty: var_ty.clone(),
name: Some(name),
source_info: Some(source_info),
});
let extent = self.extent_of_innermost_scope();
self.schedule_drop(source_info.span, extent, &Lvalue::Var(var), var_ty);
self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty);
self.var_indices.insert(var_id, var);
debug!("declare_binding: var={:?}", var);

View file

@ -28,10 +28,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// NB: **No cleanup is scheduled for this temporary.** You should
/// call `schedule_drop` once the temporary is initialized.
pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> {
let temp = self.temp_decls.push(TempDecl { ty: ty });
let lvalue = Lvalue::Temp(temp);
let temp = self.local_decls.push(LocalDecl::new_temp(ty));
let lvalue = Lvalue::Local(temp);
debug!("temp: created temp {:?} with type {:?}",
lvalue, self.temp_decls[temp].ty);
lvalue, self.local_decls[temp].ty);
lvalue
}

View file

@ -28,6 +28,7 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
cfg: CFG<'tcx>,
fn_span: Span,
arg_count: usize,
/// the current set of scopes, updated as we traverse;
/// see the `scope` module for more details
@ -49,9 +50,9 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
visibility_scope: VisibilityScope,
var_decls: IndexVec<Var, VarDecl<'tcx>>,
var_indices: NodeMap<Var>,
temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
/// Maps node ids of variable bindings to the `Local`s created for them.
var_indices: NodeMap<Local>,
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
unit_temp: Option<Lvalue<'tcx>>,
/// cached block with the RESUME terminator; this is created
@ -157,9 +158,11 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
-> (Mir<'tcx>, ScopeAuxiliaryVec)
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
{
let arguments: Vec<_> = arguments.collect();
let tcx = hir.tcx();
let span = tcx.map.span(fn_id);
let mut builder = Builder::new(hir, span);
let mut builder = Builder::new(hir, span, arguments.len(), return_ty);
let body_id = ast_block.id;
let call_site_extent =
@ -169,9 +172,9 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
tcx.region_maps.lookup_code_extent(
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
let mut block = START_BLOCK;
let arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, |builder| {
builder.args_and_body(block, return_ty, arguments, arg_extent, ast_block)
unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
unpack!(block = builder.in_scope(arg_extent, block, |builder| {
builder.args_and_body(block, return_ty, &arguments, arg_extent, ast_block)
}));
let source_info = builder.source_info(span);
@ -180,7 +183,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
TerminatorKind::Goto { target: return_block });
builder.cfg.terminate(return_block, source_info,
TerminatorKind::Return);
return_block.and(arg_decls)
return_block.unit()
}));
assert_eq!(block, builder.return_block());
@ -217,7 +220,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
}).collect()
});
let (mut mir, aux) = builder.finish(upvar_decls, arg_decls, return_ty);
let (mut mir, aux) = builder.finish(upvar_decls, return_ty);
mir.spread_last_arg = spread_last_arg;
(mir, aux)
}
@ -227,15 +230,16 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
ast_expr: &'tcx hir::Expr)
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
let tcx = hir.tcx();
let ty = tcx.expr_ty_adjusted(ast_expr);
let span = tcx.map.span(item_id);
let mut builder = Builder::new(hir, span);
let mut builder = Builder::new(hir, span, 0, ty);
let extent = tcx.region_maps.temporary_scope(ast_expr.id)
.unwrap_or(ROOT_CODE_EXTENT);
let mut block = START_BLOCK;
let _ = builder.in_scope(extent, block, |builder| {
let expr = builder.hir.mirror(ast_expr);
unpack!(block = builder.into(&Lvalue::ReturnPointer, block, expr));
unpack!(block = builder.into(&Lvalue::Local(RETURN_POINTER), block, expr));
let source_info = builder.source_info(span);
let return_block = builder.return_block();
@ -247,23 +251,26 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
return_block.unit()
});
let ty = tcx.expr_ty_adjusted(ast_expr);
builder.finish(vec![], IndexVec::new(), ty)
builder.finish(vec![], ty)
}
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span) -> Builder<'a, 'gcx, 'tcx> {
fn new(hir: Cx<'a, 'gcx, 'tcx>,
span: Span,
arg_count: usize,
return_ty: Ty<'tcx>)
-> Builder<'a, 'gcx, 'tcx> {
let mut builder = Builder {
hir: hir,
cfg: CFG { basic_blocks: IndexVec::new() },
fn_span: span,
arg_count: arg_count,
scopes: vec![],
visibility_scopes: IndexVec::new(),
visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
scope_auxiliary: IndexVec::new(),
loop_scopes: vec![],
temp_decls: IndexVec::new(),
var_decls: IndexVec::new(),
local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1),
var_indices: NodeMap(),
unit_temp: None,
cached_resume_block: None,
@ -279,7 +286,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn finish(self,
upvar_decls: Vec<UpvarDecl>,
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
return_ty: Ty<'tcx>)
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
@ -292,27 +298,45 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
self.visibility_scopes,
IndexVec::new(),
return_ty,
self.var_decls,
arg_decls,
self.temp_decls,
self.local_decls,
self.arg_count,
upvar_decls,
self.fn_span
), self.scope_auxiliary)
}
fn args_and_body<A>(&mut self,
mut block: BasicBlock,
return_ty: Ty<'tcx>,
arguments: A,
argument_extent: CodeExtent,
ast_block: &'gcx hir::Block)
-> BlockAnd<IndexVec<Arg, ArgDecl<'tcx>>>
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
fn args_and_body(&mut self,
mut block: BasicBlock,
return_ty: Ty<'tcx>,
arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)],
argument_extent: CodeExtent,
ast_block: &'gcx hir::Block)
-> BlockAnd<()>
{
// to start, translate the argument patterns and collect the argument types.
// Allocate locals for the function arguments
for &(ty, pattern) in arguments.iter() {
// If this is a simple binding pattern, give the local a nice name for debuginfo.
let mut name = None;
if let Some(pat) = pattern {
if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
name = Some(ident.node);
}
}
self.local_decls.push(LocalDecl {
mutability: Mutability::Not,
ty: ty,
source_info: None,
name: name,
});
}
let mut scope = None;
let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| {
let lvalue = Lvalue::Arg(Arg::new(index));
// Bind the argument patterns
for (index, &(ty, pattern)) in arguments.iter().enumerate() {
// Function arguments always get the first Local indices after the return pointer
let lvalue = Lvalue::Local(Local::new(index + 1));
if let Some(pattern) = pattern {
let pattern = self.hir.irrefutable_pat(pattern);
scope = self.declare_bindings(scope, ast_block.span, &pattern);
@ -323,18 +347,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
argument_extent, &lvalue, ty);
let mut name = keywords::Invalid.name();
if let Some(pat) = pattern {
if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
name = ident.node;
}
}
ArgDecl {
ty: ty,
debug_name: name
}
}).collect();
}
// Enter the argument pattern bindings visibility scope, if it exists.
if let Some(visibility_scope) = scope {
@ -344,9 +357,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// FIXME(#32959): temporary hack for the issue at hand
let return_is_unit = return_ty.is_nil();
// start the first basic block and translate the body
unpack!(block = self.ast_block(&Lvalue::ReturnPointer, return_is_unit, block, ast_block));
unpack!(block = self.ast_block(&Lvalue::Local(RETURN_POINTER),
return_is_unit, block, ast_block));
block.and(arg_decls)
block.unit()
}
fn get_unit_temp(&mut self) -> Lvalue<'tcx> {

View file

@ -26,7 +26,7 @@ multiple-exit (SEME) region in the control-flow graph.
For now, we keep a mapping from each `CodeExtent` to its
corresponding SEME region for later reference (see caveat in next
paragraph). This is because region scopes are tied to
them. Eventually, when we shift to non-lexical lifetimes, three should
them. Eventually, when we shift to non-lexical lifetimes, there should
be no need to remember this mapping.
There is one additional wrinkle, actually, that I wanted to hide from
@ -67,7 +67,7 @@ There are numerous "normal" ways to early exit a scope: `break`,
early exit occurs, the method `exit_scope` is called. It is given the
current point in execution where the early exit occurs, as well as the
scope you want to branch to (note that all early exits from to some
other enclosing scope). `exit_scope` will record thid exit point and
other enclosing scope). `exit_scope` will record this exit point and
also add all drops.
Panics are handled in a similar fashion, except that a panic always
@ -322,7 +322,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
self.diverge_cleanup();
let scope = self.scopes.pop().unwrap();
assert_eq!(scope.extent, extent);
unpack!(block = build_scope_drops(&mut self.cfg, &scope, &self.scopes, block));
unpack!(block = build_scope_drops(&mut self.cfg,
&scope,
&self.scopes,
block,
self.arg_count));
self.scope_auxiliary[scope.id]
.postdoms
.push(self.cfg.current_location(block));
@ -362,7 +366,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
scope.cached_exits.insert((target, extent), b);
b
};
unpack!(block = build_scope_drops(&mut self.cfg, scope, rest, block));
unpack!(block = build_scope_drops(&mut self.cfg,
scope,
rest,
block,
self.arg_count));
if let Some(ref free_data) = scope.free {
let next = self.cfg.start_new_block();
let free = build_free(self.hir.tcx(), &tmp, free_data, next);
@ -454,7 +462,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
} else {
// Only temps and vars need their storage dead.
match *lvalue {
Lvalue::Temp(_) | Lvalue::Var(_) => DropKind::Storage,
Lvalue::Local(index) if index.index() > self.arg_count + 1 => DropKind::Storage,
_ => return
}
};
@ -671,7 +679,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
scope: &Scope<'tcx>,
earlier_scopes: &[Scope<'tcx>],
mut block: BasicBlock)
mut block: BasicBlock,
arg_count: usize)
-> BlockAnd<()> {
let mut iter = scope.drops.iter().rev().peekable();
while let Some(drop_data) = iter.next() {
@ -703,7 +712,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
DropKind::Storage => {
// Only temps and vars need their storage dead.
match drop_data.location {
Lvalue::Temp(_) | Lvalue::Var(_) => {}
Lvalue::Local(index) if index.index() > arg_count => {}
_ => continue
}

View file

@ -12,13 +12,12 @@
use rustc::mir::repr::{Local, Location, Lvalue, Mir};
use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::indexed_vec::IndexVec;
use std::marker::PhantomData;
use std::mem;
pub struct DefUseAnalysis<'tcx> {
info: IndexVec<Local, Info<'tcx>>,
mir_summary: MirSummary,
}
#[derive(Clone)]
@ -35,15 +34,13 @@ pub struct Use<'tcx> {
impl<'tcx> DefUseAnalysis<'tcx> {
pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> {
DefUseAnalysis {
info: IndexVec::from_elem_n(Info::new(), mir.count_locals()),
mir_summary: MirSummary::new(mir),
info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()),
}
}
pub fn analyze(&mut self, mir: &Mir<'tcx>) {
let mut finder = DefUseFinder {
info: mem::replace(&mut self.info, IndexVec::new()),
mir_summary: self.mir_summary,
};
finder.visit_mir(mir);
self.info = finder.info
@ -64,7 +61,6 @@ impl<'tcx> DefUseAnalysis<'tcx> {
for lvalue_use in &self.info[local].defs_and_uses {
MutateUseVisitor::new(local,
&mut callback,
self.mir_summary,
mir).visit_location(mir, lvalue_use.location)
}
}
@ -80,13 +76,17 @@ impl<'tcx> DefUseAnalysis<'tcx> {
struct DefUseFinder<'tcx> {
info: IndexVec<Local, Info<'tcx>>,
mir_summary: MirSummary,
}
impl<'tcx> DefUseFinder<'tcx> {
fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> {
let info = &mut self.info;
self.mir_summary.local_index(lvalue).map(move |local| &mut info[local])
if let Lvalue::Local(local) = *lvalue {
Some(&mut info[local])
} else {
None
}
}
}
@ -132,18 +132,16 @@ impl<'tcx> Info<'tcx> {
struct MutateUseVisitor<'tcx, F> {
query: Local,
callback: F,
mir_summary: MirSummary,
phantom: PhantomData<&'tcx ()>,
}
impl<'tcx, F> MutateUseVisitor<'tcx, F> {
fn new(query: Local, callback: F, mir_summary: MirSummary, _: &Mir<'tcx>)
fn new(query: Local, callback: F, _: &Mir<'tcx>)
-> MutateUseVisitor<'tcx, F>
where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
MutateUseVisitor {
query: query,
callback: callback,
mir_summary: mir_summary,
phantom: PhantomData,
}
}
@ -155,43 +153,11 @@ impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F>
lvalue: &mut Lvalue<'tcx>,
context: LvalueContext<'tcx>,
location: Location) {
if self.mir_summary.local_index(lvalue) == Some(self.query) {
(self.callback)(lvalue, context, location)
if let Lvalue::Local(local) = *lvalue {
if local == self.query {
(self.callback)(lvalue, context, location)
}
}
self.super_lvalue(lvalue, context, location)
}
}
/// A small structure that enables various metadata of the MIR to be queried
/// without a reference to the MIR itself.
#[derive(Clone, Copy)]
pub struct MirSummary {
arg_count: usize,
var_count: usize,
temp_count: usize,
}
impl MirSummary {
pub fn new(mir: &Mir) -> MirSummary {
MirSummary {
arg_count: mir.arg_decls.len(),
var_count: mir.var_decls.len(),
temp_count: mir.temp_decls.len(),
}
}
pub fn local_index<'tcx>(&self, lvalue: &Lvalue<'tcx>) -> Option<Local> {
match *lvalue {
Lvalue::Arg(arg) => Some(Local::new(arg.index())),
Lvalue::Var(var) => Some(Local::new(var.index() + self.arg_count)),
Lvalue::Temp(temp) => {
Some(Local::new(temp.index() + self.arg_count + self.var_count))
}
Lvalue::ReturnPointer => {
Some(Local::new(self.arg_count + self.var_count + self.temp_count))
}
_ => None,
}
}
}

View file

@ -136,30 +136,31 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
write!(w, " label=<fn {}(", dot::escape_html(&tcx.node_path_str(nid)))?;
// fn argument types.
for (i, arg) in mir.arg_decls.iter().enumerate() {
for (i, arg) in mir.arg_iter().enumerate() {
if i > 0 {
write!(w, ", ")?;
}
write!(w, "{:?}: {}", Lvalue::Arg(Arg::new(i)), escape(&arg.ty))?;
write!(w, "{:?}: {}", Lvalue::Local(arg), escape(&mir.local_decls[arg].ty))?;
}
write!(w, ") -&gt; {}", escape(mir.return_ty))?;
write!(w, r#"<br align="left"/>"#)?;
// User variable types (including the user's name in a comment).
for (i, var) in mir.var_decls.iter().enumerate() {
for local in mir.var_and_temp_iter() {
let decl = &mir.local_decls[local];
write!(w, "let ")?;
if var.mutability == Mutability::Mut {
if decl.mutability == Mutability::Mut {
write!(w, "mut ")?;
}
write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
Lvalue::Var(Var::new(i)), escape(&var.ty), var.name)?;
}
// Compiler-introduced temporary types.
for (i, temp) in mir.temp_decls.iter().enumerate() {
write!(w, r#"let mut {:?}: {};<br align="left"/>"#,
Lvalue::Temp(Temp::new(i)), escape(&temp.ty))?;
if let Some(name) = decl.name {
write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
Lvalue::Local(local), escape(&decl.ty), name)?;
} else {
write!(w, r#"let mut {:?}: {};<br align="left"/>"#,
Lvalue::Local(local), escape(&decl.ty))?;
}
}
writeln!(w, ">;")
@ -172,3 +173,5 @@ fn node(block: BasicBlock) -> String {
fn escape<T: Debug>(t: &T) -> String {
dot::escape_html(&format!("{:?}", t))
}
// TODO manually test

View file

@ -214,6 +214,9 @@ fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}
/// Prints user-defined variables in a scope tree.
///
/// Returns the total number of variables printed.
fn write_scope_tree(tcx: TyCtxt,
mir: &Mir,
scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>,
@ -234,11 +237,14 @@ fn write_scope_tree(tcx: TyCtxt,
writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;
// User variable types (including the user's name in a comment).
for (id, var) in mir.var_decls.iter_enumerated() {
// Skip if not declared in this scope.
if var.source_info.scope != child {
for local in mir.var_iter() {
let var = &mir.local_decls[local];
let (name, source_info) = if var.source_info.unwrap().scope == child {
(var.name.unwrap(), var.source_info.unwrap())
} else {
// Not a variable or not declared in this scope.
continue;
}
};
let mut_str = if var.mutability == Mutability::Mut {
"mut "
@ -251,13 +257,13 @@ fn write_scope_tree(tcx: TyCtxt,
INDENT,
indent,
mut_str,
id,
local,
var.ty);
writeln!(w, "{0:1$} // \"{2}\" in {3}",
indented_var,
ALIGN,
var.name,
comment(tcx, var.source_info))?;
name,
comment(tcx, source_info))?;
}
write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;
@ -291,9 +297,23 @@ fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
// Print return pointer
let indented_retptr = format!("{}let mut {:?}: {};",
INDENT,
RETURN_POINTER,
mir.return_ty);
writeln!(w, "{0:1$} // return pointer",
indented_retptr,
ALIGN)?;
write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;
write_mir_decls(mir, w)
write_temp_decls(mir, w)?;
// Add an empty line before the first block is printed.
writeln!(w, "")?;
Ok(())
}
fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
@ -313,30 +333,27 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
write!(w, "(")?;
// fn argument types.
for (i, arg) in mir.arg_decls.iter_enumerated() {
if i.index() != 0 {
for (i, arg) in mir.arg_iter().enumerate() {
if i != 0 {
write!(w, ", ")?;
}
write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?;
write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?;
}
write!(w, ") -> {}", mir.return_ty)
} else {
assert!(mir.arg_decls.is_empty());
assert_eq!(mir.arg_count, 0);
write!(w, ": {} =", mir.return_ty)
}
}
fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
// Compiler-introduced temporary types.
for (id, temp) in mir.temp_decls.iter_enumerated() {
writeln!(w, "{}let mut {:?}: {};", INDENT, id, temp.ty)?;
}
// Wrote any declaration? Add an empty line before the first block is printed.
if !mir.var_decls.is_empty() || !mir.temp_decls.is_empty() {
writeln!(w, "")?;
for temp in mir.temp_iter() {
writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[temp].ty)?;
}
Ok(())
}
// TODO manually test

View file

@ -29,12 +29,11 @@
//! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the
//! future.
use def_use::{DefUseAnalysis, MirSummary};
use def_use::DefUseAnalysis;
use rustc::mir::repr::{Constant, Local, Location, Lvalue, Mir, Operand, Rvalue, StatementKind};
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::visit::MutVisitor;
use rustc::ty::TyCtxt;
use rustc_data_structures::indexed_vec::Idx;
use transform::qualify_consts;
pub struct CopyPropagation;
@ -78,9 +77,8 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
def_use_analysis.analyze(mir);
let mut changed = false;
for dest_local_index in 0..mir.count_locals() {
let dest_local = Local::new(dest_local_index);
debug!("Considering destination local: {}", mir.format_local(dest_local));
for dest_local in mir.local_decls.indices() {
debug!("Considering destination local: {:?}", dest_local);
let action;
let location;
@ -89,19 +87,19 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
let dest_use_info = def_use_analysis.local_info(dest_local);
let dest_def_count = dest_use_info.def_count_not_including_drop();
if dest_def_count == 0 {
debug!(" Can't copy-propagate local: dest {} undefined",
mir.format_local(dest_local));
debug!(" Can't copy-propagate local: dest {:?} undefined",
dest_local);
continue
}
if dest_def_count > 1 {
debug!(" Can't copy-propagate local: dest {} defined {} times",
mir.format_local(dest_local),
debug!(" Can't copy-propagate local: dest {:?} defined {} times",
dest_local,
dest_use_info.def_count());
continue
}
if dest_use_info.use_count() == 0 {
debug!(" Can't copy-propagate local: dest {} unused",
mir.format_local(dest_local));
debug!(" Can't copy-propagate local: dest {:?} unused",
dest_local);
continue
}
let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| {
@ -121,11 +119,11 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
// That use of the source must be an assignment.
match statement.kind {
StatementKind::Assign(ref dest_lvalue, Rvalue::Use(ref operand)) if
Some(dest_local) == mir.local_index(dest_lvalue) => {
StatementKind::Assign(Lvalue::Local(local), Rvalue::Use(ref operand)) if
local == dest_local => {
let maybe_action = match *operand {
Operand::Consume(ref src_lvalue) => {
Action::local_copy(mir, &def_use_analysis, src_lvalue)
Action::local_copy(&def_use_analysis, src_lvalue)
}
Operand::Constant(ref src_constant) => {
Action::constant(src_constant)
@ -162,15 +160,14 @@ enum Action<'tcx> {
}
impl<'tcx> Action<'tcx> {
fn local_copy(mir: &Mir<'tcx>, def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>)
fn local_copy(def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>)
-> Option<Action<'tcx>> {
// The source must be a local.
let src_local = match mir.local_index(src_lvalue) {
Some(src_local) => src_local,
None => {
debug!(" Can't copy-propagate local: source is not a local");
return None
}
let src_local = if let Lvalue::Local(local) = *src_lvalue {
local
} else {
debug!(" Can't copy-propagate local: source is not a local");
return None;
};
// We're trying to copy propagate a local.
@ -225,9 +222,9 @@ impl<'tcx> Action<'tcx> {
// First, remove all markers.
//
// FIXME(pcwalton): Don't do this. Merge live ranges instead.
debug!(" Replacing all uses of {} with {} (local)",
mir.format_local(dest_local),
mir.format_local(src_local));
debug!(" Replacing all uses of {:?} with {:?} (local)",
dest_local,
src_local);
for lvalue_use in &def_use_analysis.local_info(dest_local).defs_and_uses {
if lvalue_use.context.is_storage_marker() {
mir.make_statement_nop(lvalue_use.location)
@ -240,7 +237,7 @@ impl<'tcx> Action<'tcx> {
}
// Replace all uses of the destination local with the source local.
let src_lvalue = Lvalue::from_local(mir, src_local);
let src_lvalue = Lvalue::Local(src_local);
def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue);
// Finally, zap the now-useless assignment instruction.
@ -253,8 +250,8 @@ impl<'tcx> Action<'tcx> {
// First, remove all markers.
//
// FIXME(pcwalton): Don't do this. Merge live ranges instead.
debug!(" Replacing all uses of {} with {:?} (constant)",
mir.format_local(dest_local),
debug!(" Replacing all uses of {:?} with {:?} (constant)",
dest_local,
src_constant);
let dest_local_info = def_use_analysis.local_info(dest_local);
for lvalue_use in &dest_local_info.defs_and_uses {
@ -264,8 +261,7 @@ impl<'tcx> Action<'tcx> {
}
// Replace all uses of the destination local with the constant.
let mut visitor = ConstantPropagationVisitor::new(MirSummary::new(mir),
dest_local,
let mut visitor = ConstantPropagationVisitor::new(dest_local,
src_constant);
for dest_lvalue_use in &dest_local_info.defs_and_uses {
visitor.visit_location(mir, dest_lvalue_use.location)
@ -298,17 +294,15 @@ impl<'tcx> Action<'tcx> {
struct ConstantPropagationVisitor<'tcx> {
dest_local: Local,
constant: Constant<'tcx>,
mir_summary: MirSummary,
uses_replaced: usize,
}
impl<'tcx> ConstantPropagationVisitor<'tcx> {
fn new(mir_summary: MirSummary, dest_local: Local, constant: Constant<'tcx>)
fn new(dest_local: Local, constant: Constant<'tcx>)
-> ConstantPropagationVisitor<'tcx> {
ConstantPropagationVisitor {
dest_local: dest_local,
constant: constant,
mir_summary: mir_summary,
uses_replaced: 0,
}
}
@ -319,16 +313,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
self.super_operand(operand, location);
match *operand {
Operand::Consume(ref lvalue) => {
if self.mir_summary.local_index(lvalue) != Some(self.dest_local) {
return
}
}
Operand::Constant(_) => return,
Operand::Consume(Lvalue::Local(local)) if local == self.dest_local => {}
_ => return,
}
*operand = Operand::Constant(self.constant.clone());
self.uses_replaced += 1
}
}

View file

@ -10,11 +10,12 @@
//! Performs various peephole optimizations.
use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue};
use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue, Local};
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::visit::{MutVisitor, Visitor};
use rustc::ty::TyCtxt;
use rustc::util::nodemap::FnvHashSet;
use rustc_data_structures::indexed_vec::Idx;
use std::mem;
pub struct InstCombine {
@ -61,7 +62,8 @@ impl<'tcx> MutVisitor<'tcx> for InstCombine {
debug!("Replacing `&*`: {:?}", rvalue);
let new_lvalue = match *rvalue {
Rvalue::Ref(_, _, Lvalue::Projection(ref mut projection)) => {
mem::replace(&mut projection.base, Lvalue::ReturnPointer)
// Replace with dummy
mem::replace(&mut projection.base, Lvalue::Local(Local::new(0)))
}
_ => bug!("Detected `&*` but didn't find `&*`!"),
};
@ -107,4 +109,3 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> {
struct OptimizationList {
and_stars: FnvHashSet<Location>,
}

View file

@ -30,6 +30,7 @@ use syntax_pos::Span;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use std::iter;
use std::mem;
use std::usize;
@ -74,15 +75,21 @@ pub enum Candidate {
ShuffleIndices(BasicBlock)
}
struct TempCollector {
temps: IndexVec<Temp, TempState>,
span: Span
struct TempCollector<'tcx> {
temps: IndexVec<Local, TempState>,
span: Span,
mir: &'tcx Mir<'tcx>,
}
impl<'tcx> Visitor<'tcx> for TempCollector {
fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) {
impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext<'tcx>, location: Location) {
self.super_lvalue(lvalue, context, location);
if let Lvalue::Temp(index) = *lvalue {
if let Lvalue::Local(index) = *lvalue {
// We're only interested in temporaries
if self.mir.local_kind(index) != LocalKind::Temp {
return;
}
// Ignore drops, if the temp gets promoted,
// then it's constant and thus drop is noop.
// Storage live ranges are also irrelevant.
@ -126,10 +133,11 @@ impl<'tcx> Visitor<'tcx> for TempCollector {
}
}
pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, TempState> {
pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Local, TempState> {
let mut collector = TempCollector {
temps: IndexVec::from_elem(TempState::Undefined, &mir.temp_decls),
span: mir.span
temps: IndexVec::from_elem(TempState::Undefined, &mir.local_decls),
span: mir.span,
mir: mir,
};
for (bb, data) in rpo {
collector.visit_basic_block_data(bb, data);
@ -140,7 +148,7 @@ pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, Te
struct Promoter<'a, 'tcx: 'a> {
source: &'a mut Mir<'tcx>,
promoted: Mir<'tcx>,
temps: &'a mut IndexVec<Temp, TempState>,
temps: &'a mut IndexVec<Local, TempState>,
/// If true, all nested temps are also kept in the
/// source MIR, not moved to the promoted MIR.
@ -177,7 +185,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
/// Copy the initialization of this temp to the
/// promoted MIR, recursing through temps.
fn promote_temp(&mut self, temp: Temp) -> Temp {
fn promote_temp(&mut self, temp: Local) -> Local {
let old_keep_original = self.keep_original;
let (bb, stmt_idx) = match self.temps[temp] {
TempState::Defined {
@ -259,20 +267,19 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
});
}
let new_temp = self.promoted.temp_decls.push(TempDecl {
ty: self.source.temp_decls[temp].ty
});
let new_temp = self.promoted.local_decls.push(
LocalDecl::new_temp(self.source.local_decls[temp].ty));
// Inject the Rvalue or Call into the promoted MIR.
if stmt_idx < no_stmts {
self.assign(Lvalue::Temp(new_temp), rvalue.unwrap(), source_info.span);
self.assign(Lvalue::Local(new_temp), rvalue.unwrap(), source_info.span);
} else {
let last = self.promoted.basic_blocks().last().unwrap();
let new_target = self.new_block();
let mut call = call.unwrap();
match call {
TerminatorKind::Call { ref mut destination, ..} => {
*destination = Some((Lvalue::Temp(new_temp), new_target));
*destination = Some((Lvalue::Local(new_temp), new_target));
}
_ => bug!()
}
@ -315,11 +322,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
}
}
};
self.visit_rvalue(&mut rvalue, Location{
self.visit_rvalue(&mut rvalue, Location {
block: BasicBlock::new(0),
statement_index: usize::MAX
});
self.assign(Lvalue::ReturnPointer, rvalue, span);
self.assign(Lvalue::Local(RETURN_POINTER), rvalue, span);
self.source.promoted.push(self.promoted);
}
}
@ -330,8 +338,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
lvalue: &mut Lvalue<'tcx>,
context: LvalueContext<'tcx>,
location: Location) {
if let Lvalue::Temp(ref mut temp) = *lvalue {
*temp = self.promote_temp(*temp);
if let Lvalue::Local(ref mut temp) = *lvalue {
if self.source.local_kind(*temp) == LocalKind::Temp {
*temp = self.promote_temp(*temp);
}
}
self.super_lvalue(lvalue, context, location);
}
@ -339,7 +349,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mut temps: IndexVec<Temp, TempState>,
mut temps: IndexVec<Local, TempState>,
candidates: Vec<Candidate>) {
// Visit candidates in reverse, in case they're nested.
for candidate in candidates.into_iter().rev() {
@ -353,7 +363,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
"expected assignment to promote");
}
};
if let Lvalue::Temp(index) = *dest {
if let Lvalue::Local(index) = *dest {
if temps[index] == TempState::PromotedOut {
// Already promoted.
continue;
@ -376,8 +386,10 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
}
};
// Declare return pointer local
let initial_locals = iter::once(LocalDecl::new_return_pointer(ty)).collect();
let mut promoter = Promoter {
source: mir,
promoted: Mir::new(
IndexVec::new(),
Some(VisibilityScopeData {
@ -386,12 +398,12 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
}).into_iter().collect(),
IndexVec::new(),
ty,
IndexVec::new(),
IndexVec::new(),
IndexVec::new(),
initial_locals,
0,
vec![],
span
),
source: mir,
temps: &mut temps,
keep_original: false
};
@ -400,13 +412,13 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
}
// Eliminate assignments to, and drops of promoted temps.
let promoted = |index: Temp| temps[index] == TempState::PromotedOut;
let promoted = |index: Local| temps[index] == TempState::PromotedOut;
for block in mir.basic_blocks_mut() {
block.statements.retain(|statement| {
match statement.kind {
StatementKind::Assign(Lvalue::Temp(index), _) |
StatementKind::StorageLive(Lvalue::Temp(index)) |
StatementKind::StorageDead(Lvalue::Temp(index)) => {
StatementKind::Assign(Lvalue::Local(index), _) |
StatementKind::StorageLive(Lvalue::Local(index)) |
StatementKind::StorageDead(Lvalue::Local(index)) => {
!promoted(index)
}
_ => true
@ -414,7 +426,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
});
let terminator = block.terminator_mut();
match terminator.kind {
TerminatorKind::Drop { location: Lvalue::Temp(index), target, .. } => {
TerminatorKind::Drop { location: Lvalue::Local(index), target, .. } => {
if promoted(index) {
terminator.kind = TerminatorKind::Goto {
target: target

View file

@ -143,11 +143,11 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
param_env: ty::ParameterEnvironment<'tcx>,
qualif_map: &'a mut DefIdMap<Qualif>,
mir_map: Option<&'a MirMap<'tcx>>,
temp_qualif: IndexVec<Temp, Option<Qualif>>,
temp_qualif: IndexVec<Local, Option<Qualif>>,
return_qualif: Option<Qualif>,
qualif: Qualif,
const_fn_arg_vars: BitVector,
temp_promotion_state: IndexVec<Temp, TempState>,
temp_promotion_state: IndexVec<Local, TempState>,
promotion_candidates: Vec<Candidate>
}
@ -173,10 +173,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
param_env: param_env,
qualif_map: qualif_map,
mir_map: mir_map,
temp_qualif: IndexVec::from_elem(None, &mir.temp_decls),
temp_qualif: IndexVec::from_elem(None, &mir.local_decls),
return_qualif: None,
qualif: Qualif::empty(),
const_fn_arg_vars: BitVector::new(mir.var_decls.len()),
const_fn_arg_vars: BitVector::new(mir.local_decls.len()),
temp_promotion_state: temps,
promotion_candidates: vec![]
}
@ -332,8 +332,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
// Only handle promotable temps in non-const functions.
if self.mode == Mode::Fn {
if let Lvalue::Temp(index) = *dest {
if self.temp_promotion_state[index].is_promotable() {
if let Lvalue::Local(index) = *dest {
if self.mir.local_kind(index) == LocalKind::Temp
&& self.temp_promotion_state[index].is_promotable() {
debug!("store to promotable temp {:?}", index);
store(&mut self.temp_qualif[index]);
}
}
@ -341,13 +343,20 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
}
match *dest {
Lvalue::Temp(index) => store(&mut self.temp_qualif[index]),
Lvalue::ReturnPointer => store(&mut self.return_qualif),
Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::Temp => {
debug!("store to temp {:?}", index);
store(&mut self.temp_qualif[index])
}
Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::ReturnPointer => {
debug!("store to return pointer {:?}", index);
store(&mut self.return_qualif)
}
Lvalue::Projection(box Projection {
base: Lvalue::Temp(index),
base: Lvalue::Local(index),
elem: ProjectionElem::Deref
}) if self.mir.temp_decls[index].ty.is_unique()
}) if self.mir.local_kind(index) == LocalKind::Temp
&& self.mir.local_decls[index].ty.is_unique()
&& self.temp_qualif[index].map_or(false, |qualif| {
qualif.intersects(Qualif::NOT_CONST)
}) => {
@ -366,6 +375,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
/// Qualify a whole const, static initializer or const fn.
fn qualify_const(&mut self) -> Qualif {
debug!("qualifying {} {}", self.mode, self.tcx.item_path_str(self.def_id));
let mir = self.mir;
let mut seen_blocks = BitVector::new(mir.basic_blocks().len());
@ -399,7 +410,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
TerminatorKind::Return => {
// Check for unused values. This usually means
// there are extra statements in the AST.
for temp in mir.temp_decls.indices() {
for temp in mir.temp_iter() {
if self.temp_qualif[temp].is_none() {
continue;
}
@ -424,9 +435,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
// Make sure there are no extra unassigned variables.
self.qualif = Qualif::NOT_CONST;
for index in 0..mir.var_decls.len() {
if !self.const_fn_arg_vars.contains(index) {
self.assign(&Lvalue::Var(Var::new(index)), Location {
for index in mir.var_iter() {
if !self.const_fn_arg_vars.contains(index.index()) {
debug!("unassigned variable {:?}", index);
self.assign(&Lvalue::Local(index), Location {
block: bb,
statement_index: usize::MAX,
});
@ -480,23 +492,28 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
context: LvalueContext<'tcx>,
location: Location) {
match *lvalue {
Lvalue::Arg(_) => {
self.add(Qualif::FN_ARGUMENT);
}
Lvalue::Var(_) => {
self.add(Qualif::NOT_CONST);
}
Lvalue::Temp(index) => {
if !self.temp_promotion_state[index].is_promotable() {
self.add(Qualif::NOT_PROMOTABLE);
}
if let Some(qualif) = self.temp_qualif[index] {
self.add(qualif);
} else {
Lvalue::Local(local) => match self.mir.local_kind(local) {
LocalKind::ReturnPointer => {
self.not_const();
}
}
LocalKind::Arg => {
self.add(Qualif::FN_ARGUMENT);
}
LocalKind::Var => {
self.add(Qualif::NOT_CONST);
}
LocalKind::Temp => {
if !self.temp_promotion_state[local].is_promotable() {
self.add(Qualif::NOT_PROMOTABLE);
}
if let Some(qualif) = self.temp_qualif[local] {
self.add(qualif);
} else {
self.not_const();
}
}
},
Lvalue::Static(_) => {
self.add(Qualif::STATIC);
if self.mode == Mode::Const || self.mode == Mode::ConstFn {
@ -505,9 +522,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
a constant instead", self.mode);
}
}
Lvalue::ReturnPointer => {
self.not_const();
}
Lvalue::Projection(ref proj) => {
self.nest(|this| {
this.super_lvalue(lvalue, context, location);
@ -685,8 +699,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
if self.mode == Mode::Fn || self.mode == Mode::ConstFn {
if !self.qualif.intersects(Qualif::NEVER_PROMOTE) {
// We can only promote direct borrows of temps.
if let Lvalue::Temp(_) = *lvalue {
self.promotion_candidates.push(candidate);
if let Lvalue::Local(local) = *lvalue {
if self.mir.local_kind(local) == LocalKind::Temp {
self.promotion_candidates.push(candidate);
}
}
}
}
@ -879,17 +895,21 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
self.visit_rvalue(rvalue, location);
// Check the allowed const fn argument forms.
if let (Mode::ConstFn, &Lvalue::Var(index)) = (self.mode, dest) {
if self.const_fn_arg_vars.insert(index.index()) {
if let (Mode::ConstFn, &Lvalue::Local(index)) = (self.mode, dest) {
if self.mir.local_kind(index) == LocalKind::Var &&
self.const_fn_arg_vars.insert(index.index()) {
// Direct use of an argument is permitted.
if let Rvalue::Use(Operand::Consume(Lvalue::Arg(_))) = *rvalue {
return;
if let Rvalue::Use(Operand::Consume(Lvalue::Local(local))) = *rvalue {
if self.mir.local_kind(local) == LocalKind::Arg {
return;
}
}
// Avoid a generic error for other uses of arguments.
if self.qualif.intersects(Qualif::FN_ARGUMENT) {
let decl = &self.mir.var_decls[index];
span_err!(self.tcx.sess, decl.source_info.span, E0022,
let decl = &self.mir.local_decls[index];
span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022,
"arguments of constant functions can only \
be immutable by-value bindings");
return;

View file

@ -90,14 +90,8 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
self.sanitize_type(&"return type", mir.return_ty);
for var_decl in &mir.var_decls {
self.sanitize_type(var_decl, var_decl.ty);
}
for (n, arg_decl) in mir.arg_decls.iter().enumerate() {
self.sanitize_type(&(n, arg_decl), arg_decl.ty);
}
for (n, tmp_decl) in mir.temp_decls.iter().enumerate() {
self.sanitize_type(&(n, tmp_decl), tmp_decl.ty);
for local_decl in &mir.local_decls {
self.sanitize_type(local_decl, local_decl.ty);
}
if self.errors_reported {
return;
@ -131,14 +125,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> {
debug!("sanitize_lvalue: {:?}", lvalue);
match *lvalue {
Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index].ty },
Lvalue::Temp(index) => LvalueTy::Ty { ty: self.mir.temp_decls[index].ty },
Lvalue::Arg(index) => LvalueTy::Ty { ty: self.mir.arg_decls[index].ty },
Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty },
Lvalue::Static(def_id) =>
LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty },
Lvalue::ReturnPointer => {
LvalueTy::Ty { ty: self.mir.return_ty }
}
Lvalue::Projection(ref proj) => {
let base_ty = self.sanitize_lvalue(&proj.base, location);
if let LvalueTy::Ty { ty } = base_ty {
@ -380,9 +369,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
StatementKind::StorageLive(ref lv) |
StatementKind::StorageDead(ref lv) => {
match *lv {
Lvalue::Temp(_) | Lvalue::Var(_) => {}
Lvalue::Local(_) => {}
_ => {
span_mirbug!(self, stmt, "bad lvalue: expected temp or var");
span_mirbug!(self, stmt, "bad lvalue: expected local");
}
}
}
@ -711,6 +700,8 @@ impl TypeckMir {
impl<'tcx> MirPass<'tcx> for TypeckMir {
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource, mir: &mut Mir<'tcx>) {
debug!("run_pass: {}", tcx.node_path_str(src.item_id()));
if tcx.sess.err_count() > 0 {
// compiling a broken program can obviously result in a
// broken MIR, so try not to report duplicate errors.

View file

@ -63,8 +63,9 @@ pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, Mir
// Find all the scopes with variables defined in them.
let mut has_variables = BitVector::new(mir.visibility_scopes.len());
for var in &mir.var_decls {
has_variables.insert(var.source_info.scope.index());
for var in mir.var_iter() {
let decl = &mir.local_decls[var];
has_variables.insert(decl.source_info.unwrap().scope.index());
}
// Instantiate all scopes.

View file

@ -20,7 +20,6 @@ use rustc::mir::visit::{Visitor, LvalueContext};
use rustc::mir::traversal;
use common::{self, Block, BlockAndBuilder};
use glue;
use std::iter;
use super::rvalue;
pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
@ -30,11 +29,7 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
analyzer.visit_mir(mir);
let local_types = mir.arg_decls.iter().map(|a| a.ty)
.chain(mir.var_decls.iter().map(|v| v.ty))
.chain(mir.temp_decls.iter().map(|t| t.ty))
.chain(iter::once(mir.return_ty));
for (index, ty) in local_types.enumerate() {
for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() {
let ty = bcx.monomorphize(&ty);
debug!("local {} has type {:?}", index, ty);
if ty.is_scalar() ||
@ -80,12 +75,11 @@ impl<'mir, 'bcx, 'tcx> LocalAnalyzer<'mir, 'bcx, 'tcx> {
fn new(mir: &'mir mir::Mir<'tcx>,
bcx: &'mir BlockAndBuilder<'bcx, 'tcx>)
-> LocalAnalyzer<'mir, 'bcx, 'tcx> {
let local_count = mir.count_locals();
LocalAnalyzer {
mir: mir,
bcx: bcx,
lvalue_locals: BitVector::new(local_count),
seen_assigned: BitVector::new(local_count)
lvalue_locals: BitVector::new(mir.local_decls.len()),
seen_assigned: BitVector::new(mir.local_decls.len())
}
}
@ -109,7 +103,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
location: Location) {
debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue);
if let Some(index) = self.mir.local_index(lvalue) {
if let mir::Lvalue::Local(index) = *lvalue {
self.mark_assigned(index);
if !rvalue::rvalue_creates_operand(self.mir, self.bcx, rvalue) {
self.mark_as_lvalue(index);
@ -153,7 +147,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
// Allow uses of projections of immediate pair fields.
if let mir::Lvalue::Projection(ref proj) = *lvalue {
if self.mir.local_index(&proj.base).is_some() {
if let mir::Lvalue::Local(_) = proj.base {
let ty = proj.base.ty(self.mir, self.bcx.tcx());
let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx()));
@ -167,7 +161,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
}
}
if let Some(index) = self.mir.local_index(lvalue) {
if let mir::Lvalue::Local(index) = *lvalue {
match context {
LvalueContext::Call => {
self.mark_assigned(index);

View file

@ -192,8 +192,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
let llval = if let Some(cast_ty) = ret.cast {
let index = mir.local_index(&mir::Lvalue::ReturnPointer).unwrap();
let op = match self.locals[index] {
let op = match self.locals[mir::RETURN_POINTER] {
LocalRef::Operand(Some(op)) => op,
LocalRef::Operand(None) => bug!("use of return before def"),
LocalRef::Lvalue(tr_lvalue) => {
@ -218,7 +217,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
load
} else {
let op = self.trans_consume(&bcx, &mir::Lvalue::ReturnPointer);
let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER));
op.pack_if_pair(&bcx).immediate()
};
bcx.ret(llval);
@ -844,7 +843,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
if fn_ret_ty.is_ignore() {
return ReturnDest::Nothing;
}
let dest = if let Some(index) = self.mir.local_index(dest) {
let dest = if let mir::Lvalue::Local(index) = *dest {
let ret_ty = self.monomorphized_lvalue_ty(dest);
match self.locals[index] {
LocalRef::Lvalue(dest) => dest,

View file

@ -221,16 +221,17 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
fn new(ccx: &'a CrateContext<'a, 'tcx>,
mir: &'a mir::Mir<'tcx>,
substs: &'tcx Substs<'tcx>,
args: IndexVec<mir::Arg, Const<'tcx>>)
args: IndexVec<mir::Local, Const<'tcx>>)
-> MirConstContext<'a, 'tcx> {
let mut context = MirConstContext {
ccx: ccx,
mir: mir,
substs: substs,
locals: (0..mir.count_locals()).map(|_| None).collect(),
locals: (0..mir.local_decls.len()).map(|_| None).collect(),
};
for (i, arg) in args.into_iter().enumerate() {
let index = mir.local_index(&mir::Lvalue::Arg(mir::Arg::new(i))).unwrap();
// Locals after local0 are the function arguments
let index = mir::Local::new(i + 1);
context.locals[index] = Some(arg);
}
context
@ -238,7 +239,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
mut instance: Instance<'tcx>,
args: IndexVec<mir::Arg, Const<'tcx>>)
args: IndexVec<mir::Local, Const<'tcx>>)
-> Result<Const<'tcx>, ConstEvalErr> {
// Try to resolve associated constants.
if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) {
@ -311,8 +312,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
mir::TerminatorKind::Goto { target } => target,
mir::TerminatorKind::Return => {
failure?;
let index = self.mir.local_index(&mir::Lvalue::ReturnPointer).unwrap();
return Ok(self.locals[index].unwrap_or_else(|| {
return Ok(self.locals[mir::RETURN_POINTER].unwrap_or_else(|| {
span_bug!(span, "no returned value in constant");
}));
}
@ -376,7 +376,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
}
fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) {
if let Some(index) = self.mir.local_index(dest) {
if let mir::Lvalue::Local(index) = *dest {
self.locals[index] = Some(value);
} else {
span_bug!(span, "assignment to {:?} in constant", dest);
@ -387,17 +387,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
-> Result<ConstLvalue<'tcx>, ConstEvalErr> {
let tcx = self.ccx.tcx();
if let Some(index) = self.mir.local_index(lvalue) {
if let mir::Lvalue::Local(index) = *lvalue {
return Ok(self.locals[index].unwrap_or_else(|| {
span_bug!(span, "{:?} not initialized", lvalue)
}).as_lvalue());
}
let lvalue = match *lvalue {
mir::Lvalue::Var(_) |
mir::Lvalue::Temp(_) |
mir::Lvalue::Arg(_) |
mir::Lvalue::ReturnPointer => bug!(), // handled above
mir::Lvalue::Local(_) => bug!(), // handled above
mir::Lvalue::Static(def_id) => {
ConstLvalue {
base: Base::Static(consts::get_static(self.ccx, def_id)),

View file

@ -91,7 +91,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let ccx = bcx.ccx();
let tcx = bcx.tcx();
if let Some(index) = self.mir.local_index(lvalue) {
if let mir::Lvalue::Local(index) = *lvalue {
match self.locals[index] {
LocalRef::Lvalue(lvalue) => {
return lvalue;
@ -103,10 +103,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
let result = match *lvalue {
mir::Lvalue::Var(_) |
mir::Lvalue::Temp(_) |
mir::Lvalue::Arg(_) |
mir::Lvalue::ReturnPointer => bug!(), // handled above
mir::Lvalue::Local(_) => bug!(), // handled above
mir::Lvalue::Static(def_id) => {
let const_ty = self.monomorphized_lvalue_ty(lvalue);
LvalueRef::new_sized(consts::get_static(ccx, def_id),
@ -235,7 +232,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
lvalue: &mir::Lvalue<'tcx>, f: F) -> U
where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
{
if let Some(index) = self.mir.local_index(lvalue) {
if let mir::Lvalue::Local(index) = *lvalue {
match self.locals[index] {
LocalRef::Lvalue(lvalue) => f(self, lvalue),
LocalRef::Operand(None) => {

View file

@ -237,51 +237,61 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
// Allocate variable and temp allocas
mircx.locals = {
let args = arg_local_refs(&bcx, &mir, &mircx.scopes, &lvalue_locals);
let vars = mir.var_decls.iter().enumerate().map(|(i, decl)| {
let mut allocate_local = |local| {
let decl = &mir.local_decls[local];
let ty = bcx.monomorphize(&decl.ty);
let debug_scope = mircx.scopes[decl.source_info.scope];
let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo;
let local = mir.local_index(&mir::Lvalue::Var(mir::Var::new(i))).unwrap();
if !lvalue_locals.contains(local.index()) && !dbg {
return LocalRef::new_operand(bcx.ccx(), ty);
}
if let Some(name) = decl.name {
// User variable
let source_info = decl.source_info.unwrap();
let debug_scope = mircx.scopes[source_info.scope];
let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo;
let lvalue = LvalueRef::alloca(&bcx, ty, &decl.name.as_str());
if dbg {
let dbg_loc = mircx.debug_loc(decl.source_info);
if let DebugLoc::ScopeAt(scope, span) = dbg_loc {
bcx.with_block(|bcx| {
declare_local(bcx, decl.name, ty, scope,
VariableAccess::DirectVariable { alloca: lvalue.llval },
VariableKind::LocalVariable, span);
});
if !lvalue_locals.contains(local.index()) && !dbg {
debug!("alloc: {:?} ({}) -> operand", local, name);
return LocalRef::new_operand(bcx.ccx(), ty);
}
debug!("alloc: {:?} ({}) -> lvalue", local, name);
let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str());
if dbg {
let dbg_loc = mircx.debug_loc(source_info);
if let DebugLoc::ScopeAt(scope, span) = dbg_loc {
bcx.with_block(|bcx| {
declare_local(bcx, name, ty, scope,
VariableAccess::DirectVariable { alloca: lvalue.llval },
VariableKind::LocalVariable, span);
});
} else {
panic!("Unexpected");
}
}
LocalRef::Lvalue(lvalue)
} else {
// Temporary or return pointer
if local == mir::RETURN_POINTER && fcx.fn_ty.ret.is_indirect() {
debug!("alloc: {:?} (return pointer) -> lvalue", local);
let llretptr = llvm::get_param(fcx.llfn, 0);
LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty)))
} else if lvalue_locals.contains(local.index()) {
debug!("alloc: {:?} -> lvalue", local);
LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", local)))
} else {
panic!("Unexpected");
// If this is an immediate local, we do not create an
// alloca in advance. Instead we wait until we see the
// definition and update the operand there.
debug!("alloc: {:?} -> operand", local);
LocalRef::new_operand(bcx.ccx(), ty)
}
}
LocalRef::Lvalue(lvalue)
});
};
let locals = mir.temp_decls.iter().enumerate().map(|(i, decl)| {
(mir::Lvalue::Temp(mir::Temp::new(i)), decl.ty)
}).chain(iter::once((mir::Lvalue::ReturnPointer, mir.return_ty)));
args.into_iter().chain(vars).chain(locals.map(|(lvalue, ty)| {
let ty = bcx.monomorphize(&ty);
let local = mir.local_index(&lvalue).unwrap();
if lvalue == mir::Lvalue::ReturnPointer && fcx.fn_ty.ret.is_indirect() {
let llretptr = llvm::get_param(fcx.llfn, 0);
LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty)))
} else if lvalue_locals.contains(local.index()) {
LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", lvalue)))
} else {
// If this is an immediate local, we do not create an
// alloca in advance. Instead we wait until we see the
// definition and update the operand there.
LocalRef::new_operand(bcx.ccx(), ty)
}
})).collect()
let retptr = allocate_local(mir::RETURN_POINTER);
iter::once(retptr)
.chain(args.into_iter())
.chain(mir.var_and_temp_iter().map(&mut allocate_local))
.collect()
};
// Branch to the START block
@ -346,10 +356,10 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
None
};
mir.arg_decls.iter().enumerate().map(|(arg_index, arg_decl)| {
mir.arg_iter().enumerate().map(|(arg_index, local)| {
let arg_decl = &mir.local_decls[local];
let arg_ty = bcx.monomorphize(&arg_decl.ty);
let local = mir.local_index(&mir::Lvalue::Arg(mir::Arg::new(arg_index))).unwrap();
if mir.spread_last_arg && arg_index == mir.arg_decls.len() - 1 {
if mir.spread_last_arg && arg_index == mir.arg_count - 1 {
// This argument (e.g. the last argument in the "rust-call" ABI)
// is a tuple that was spread at the ABI level and now we have
// to reconstruct it into a tuple local variable, from multiple
@ -467,8 +477,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
bcx.with_block(|bcx| arg_scope.map(|scope| {
// Is this a regular argument?
if arg_index > 0 || mir.upvar_decls.is_empty() {
declare_local(bcx, arg_decl.debug_name, arg_ty, scope,
VariableAccess::DirectVariable { alloca: llval },
declare_local(bcx, arg_decl.name.unwrap_or(keywords::Invalid.name()), arg_ty,
scope, VariableAccess::DirectVariable { alloca: llval },
VariableKind::ArgumentVariable(arg_index + 1),
bcx.fcx().span.unwrap_or(DUMMY_SP));
return;

View file

@ -175,7 +175,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
// watch out for locals that do not have an
// alloca; they are handled somewhat differently
if let Some(index) = self.mir.local_index(lvalue) {
if let mir::Lvalue::Local(index) = *lvalue {
match self.locals[index] {
LocalRef::Operand(Some(o)) => {
return o;
@ -191,7 +191,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
// Moves out of pair fields are trivial.
if let &mir::Lvalue::Projection(ref proj) = lvalue {
if let Some(index) = self.mir.local_index(&proj.base) {
if let mir::Lvalue::Local(index) = proj.base {
if let LocalRef::Operand(Some(o)) = self.locals[index] {
match (o.val, &proj.elem) {
(OperandValue::Pair(a, b),

View file

@ -30,7 +30,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
debug_loc.apply(bcx.fcx());
match statement.kind {
mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
if let Some(index) = self.mir.local_index(lvalue) {
if let mir::Lvalue::Local(index) = *lvalue {
match self.locals[index] {
LocalRef::Lvalue(tr_dest) => {
self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc)
@ -86,7 +86,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
lvalue: &mir::Lvalue<'tcx>,
intrinsic: base::Lifetime)
-> BlockAndBuilder<'bcx, 'tcx> {
if let Some(index) = self.mir.local_index(lvalue) {
if let mir::Lvalue::Local(index) = *lvalue {
if let LocalRef::Lvalue(tr_lval) = self.locals[index] {
intrinsic.call(&bcx, tr_lval.llval);
}

View file

@ -23,19 +23,19 @@ fn main() {}
// END RUST SOURCE
// START rustc.node13.Deaggregator.before.mir
// bb0: {
// var0 = arg0; // scope 0 at main.rs:8:8: 8:9
// tmp0 = var0; // scope 1 at main.rs:9:14: 9:15
// return = Baz { x: tmp0, y: const F32(0), z: const false }; // scope ...
// local2 = local1; // scope 0 at main.rs:8:8: 8:9
// local3 = local2; // scope 1 at main.rs:9:14: 9:15
// local0 = Baz { x: local3, y: const F32(0), z: const false }; // scope ...
// goto -> bb1; // scope 1 at main.rs:8:1: 10:2
// }
// END rustc.node13.Deaggregator.before.mir
// START rustc.node13.Deaggregator.after.mir
// bb0: {
// var0 = arg0; // scope 0 at main.rs:8:8: 8:9
// tmp0 = var0; // scope 1 at main.rs:9:14: 9:15
// (return.0: usize) = tmp0; // scope 1 at main.rs:9:5: 9:34
// (return.1: f32) = const F32(0); // scope 1 at main.rs:9:5: 9:34
// (return.2: bool) = const false; // scope 1 at main.rs:9:5: 9:34
// local2 = local1; // scope 0 at main.rs:8:8: 8:9
// local3 = local2; // scope 1 at main.rs:9:14: 9:15
// (local0.0: usize) = local3; // scope 1 at main.rs:9:5: 9:34
// (local0.1: f32) = const F32(0); // scope 1 at main.rs:9:5: 9:34
// (local0.2: bool) = const false; // scope 1 at main.rs:9:5: 9:34
// goto -> bb1; // scope 1 at main.rs:8:1: 10:2
// }
// END rustc.node13.Deaggregator.after.mir

View file

@ -28,18 +28,18 @@ fn main() {
// END RUST SOURCE
// START rustc.node10.Deaggregator.before.mir
// bb0: {
// var0 = arg0; // scope 0 at main.rs:7:8: 7:9
// tmp0 = var0; // scope 1 at main.rs:8:19: 8:20
// return = Baz::Foo { x: tmp0 }; // scope 1 at main.rs:8:5: 8:21
// local2 = local1; // scope 0 at main.rs:7:8: 7:9
// local3 = local2; // scope 1 at main.rs:8:19: 8:20
// local0 = Baz::Foo { x: local3 }; // scope 1 at main.rs:8:5: 8:21
// goto -> bb1; // scope 1 at main.rs:7:1: 9:2
// }
// END rustc.node10.Deaggregator.before.mir
// START rustc.node10.Deaggregator.after.mir
// bb0: {
// var0 = arg0; // scope 0 at main.rs:7:8: 7:9
// tmp0 = var0; // scope 1 at main.rs:8:19: 8:20
// ((return as Foo).0: usize) = tmp0; // scope 1 at main.rs:8:5: 8:21
// discriminant(return) = 1; // scope 1 at main.rs:8:5: 8:21
// local2 = local1; // scope 0 at main.rs:7:8: 7:9
// local3 = local2; // scope 1 at main.rs:8:19: 8:20
// ((local0 as Foo).0: usize) = local3; // scope 1 at main.rs:8:5: 8:21
// discriminant(local0) = 1; // scope 1 at main.rs:8:5: 8:21
// goto -> bb1; // scope 1 at main.rs:7:1: 9:2
// }
// END rustc.node10.Deaggregator.after.mir

View file

@ -18,27 +18,28 @@ fn main() {
let c = 1;
}
// TODO The StorageDead for local1 (a) after local6's (c) is missing!
// END RUST SOURCE
// START rustc.node4.TypeckMir.before.mir
// bb0: {
// StorageLive(var0); // scope 0 at storage_ranges.rs:14:9: 14:10
// var0 = const 0i32; // scope 0 at storage_ranges.rs:14:13: 14:14
// StorageLive(var1); // scope 1 at storage_ranges.rs:16:13: 16:14
// StorageLive(tmp1); // scope 1 at storage_ranges.rs:16:18: 16:25
// StorageLive(tmp2); // scope 1 at storage_ranges.rs:16:23: 16:24
// tmp2 = var0; // scope 1 at storage_ranges.rs:16:23: 16:24
// tmp1 = std::option::Option<i32>::Some(tmp2,); // scope 1 at storage_ranges.rs:16:18: 16:25
// var1 = &tmp1; // scope 1 at storage_ranges.rs:16:17: 16:25
// StorageDead(tmp2); // scope 1 at storage_ranges.rs:16:23: 16:24
// tmp0 = (); // scope 2 at storage_ranges.rs:15:5: 17:6
// StorageDead(tmp1); // scope 1 at storage_ranges.rs:16:18: 16:25
// StorageDead(var1); // scope 1 at storage_ranges.rs:16:13: 16:14
// StorageLive(var2); // scope 1 at storage_ranges.rs:18:9: 18:10
// var2 = const 1i32; // scope 1 at storage_ranges.rs:18:13: 18:14
// return = (); // scope 3 at storage_ranges.rs:13:11: 19:2
// StorageDead(var2); // scope 1 at storage_ranges.rs:18:9: 18:10
// StorageDead(var0); // scope 0 at storage_ranges.rs:14:9: 14:10
// goto -> bb1; // scope 0 at storage_ranges.rs:13:1: 19:2
// StorageLive(local1); // scope 0 at storage_ranges.rs:12:9: 12:10
// local1 = const 0i32; // scope 0 at storage_ranges.rs:12:13: 12:14
// StorageLive(local3); // scope 1 at storage_ranges.rs:14:13: 14:14
// StorageLive(local4); // scope 1 at storage_ranges.rs:14:18: 14:25
// StorageLive(local5); // scope 1 at storage_ranges.rs:14:23: 14:24
// local5 = local1; // scope 1 at storage_ranges.rs:14:23: 14:24
// local4 = std::option::Option<i32>::Some(local5,); // scope 1 at storage_ranges.rs:14:18: 14:25
// local3 = &local4; // scope 1 at storage_ranges.rs:14:17: 14:25
// StorageDead(local5); // scope 1 at storage_ranges.rs:14:23: 14:24
// local2 = (); // scope 2 at storage_ranges.rs:13:5: 15:6
// StorageDead(local4); // scope 1 at storage_ranges.rs:14:18: 14:25
// StorageDead(local3); // scope 1 at storage_ranges.rs:14:13: 14:14
// StorageLive(local6); // scope 1 at storage_ranges.rs:16:9: 16:10
// local6 = const 1i32; // scope 1 at storage_ranges.rs:16:13: 16:14
// local0 = (); // scope 3 at storage_ranges.rs:11:11: 17:2
// StorageDead(local6); // scope 1 at storage_ranges.rs:16:9: 16:10
// goto -> bb1; // scope 0 at storage_ranges.rs:11:1: 17:2
// }
//
// bb1: {