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. /// 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 /// 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>>, pub promoted: IndexVec<Promoted, Mir<'tcx>>,
/// Return type of the function. /// Return type of the function.
pub return_ty: Ty<'tcx>, pub return_ty: Ty<'tcx>,
/// Variables: these are stack slots corresponding to user variables. They may be /// Declarations of locals.
/// assigned many times. ///
pub var_decls: IndexVec<Var, VarDecl<'tcx>>, /// 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. /// Number of arguments this function takes.
pub arg_decls: IndexVec<Arg, ArgDecl<'tcx>>, ///
/// Starting at local1, `arg_count` locals will be provided by the caller
/// Temp declarations: stack slots that for temporaries created by /// and can be assumed to be initialized.
/// the compiler. These are assigned once, but they are not SSA ///
/// values in that it is possible to borrow them and mutate them /// If this MIR was built for a constant, this will be 0.
/// through the resulting reference. pub arg_count: usize,
pub temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
/// Names and capture modes of all the closure upvars, assuming /// Names and capture modes of all the closure upvars, assuming
/// the first argument is either the closure or a reference to it. /// 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>, visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
promoted: IndexVec<Promoted, Mir<'tcx>>, promoted: IndexVec<Promoted, Mir<'tcx>>,
return_ty: Ty<'tcx>, return_ty: Ty<'tcx>,
var_decls: IndexVec<Var, VarDecl<'tcx>>, local_decls: IndexVec<Local, LocalDecl<'tcx>>,
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>, arg_count: usize,
temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
upvar_decls: Vec<UpvarDecl>, upvar_decls: Vec<UpvarDecl>,
span: Span) -> Self 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 { Mir {
basic_blocks: basic_blocks, basic_blocks: basic_blocks,
visibility_scopes: visibility_scopes, visibility_scopes: visibility_scopes,
promoted: promoted, promoted: promoted,
return_ty: return_ty, return_ty: return_ty,
var_decls: var_decls, local_decls: local_decls,
arg_decls: arg_decls, arg_count: arg_count,
temp_decls: temp_decls,
upvar_decls: upvar_decls, upvar_decls: upvar_decls,
spread_last_arg: false, spread_last_arg: false,
span: span, span: span,
@ -161,56 +166,63 @@ impl<'tcx> Mir<'tcx> {
dominators(self) dominators(self)
} }
/// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order) #[inline]
/// to their index in the whole list of locals. This is useful if you pub fn local_kind(&self, local: Local) -> LocalKind {
/// want to treat all locals the same instead of repeating yourself. let index = local.0 as usize;
pub fn local_index(&self, lvalue: &Lvalue<'tcx>) -> Option<Local> { if index == 0 {
let idx = match *lvalue { debug_assert!(self.local_decls[local].mutability == Mutability::Mut,
Lvalue::Arg(arg) => arg.index(), "return pointer should be mutable");
Lvalue::Var(var) => {
self.arg_decls.len() + LocalKind::ReturnPointer
var.index() } 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
} }
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))
} }
/// Counts the number of locals, such that local_index /// Returns an iterator over all temporaries.
/// will always return an index smaller than this count. #[inline]
pub fn count_locals(&self) -> usize { pub fn temp_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
self.arg_decls.len() + (self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
self.var_decls.len() + let local = Local::new(index);
self.temp_decls.len() + 1 if self.local_decls[local].source_info.is_none() {
Some(local)
} else {
None
}
})
} }
pub fn format_local(&self, local: Local) -> String { /// Returns an iterator over all user-declared locals.
let mut index = local.index(); #[inline]
index = match index.checked_sub(self.arg_decls.len()) { pub fn var_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
None => return format!("{:?}", Arg::new(index)), (self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
Some(index) => index, let local = Local::new(index);
}; if self.local_decls[local].source_info.is_none() {
index = match index.checked_sub(self.var_decls.len()) { None
None => return format!("{:?}", Var::new(index)), } else {
Some(index) => index, Some(local)
}; }
index = match index.checked_sub(self.temp_decls.len()) { })
None => return format!("{:?}", Temp::new(index)), }
Some(index) => index,
}; /// Returns an iterator over all function arguments.
debug_assert!(index == 0); #[inline]
return "ReturnPointer".to_string() 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 /// 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 // Variables and temps
/// A "variable" is a binding declared by the user as part of the fn newtype_index!(Local, "local");
/// decl, a let, etc.
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)] #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct VarDecl<'tcx> { pub struct LocalDecl<'tcx> {
/// `let mut x` vs `let x` /// `let mut x` vs `let x`.
///
/// Temporaries and the return pointer are always mutable.
pub mutability: Mutability, pub mutability: Mutability,
/// name that user gave the variable; not that, internally, /// Type of this local.
/// mir references variables by index
pub name: Name,
/// type inferred for this variable (`let x: ty = ...`)
pub ty: Ty<'tcx>, pub ty: Ty<'tcx>,
/// source information (span, scope, etc.) for the declaration /// Name of the local, used in debuginfo and pretty-printing.
pub source_info: SourceInfo, ///
/// 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 impl<'tcx> LocalDecl<'tcx> {
/// anonymous, always mutable, and have only a type. /// Create a new `LocalDecl` for a temporary.
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] #[inline]
pub struct TempDecl<'tcx> { pub fn new_temp(ty: Ty<'tcx>) -> Self {
pub ty: Ty<'tcx>, LocalDecl {
} mutability: Mutability::Mut,
ty: ty,
name: None,
source_info: None,
}
}
/// A "arg" is one of the function's formal arguments. These are /// Builds a `LocalDecl` for the return pointer.
/// anonymous and distinct from the bindings that the user declares. ///
/// /// This must be inserted into the `local_decls` list as the first local.
/// For example, in this function: #[inline]
/// pub fn new_return_pointer(return_ty: Ty) -> LocalDecl {
/// ``` LocalDecl {
/// fn foo((x, y): (i32, u32)) { ... } mutability: Mutability::Mut,
/// ``` ty: return_ty,
/// source_info: None,
/// there is only one argument, of type `(i32, u32)`, but two bindings name: None, // FIXME maybe we do want some name here?
/// (`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
} }
/// A closure capture, with its name and mode. /// A closure capture, with its name and mode.
@ -442,7 +481,7 @@ pub enum TerminatorKind<'tcx> {
/// continue. Emitted by build::scope::diverge_cleanup. /// continue. Emitted by build::scope::diverge_cleanup.
Resume, 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. /// have been filled in by now. This should occur at most once.
Return, Return,
@ -759,31 +798,16 @@ impl<'tcx> Debug for Statement<'tcx> {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Lvalues // 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 /// A path to a value; something that can be evaluated without
/// changing or disturbing program state. /// changing or disturbing program state.
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Lvalue<'tcx> { pub enum Lvalue<'tcx> {
/// local variable declared by the user /// local variable
Var(Var), Local(Local),
/// 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),
/// static or static mut variable /// static or static mut variable
Static(DefId), Static(DefId),
/// the return pointer of the fn
ReturnPointer,
/// projection out of an lvalue (access a field, deref a pointer, etc) /// projection out of an lvalue (access a field, deref a pointer, etc)
Projection(Box<LvalueProjection<'tcx>>), Projection(Box<LvalueProjection<'tcx>>),
} }
@ -865,24 +889,6 @@ impl<'tcx> Lvalue<'tcx> {
elem: elem, 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> { impl<'tcx> Debug for Lvalue<'tcx> {
@ -890,13 +896,9 @@ impl<'tcx> Debug for Lvalue<'tcx> {
use self::Lvalue::*; use self::Lvalue::*;
match *self { match *self {
Var(id) => write!(fmt, "{:?}", id), Local(id) => write!(fmt, "{:?}", id),
Arg(id) => write!(fmt, "{:?}", id),
Temp(id) => write!(fmt, "{:?}", id),
Static(def_id) => Static(def_id) =>
write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))), write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))),
ReturnPointer =>
write!(fmt, "return"),
Projection(ref data) => Projection(ref data) =>
match data.elem { match data.elem {
ProjectionElem::Downcast(ref adt_def, index) => ProjectionElem::Downcast(ref adt_def, index) =>

View file

@ -49,12 +49,17 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
-> LvalueTy<'tcx> -> LvalueTy<'tcx>
{ {
match *elem { 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 { LvalueTy::Ty {
ty: self.to_ty(tcx).builtin_deref(true, ty::LvaluePreference::NoPreference) ty: ty,
.unwrap() }
.ty }
},
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
LvalueTy::Ty { LvalueTy::Ty {
ty: self.to_ty(tcx).builtin_index().unwrap() ty: self.to_ty(tcx).builtin_index().unwrap()
@ -116,18 +121,12 @@ impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> {
impl<'tcx> Lvalue<'tcx> { impl<'tcx> Lvalue<'tcx> {
pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> LvalueTy<'tcx> { pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> LvalueTy<'tcx> {
match self { match *self {
&Lvalue::Var(index) => Lvalue::Local(index) =>
LvalueTy::Ty { ty: mir.var_decls[index].ty }, LvalueTy::Ty { ty: mir.local_decls[index].ty },
&Lvalue::Temp(index) => Lvalue::Static(def_id) =>
LvalueTy::Ty { ty: mir.temp_decls[index].ty },
&Lvalue::Arg(index) =>
LvalueTy::Ty { ty: mir.arg_decls[index].ty },
&Lvalue::Static(def_id) =>
LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty }, LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty },
&Lvalue::ReturnPointer => Lvalue::Projection(ref proj) =>
LvalueTy::Ty { ty: mir.return_ty },
&Lvalue::Projection(ref proj) =>
proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem), 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); self.super_typed_const_val(val, location);
} }
fn visit_var_decl(&mut self, fn visit_local_decl(&mut self,
var_decl: & $($mutability)* VarDecl<'tcx>) { local_decl: & $($mutability)* LocalDecl<'tcx>) {
self.super_var_decl(var_decl); self.super_local_decl(local_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_visibility_scope(&mut self, fn visit_visibility_scope(&mut self,
@ -272,16 +262,8 @@ macro_rules! make_mir_visitor {
self.visit_ty(&$($mutability)* mir.return_ty); self.visit_ty(&$($mutability)* mir.return_ty);
for var_decl in &$($mutability)* mir.var_decls { for local_decl in &$($mutability)* mir.local_decls {
self.visit_var_decl(var_decl); self.visit_local_decl(local_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);
} }
self.visit_span(&$($mutability)* mir.span); self.visit_span(&$($mutability)* mir.span);
@ -584,10 +566,7 @@ macro_rules! make_mir_visitor {
context: LvalueContext<'tcx>, context: LvalueContext<'tcx>,
location: Location) { location: Location) {
match *lvalue { match *lvalue {
Lvalue::Var(_) | Lvalue::Local(_) => {
Lvalue::Temp(_) |
Lvalue::Arg(_) |
Lvalue::ReturnPointer => {
} }
Lvalue::Static(ref $($mutability)* def_id) => { Lvalue::Static(ref $($mutability)* def_id) => {
self.visit_def_id(def_id, location); self.visit_def_id(def_id, location);
@ -639,36 +618,19 @@ macro_rules! make_mir_visitor {
} }
} }
fn super_var_decl(&mut self, fn super_local_decl(&mut self,
var_decl: & $($mutability)* VarDecl<'tcx>) { local_decl: & $($mutability)* LocalDecl<'tcx>) {
let VarDecl { let LocalDecl {
mutability: _, mutability: _,
ref $($mutability)* ty,
name: _, name: _,
ref $($mutability)* ty,
ref $($mutability)* source_info, ref $($mutability)* source_info,
} = *var_decl; } = *local_decl;
self.visit_ty(ty); self.visit_ty(ty);
self.visit_source_info(source_info); if let Some(ref $($mutability)* info) = *source_info {
self.visit_source_info(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;
self.visit_ty(ty);
} }
fn super_visibility_scope(&mut self, fn super_visibility_scope(&mut self,

View file

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

View file

@ -118,7 +118,7 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> {
env: &'a MoveDataParamEnv<'tcx>, env: &'a MoveDataParamEnv<'tcx>,
flow_inits: DataflowResults<MaybeInitializedLvals<'a, 'tcx>>, flow_inits: DataflowResults<MaybeInitializedLvals<'a, 'tcx>>,
flow_uninits: DataflowResults<MaybeUninitializedLvals<'a, 'tcx>>, flow_uninits: DataflowResults<MaybeUninitializedLvals<'a, 'tcx>>,
drop_flags: FnvHashMap<MovePathIndex, Temp>, drop_flags: FnvHashMap<MovePathIndex, Local>,
patch: MirPatch<'tcx>, patch: MirPatch<'tcx>,
} }
@ -164,7 +164,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
} }
fn drop_flag(&mut self, index: MovePathIndex) -> Option<Lvalue<'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 /// create a patch that elaborates all drops in the input
@ -847,14 +847,14 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
statements.push(Statement { statements.push(Statement {
source_info: c.source_info, source_info: c.source_info,
kind: StatementKind::Assign( kind: StatementKind::Assign(
Lvalue::Temp(flag), Lvalue::Local(flag),
self.constant_bool(c.source_info.span, false) self.constant_bool(c.source_info.span, false)
) )
}); });
} }
let tcx = self.tcx; 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) let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
.unwrap_or_else(|e| tcx.sess.fatal(&e)); .unwrap_or_else(|e| tcx.sess.fatal(&e));
let substs = Substs::new(tcx, iter::once(Kind::from(ty))); 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) { if let Some(&flag) = self.drop_flags.get(&path) {
let span = self.patch.source_info_for_location(self.mir, loc).span; let span = self.patch.source_info_for_location(self.mir, loc).span;
let val = self.constant_bool(span, val.value()); 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 span = self.patch.source_info_for_location(self.mir, loc).span;
let false_ = self.constant_bool(span, false); let false_ = self.constant_bool(span, false);
for flag in self.drop_flags.values() { 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. /// Tables mapping from an l-value to its MovePathIndex.
#[derive(Debug)] #[derive(Debug)]
pub struct MovePathLookup<'tcx> { pub struct MovePathLookup<'tcx> {
vars: IndexVec<Var, MovePathIndex>, locals: IndexVec<Local, 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>,
/// projections are made from a base-lvalue and a projection /// projections are made from a base-lvalue and a projection
/// elem. The base-lvalue will have a unique MovePathIndex; we use /// elem. The base-lvalue will have a unique MovePathIndex; we use
@ -218,16 +212,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
moves: IndexVec::new(), moves: IndexVec::new(),
loc_map: LocationMap::new(mir), loc_map: LocationMap::new(mir),
rev_lookup: MovePathLookup { 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) Self::new_move_path(&mut move_paths, &mut path_map, None, v)
}).collect(), }).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(), projections: FnvHashMap(),
}, },
move_paths: move_paths, move_paths: move_paths,
@ -272,23 +259,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
{ {
debug!("lookup({:?})", lval); debug!("lookup({:?})", lval);
match *lval { match *lval {
Lvalue::Var(var) => Ok(self.data.rev_lookup.vars[var]), Lvalue::Local(local) => Ok(self.data.rev_lookup.locals[local]),
Lvalue::Arg(arg) => Ok(self.data.rev_lookup.args[arg]),
Lvalue::Temp(temp) => Ok(self.data.rev_lookup.temps[temp]),
// error: can't move out of a static // error: can't move out of a static
Lvalue::Static(..) => Err(MovePathError::IllegalMove), 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) => { Lvalue::Projection(ref proj) => {
self.move_path_for_projection(lval, proj) self.move_path_for_projection(lval, proj)
} }
@ -373,11 +346,8 @@ impl<'tcx> MovePathLookup<'tcx> {
// parent. // parent.
pub fn find(&self, lval: &Lvalue<'tcx>) -> LookupResult { pub fn find(&self, lval: &Lvalue<'tcx>) -> LookupResult {
match *lval { match *lval {
Lvalue::Var(var) => LookupResult::Exact(self.vars[var]), Lvalue::Local(local) => LookupResult::Exact(self.locals[local]),
Lvalue::Temp(temp) => LookupResult::Exact(self.temps[temp]),
Lvalue::Arg(arg) => LookupResult::Exact(self.args[arg]),
Lvalue::Static(..) => LookupResult::Parent(None), Lvalue::Static(..) => LookupResult::Parent(None),
Lvalue::ReturnPointer => LookupResult::Exact(self.return_ptr.unwrap()),
Lvalue::Projection(ref proj) => { Lvalue::Projection(ref proj) => {
match self.find(&proj.base) { match self.find(&proj.base) {
LookupResult::Exact(base_path) => { LookupResult::Exact(base_path) => {
@ -486,7 +456,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
TerminatorKind::Unreachable => { } TerminatorKind::Unreachable => { }
TerminatorKind::Return => { TerminatorKind::Return => {
self.gather_move(loc, &Lvalue::ReturnPointer); self.gather_move(loc, &Lvalue::Local(RETURN_POINTER));
} }
TerminatorKind::If { .. } | TerminatorKind::If { .. } |

View file

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

View file

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

View file

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

View file

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

View file

@ -123,7 +123,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
var, var,
subpattern: None, .. } => { subpattern: None, .. } => {
self.storage_live_for_bindings(block, &irrefutable_pat); 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); return self.into(&lvalue, block, initializer);
} }
_ => {} _ => {}
@ -214,7 +214,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
pattern: &Pattern<'tcx>) { pattern: &Pattern<'tcx>) {
match *pattern.kind { match *pattern.kind {
PatternKind::Binding { var, ref subpattern, .. } => { 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); let source_info = self.source_info(pattern.span);
self.cfg.push(block, Statement { self.cfg.push(block, Statement {
source_info: source_info, source_info: source_info,
@ -705,10 +705,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let source_info = self.source_info(binding.span); let source_info = self.source_info(binding.span);
self.cfg.push(block, Statement { self.cfg.push(block, Statement {
source_info: source_info, 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, 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, name: Name,
var_id: NodeId, var_id: NodeId,
var_ty: Ty<'tcx>) var_ty: Ty<'tcx>)
-> Var -> Local
{ {
debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, source_info={:?})", debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, source_info={:?})",
var_id, name, var_ty, source_info); var_id, name, var_ty, source_info);
let var = self.var_decls.push(VarDecl::<'tcx> { let var = self.local_decls.push(LocalDecl::<'tcx> {
source_info: source_info,
mutability: mutability, mutability: mutability,
name: name,
ty: var_ty.clone(), ty: var_ty.clone(),
name: Some(name),
source_info: Some(source_info),
}); });
let extent = self.extent_of_innermost_scope(); 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); self.var_indices.insert(var_id, var);
debug!("declare_binding: var={:?}", 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 /// NB: **No cleanup is scheduled for this temporary.** You should
/// call `schedule_drop` once the temporary is initialized. /// call `schedule_drop` once the temporary is initialized.
pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> { pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> {
let temp = self.temp_decls.push(TempDecl { ty: ty }); let temp = self.local_decls.push(LocalDecl::new_temp(ty));
let lvalue = Lvalue::Temp(temp); let lvalue = Lvalue::Local(temp);
debug!("temp: created temp {:?} with type {:?}", debug!("temp: created temp {:?} with type {:?}",
lvalue, self.temp_decls[temp].ty); lvalue, self.local_decls[temp].ty);
lvalue lvalue
} }

View file

@ -28,6 +28,7 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
cfg: CFG<'tcx>, cfg: CFG<'tcx>,
fn_span: Span, fn_span: Span,
arg_count: usize,
/// the current set of scopes, updated as we traverse; /// the current set of scopes, updated as we traverse;
/// see the `scope` module for more details /// 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_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
visibility_scope: VisibilityScope, visibility_scope: VisibilityScope,
var_decls: IndexVec<Var, VarDecl<'tcx>>, /// Maps node ids of variable bindings to the `Local`s created for them.
var_indices: NodeMap<Var>, var_indices: NodeMap<Local>,
temp_decls: IndexVec<Temp, TempDecl<'tcx>>, local_decls: IndexVec<Local, LocalDecl<'tcx>>,
unit_temp: Option<Lvalue<'tcx>>, unit_temp: Option<Lvalue<'tcx>>,
/// cached block with the RESUME terminator; this is created /// 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) -> (Mir<'tcx>, ScopeAuxiliaryVec)
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)> where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
{ {
let arguments: Vec<_> = arguments.collect();
let tcx = hir.tcx(); let tcx = hir.tcx();
let span = tcx.map.span(fn_id); 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 body_id = ast_block.id;
let call_site_extent = 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( tcx.region_maps.lookup_code_extent(
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id }); CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
let mut block = START_BLOCK; let mut block = START_BLOCK;
let arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, |builder| { unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, |builder| { unpack!(block = builder.in_scope(arg_extent, block, |builder| {
builder.args_and_body(block, return_ty, arguments, arg_extent, ast_block) builder.args_and_body(block, return_ty, &arguments, arg_extent, ast_block)
})); }));
let source_info = builder.source_info(span); 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 }); TerminatorKind::Goto { target: return_block });
builder.cfg.terminate(return_block, source_info, builder.cfg.terminate(return_block, source_info,
TerminatorKind::Return); TerminatorKind::Return);
return_block.and(arg_decls) return_block.unit()
})); }));
assert_eq!(block, builder.return_block()); assert_eq!(block, builder.return_block());
@ -217,7 +220,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
}).collect() }).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.spread_last_arg = spread_last_arg;
(mir, aux) (mir, aux)
} }
@ -227,15 +230,16 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
ast_expr: &'tcx hir::Expr) ast_expr: &'tcx hir::Expr)
-> (Mir<'tcx>, ScopeAuxiliaryVec) { -> (Mir<'tcx>, ScopeAuxiliaryVec) {
let tcx = hir.tcx(); let tcx = hir.tcx();
let ty = tcx.expr_ty_adjusted(ast_expr);
let span = tcx.map.span(item_id); 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) let extent = tcx.region_maps.temporary_scope(ast_expr.id)
.unwrap_or(ROOT_CODE_EXTENT); .unwrap_or(ROOT_CODE_EXTENT);
let mut block = START_BLOCK; let mut block = START_BLOCK;
let _ = builder.in_scope(extent, block, |builder| { let _ = builder.in_scope(extent, block, |builder| {
let expr = builder.hir.mirror(ast_expr); 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 source_info = builder.source_info(span);
let return_block = builder.return_block(); 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() return_block.unit()
}); });
let ty = tcx.expr_ty_adjusted(ast_expr); builder.finish(vec![], ty)
builder.finish(vec![], IndexVec::new(), ty)
} }
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { 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 { let mut builder = Builder {
hir: hir, hir: hir,
cfg: CFG { basic_blocks: IndexVec::new() }, cfg: CFG { basic_blocks: IndexVec::new() },
fn_span: span, fn_span: span,
arg_count: arg_count,
scopes: vec![], scopes: vec![],
visibility_scopes: IndexVec::new(), visibility_scopes: IndexVec::new(),
visibility_scope: ARGUMENT_VISIBILITY_SCOPE, visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
scope_auxiliary: IndexVec::new(), scope_auxiliary: IndexVec::new(),
loop_scopes: vec![], loop_scopes: vec![],
temp_decls: IndexVec::new(), local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1),
var_decls: IndexVec::new(),
var_indices: NodeMap(), var_indices: NodeMap(),
unit_temp: None, unit_temp: None,
cached_resume_block: None, cached_resume_block: None,
@ -279,7 +286,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn finish(self, fn finish(self,
upvar_decls: Vec<UpvarDecl>, upvar_decls: Vec<UpvarDecl>,
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
return_ty: Ty<'tcx>) return_ty: Ty<'tcx>)
-> (Mir<'tcx>, ScopeAuxiliaryVec) { -> (Mir<'tcx>, ScopeAuxiliaryVec) {
for (index, block) in self.cfg.basic_blocks.iter().enumerate() { 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, self.visibility_scopes,
IndexVec::new(), IndexVec::new(),
return_ty, return_ty,
self.var_decls, self.local_decls,
arg_decls, self.arg_count,
self.temp_decls,
upvar_decls, upvar_decls,
self.fn_span self.fn_span
), self.scope_auxiliary) ), self.scope_auxiliary)
} }
fn args_and_body<A>(&mut self, fn args_and_body(&mut self,
mut block: BasicBlock, mut block: BasicBlock,
return_ty: Ty<'tcx>, return_ty: Ty<'tcx>,
arguments: A, arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)],
argument_extent: CodeExtent, argument_extent: CodeExtent,
ast_block: &'gcx hir::Block) ast_block: &'gcx hir::Block)
-> BlockAnd<IndexVec<Arg, ArgDecl<'tcx>>> -> BlockAnd<()>
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
{ {
// 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 mut scope = None;
let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| { // Bind the argument patterns
let lvalue = Lvalue::Arg(Arg::new(index)); 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 { if let Some(pattern) = pattern {
let pattern = self.hir.irrefutable_pat(pattern); let pattern = self.hir.irrefutable_pat(pattern);
scope = self.declare_bindings(scope, ast_block.span, &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), self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
argument_extent, &lvalue, ty); 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. // Enter the argument pattern bindings visibility scope, if it exists.
if let Some(visibility_scope) = scope { 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 // FIXME(#32959): temporary hack for the issue at hand
let return_is_unit = return_ty.is_nil(); let return_is_unit = return_ty.is_nil();
// start the first basic block and translate the body // 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> { 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 For now, we keep a mapping from each `CodeExtent` to its
corresponding SEME region for later reference (see caveat in next corresponding SEME region for later reference (see caveat in next
paragraph). This is because region scopes are tied to 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. be no need to remember this mapping.
There is one additional wrinkle, actually, that I wanted to hide from 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 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 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 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. also add all drops.
Panics are handled in a similar fashion, except that a panic always 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(); self.diverge_cleanup();
let scope = self.scopes.pop().unwrap(); let scope = self.scopes.pop().unwrap();
assert_eq!(scope.extent, extent); 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] self.scope_auxiliary[scope.id]
.postdoms .postdoms
.push(self.cfg.current_location(block)); .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); scope.cached_exits.insert((target, extent), b);
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 { if let Some(ref free_data) = scope.free {
let next = self.cfg.start_new_block(); let next = self.cfg.start_new_block();
let free = build_free(self.hir.tcx(), &tmp, free_data, next); let free = build_free(self.hir.tcx(), &tmp, free_data, next);
@ -454,7 +462,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
} else { } else {
// Only temps and vars need their storage dead. // Only temps and vars need their storage dead.
match *lvalue { match *lvalue {
Lvalue::Temp(_) | Lvalue::Var(_) => DropKind::Storage, Lvalue::Local(index) if index.index() > self.arg_count + 1 => DropKind::Storage,
_ => return _ => return
} }
}; };
@ -671,7 +679,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
scope: &Scope<'tcx>, scope: &Scope<'tcx>,
earlier_scopes: &[Scope<'tcx>], earlier_scopes: &[Scope<'tcx>],
mut block: BasicBlock) mut block: BasicBlock,
arg_count: usize)
-> BlockAnd<()> { -> BlockAnd<()> {
let mut iter = scope.drops.iter().rev().peekable(); let mut iter = scope.drops.iter().rev().peekable();
while let Some(drop_data) = iter.next() { while let Some(drop_data) = iter.next() {
@ -703,7 +712,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
DropKind::Storage => { DropKind::Storage => {
// Only temps and vars need their storage dead. // Only temps and vars need their storage dead.
match drop_data.location { match drop_data.location {
Lvalue::Temp(_) | Lvalue::Var(_) => {} Lvalue::Local(index) if index.index() > arg_count => {}
_ => continue _ => continue
} }

View file

@ -12,13 +12,12 @@
use rustc::mir::repr::{Local, Location, Lvalue, Mir}; use rustc::mir::repr::{Local, Location, Lvalue, Mir};
use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor}; 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::marker::PhantomData;
use std::mem; use std::mem;
pub struct DefUseAnalysis<'tcx> { pub struct DefUseAnalysis<'tcx> {
info: IndexVec<Local, Info<'tcx>>, info: IndexVec<Local, Info<'tcx>>,
mir_summary: MirSummary,
} }
#[derive(Clone)] #[derive(Clone)]
@ -35,15 +34,13 @@ pub struct Use<'tcx> {
impl<'tcx> DefUseAnalysis<'tcx> { impl<'tcx> DefUseAnalysis<'tcx> {
pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> { pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> {
DefUseAnalysis { DefUseAnalysis {
info: IndexVec::from_elem_n(Info::new(), mir.count_locals()), info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()),
mir_summary: MirSummary::new(mir),
} }
} }
pub fn analyze(&mut self, mir: &Mir<'tcx>) { pub fn analyze(&mut self, mir: &Mir<'tcx>) {
let mut finder = DefUseFinder { let mut finder = DefUseFinder {
info: mem::replace(&mut self.info, IndexVec::new()), info: mem::replace(&mut self.info, IndexVec::new()),
mir_summary: self.mir_summary,
}; };
finder.visit_mir(mir); finder.visit_mir(mir);
self.info = finder.info self.info = finder.info
@ -64,7 +61,6 @@ impl<'tcx> DefUseAnalysis<'tcx> {
for lvalue_use in &self.info[local].defs_and_uses { for lvalue_use in &self.info[local].defs_and_uses {
MutateUseVisitor::new(local, MutateUseVisitor::new(local,
&mut callback, &mut callback,
self.mir_summary,
mir).visit_location(mir, lvalue_use.location) mir).visit_location(mir, lvalue_use.location)
} }
} }
@ -80,13 +76,17 @@ impl<'tcx> DefUseAnalysis<'tcx> {
struct DefUseFinder<'tcx> { struct DefUseFinder<'tcx> {
info: IndexVec<Local, Info<'tcx>>, info: IndexVec<Local, Info<'tcx>>,
mir_summary: MirSummary,
} }
impl<'tcx> DefUseFinder<'tcx> { impl<'tcx> DefUseFinder<'tcx> {
fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> { fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> {
let info = &mut self.info; 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> { struct MutateUseVisitor<'tcx, F> {
query: Local, query: Local,
callback: F, callback: F,
mir_summary: MirSummary,
phantom: PhantomData<&'tcx ()>, phantom: PhantomData<&'tcx ()>,
} }
impl<'tcx, F> MutateUseVisitor<'tcx, F> { 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> -> MutateUseVisitor<'tcx, F>
where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) { where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
MutateUseVisitor { MutateUseVisitor {
query: query, query: query,
callback: callback, callback: callback,
mir_summary: mir_summary,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -155,43 +153,11 @@ impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F>
lvalue: &mut Lvalue<'tcx>, lvalue: &mut Lvalue<'tcx>,
context: LvalueContext<'tcx>, context: LvalueContext<'tcx>,
location: Location) { location: Location) {
if self.mir_summary.local_index(lvalue) == Some(self.query) { if let Lvalue::Local(local) = *lvalue {
if local == self.query {
(self.callback)(lvalue, context, location) (self.callback)(lvalue, context, location)
} }
}
self.super_lvalue(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)))?; write!(w, " label=<fn {}(", dot::escape_html(&tcx.node_path_str(nid)))?;
// fn argument types. // fn argument types.
for (i, arg) in mir.arg_decls.iter().enumerate() { for (i, arg) in mir.arg_iter().enumerate() {
if i > 0 { if i > 0 {
write!(w, ", ")?; 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, ") -&gt; {}", escape(mir.return_ty))?;
write!(w, r#"<br align="left"/>"#)?; write!(w, r#"<br align="left"/>"#)?;
// User variable types (including the user's name in a comment). for local in mir.var_and_temp_iter() {
for (i, var) in mir.var_decls.iter().enumerate() { let decl = &mir.local_decls[local];
write!(w, "let ")?; write!(w, "let ")?;
if var.mutability == Mutability::Mut { if decl.mutability == Mutability::Mut {
write!(w, "mut ")?; write!(w, "mut ")?;
} }
write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
Lvalue::Var(Var::new(i)), escape(&var.ty), var.name)?;
}
// Compiler-introduced temporary types. if let Some(name) = decl.name {
for (i, temp) in mir.temp_decls.iter().enumerate() { write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
Lvalue::Local(local), escape(&decl.ty), name)?;
} else {
write!(w, r#"let mut {:?}: {};<br align="left"/>"#, write!(w, r#"let mut {:?}: {};<br align="left"/>"#,
Lvalue::Temp(Temp::new(i)), escape(&temp.ty))?; Lvalue::Local(local), escape(&decl.ty))?;
}
} }
writeln!(w, ">;") writeln!(w, ">;")
@ -172,3 +173,5 @@ fn node(block: BasicBlock) -> String {
fn escape<T: Debug>(t: &T) -> String { fn escape<T: Debug>(t: &T) -> String {
dot::escape_html(&format!("{:?}", t)) 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)) 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, fn write_scope_tree(tcx: TyCtxt,
mir: &Mir, mir: &Mir,
scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>, 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())?; writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;
// User variable types (including the user's name in a comment). // User variable types (including the user's name in a comment).
for (id, var) in mir.var_decls.iter_enumerated() { for local in mir.var_iter() {
// Skip if not declared in this scope. let var = &mir.local_decls[local];
if var.source_info.scope != child { 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; continue;
} };
let mut_str = if var.mutability == Mutability::Mut { let mut_str = if var.mutability == Mutability::Mut {
"mut " "mut "
@ -251,13 +257,13 @@ fn write_scope_tree(tcx: TyCtxt,
INDENT, INDENT,
indent, indent,
mut_str, mut_str,
id, local,
var.ty); var.ty);
writeln!(w, "{0:1$} // \"{2}\" in {3}", writeln!(w, "{0:1$} // \"{2}\" in {3}",
indented_var, indented_var,
ALIGN, ALIGN,
var.name, name,
comment(tcx, var.source_info))?; comment(tcx, source_info))?;
} }
write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?; 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_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) 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, "(")?; write!(w, "(")?;
// fn argument types. // fn argument types.
for (i, arg) in mir.arg_decls.iter_enumerated() { for (i, arg) in mir.arg_iter().enumerate() {
if i.index() != 0 { if i != 0 {
write!(w, ", ")?; write!(w, ", ")?;
} }
write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?; write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?;
} }
write!(w, ") -> {}", mir.return_ty) write!(w, ") -> {}", mir.return_ty)
} else { } else {
assert!(mir.arg_decls.is_empty()); assert_eq!(mir.arg_count, 0);
write!(w, ": {} =", mir.return_ty) 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. // Compiler-introduced temporary types.
for (id, temp) in mir.temp_decls.iter_enumerated() { for temp in mir.temp_iter() {
writeln!(w, "{}let mut {:?}: {};", INDENT, id, temp.ty)?; writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[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, "")?;
} }
Ok(()) 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 //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the
//! future. //! 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::repr::{Constant, Local, Location, Lvalue, Mir, Operand, Rvalue, StatementKind};
use rustc::mir::transform::{MirPass, MirSource, Pass}; use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc::mir::visit::MutVisitor; use rustc::mir::visit::MutVisitor;
use rustc::ty::TyCtxt; use rustc::ty::TyCtxt;
use rustc_data_structures::indexed_vec::Idx;
use transform::qualify_consts; use transform::qualify_consts;
pub struct CopyPropagation; pub struct CopyPropagation;
@ -78,9 +77,8 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
def_use_analysis.analyze(mir); def_use_analysis.analyze(mir);
let mut changed = false; let mut changed = false;
for dest_local_index in 0..mir.count_locals() { for dest_local in mir.local_decls.indices() {
let dest_local = Local::new(dest_local_index); debug!("Considering destination local: {:?}", dest_local);
debug!("Considering destination local: {}", mir.format_local(dest_local));
let action; let action;
let location; 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_use_info = def_use_analysis.local_info(dest_local);
let dest_def_count = dest_use_info.def_count_not_including_drop(); let dest_def_count = dest_use_info.def_count_not_including_drop();
if dest_def_count == 0 { if dest_def_count == 0 {
debug!(" Can't copy-propagate local: dest {} undefined", debug!(" Can't copy-propagate local: dest {:?} undefined",
mir.format_local(dest_local)); dest_local);
continue continue
} }
if dest_def_count > 1 { if dest_def_count > 1 {
debug!(" Can't copy-propagate local: dest {} defined {} times", debug!(" Can't copy-propagate local: dest {:?} defined {} times",
mir.format_local(dest_local), dest_local,
dest_use_info.def_count()); dest_use_info.def_count());
continue continue
} }
if dest_use_info.use_count() == 0 { if dest_use_info.use_count() == 0 {
debug!(" Can't copy-propagate local: dest {} unused", debug!(" Can't copy-propagate local: dest {:?} unused",
mir.format_local(dest_local)); dest_local);
continue continue
} }
let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| { 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. // That use of the source must be an assignment.
match statement.kind { match statement.kind {
StatementKind::Assign(ref dest_lvalue, Rvalue::Use(ref operand)) if StatementKind::Assign(Lvalue::Local(local), Rvalue::Use(ref operand)) if
Some(dest_local) == mir.local_index(dest_lvalue) => { local == dest_local => {
let maybe_action = match *operand { let maybe_action = match *operand {
Operand::Consume(ref src_lvalue) => { 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) => { Operand::Constant(ref src_constant) => {
Action::constant(src_constant) Action::constant(src_constant)
@ -162,15 +160,14 @@ enum Action<'tcx> {
} }
impl<'tcx> 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>> { -> Option<Action<'tcx>> {
// The source must be a local. // The source must be a local.
let src_local = match mir.local_index(src_lvalue) { let src_local = if let Lvalue::Local(local) = *src_lvalue {
Some(src_local) => src_local, local
None => { } else {
debug!(" Can't copy-propagate local: source is not a local"); debug!(" Can't copy-propagate local: source is not a local");
return None return None;
}
}; };
// We're trying to copy propagate a local. // We're trying to copy propagate a local.
@ -225,9 +222,9 @@ impl<'tcx> Action<'tcx> {
// First, remove all markers. // First, remove all markers.
// //
// FIXME(pcwalton): Don't do this. Merge live ranges instead. // FIXME(pcwalton): Don't do this. Merge live ranges instead.
debug!(" Replacing all uses of {} with {} (local)", debug!(" Replacing all uses of {:?} with {:?} (local)",
mir.format_local(dest_local), dest_local,
mir.format_local(src_local)); src_local);
for lvalue_use in &def_use_analysis.local_info(dest_local).defs_and_uses { for lvalue_use in &def_use_analysis.local_info(dest_local).defs_and_uses {
if lvalue_use.context.is_storage_marker() { if lvalue_use.context.is_storage_marker() {
mir.make_statement_nop(lvalue_use.location) 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. // 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); def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue);
// Finally, zap the now-useless assignment instruction. // Finally, zap the now-useless assignment instruction.
@ -253,8 +250,8 @@ impl<'tcx> Action<'tcx> {
// First, remove all markers. // First, remove all markers.
// //
// FIXME(pcwalton): Don't do this. Merge live ranges instead. // FIXME(pcwalton): Don't do this. Merge live ranges instead.
debug!(" Replacing all uses of {} with {:?} (constant)", debug!(" Replacing all uses of {:?} with {:?} (constant)",
mir.format_local(dest_local), dest_local,
src_constant); src_constant);
let dest_local_info = def_use_analysis.local_info(dest_local); let dest_local_info = def_use_analysis.local_info(dest_local);
for lvalue_use in &dest_local_info.defs_and_uses { 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. // Replace all uses of the destination local with the constant.
let mut visitor = ConstantPropagationVisitor::new(MirSummary::new(mir), let mut visitor = ConstantPropagationVisitor::new(dest_local,
dest_local,
src_constant); src_constant);
for dest_lvalue_use in &dest_local_info.defs_and_uses { for dest_lvalue_use in &dest_local_info.defs_and_uses {
visitor.visit_location(mir, dest_lvalue_use.location) visitor.visit_location(mir, dest_lvalue_use.location)
@ -298,17 +294,15 @@ impl<'tcx> Action<'tcx> {
struct ConstantPropagationVisitor<'tcx> { struct ConstantPropagationVisitor<'tcx> {
dest_local: Local, dest_local: Local,
constant: Constant<'tcx>, constant: Constant<'tcx>,
mir_summary: MirSummary,
uses_replaced: usize, uses_replaced: usize,
} }
impl<'tcx> ConstantPropagationVisitor<'tcx> { 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<'tcx> {
ConstantPropagationVisitor { ConstantPropagationVisitor {
dest_local: dest_local, dest_local: dest_local,
constant: constant, constant: constant,
mir_summary: mir_summary,
uses_replaced: 0, uses_replaced: 0,
} }
} }
@ -319,16 +313,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
self.super_operand(operand, location); self.super_operand(operand, location);
match *operand { match *operand {
Operand::Consume(ref lvalue) => { Operand::Consume(Lvalue::Local(local)) if local == self.dest_local => {}
if self.mir_summary.local_index(lvalue) != Some(self.dest_local) { _ => return,
return
}
}
Operand::Constant(_) => return,
} }
*operand = Operand::Constant(self.constant.clone()); *operand = Operand::Constant(self.constant.clone());
self.uses_replaced += 1 self.uses_replaced += 1
} }
} }

View file

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

View file

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

View file

@ -143,11 +143,11 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
param_env: ty::ParameterEnvironment<'tcx>, param_env: ty::ParameterEnvironment<'tcx>,
qualif_map: &'a mut DefIdMap<Qualif>, qualif_map: &'a mut DefIdMap<Qualif>,
mir_map: Option<&'a MirMap<'tcx>>, mir_map: Option<&'a MirMap<'tcx>>,
temp_qualif: IndexVec<Temp, Option<Qualif>>, temp_qualif: IndexVec<Local, Option<Qualif>>,
return_qualif: Option<Qualif>, return_qualif: Option<Qualif>,
qualif: Qualif, qualif: Qualif,
const_fn_arg_vars: BitVector, const_fn_arg_vars: BitVector,
temp_promotion_state: IndexVec<Temp, TempState>, temp_promotion_state: IndexVec<Local, TempState>,
promotion_candidates: Vec<Candidate> promotion_candidates: Vec<Candidate>
} }
@ -173,10 +173,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
param_env: param_env, param_env: param_env,
qualif_map: qualif_map, qualif_map: qualif_map,
mir_map: mir_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, return_qualif: None,
qualif: Qualif::empty(), 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, temp_promotion_state: temps,
promotion_candidates: vec![] promotion_candidates: vec![]
} }
@ -332,8 +332,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
// Only handle promotable temps in non-const functions. // Only handle promotable temps in non-const functions.
if self.mode == Mode::Fn { if self.mode == Mode::Fn {
if let Lvalue::Temp(index) = *dest { if let Lvalue::Local(index) = *dest {
if self.temp_promotion_state[index].is_promotable() { 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]); store(&mut self.temp_qualif[index]);
} }
} }
@ -341,13 +343,20 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
} }
match *dest { match *dest {
Lvalue::Temp(index) => store(&mut self.temp_qualif[index]), Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::Temp => {
Lvalue::ReturnPointer => store(&mut self.return_qualif), 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 { Lvalue::Projection(box Projection {
base: Lvalue::Temp(index), base: Lvalue::Local(index),
elem: ProjectionElem::Deref 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| { && self.temp_qualif[index].map_or(false, |qualif| {
qualif.intersects(Qualif::NOT_CONST) 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. /// Qualify a whole const, static initializer or const fn.
fn qualify_const(&mut self) -> Qualif { fn qualify_const(&mut self) -> Qualif {
debug!("qualifying {} {}", self.mode, self.tcx.item_path_str(self.def_id));
let mir = self.mir; let mir = self.mir;
let mut seen_blocks = BitVector::new(mir.basic_blocks().len()); let mut seen_blocks = BitVector::new(mir.basic_blocks().len());
@ -399,7 +410,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
TerminatorKind::Return => { TerminatorKind::Return => {
// Check for unused values. This usually means // Check for unused values. This usually means
// there are extra statements in the AST. // 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() { if self.temp_qualif[temp].is_none() {
continue; continue;
} }
@ -424,9 +435,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
// Make sure there are no extra unassigned variables. // Make sure there are no extra unassigned variables.
self.qualif = Qualif::NOT_CONST; self.qualif = Qualif::NOT_CONST;
for index in 0..mir.var_decls.len() { for index in mir.var_iter() {
if !self.const_fn_arg_vars.contains(index) { if !self.const_fn_arg_vars.contains(index.index()) {
self.assign(&Lvalue::Var(Var::new(index)), Location { debug!("unassigned variable {:?}", index);
self.assign(&Lvalue::Local(index), Location {
block: bb, block: bb,
statement_index: usize::MAX, statement_index: usize::MAX,
}); });
@ -480,23 +492,28 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
context: LvalueContext<'tcx>, context: LvalueContext<'tcx>,
location: Location) { location: Location) {
match *lvalue { match *lvalue {
Lvalue::Arg(_) => { Lvalue::Local(local) => match self.mir.local_kind(local) {
LocalKind::ReturnPointer => {
self.not_const();
}
LocalKind::Arg => {
self.add(Qualif::FN_ARGUMENT); self.add(Qualif::FN_ARGUMENT);
} }
Lvalue::Var(_) => { LocalKind::Var => {
self.add(Qualif::NOT_CONST); self.add(Qualif::NOT_CONST);
} }
Lvalue::Temp(index) => { LocalKind::Temp => {
if !self.temp_promotion_state[index].is_promotable() { if !self.temp_promotion_state[local].is_promotable() {
self.add(Qualif::NOT_PROMOTABLE); self.add(Qualif::NOT_PROMOTABLE);
} }
if let Some(qualif) = self.temp_qualif[index] { if let Some(qualif) = self.temp_qualif[local] {
self.add(qualif); self.add(qualif);
} else { } else {
self.not_const(); self.not_const();
} }
} }
},
Lvalue::Static(_) => { Lvalue::Static(_) => {
self.add(Qualif::STATIC); self.add(Qualif::STATIC);
if self.mode == Mode::Const || self.mode == Mode::ConstFn { 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); a constant instead", self.mode);
} }
} }
Lvalue::ReturnPointer => {
self.not_const();
}
Lvalue::Projection(ref proj) => { Lvalue::Projection(ref proj) => {
self.nest(|this| { self.nest(|this| {
this.super_lvalue(lvalue, context, location); this.super_lvalue(lvalue, context, location);
@ -685,12 +699,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
if self.mode == Mode::Fn || self.mode == Mode::ConstFn { if self.mode == Mode::Fn || self.mode == Mode::ConstFn {
if !self.qualif.intersects(Qualif::NEVER_PROMOTE) { if !self.qualif.intersects(Qualif::NEVER_PROMOTE) {
// We can only promote direct borrows of temps. // We can only promote direct borrows of temps.
if let Lvalue::Temp(_) = *lvalue { if let Lvalue::Local(local) = *lvalue {
if self.mir.local_kind(local) == LocalKind::Temp {
self.promotion_candidates.push(candidate); self.promotion_candidates.push(candidate);
} }
} }
} }
} }
}
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
let operand_ty = operand.ty(self.mir, self.tcx); let operand_ty = operand.ty(self.mir, self.tcx);
@ -879,17 +895,21 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
self.visit_rvalue(rvalue, location); self.visit_rvalue(rvalue, location);
// Check the allowed const fn argument forms. // Check the allowed const fn argument forms.
if let (Mode::ConstFn, &Lvalue::Var(index)) = (self.mode, dest) { if let (Mode::ConstFn, &Lvalue::Local(index)) = (self.mode, dest) {
if self.const_fn_arg_vars.insert(index.index()) { if self.mir.local_kind(index) == LocalKind::Var &&
self.const_fn_arg_vars.insert(index.index()) {
// Direct use of an argument is permitted. // Direct use of an argument is permitted.
if let Rvalue::Use(Operand::Consume(Lvalue::Arg(_))) = *rvalue { if let Rvalue::Use(Operand::Consume(Lvalue::Local(local))) = *rvalue {
if self.mir.local_kind(local) == LocalKind::Arg {
return; return;
} }
}
// Avoid a generic error for other uses of arguments. // Avoid a generic error for other uses of arguments.
if self.qualif.intersects(Qualif::FN_ARGUMENT) { if self.qualif.intersects(Qualif::FN_ARGUMENT) {
let decl = &self.mir.var_decls[index]; let decl = &self.mir.local_decls[index];
span_err!(self.tcx.sess, decl.source_info.span, E0022, span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022,
"arguments of constant functions can only \ "arguments of constant functions can only \
be immutable by-value bindings"); be immutable by-value bindings");
return; 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>) { fn visit_mir(&mut self, mir: &Mir<'tcx>) {
self.sanitize_type(&"return type", mir.return_ty); self.sanitize_type(&"return type", mir.return_ty);
for var_decl in &mir.var_decls { for local_decl in &mir.local_decls {
self.sanitize_type(var_decl, var_decl.ty); self.sanitize_type(local_decl, local_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);
} }
if self.errors_reported { if self.errors_reported {
return; 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> { fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> {
debug!("sanitize_lvalue: {:?}", lvalue); debug!("sanitize_lvalue: {:?}", lvalue);
match *lvalue { match *lvalue {
Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index].ty }, Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_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::Static(def_id) => Lvalue::Static(def_id) =>
LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty }, LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty },
Lvalue::ReturnPointer => {
LvalueTy::Ty { ty: self.mir.return_ty }
}
Lvalue::Projection(ref proj) => { Lvalue::Projection(ref proj) => {
let base_ty = self.sanitize_lvalue(&proj.base, location); let base_ty = self.sanitize_lvalue(&proj.base, location);
if let LvalueTy::Ty { ty } = base_ty { if let LvalueTy::Ty { ty } = base_ty {
@ -380,9 +369,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
StatementKind::StorageLive(ref lv) | StatementKind::StorageLive(ref lv) |
StatementKind::StorageDead(ref lv) => { StatementKind::StorageDead(ref lv) => {
match *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 { impl<'tcx> MirPass<'tcx> for TypeckMir {
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource, mir: &mut Mir<'tcx>) { src: MirSource, mir: &mut Mir<'tcx>) {
debug!("run_pass: {}", tcx.node_path_str(src.item_id()));
if tcx.sess.err_count() > 0 { if tcx.sess.err_count() > 0 {
// compiling a broken program can obviously result in a // compiling a broken program can obviously result in a
// broken MIR, so try not to report duplicate errors. // 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. // Find all the scopes with variables defined in them.
let mut has_variables = BitVector::new(mir.visibility_scopes.len()); let mut has_variables = BitVector::new(mir.visibility_scopes.len());
for var in &mir.var_decls { for var in mir.var_iter() {
has_variables.insert(var.source_info.scope.index()); let decl = &mir.local_decls[var];
has_variables.insert(decl.source_info.unwrap().scope.index());
} }
// Instantiate all scopes. // Instantiate all scopes.

View file

@ -20,7 +20,6 @@ use rustc::mir::visit::{Visitor, LvalueContext};
use rustc::mir::traversal; use rustc::mir::traversal;
use common::{self, Block, BlockAndBuilder}; use common::{self, Block, BlockAndBuilder};
use glue; use glue;
use std::iter;
use super::rvalue; use super::rvalue;
pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>, 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); analyzer.visit_mir(mir);
let local_types = mir.arg_decls.iter().map(|a| a.ty) for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() {
.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() {
let ty = bcx.monomorphize(&ty); let ty = bcx.monomorphize(&ty);
debug!("local {} has type {:?}", index, ty); debug!("local {} has type {:?}", index, ty);
if ty.is_scalar() || if ty.is_scalar() ||
@ -80,12 +75,11 @@ impl<'mir, 'bcx, 'tcx> LocalAnalyzer<'mir, 'bcx, 'tcx> {
fn new(mir: &'mir mir::Mir<'tcx>, fn new(mir: &'mir mir::Mir<'tcx>,
bcx: &'mir BlockAndBuilder<'bcx, 'tcx>) bcx: &'mir BlockAndBuilder<'bcx, 'tcx>)
-> LocalAnalyzer<'mir, 'bcx, 'tcx> { -> LocalAnalyzer<'mir, 'bcx, 'tcx> {
let local_count = mir.count_locals();
LocalAnalyzer { LocalAnalyzer {
mir: mir, mir: mir,
bcx: bcx, bcx: bcx,
lvalue_locals: BitVector::new(local_count), lvalue_locals: BitVector::new(mir.local_decls.len()),
seen_assigned: BitVector::new(local_count) 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) { location: Location) {
debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue); 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); self.mark_assigned(index);
if !rvalue::rvalue_creates_operand(self.mir, self.bcx, rvalue) { if !rvalue::rvalue_creates_operand(self.mir, self.bcx, rvalue) {
self.mark_as_lvalue(index); 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. // Allow uses of projections of immediate pair fields.
if let mir::Lvalue::Projection(ref proj) = *lvalue { 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 = proj.base.ty(self.mir, self.bcx.tcx());
let ty = self.bcx.monomorphize(&ty.to_ty(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 { match context {
LvalueContext::Call => { LvalueContext::Call => {
self.mark_assigned(index); 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 llval = if let Some(cast_ty) = ret.cast {
let index = mir.local_index(&mir::Lvalue::ReturnPointer).unwrap(); let op = match self.locals[mir::RETURN_POINTER] {
let op = match self.locals[index] {
LocalRef::Operand(Some(op)) => op, LocalRef::Operand(Some(op)) => op,
LocalRef::Operand(None) => bug!("use of return before def"), LocalRef::Operand(None) => bug!("use of return before def"),
LocalRef::Lvalue(tr_lvalue) => { LocalRef::Lvalue(tr_lvalue) => {
@ -218,7 +217,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
} }
load load
} else { } 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() op.pack_if_pair(&bcx).immediate()
}; };
bcx.ret(llval); bcx.ret(llval);
@ -844,7 +843,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
if fn_ret_ty.is_ignore() { if fn_ret_ty.is_ignore() {
return ReturnDest::Nothing; 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); let ret_ty = self.monomorphized_lvalue_ty(dest);
match self.locals[index] { match self.locals[index] {
LocalRef::Lvalue(dest) => dest, LocalRef::Lvalue(dest) => dest,

View file

@ -221,16 +221,17 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
fn new(ccx: &'a CrateContext<'a, 'tcx>, fn new(ccx: &'a CrateContext<'a, 'tcx>,
mir: &'a mir::Mir<'tcx>, mir: &'a mir::Mir<'tcx>,
substs: &'tcx Substs<'tcx>, substs: &'tcx Substs<'tcx>,
args: IndexVec<mir::Arg, Const<'tcx>>) args: IndexVec<mir::Local, Const<'tcx>>)
-> MirConstContext<'a, 'tcx> { -> MirConstContext<'a, 'tcx> {
let mut context = MirConstContext { let mut context = MirConstContext {
ccx: ccx, ccx: ccx,
mir: mir, mir: mir,
substs: substs, 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() { 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.locals[index] = Some(arg);
} }
context context
@ -238,7 +239,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
fn trans_def(ccx: &'a CrateContext<'a, 'tcx>, fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
mut instance: Instance<'tcx>, mut instance: Instance<'tcx>,
args: IndexVec<mir::Arg, Const<'tcx>>) args: IndexVec<mir::Local, Const<'tcx>>)
-> Result<Const<'tcx>, ConstEvalErr> { -> Result<Const<'tcx>, ConstEvalErr> {
// Try to resolve associated constants. // Try to resolve associated constants.
if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) { 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::Goto { target } => target,
mir::TerminatorKind::Return => { mir::TerminatorKind::Return => {
failure?; failure?;
let index = self.mir.local_index(&mir::Lvalue::ReturnPointer).unwrap(); return Ok(self.locals[mir::RETURN_POINTER].unwrap_or_else(|| {
return Ok(self.locals[index].unwrap_or_else(|| {
span_bug!(span, "no returned value in constant"); 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) { 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); self.locals[index] = Some(value);
} else { } else {
span_bug!(span, "assignment to {:?} in constant", dest); span_bug!(span, "assignment to {:?} in constant", dest);
@ -387,17 +387,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
-> Result<ConstLvalue<'tcx>, ConstEvalErr> { -> Result<ConstLvalue<'tcx>, ConstEvalErr> {
let tcx = self.ccx.tcx(); 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(|| { return Ok(self.locals[index].unwrap_or_else(|| {
span_bug!(span, "{:?} not initialized", lvalue) span_bug!(span, "{:?} not initialized", lvalue)
}).as_lvalue()); }).as_lvalue());
} }
let lvalue = match *lvalue { let lvalue = match *lvalue {
mir::Lvalue::Var(_) | mir::Lvalue::Local(_) => bug!(), // handled above
mir::Lvalue::Temp(_) |
mir::Lvalue::Arg(_) |
mir::Lvalue::ReturnPointer => bug!(), // handled above
mir::Lvalue::Static(def_id) => { mir::Lvalue::Static(def_id) => {
ConstLvalue { ConstLvalue {
base: Base::Static(consts::get_static(self.ccx, def_id)), 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 ccx = bcx.ccx();
let tcx = bcx.tcx(); let tcx = bcx.tcx();
if let Some(index) = self.mir.local_index(lvalue) { if let mir::Lvalue::Local(index) = *lvalue {
match self.locals[index] { match self.locals[index] {
LocalRef::Lvalue(lvalue) => { LocalRef::Lvalue(lvalue) => {
return lvalue; return lvalue;
@ -103,10 +103,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
} }
let result = match *lvalue { let result = match *lvalue {
mir::Lvalue::Var(_) | mir::Lvalue::Local(_) => bug!(), // handled above
mir::Lvalue::Temp(_) |
mir::Lvalue::Arg(_) |
mir::Lvalue::ReturnPointer => bug!(), // handled above
mir::Lvalue::Static(def_id) => { mir::Lvalue::Static(def_id) => {
let const_ty = self.monomorphized_lvalue_ty(lvalue); let const_ty = self.monomorphized_lvalue_ty(lvalue);
LvalueRef::new_sized(consts::get_static(ccx, def_id), 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 lvalue: &mir::Lvalue<'tcx>, f: F) -> U
where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> 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] { match self.locals[index] {
LocalRef::Lvalue(lvalue) => f(self, lvalue), LocalRef::Lvalue(lvalue) => f(self, lvalue),
LocalRef::Operand(None) => { LocalRef::Operand(None) => {

View file

@ -237,22 +237,29 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
// Allocate variable and temp allocas // Allocate variable and temp allocas
mircx.locals = { mircx.locals = {
let args = arg_local_refs(&bcx, &mir, &mircx.scopes, &lvalue_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 ty = bcx.monomorphize(&decl.ty);
let debug_scope = mircx.scopes[decl.source_info.scope];
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 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 { if !lvalue_locals.contains(local.index()) && !dbg {
debug!("alloc: {:?} ({}) -> operand", local, name);
return LocalRef::new_operand(bcx.ccx(), ty); return LocalRef::new_operand(bcx.ccx(), ty);
} }
let lvalue = LvalueRef::alloca(&bcx, ty, &decl.name.as_str()); debug!("alloc: {:?} ({}) -> lvalue", local, name);
let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str());
if dbg { if dbg {
let dbg_loc = mircx.debug_loc(decl.source_info); let dbg_loc = mircx.debug_loc(source_info);
if let DebugLoc::ScopeAt(scope, span) = dbg_loc { if let DebugLoc::ScopeAt(scope, span) = dbg_loc {
bcx.with_block(|bcx| { bcx.with_block(|bcx| {
declare_local(bcx, decl.name, ty, scope, declare_local(bcx, name, ty, scope,
VariableAccess::DirectVariable { alloca: lvalue.llval }, VariableAccess::DirectVariable { alloca: lvalue.llval },
VariableKind::LocalVariable, span); VariableKind::LocalVariable, span);
}); });
@ -261,27 +268,30 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
} }
} }
LocalRef::Lvalue(lvalue) LocalRef::Lvalue(lvalue)
}); } else {
// Temporary or return pointer
let locals = mir.temp_decls.iter().enumerate().map(|(i, decl)| { if local == mir::RETURN_POINTER && fcx.fn_ty.ret.is_indirect() {
(mir::Lvalue::Temp(mir::Temp::new(i)), decl.ty) debug!("alloc: {:?} (return pointer) -> lvalue", local);
}).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); let llretptr = llvm::get_param(fcx.llfn, 0);
LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty))) LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty)))
} else if lvalue_locals.contains(local.index()) { } else if lvalue_locals.contains(local.index()) {
LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", lvalue))) debug!("alloc: {:?} -> lvalue", local);
LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", local)))
} else { } else {
// If this is an immediate local, we do not create an // If this is an immediate local, we do not create an
// alloca in advance. Instead we wait until we see the // alloca in advance. Instead we wait until we see the
// definition and update the operand there. // definition and update the operand there.
debug!("alloc: {:?} -> operand", local);
LocalRef::new_operand(bcx.ccx(), ty) 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 // Branch to the START block
@ -346,10 +356,10 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
None 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 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_count - 1 {
if mir.spread_last_arg && arg_index == mir.arg_decls.len() - 1 {
// This argument (e.g. the last argument in the "rust-call" ABI) // 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 // is a tuple that was spread at the ABI level and now we have
// to reconstruct it into a tuple local variable, from multiple // 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| { bcx.with_block(|bcx| arg_scope.map(|scope| {
// Is this a regular argument? // Is this a regular argument?
if arg_index > 0 || mir.upvar_decls.is_empty() { if arg_index > 0 || mir.upvar_decls.is_empty() {
declare_local(bcx, arg_decl.debug_name, arg_ty, scope, declare_local(bcx, arg_decl.name.unwrap_or(keywords::Invalid.name()), arg_ty,
VariableAccess::DirectVariable { alloca: llval }, scope, VariableAccess::DirectVariable { alloca: llval },
VariableKind::ArgumentVariable(arg_index + 1), VariableKind::ArgumentVariable(arg_index + 1),
bcx.fcx().span.unwrap_or(DUMMY_SP)); bcx.fcx().span.unwrap_or(DUMMY_SP));
return; return;

View file

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

View file

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

View file

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

View file

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

View file

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