[WIP] Move MIR towards a single kind of local
This commit is contained in:
parent
205dac9355
commit
393db2d830
33 changed files with 628 additions and 661 deletions
|
@ -70,24 +70,26 @@ pub struct Mir<'tcx> {
|
|||
|
||||
/// Rvalues promoted from this function, such as borrows of constants.
|
||||
/// Each of them is the Mir of a constant with the fn's type parameters
|
||||
/// in scope, but no vars or args and a separate set of temps.
|
||||
/// in scope, but a separate set of locals.
|
||||
pub promoted: IndexVec<Promoted, Mir<'tcx>>,
|
||||
|
||||
/// Return type of the function.
|
||||
pub return_ty: Ty<'tcx>,
|
||||
|
||||
/// Variables: these are stack slots corresponding to user variables. They may be
|
||||
/// assigned many times.
|
||||
pub var_decls: IndexVec<Var, VarDecl<'tcx>>,
|
||||
/// Declarations of locals.
|
||||
///
|
||||
/// The first local is the return value pointer, followed by `arg_count`
|
||||
/// locals for the function arguments, followed by any user-declared
|
||||
/// variables and temporaries.
|
||||
pub local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
||||
|
||||
/// Args: these are stack slots corresponding to the input arguments.
|
||||
pub arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
|
||||
|
||||
/// Temp declarations: stack slots that for temporaries created by
|
||||
/// the compiler. These are assigned once, but they are not SSA
|
||||
/// values in that it is possible to borrow them and mutate them
|
||||
/// through the resulting reference.
|
||||
pub temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
|
||||
/// Number of arguments this function takes.
|
||||
///
|
||||
/// Starting at local1, `arg_count` locals will be provided by the caller
|
||||
/// and can be assumed to be initialized.
|
||||
///
|
||||
/// If this MIR was built for a constant, this will be 0.
|
||||
pub arg_count: usize,
|
||||
|
||||
/// Names and capture modes of all the closure upvars, assuming
|
||||
/// the first argument is either the closure or a reference to it.
|
||||
|
@ -114,20 +116,23 @@ impl<'tcx> Mir<'tcx> {
|
|||
visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
|
||||
promoted: IndexVec<Promoted, Mir<'tcx>>,
|
||||
return_ty: Ty<'tcx>,
|
||||
var_decls: IndexVec<Var, VarDecl<'tcx>>,
|
||||
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
|
||||
temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
|
||||
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
||||
arg_count: usize,
|
||||
upvar_decls: Vec<UpvarDecl>,
|
||||
span: Span) -> Self
|
||||
{
|
||||
// We need `arg_count` locals, and one for the return pointer
|
||||
assert!(local_decls.len() >= arg_count + 1,
|
||||
"expected at least {} locals, got {}", arg_count + 1, local_decls.len());
|
||||
assert_eq!(local_decls[RETURN_POINTER].ty, return_ty);
|
||||
|
||||
Mir {
|
||||
basic_blocks: basic_blocks,
|
||||
visibility_scopes: visibility_scopes,
|
||||
promoted: promoted,
|
||||
return_ty: return_ty,
|
||||
var_decls: var_decls,
|
||||
arg_decls: arg_decls,
|
||||
temp_decls: temp_decls,
|
||||
local_decls: local_decls,
|
||||
arg_count: arg_count,
|
||||
upvar_decls: upvar_decls,
|
||||
spread_last_arg: false,
|
||||
span: span,
|
||||
|
@ -161,56 +166,63 @@ impl<'tcx> Mir<'tcx> {
|
|||
dominators(self)
|
||||
}
|
||||
|
||||
/// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order)
|
||||
/// to their index in the whole list of locals. This is useful if you
|
||||
/// want to treat all locals the same instead of repeating yourself.
|
||||
pub fn local_index(&self, lvalue: &Lvalue<'tcx>) -> Option<Local> {
|
||||
let idx = match *lvalue {
|
||||
Lvalue::Arg(arg) => arg.index(),
|
||||
Lvalue::Var(var) => {
|
||||
self.arg_decls.len() +
|
||||
var.index()
|
||||
}
|
||||
Lvalue::Temp(temp) => {
|
||||
self.arg_decls.len() +
|
||||
self.var_decls.len() +
|
||||
temp.index()
|
||||
}
|
||||
Lvalue::ReturnPointer => {
|
||||
self.arg_decls.len() +
|
||||
self.var_decls.len() +
|
||||
self.temp_decls.len()
|
||||
}
|
||||
Lvalue::Static(_) |
|
||||
Lvalue::Projection(_) => return None
|
||||
};
|
||||
Some(Local::new(idx))
|
||||
#[inline]
|
||||
pub fn local_kind(&self, local: Local) -> LocalKind {
|
||||
let index = local.0 as usize;
|
||||
if index == 0 {
|
||||
debug_assert!(self.local_decls[local].mutability == Mutability::Mut,
|
||||
"return pointer should be mutable");
|
||||
|
||||
LocalKind::ReturnPointer
|
||||
} else if index < self.arg_count + 1 {
|
||||
LocalKind::Arg
|
||||
} else if self.local_decls[local].name.is_some() {
|
||||
LocalKind::Var
|
||||
} else {
|
||||
debug_assert!(self.local_decls[local].mutability == Mutability::Mut,
|
||||
"temp should be mutable");
|
||||
|
||||
LocalKind::Temp
|
||||
}
|
||||
}
|
||||
|
||||
/// Counts the number of locals, such that local_index
|
||||
/// will always return an index smaller than this count.
|
||||
pub fn count_locals(&self) -> usize {
|
||||
self.arg_decls.len() +
|
||||
self.var_decls.len() +
|
||||
self.temp_decls.len() + 1
|
||||
/// Returns an iterator over all temporaries.
|
||||
#[inline]
|
||||
pub fn temp_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
|
||||
(self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
|
||||
let local = Local::new(index);
|
||||
if self.local_decls[local].source_info.is_none() {
|
||||
Some(local)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn format_local(&self, local: Local) -> String {
|
||||
let mut index = local.index();
|
||||
index = match index.checked_sub(self.arg_decls.len()) {
|
||||
None => return format!("{:?}", Arg::new(index)),
|
||||
Some(index) => index,
|
||||
};
|
||||
index = match index.checked_sub(self.var_decls.len()) {
|
||||
None => return format!("{:?}", Var::new(index)),
|
||||
Some(index) => index,
|
||||
};
|
||||
index = match index.checked_sub(self.temp_decls.len()) {
|
||||
None => return format!("{:?}", Temp::new(index)),
|
||||
Some(index) => index,
|
||||
};
|
||||
debug_assert!(index == 0);
|
||||
return "ReturnPointer".to_string()
|
||||
/// Returns an iterator over all user-declared locals.
|
||||
#[inline]
|
||||
pub fn var_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
|
||||
(self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
|
||||
let local = Local::new(index);
|
||||
if self.local_decls[local].source_info.is_none() {
|
||||
None
|
||||
} else {
|
||||
Some(local)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns an iterator over all function arguments.
|
||||
#[inline]
|
||||
pub fn arg_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
|
||||
(1..self.arg_count+1).map(Local::new)
|
||||
}
|
||||
|
||||
/// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
|
||||
/// locals that are neither arguments nor the return pointer).
|
||||
#[inline]
|
||||
pub fn var_and_temp_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
|
||||
(self.arg_count+1..self.local_decls.len()).map(Local::new)
|
||||
}
|
||||
|
||||
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
|
||||
|
@ -308,49 +320,76 @@ pub enum BorrowKind {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// Variables and temps
|
||||
|
||||
/// A "variable" is a binding declared by the user as part of the fn
|
||||
/// decl, a let, etc.
|
||||
newtype_index!(Local, "local");
|
||||
|
||||
pub const RETURN_POINTER: Local = Local(0);
|
||||
|
||||
/// Classifies locals into categories. See `Mir::local_kind`.
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum LocalKind {
|
||||
/// User-declared variable binding
|
||||
Var,
|
||||
/// Compiler-introduced temporary
|
||||
Temp,
|
||||
/// Function argument
|
||||
Arg,
|
||||
/// Location of function's return value
|
||||
ReturnPointer,
|
||||
}
|
||||
|
||||
/// A MIR local.
|
||||
///
|
||||
/// This can be a binding declared by the user, a temporary inserted by the compiler, a function
|
||||
/// argument, or the return pointer.
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct VarDecl<'tcx> {
|
||||
/// `let mut x` vs `let x`
|
||||
pub struct LocalDecl<'tcx> {
|
||||
/// `let mut x` vs `let x`.
|
||||
///
|
||||
/// Temporaries and the return pointer are always mutable.
|
||||
pub mutability: Mutability,
|
||||
|
||||
/// name that user gave the variable; not that, internally,
|
||||
/// mir references variables by index
|
||||
pub name: Name,
|
||||
|
||||
/// type inferred for this variable (`let x: ty = ...`)
|
||||
/// Type of this local.
|
||||
pub ty: Ty<'tcx>,
|
||||
|
||||
/// source information (span, scope, etc.) for the declaration
|
||||
pub source_info: SourceInfo,
|
||||
/// Name of the local, used in debuginfo and pretty-printing.
|
||||
///
|
||||
/// Note that function arguments can also have this set to `Some(_)`
|
||||
/// to generate better debuginfo.
|
||||
pub name: Option<Name>,
|
||||
|
||||
/// For user-declared variables, stores their source information.
|
||||
///
|
||||
/// For temporaries, this is `None`.
|
||||
///
|
||||
/// This is the primary way to differentiate between user-declared
|
||||
/// variables and compiler-generated temporaries.
|
||||
pub source_info: Option<SourceInfo>,
|
||||
}
|
||||
|
||||
/// A "temp" is a temporary that we place on the stack. They are
|
||||
/// anonymous, always mutable, and have only a type.
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct TempDecl<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
impl<'tcx> LocalDecl<'tcx> {
|
||||
/// Create a new `LocalDecl` for a temporary.
|
||||
#[inline]
|
||||
pub fn new_temp(ty: Ty<'tcx>) -> Self {
|
||||
LocalDecl {
|
||||
mutability: Mutability::Mut,
|
||||
ty: ty,
|
||||
name: None,
|
||||
source_info: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A "arg" is one of the function's formal arguments. These are
|
||||
/// anonymous and distinct from the bindings that the user declares.
|
||||
///
|
||||
/// For example, in this function:
|
||||
///
|
||||
/// ```
|
||||
/// fn foo((x, y): (i32, u32)) { ... }
|
||||
/// ```
|
||||
///
|
||||
/// there is only one argument, of type `(i32, u32)`, but two bindings
|
||||
/// (`x` and `y`).
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct ArgDecl<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
|
||||
/// Either keywords::Invalid or the name of a single-binding
|
||||
/// pattern associated with this argument. Useful for debuginfo.
|
||||
pub debug_name: Name
|
||||
/// Builds a `LocalDecl` for the return pointer.
|
||||
///
|
||||
/// This must be inserted into the `local_decls` list as the first local.
|
||||
#[inline]
|
||||
pub fn new_return_pointer(return_ty: Ty) -> LocalDecl {
|
||||
LocalDecl {
|
||||
mutability: Mutability::Mut,
|
||||
ty: return_ty,
|
||||
source_info: None,
|
||||
name: None, // FIXME maybe we do want some name here?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A closure capture, with its name and mode.
|
||||
|
@ -442,7 +481,7 @@ pub enum TerminatorKind<'tcx> {
|
|||
/// continue. Emitted by build::scope::diverge_cleanup.
|
||||
Resume,
|
||||
|
||||
/// Indicates a normal return. The ReturnPointer lvalue should
|
||||
/// Indicates a normal return. The return pointer lvalue should
|
||||
/// have been filled in by now. This should occur at most once.
|
||||
Return,
|
||||
|
||||
|
@ -759,31 +798,16 @@ impl<'tcx> Debug for Statement<'tcx> {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// Lvalues
|
||||
|
||||
newtype_index!(Var, "var");
|
||||
newtype_index!(Temp, "tmp");
|
||||
newtype_index!(Arg, "arg");
|
||||
newtype_index!(Local, "local");
|
||||
|
||||
/// A path to a value; something that can be evaluated without
|
||||
/// changing or disturbing program state.
|
||||
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum Lvalue<'tcx> {
|
||||
/// local variable declared by the user
|
||||
Var(Var),
|
||||
|
||||
/// temporary introduced during lowering into MIR
|
||||
Temp(Temp),
|
||||
|
||||
/// formal parameter of the function; note that these are NOT the
|
||||
/// bindings that the user declares, which are vars
|
||||
Arg(Arg),
|
||||
/// local variable
|
||||
Local(Local),
|
||||
|
||||
/// static or static mut variable
|
||||
Static(DefId),
|
||||
|
||||
/// the return pointer of the fn
|
||||
ReturnPointer,
|
||||
|
||||
/// projection out of an lvalue (access a field, deref a pointer, etc)
|
||||
Projection(Box<LvalueProjection<'tcx>>),
|
||||
}
|
||||
|
@ -865,24 +889,6 @@ impl<'tcx> Lvalue<'tcx> {
|
|||
elem: elem,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn from_local(mir: &Mir<'tcx>, local: Local) -> Lvalue<'tcx> {
|
||||
let mut index = local.index();
|
||||
index = match index.checked_sub(mir.arg_decls.len()) {
|
||||
None => return Lvalue::Arg(Arg(index as u32)),
|
||||
Some(index) => index,
|
||||
};
|
||||
index = match index.checked_sub(mir.var_decls.len()) {
|
||||
None => return Lvalue::Var(Var(index as u32)),
|
||||
Some(index) => index,
|
||||
};
|
||||
index = match index.checked_sub(mir.temp_decls.len()) {
|
||||
None => return Lvalue::Temp(Temp(index as u32)),
|
||||
Some(index) => index,
|
||||
};
|
||||
debug_assert!(index == 0);
|
||||
Lvalue::ReturnPointer
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for Lvalue<'tcx> {
|
||||
|
@ -890,13 +896,9 @@ impl<'tcx> Debug for Lvalue<'tcx> {
|
|||
use self::Lvalue::*;
|
||||
|
||||
match *self {
|
||||
Var(id) => write!(fmt, "{:?}", id),
|
||||
Arg(id) => write!(fmt, "{:?}", id),
|
||||
Temp(id) => write!(fmt, "{:?}", id),
|
||||
Local(id) => write!(fmt, "{:?}", id),
|
||||
Static(def_id) =>
|
||||
write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))),
|
||||
ReturnPointer =>
|
||||
write!(fmt, "return"),
|
||||
Projection(ref data) =>
|
||||
match data.elem {
|
||||
ProjectionElem::Downcast(ref adt_def, index) =>
|
||||
|
|
|
@ -49,12 +49,17 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
|
|||
-> LvalueTy<'tcx>
|
||||
{
|
||||
match *elem {
|
||||
ProjectionElem::Deref =>
|
||||
ProjectionElem::Deref => {
|
||||
let ty = self.to_ty(tcx)
|
||||
.builtin_deref(true, ty::LvaluePreference::NoPreference)
|
||||
.unwrap_or_else(|| {
|
||||
bug!("deref projection of non-dereferencable ty {:?}", self)
|
||||
})
|
||||
.ty;
|
||||
LvalueTy::Ty {
|
||||
ty: self.to_ty(tcx).builtin_deref(true, ty::LvaluePreference::NoPreference)
|
||||
.unwrap()
|
||||
.ty
|
||||
},
|
||||
ty: ty,
|
||||
}
|
||||
}
|
||||
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
|
||||
LvalueTy::Ty {
|
||||
ty: self.to_ty(tcx).builtin_index().unwrap()
|
||||
|
@ -116,18 +121,12 @@ impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> {
|
|||
|
||||
impl<'tcx> Lvalue<'tcx> {
|
||||
pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> LvalueTy<'tcx> {
|
||||
match self {
|
||||
&Lvalue::Var(index) =>
|
||||
LvalueTy::Ty { ty: mir.var_decls[index].ty },
|
||||
&Lvalue::Temp(index) =>
|
||||
LvalueTy::Ty { ty: mir.temp_decls[index].ty },
|
||||
&Lvalue::Arg(index) =>
|
||||
LvalueTy::Ty { ty: mir.arg_decls[index].ty },
|
||||
&Lvalue::Static(def_id) =>
|
||||
match *self {
|
||||
Lvalue::Local(index) =>
|
||||
LvalueTy::Ty { ty: mir.local_decls[index].ty },
|
||||
Lvalue::Static(def_id) =>
|
||||
LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty },
|
||||
&Lvalue::ReturnPointer =>
|
||||
LvalueTy::Ty { ty: mir.return_ty },
|
||||
&Lvalue::Projection(ref proj) =>
|
||||
Lvalue::Projection(ref proj) =>
|
||||
proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,19 +236,9 @@ macro_rules! make_mir_visitor {
|
|||
self.super_typed_const_val(val, location);
|
||||
}
|
||||
|
||||
fn visit_var_decl(&mut self,
|
||||
var_decl: & $($mutability)* VarDecl<'tcx>) {
|
||||
self.super_var_decl(var_decl);
|
||||
}
|
||||
|
||||
fn visit_temp_decl(&mut self,
|
||||
temp_decl: & $($mutability)* TempDecl<'tcx>) {
|
||||
self.super_temp_decl(temp_decl);
|
||||
}
|
||||
|
||||
fn visit_arg_decl(&mut self,
|
||||
arg_decl: & $($mutability)* ArgDecl<'tcx>) {
|
||||
self.super_arg_decl(arg_decl);
|
||||
fn visit_local_decl(&mut self,
|
||||
local_decl: & $($mutability)* LocalDecl<'tcx>) {
|
||||
self.super_local_decl(local_decl);
|
||||
}
|
||||
|
||||
fn visit_visibility_scope(&mut self,
|
||||
|
@ -272,16 +262,8 @@ macro_rules! make_mir_visitor {
|
|||
|
||||
self.visit_ty(&$($mutability)* mir.return_ty);
|
||||
|
||||
for var_decl in &$($mutability)* mir.var_decls {
|
||||
self.visit_var_decl(var_decl);
|
||||
}
|
||||
|
||||
for arg_decl in &$($mutability)* mir.arg_decls {
|
||||
self.visit_arg_decl(arg_decl);
|
||||
}
|
||||
|
||||
for temp_decl in &$($mutability)* mir.temp_decls {
|
||||
self.visit_temp_decl(temp_decl);
|
||||
for local_decl in &$($mutability)* mir.local_decls {
|
||||
self.visit_local_decl(local_decl);
|
||||
}
|
||||
|
||||
self.visit_span(&$($mutability)* mir.span);
|
||||
|
@ -584,10 +566,7 @@ macro_rules! make_mir_visitor {
|
|||
context: LvalueContext<'tcx>,
|
||||
location: Location) {
|
||||
match *lvalue {
|
||||
Lvalue::Var(_) |
|
||||
Lvalue::Temp(_) |
|
||||
Lvalue::Arg(_) |
|
||||
Lvalue::ReturnPointer => {
|
||||
Lvalue::Local(_) => {
|
||||
}
|
||||
Lvalue::Static(ref $($mutability)* def_id) => {
|
||||
self.visit_def_id(def_id, location);
|
||||
|
@ -639,36 +618,19 @@ macro_rules! make_mir_visitor {
|
|||
}
|
||||
}
|
||||
|
||||
fn super_var_decl(&mut self,
|
||||
var_decl: & $($mutability)* VarDecl<'tcx>) {
|
||||
let VarDecl {
|
||||
fn super_local_decl(&mut self,
|
||||
local_decl: & $($mutability)* LocalDecl<'tcx>) {
|
||||
let LocalDecl {
|
||||
mutability: _,
|
||||
ref $($mutability)* ty,
|
||||
name: _,
|
||||
ref $($mutability)* ty,
|
||||
ref $($mutability)* source_info,
|
||||
} = *var_decl;
|
||||
|
||||
self.visit_ty(ty);
|
||||
self.visit_source_info(source_info);
|
||||
}
|
||||
|
||||
fn super_temp_decl(&mut self,
|
||||
temp_decl: & $($mutability)* TempDecl<'tcx>) {
|
||||
let TempDecl {
|
||||
ref $($mutability)* ty,
|
||||
} = *temp_decl;
|
||||
|
||||
self.visit_ty(ty);
|
||||
}
|
||||
|
||||
fn super_arg_decl(&mut self,
|
||||
arg_decl: & $($mutability)* ArgDecl<'tcx>) {
|
||||
let ArgDecl {
|
||||
ref $($mutability)* ty,
|
||||
debug_name: _
|
||||
} = *arg_decl;
|
||||
} = *local_decl;
|
||||
|
||||
self.visit_ty(ty);
|
||||
if let Some(ref $($mutability)* info) = *source_info {
|
||||
self.visit_source_info(info);
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visibility_scope(&mut self,
|
||||
|
|
|
@ -13,7 +13,7 @@ use syntax::ast;
|
|||
use syntax_pos::Span;
|
||||
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::mir::repr::{self, Mir};
|
||||
use rustc::mir::repr::{self, Mir, LocalKind};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
use super::super::gather_moves::{MovePathIndex, LookupResult};
|
||||
|
@ -73,11 +73,20 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
};
|
||||
assert!(args.len() == 1);
|
||||
let peek_arg_lval = match args[0] {
|
||||
repr::Operand::Consume(ref lval @ repr::Lvalue::Temp(_)) => {
|
||||
lval
|
||||
}
|
||||
repr::Operand::Consume(_) |
|
||||
repr::Operand::Consume(ref lval) => match *lval {
|
||||
repr::Lvalue::Local(local) if mir.local_kind(local) == LocalKind::Temp => {
|
||||
Some(lval)
|
||||
}
|
||||
_ => None
|
||||
},
|
||||
repr::Operand::Constant(_) => {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let peek_arg_lval = match peek_arg_lval {
|
||||
Some(arg) => arg,
|
||||
None => {
|
||||
tcx.sess.diagnostic().span_err(
|
||||
span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
|
||||
return;
|
||||
|
|
|
@ -118,7 +118,7 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> {
|
|||
env: &'a MoveDataParamEnv<'tcx>,
|
||||
flow_inits: DataflowResults<MaybeInitializedLvals<'a, 'tcx>>,
|
||||
flow_uninits: DataflowResults<MaybeUninitializedLvals<'a, 'tcx>>,
|
||||
drop_flags: FnvHashMap<MovePathIndex, Temp>,
|
||||
drop_flags: FnvHashMap<MovePathIndex, Local>,
|
||||
patch: MirPatch<'tcx>,
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
}
|
||||
|
||||
fn drop_flag(&mut self, index: MovePathIndex) -> Option<Lvalue<'tcx>> {
|
||||
self.drop_flags.get(&index).map(|t| Lvalue::Temp(*t))
|
||||
self.drop_flags.get(&index).map(|t| Lvalue::Local(*t))
|
||||
}
|
||||
|
||||
/// create a patch that elaborates all drops in the input
|
||||
|
@ -847,14 +847,14 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
statements.push(Statement {
|
||||
source_info: c.source_info,
|
||||
kind: StatementKind::Assign(
|
||||
Lvalue::Temp(flag),
|
||||
Lvalue::Local(flag),
|
||||
self.constant_bool(c.source_info.span, false)
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
let tcx = self.tcx;
|
||||
let unit_temp = Lvalue::Temp(self.patch.new_temp(tcx.mk_nil()));
|
||||
let unit_temp = Lvalue::Local(self.patch.new_temp(tcx.mk_nil()));
|
||||
let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
|
||||
.unwrap_or_else(|e| tcx.sess.fatal(&e));
|
||||
let substs = Substs::new(tcx, iter::once(Kind::from(ty)));
|
||||
|
@ -917,7 +917,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
if let Some(&flag) = self.drop_flags.get(&path) {
|
||||
let span = self.patch.source_info_for_location(self.mir, loc).span;
|
||||
let val = self.constant_bool(span, val.value());
|
||||
self.patch.add_assign(loc, Lvalue::Temp(flag), val);
|
||||
self.patch.add_assign(loc, Lvalue::Local(flag), val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -926,7 +926,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
let span = self.patch.source_info_for_location(self.mir, loc).span;
|
||||
let false_ = self.constant_bool(span, false);
|
||||
for flag in self.drop_flags.values() {
|
||||
self.patch.add_assign(loc, Lvalue::Temp(*flag), false_.clone());
|
||||
self.patch.add_assign(loc, Lvalue::Local(*flag), false_.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -173,13 +173,7 @@ impl fmt::Debug for MoveOut {
|
|||
/// Tables mapping from an l-value to its MovePathIndex.
|
||||
#[derive(Debug)]
|
||||
pub struct MovePathLookup<'tcx> {
|
||||
vars: IndexVec<Var, MovePathIndex>,
|
||||
temps: IndexVec<Temp, MovePathIndex>,
|
||||
args: IndexVec<Arg, MovePathIndex>,
|
||||
|
||||
/// The move path representing the return value is constructed
|
||||
/// lazily when we first encounter it in the input MIR.
|
||||
return_ptr: Option<MovePathIndex>,
|
||||
locals: IndexVec<Local, MovePathIndex>,
|
||||
|
||||
/// projections are made from a base-lvalue and a projection
|
||||
/// elem. The base-lvalue will have a unique MovePathIndex; we use
|
||||
|
@ -218,16 +212,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
|||
moves: IndexVec::new(),
|
||||
loc_map: LocationMap::new(mir),
|
||||
rev_lookup: MovePathLookup {
|
||||
vars: mir.var_decls.indices().map(Lvalue::Var).map(|v| {
|
||||
locals: mir.local_decls.indices().map(Lvalue::Local).map(|v| {
|
||||
Self::new_move_path(&mut move_paths, &mut path_map, None, v)
|
||||
}).collect(),
|
||||
temps: mir.temp_decls.indices().map(Lvalue::Temp).map(|t| {
|
||||
Self::new_move_path(&mut move_paths, &mut path_map, None, t)
|
||||
}).collect(),
|
||||
args: mir.arg_decls.indices().map(Lvalue::Arg).map(|a| {
|
||||
Self::new_move_path(&mut move_paths, &mut path_map, None, a)
|
||||
}).collect(),
|
||||
return_ptr: None,
|
||||
projections: FnvHashMap(),
|
||||
},
|
||||
move_paths: move_paths,
|
||||
|
@ -272,23 +259,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
|||
{
|
||||
debug!("lookup({:?})", lval);
|
||||
match *lval {
|
||||
Lvalue::Var(var) => Ok(self.data.rev_lookup.vars[var]),
|
||||
Lvalue::Arg(arg) => Ok(self.data.rev_lookup.args[arg]),
|
||||
Lvalue::Temp(temp) => Ok(self.data.rev_lookup.temps[temp]),
|
||||
Lvalue::Local(local) => Ok(self.data.rev_lookup.locals[local]),
|
||||
// error: can't move out of a static
|
||||
Lvalue::Static(..) => Err(MovePathError::IllegalMove),
|
||||
Lvalue::ReturnPointer => match self.data.rev_lookup.return_ptr {
|
||||
Some(ptr) => Ok(ptr),
|
||||
ref mut ptr @ None => {
|
||||
let path = Self::new_move_path(
|
||||
&mut self.data.move_paths,
|
||||
&mut self.data.path_map,
|
||||
None,
|
||||
lval.clone());
|
||||
*ptr = Some(path);
|
||||
Ok(path)
|
||||
}
|
||||
},
|
||||
Lvalue::Projection(ref proj) => {
|
||||
self.move_path_for_projection(lval, proj)
|
||||
}
|
||||
|
@ -373,11 +346,8 @@ impl<'tcx> MovePathLookup<'tcx> {
|
|||
// parent.
|
||||
pub fn find(&self, lval: &Lvalue<'tcx>) -> LookupResult {
|
||||
match *lval {
|
||||
Lvalue::Var(var) => LookupResult::Exact(self.vars[var]),
|
||||
Lvalue::Temp(temp) => LookupResult::Exact(self.temps[temp]),
|
||||
Lvalue::Arg(arg) => LookupResult::Exact(self.args[arg]),
|
||||
Lvalue::Local(local) => LookupResult::Exact(self.locals[local]),
|
||||
Lvalue::Static(..) => LookupResult::Parent(None),
|
||||
Lvalue::ReturnPointer => LookupResult::Exact(self.return_ptr.unwrap()),
|
||||
Lvalue::Projection(ref proj) => {
|
||||
match self.find(&proj.base) {
|
||||
LookupResult::Exact(base_path) => {
|
||||
|
@ -486,7 +456,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
|||
TerminatorKind::Unreachable => { }
|
||||
|
||||
TerminatorKind::Return => {
|
||||
self.gather_move(loc, &Lvalue::ReturnPointer);
|
||||
self.gather_move(loc, &Lvalue::Local(RETURN_POINTER));
|
||||
}
|
||||
|
||||
TerminatorKind::If { .. } |
|
||||
|
|
|
@ -338,8 +338,8 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>(
|
|||
where F: FnMut(MovePathIndex, DropFlagState)
|
||||
{
|
||||
let move_data = &ctxt.move_data;
|
||||
for (arg, _) in mir.arg_decls.iter_enumerated() {
|
||||
let lvalue = repr::Lvalue::Arg(arg);
|
||||
for arg in mir.arg_iter() {
|
||||
let lvalue = repr::Lvalue::Local(arg);
|
||||
let lookup_result = move_data.rev_lookup.find(&lvalue);
|
||||
on_lookup_result_bits(tcx, mir, move_data,
|
||||
lookup_result,
|
||||
|
|
|
@ -19,9 +19,9 @@ pub struct MirPatch<'tcx> {
|
|||
patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>,
|
||||
new_blocks: Vec<BasicBlockData<'tcx>>,
|
||||
new_statements: Vec<(Location, StatementKind<'tcx>)>,
|
||||
new_temps: Vec<TempDecl<'tcx>>,
|
||||
new_locals: Vec<LocalDecl<'tcx>>,
|
||||
resume_block: BasicBlock,
|
||||
next_temp: usize,
|
||||
next_local: usize,
|
||||
}
|
||||
|
||||
impl<'tcx> MirPatch<'tcx> {
|
||||
|
@ -29,9 +29,9 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
let mut result = MirPatch {
|
||||
patch_map: IndexVec::from_elem(None, mir.basic_blocks()),
|
||||
new_blocks: vec![],
|
||||
new_temps: vec![],
|
||||
new_statements: vec![],
|
||||
next_temp: mir.temp_decls.len(),
|
||||
new_locals: vec![],
|
||||
next_local: mir.local_decls.len(),
|
||||
resume_block: START_BLOCK
|
||||
};
|
||||
|
||||
|
@ -92,11 +92,11 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Temp {
|
||||
let index = self.next_temp;
|
||||
self.next_temp += 1;
|
||||
self.new_temps.push(TempDecl { ty: ty });
|
||||
Temp::new(index as usize)
|
||||
pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Local {
|
||||
let index = self.next_local;
|
||||
self.next_local += 1;
|
||||
self.new_locals.push(LocalDecl::new_temp(ty));
|
||||
Local::new(index as usize)
|
||||
}
|
||||
|
||||
pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
|
||||
|
@ -124,11 +124,11 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
|
||||
pub fn apply(self, mir: &mut Mir<'tcx>) {
|
||||
debug!("MirPatch: {:?} new temps, starting from index {}: {:?}",
|
||||
self.new_temps.len(), mir.temp_decls.len(), self.new_temps);
|
||||
self.new_locals.len(), mir.local_decls.len(), self.new_locals);
|
||||
debug!("MirPatch: {} new blocks, starting from index {}",
|
||||
self.new_blocks.len(), mir.basic_blocks().len());
|
||||
mir.basic_blocks_mut().extend(self.new_blocks);
|
||||
mir.temp_decls.extend(self.new_temps);
|
||||
mir.local_decls.extend(self.new_locals);
|
||||
for (src, patch) in self.patch_map.into_iter_enumerated() {
|
||||
if let Some(patch) = patch {
|
||||
debug!("MirPatch: patching block {:?}", src);
|
||||
|
|
|
@ -77,11 +77,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
success.and(slice.index(idx))
|
||||
}
|
||||
ExprKind::SelfRef => {
|
||||
block.and(Lvalue::Arg(Arg::new(0)))
|
||||
block.and(Lvalue::Local(Local::new(1)))
|
||||
}
|
||||
ExprKind::VarRef { id } => {
|
||||
let index = this.var_indices[&id];
|
||||
block.and(Lvalue::Var(index))
|
||||
block.and(Lvalue::Local(index))
|
||||
}
|
||||
ExprKind::StaticRef { id } => {
|
||||
block.and(Lvalue::Static(id))
|
||||
|
|
|
@ -90,9 +90,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
ExprKind::Return { value } => {
|
||||
block = match value {
|
||||
Some(value) => unpack!(this.into(&Lvalue::ReturnPointer, block, value)),
|
||||
Some(value) => {
|
||||
unpack!(this.into(&Lvalue::Local(RETURN_POINTER), block, value))
|
||||
}
|
||||
None => {
|
||||
this.cfg.push_assign_unit(block, source_info, &Lvalue::ReturnPointer);
|
||||
this.cfg.push_assign_unit(block,
|
||||
source_info,
|
||||
&Lvalue::Local(RETURN_POINTER));
|
||||
block
|
||||
}
|
||||
};
|
||||
|
|
|
@ -123,7 +123,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
var,
|
||||
subpattern: None, .. } => {
|
||||
self.storage_live_for_bindings(block, &irrefutable_pat);
|
||||
let lvalue = Lvalue::Var(self.var_indices[&var]);
|
||||
let lvalue = Lvalue::Local(self.var_indices[&var]);
|
||||
return self.into(&lvalue, block, initializer);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -214,7 +214,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
pattern: &Pattern<'tcx>) {
|
||||
match *pattern.kind {
|
||||
PatternKind::Binding { var, ref subpattern, .. } => {
|
||||
let lvalue = Lvalue::Var(self.var_indices[&var]);
|
||||
let lvalue = Lvalue::Local(self.var_indices[&var]);
|
||||
let source_info = self.source_info(pattern.span);
|
||||
self.cfg.push(block, Statement {
|
||||
source_info: source_info,
|
||||
|
@ -705,10 +705,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let source_info = self.source_info(binding.span);
|
||||
self.cfg.push(block, Statement {
|
||||
source_info: source_info,
|
||||
kind: StatementKind::StorageLive(Lvalue::Var(var_index))
|
||||
kind: StatementKind::StorageLive(Lvalue::Local(var_index))
|
||||
});
|
||||
self.cfg.push_assign(block, source_info,
|
||||
&Lvalue::Var(var_index), rvalue);
|
||||
&Lvalue::Local(var_index), rvalue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -718,19 +718,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
name: Name,
|
||||
var_id: NodeId,
|
||||
var_ty: Ty<'tcx>)
|
||||
-> Var
|
||||
-> Local
|
||||
{
|
||||
debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, source_info={:?})",
|
||||
var_id, name, var_ty, source_info);
|
||||
|
||||
let var = self.var_decls.push(VarDecl::<'tcx> {
|
||||
source_info: source_info,
|
||||
let var = self.local_decls.push(LocalDecl::<'tcx> {
|
||||
mutability: mutability,
|
||||
name: name,
|
||||
ty: var_ty.clone(),
|
||||
name: Some(name),
|
||||
source_info: Some(source_info),
|
||||
});
|
||||
let extent = self.extent_of_innermost_scope();
|
||||
self.schedule_drop(source_info.span, extent, &Lvalue::Var(var), var_ty);
|
||||
self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty);
|
||||
self.var_indices.insert(var_id, var);
|
||||
|
||||
debug!("declare_binding: var={:?}", var);
|
||||
|
|
|
@ -28,10 +28,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
/// NB: **No cleanup is scheduled for this temporary.** You should
|
||||
/// call `schedule_drop` once the temporary is initialized.
|
||||
pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> {
|
||||
let temp = self.temp_decls.push(TempDecl { ty: ty });
|
||||
let lvalue = Lvalue::Temp(temp);
|
||||
let temp = self.local_decls.push(LocalDecl::new_temp(ty));
|
||||
let lvalue = Lvalue::Local(temp);
|
||||
debug!("temp: created temp {:?} with type {:?}",
|
||||
lvalue, self.temp_decls[temp].ty);
|
||||
lvalue, self.local_decls[temp].ty);
|
||||
lvalue
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
|||
cfg: CFG<'tcx>,
|
||||
|
||||
fn_span: Span,
|
||||
arg_count: usize,
|
||||
|
||||
/// the current set of scopes, updated as we traverse;
|
||||
/// see the `scope` module for more details
|
||||
|
@ -49,9 +50,9 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
|||
visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
|
||||
visibility_scope: VisibilityScope,
|
||||
|
||||
var_decls: IndexVec<Var, VarDecl<'tcx>>,
|
||||
var_indices: NodeMap<Var>,
|
||||
temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
|
||||
/// Maps node ids of variable bindings to the `Local`s created for them.
|
||||
var_indices: NodeMap<Local>,
|
||||
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
||||
unit_temp: Option<Lvalue<'tcx>>,
|
||||
|
||||
/// cached block with the RESUME terminator; this is created
|
||||
|
@ -157,9 +158,11 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
|
|||
-> (Mir<'tcx>, ScopeAuxiliaryVec)
|
||||
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
|
||||
{
|
||||
let arguments: Vec<_> = arguments.collect();
|
||||
|
||||
let tcx = hir.tcx();
|
||||
let span = tcx.map.span(fn_id);
|
||||
let mut builder = Builder::new(hir, span);
|
||||
let mut builder = Builder::new(hir, span, arguments.len(), return_ty);
|
||||
|
||||
let body_id = ast_block.id;
|
||||
let call_site_extent =
|
||||
|
@ -169,9 +172,9 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
|
|||
tcx.region_maps.lookup_code_extent(
|
||||
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
|
||||
let mut block = START_BLOCK;
|
||||
let arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
|
||||
let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, |builder| {
|
||||
builder.args_and_body(block, return_ty, arguments, arg_extent, ast_block)
|
||||
unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
|
||||
unpack!(block = builder.in_scope(arg_extent, block, |builder| {
|
||||
builder.args_and_body(block, return_ty, &arguments, arg_extent, ast_block)
|
||||
}));
|
||||
|
||||
let source_info = builder.source_info(span);
|
||||
|
@ -180,7 +183,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
|
|||
TerminatorKind::Goto { target: return_block });
|
||||
builder.cfg.terminate(return_block, source_info,
|
||||
TerminatorKind::Return);
|
||||
return_block.and(arg_decls)
|
||||
return_block.unit()
|
||||
}));
|
||||
assert_eq!(block, builder.return_block());
|
||||
|
||||
|
@ -217,7 +220,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
|
|||
}).collect()
|
||||
});
|
||||
|
||||
let (mut mir, aux) = builder.finish(upvar_decls, arg_decls, return_ty);
|
||||
let (mut mir, aux) = builder.finish(upvar_decls, return_ty);
|
||||
mir.spread_last_arg = spread_last_arg;
|
||||
(mir, aux)
|
||||
}
|
||||
|
@ -227,15 +230,16 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
|
|||
ast_expr: &'tcx hir::Expr)
|
||||
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
|
||||
let tcx = hir.tcx();
|
||||
let ty = tcx.expr_ty_adjusted(ast_expr);
|
||||
let span = tcx.map.span(item_id);
|
||||
let mut builder = Builder::new(hir, span);
|
||||
let mut builder = Builder::new(hir, span, 0, ty);
|
||||
|
||||
let extent = tcx.region_maps.temporary_scope(ast_expr.id)
|
||||
.unwrap_or(ROOT_CODE_EXTENT);
|
||||
let mut block = START_BLOCK;
|
||||
let _ = builder.in_scope(extent, block, |builder| {
|
||||
let expr = builder.hir.mirror(ast_expr);
|
||||
unpack!(block = builder.into(&Lvalue::ReturnPointer, block, expr));
|
||||
unpack!(block = builder.into(&Lvalue::Local(RETURN_POINTER), block, expr));
|
||||
|
||||
let source_info = builder.source_info(span);
|
||||
let return_block = builder.return_block();
|
||||
|
@ -247,23 +251,26 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
|
|||
return_block.unit()
|
||||
});
|
||||
|
||||
let ty = tcx.expr_ty_adjusted(ast_expr);
|
||||
builder.finish(vec![], IndexVec::new(), ty)
|
||||
builder.finish(vec![], ty)
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span) -> Builder<'a, 'gcx, 'tcx> {
|
||||
fn new(hir: Cx<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
arg_count: usize,
|
||||
return_ty: Ty<'tcx>)
|
||||
-> Builder<'a, 'gcx, 'tcx> {
|
||||
let mut builder = Builder {
|
||||
hir: hir,
|
||||
cfg: CFG { basic_blocks: IndexVec::new() },
|
||||
fn_span: span,
|
||||
arg_count: arg_count,
|
||||
scopes: vec![],
|
||||
visibility_scopes: IndexVec::new(),
|
||||
visibility_scope: ARGUMENT_VISIBILITY_SCOPE,
|
||||
scope_auxiliary: IndexVec::new(),
|
||||
loop_scopes: vec![],
|
||||
temp_decls: IndexVec::new(),
|
||||
var_decls: IndexVec::new(),
|
||||
local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1),
|
||||
var_indices: NodeMap(),
|
||||
unit_temp: None,
|
||||
cached_resume_block: None,
|
||||
|
@ -279,7 +286,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
|
||||
fn finish(self,
|
||||
upvar_decls: Vec<UpvarDecl>,
|
||||
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
|
||||
return_ty: Ty<'tcx>)
|
||||
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
|
||||
for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
|
||||
|
@ -292,27 +298,45 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
self.visibility_scopes,
|
||||
IndexVec::new(),
|
||||
return_ty,
|
||||
self.var_decls,
|
||||
arg_decls,
|
||||
self.temp_decls,
|
||||
self.local_decls,
|
||||
self.arg_count,
|
||||
upvar_decls,
|
||||
self.fn_span
|
||||
), self.scope_auxiliary)
|
||||
}
|
||||
|
||||
fn args_and_body<A>(&mut self,
|
||||
mut block: BasicBlock,
|
||||
return_ty: Ty<'tcx>,
|
||||
arguments: A,
|
||||
argument_extent: CodeExtent,
|
||||
ast_block: &'gcx hir::Block)
|
||||
-> BlockAnd<IndexVec<Arg, ArgDecl<'tcx>>>
|
||||
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
|
||||
fn args_and_body(&mut self,
|
||||
mut block: BasicBlock,
|
||||
return_ty: Ty<'tcx>,
|
||||
arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)],
|
||||
argument_extent: CodeExtent,
|
||||
ast_block: &'gcx hir::Block)
|
||||
-> BlockAnd<()>
|
||||
{
|
||||
// to start, translate the argument patterns and collect the argument types.
|
||||
// Allocate locals for the function arguments
|
||||
for &(ty, pattern) in arguments.iter() {
|
||||
// If this is a simple binding pattern, give the local a nice name for debuginfo.
|
||||
let mut name = None;
|
||||
if let Some(pat) = pattern {
|
||||
if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
|
||||
name = Some(ident.node);
|
||||
}
|
||||
}
|
||||
|
||||
self.local_decls.push(LocalDecl {
|
||||
mutability: Mutability::Not,
|
||||
ty: ty,
|
||||
source_info: None,
|
||||
name: name,
|
||||
});
|
||||
}
|
||||
|
||||
let mut scope = None;
|
||||
let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| {
|
||||
let lvalue = Lvalue::Arg(Arg::new(index));
|
||||
// Bind the argument patterns
|
||||
for (index, &(ty, pattern)) in arguments.iter().enumerate() {
|
||||
// Function arguments always get the first Local indices after the return pointer
|
||||
let lvalue = Lvalue::Local(Local::new(index + 1));
|
||||
|
||||
if let Some(pattern) = pattern {
|
||||
let pattern = self.hir.irrefutable_pat(pattern);
|
||||
scope = self.declare_bindings(scope, ast_block.span, &pattern);
|
||||
|
@ -323,18 +347,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span),
|
||||
argument_extent, &lvalue, ty);
|
||||
|
||||
let mut name = keywords::Invalid.name();
|
||||
if let Some(pat) = pattern {
|
||||
if let hir::PatKind::Binding(_, ref ident, _) = pat.node {
|
||||
name = ident.node;
|
||||
}
|
||||
}
|
||||
|
||||
ArgDecl {
|
||||
ty: ty,
|
||||
debug_name: name
|
||||
}
|
||||
}).collect();
|
||||
}
|
||||
|
||||
// Enter the argument pattern bindings visibility scope, if it exists.
|
||||
if let Some(visibility_scope) = scope {
|
||||
|
@ -344,9 +357,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
// FIXME(#32959): temporary hack for the issue at hand
|
||||
let return_is_unit = return_ty.is_nil();
|
||||
// start the first basic block and translate the body
|
||||
unpack!(block = self.ast_block(&Lvalue::ReturnPointer, return_is_unit, block, ast_block));
|
||||
unpack!(block = self.ast_block(&Lvalue::Local(RETURN_POINTER),
|
||||
return_is_unit, block, ast_block));
|
||||
|
||||
block.and(arg_decls)
|
||||
block.unit()
|
||||
}
|
||||
|
||||
fn get_unit_temp(&mut self) -> Lvalue<'tcx> {
|
||||
|
|
|
@ -26,7 +26,7 @@ multiple-exit (SEME) region in the control-flow graph.
|
|||
For now, we keep a mapping from each `CodeExtent` to its
|
||||
corresponding SEME region for later reference (see caveat in next
|
||||
paragraph). This is because region scopes are tied to
|
||||
them. Eventually, when we shift to non-lexical lifetimes, three should
|
||||
them. Eventually, when we shift to non-lexical lifetimes, there should
|
||||
be no need to remember this mapping.
|
||||
|
||||
There is one additional wrinkle, actually, that I wanted to hide from
|
||||
|
@ -67,7 +67,7 @@ There are numerous "normal" ways to early exit a scope: `break`,
|
|||
early exit occurs, the method `exit_scope` is called. It is given the
|
||||
current point in execution where the early exit occurs, as well as the
|
||||
scope you want to branch to (note that all early exits from to some
|
||||
other enclosing scope). `exit_scope` will record thid exit point and
|
||||
other enclosing scope). `exit_scope` will record this exit point and
|
||||
also add all drops.
|
||||
|
||||
Panics are handled in a similar fashion, except that a panic always
|
||||
|
@ -322,7 +322,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
self.diverge_cleanup();
|
||||
let scope = self.scopes.pop().unwrap();
|
||||
assert_eq!(scope.extent, extent);
|
||||
unpack!(block = build_scope_drops(&mut self.cfg, &scope, &self.scopes, block));
|
||||
unpack!(block = build_scope_drops(&mut self.cfg,
|
||||
&scope,
|
||||
&self.scopes,
|
||||
block,
|
||||
self.arg_count));
|
||||
self.scope_auxiliary[scope.id]
|
||||
.postdoms
|
||||
.push(self.cfg.current_location(block));
|
||||
|
@ -362,7 +366,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
scope.cached_exits.insert((target, extent), b);
|
||||
b
|
||||
};
|
||||
unpack!(block = build_scope_drops(&mut self.cfg, scope, rest, block));
|
||||
unpack!(block = build_scope_drops(&mut self.cfg,
|
||||
scope,
|
||||
rest,
|
||||
block,
|
||||
self.arg_count));
|
||||
if let Some(ref free_data) = scope.free {
|
||||
let next = self.cfg.start_new_block();
|
||||
let free = build_free(self.hir.tcx(), &tmp, free_data, next);
|
||||
|
@ -454,7 +462,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
} else {
|
||||
// Only temps and vars need their storage dead.
|
||||
match *lvalue {
|
||||
Lvalue::Temp(_) | Lvalue::Var(_) => DropKind::Storage,
|
||||
Lvalue::Local(index) if index.index() > self.arg_count + 1 => DropKind::Storage,
|
||||
_ => return
|
||||
}
|
||||
};
|
||||
|
@ -671,7 +679,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
|
||||
scope: &Scope<'tcx>,
|
||||
earlier_scopes: &[Scope<'tcx>],
|
||||
mut block: BasicBlock)
|
||||
mut block: BasicBlock,
|
||||
arg_count: usize)
|
||||
-> BlockAnd<()> {
|
||||
let mut iter = scope.drops.iter().rev().peekable();
|
||||
while let Some(drop_data) = iter.next() {
|
||||
|
@ -703,7 +712,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
|
|||
DropKind::Storage => {
|
||||
// Only temps and vars need their storage dead.
|
||||
match drop_data.location {
|
||||
Lvalue::Temp(_) | Lvalue::Var(_) => {}
|
||||
Lvalue::Local(index) if index.index() > arg_count => {}
|
||||
_ => continue
|
||||
}
|
||||
|
||||
|
|
|
@ -12,13 +12,12 @@
|
|||
|
||||
use rustc::mir::repr::{Local, Location, Lvalue, Mir};
|
||||
use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
|
||||
pub struct DefUseAnalysis<'tcx> {
|
||||
info: IndexVec<Local, Info<'tcx>>,
|
||||
mir_summary: MirSummary,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -35,15 +34,13 @@ pub struct Use<'tcx> {
|
|||
impl<'tcx> DefUseAnalysis<'tcx> {
|
||||
pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> {
|
||||
DefUseAnalysis {
|
||||
info: IndexVec::from_elem_n(Info::new(), mir.count_locals()),
|
||||
mir_summary: MirSummary::new(mir),
|
||||
info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn analyze(&mut self, mir: &Mir<'tcx>) {
|
||||
let mut finder = DefUseFinder {
|
||||
info: mem::replace(&mut self.info, IndexVec::new()),
|
||||
mir_summary: self.mir_summary,
|
||||
};
|
||||
finder.visit_mir(mir);
|
||||
self.info = finder.info
|
||||
|
@ -64,7 +61,6 @@ impl<'tcx> DefUseAnalysis<'tcx> {
|
|||
for lvalue_use in &self.info[local].defs_and_uses {
|
||||
MutateUseVisitor::new(local,
|
||||
&mut callback,
|
||||
self.mir_summary,
|
||||
mir).visit_location(mir, lvalue_use.location)
|
||||
}
|
||||
}
|
||||
|
@ -80,13 +76,17 @@ impl<'tcx> DefUseAnalysis<'tcx> {
|
|||
|
||||
struct DefUseFinder<'tcx> {
|
||||
info: IndexVec<Local, Info<'tcx>>,
|
||||
mir_summary: MirSummary,
|
||||
}
|
||||
|
||||
impl<'tcx> DefUseFinder<'tcx> {
|
||||
fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> {
|
||||
let info = &mut self.info;
|
||||
self.mir_summary.local_index(lvalue).map(move |local| &mut info[local])
|
||||
|
||||
if let Lvalue::Local(local) = *lvalue {
|
||||
Some(&mut info[local])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,18 +132,16 @@ impl<'tcx> Info<'tcx> {
|
|||
struct MutateUseVisitor<'tcx, F> {
|
||||
query: Local,
|
||||
callback: F,
|
||||
mir_summary: MirSummary,
|
||||
phantom: PhantomData<&'tcx ()>,
|
||||
}
|
||||
|
||||
impl<'tcx, F> MutateUseVisitor<'tcx, F> {
|
||||
fn new(query: Local, callback: F, mir_summary: MirSummary, _: &Mir<'tcx>)
|
||||
fn new(query: Local, callback: F, _: &Mir<'tcx>)
|
||||
-> MutateUseVisitor<'tcx, F>
|
||||
where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
|
||||
MutateUseVisitor {
|
||||
query: query,
|
||||
callback: callback,
|
||||
mir_summary: mir_summary,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -155,43 +153,11 @@ impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F>
|
|||
lvalue: &mut Lvalue<'tcx>,
|
||||
context: LvalueContext<'tcx>,
|
||||
location: Location) {
|
||||
if self.mir_summary.local_index(lvalue) == Some(self.query) {
|
||||
(self.callback)(lvalue, context, location)
|
||||
if let Lvalue::Local(local) = *lvalue {
|
||||
if local == self.query {
|
||||
(self.callback)(lvalue, context, location)
|
||||
}
|
||||
}
|
||||
self.super_lvalue(lvalue, context, location)
|
||||
}
|
||||
}
|
||||
|
||||
/// A small structure that enables various metadata of the MIR to be queried
|
||||
/// without a reference to the MIR itself.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct MirSummary {
|
||||
arg_count: usize,
|
||||
var_count: usize,
|
||||
temp_count: usize,
|
||||
}
|
||||
|
||||
impl MirSummary {
|
||||
pub fn new(mir: &Mir) -> MirSummary {
|
||||
MirSummary {
|
||||
arg_count: mir.arg_decls.len(),
|
||||
var_count: mir.var_decls.len(),
|
||||
temp_count: mir.temp_decls.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn local_index<'tcx>(&self, lvalue: &Lvalue<'tcx>) -> Option<Local> {
|
||||
match *lvalue {
|
||||
Lvalue::Arg(arg) => Some(Local::new(arg.index())),
|
||||
Lvalue::Var(var) => Some(Local::new(var.index() + self.arg_count)),
|
||||
Lvalue::Temp(temp) => {
|
||||
Some(Local::new(temp.index() + self.arg_count + self.var_count))
|
||||
}
|
||||
Lvalue::ReturnPointer => {
|
||||
Some(Local::new(self.arg_count + self.var_count + self.temp_count))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -136,30 +136,31 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
write!(w, " label=<fn {}(", dot::escape_html(&tcx.node_path_str(nid)))?;
|
||||
|
||||
// fn argument types.
|
||||
for (i, arg) in mir.arg_decls.iter().enumerate() {
|
||||
for (i, arg) in mir.arg_iter().enumerate() {
|
||||
if i > 0 {
|
||||
write!(w, ", ")?;
|
||||
}
|
||||
write!(w, "{:?}: {}", Lvalue::Arg(Arg::new(i)), escape(&arg.ty))?;
|
||||
write!(w, "{:?}: {}", Lvalue::Local(arg), escape(&mir.local_decls[arg].ty))?;
|
||||
}
|
||||
|
||||
write!(w, ") -> {}", escape(mir.return_ty))?;
|
||||
write!(w, r#"<br align="left"/>"#)?;
|
||||
|
||||
// User variable types (including the user's name in a comment).
|
||||
for (i, var) in mir.var_decls.iter().enumerate() {
|
||||
for local in mir.var_and_temp_iter() {
|
||||
let decl = &mir.local_decls[local];
|
||||
|
||||
write!(w, "let ")?;
|
||||
if var.mutability == Mutability::Mut {
|
||||
if decl.mutability == Mutability::Mut {
|
||||
write!(w, "mut ")?;
|
||||
}
|
||||
write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
|
||||
Lvalue::Var(Var::new(i)), escape(&var.ty), var.name)?;
|
||||
}
|
||||
|
||||
// Compiler-introduced temporary types.
|
||||
for (i, temp) in mir.temp_decls.iter().enumerate() {
|
||||
write!(w, r#"let mut {:?}: {};<br align="left"/>"#,
|
||||
Lvalue::Temp(Temp::new(i)), escape(&temp.ty))?;
|
||||
if let Some(name) = decl.name {
|
||||
write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
|
||||
Lvalue::Local(local), escape(&decl.ty), name)?;
|
||||
} else {
|
||||
write!(w, r#"let mut {:?}: {};<br align="left"/>"#,
|
||||
Lvalue::Local(local), escape(&decl.ty))?;
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(w, ">;")
|
||||
|
@ -172,3 +173,5 @@ fn node(block: BasicBlock) -> String {
|
|||
fn escape<T: Debug>(t: &T) -> String {
|
||||
dot::escape_html(&format!("{:?}", t))
|
||||
}
|
||||
|
||||
// TODO manually test
|
||||
|
|
|
@ -214,6 +214,9 @@ fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
|
|||
format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
|
||||
}
|
||||
|
||||
/// Prints user-defined variables in a scope tree.
|
||||
///
|
||||
/// Returns the total number of variables printed.
|
||||
fn write_scope_tree(tcx: TyCtxt,
|
||||
mir: &Mir,
|
||||
scope_tree: &FnvHashMap<VisibilityScope, Vec<VisibilityScope>>,
|
||||
|
@ -234,11 +237,14 @@ fn write_scope_tree(tcx: TyCtxt,
|
|||
writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;
|
||||
|
||||
// User variable types (including the user's name in a comment).
|
||||
for (id, var) in mir.var_decls.iter_enumerated() {
|
||||
// Skip if not declared in this scope.
|
||||
if var.source_info.scope != child {
|
||||
for local in mir.var_iter() {
|
||||
let var = &mir.local_decls[local];
|
||||
let (name, source_info) = if var.source_info.unwrap().scope == child {
|
||||
(var.name.unwrap(), var.source_info.unwrap())
|
||||
} else {
|
||||
// Not a variable or not declared in this scope.
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let mut_str = if var.mutability == Mutability::Mut {
|
||||
"mut "
|
||||
|
@ -251,13 +257,13 @@ fn write_scope_tree(tcx: TyCtxt,
|
|||
INDENT,
|
||||
indent,
|
||||
mut_str,
|
||||
id,
|
||||
local,
|
||||
var.ty);
|
||||
writeln!(w, "{0:1$} // \"{2}\" in {3}",
|
||||
indented_var,
|
||||
ALIGN,
|
||||
var.name,
|
||||
comment(tcx, var.source_info))?;
|
||||
name,
|
||||
comment(tcx, source_info))?;
|
||||
}
|
||||
|
||||
write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;
|
||||
|
@ -291,9 +297,23 @@ fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
// Print return pointer
|
||||
let indented_retptr = format!("{}let mut {:?}: {};",
|
||||
INDENT,
|
||||
RETURN_POINTER,
|
||||
mir.return_ty);
|
||||
writeln!(w, "{0:1$} // return pointer",
|
||||
indented_retptr,
|
||||
ALIGN)?;
|
||||
|
||||
write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;
|
||||
|
||||
write_mir_decls(mir, w)
|
||||
write_temp_decls(mir, w)?;
|
||||
|
||||
// Add an empty line before the first block is printed.
|
||||
writeln!(w, "")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
|
||||
|
@ -313,30 +333,27 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
|
|||
write!(w, "(")?;
|
||||
|
||||
// fn argument types.
|
||||
for (i, arg) in mir.arg_decls.iter_enumerated() {
|
||||
if i.index() != 0 {
|
||||
for (i, arg) in mir.arg_iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(w, ", ")?;
|
||||
}
|
||||
write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?;
|
||||
write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?;
|
||||
}
|
||||
|
||||
write!(w, ") -> {}", mir.return_ty)
|
||||
} else {
|
||||
assert!(mir.arg_decls.is_empty());
|
||||
assert_eq!(mir.arg_count, 0);
|
||||
write!(w, ": {} =", mir.return_ty)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
|
||||
fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
|
||||
// Compiler-introduced temporary types.
|
||||
for (id, temp) in mir.temp_decls.iter_enumerated() {
|
||||
writeln!(w, "{}let mut {:?}: {};", INDENT, id, temp.ty)?;
|
||||
}
|
||||
|
||||
// Wrote any declaration? Add an empty line before the first block is printed.
|
||||
if !mir.var_decls.is_empty() || !mir.temp_decls.is_empty() {
|
||||
writeln!(w, "")?;
|
||||
for temp in mir.temp_iter() {
|
||||
writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[temp].ty)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO manually test
|
||||
|
|
|
@ -29,12 +29,11 @@
|
|||
//! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the
|
||||
//! future.
|
||||
|
||||
use def_use::{DefUseAnalysis, MirSummary};
|
||||
use def_use::DefUseAnalysis;
|
||||
use rustc::mir::repr::{Constant, Local, Location, Lvalue, Mir, Operand, Rvalue, StatementKind};
|
||||
use rustc::mir::transform::{MirPass, MirSource, Pass};
|
||||
use rustc::mir::visit::MutVisitor;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use transform::qualify_consts;
|
||||
|
||||
pub struct CopyPropagation;
|
||||
|
@ -78,9 +77,8 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
|
|||
def_use_analysis.analyze(mir);
|
||||
|
||||
let mut changed = false;
|
||||
for dest_local_index in 0..mir.count_locals() {
|
||||
let dest_local = Local::new(dest_local_index);
|
||||
debug!("Considering destination local: {}", mir.format_local(dest_local));
|
||||
for dest_local in mir.local_decls.indices() {
|
||||
debug!("Considering destination local: {:?}", dest_local);
|
||||
|
||||
let action;
|
||||
let location;
|
||||
|
@ -89,19 +87,19 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
|
|||
let dest_use_info = def_use_analysis.local_info(dest_local);
|
||||
let dest_def_count = dest_use_info.def_count_not_including_drop();
|
||||
if dest_def_count == 0 {
|
||||
debug!(" Can't copy-propagate local: dest {} undefined",
|
||||
mir.format_local(dest_local));
|
||||
debug!(" Can't copy-propagate local: dest {:?} undefined",
|
||||
dest_local);
|
||||
continue
|
||||
}
|
||||
if dest_def_count > 1 {
|
||||
debug!(" Can't copy-propagate local: dest {} defined {} times",
|
||||
mir.format_local(dest_local),
|
||||
debug!(" Can't copy-propagate local: dest {:?} defined {} times",
|
||||
dest_local,
|
||||
dest_use_info.def_count());
|
||||
continue
|
||||
}
|
||||
if dest_use_info.use_count() == 0 {
|
||||
debug!(" Can't copy-propagate local: dest {} unused",
|
||||
mir.format_local(dest_local));
|
||||
debug!(" Can't copy-propagate local: dest {:?} unused",
|
||||
dest_local);
|
||||
continue
|
||||
}
|
||||
let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| {
|
||||
|
@ -121,11 +119,11 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation {
|
|||
|
||||
// That use of the source must be an assignment.
|
||||
match statement.kind {
|
||||
StatementKind::Assign(ref dest_lvalue, Rvalue::Use(ref operand)) if
|
||||
Some(dest_local) == mir.local_index(dest_lvalue) => {
|
||||
StatementKind::Assign(Lvalue::Local(local), Rvalue::Use(ref operand)) if
|
||||
local == dest_local => {
|
||||
let maybe_action = match *operand {
|
||||
Operand::Consume(ref src_lvalue) => {
|
||||
Action::local_copy(mir, &def_use_analysis, src_lvalue)
|
||||
Action::local_copy(&def_use_analysis, src_lvalue)
|
||||
}
|
||||
Operand::Constant(ref src_constant) => {
|
||||
Action::constant(src_constant)
|
||||
|
@ -162,15 +160,14 @@ enum Action<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> Action<'tcx> {
|
||||
fn local_copy(mir: &Mir<'tcx>, def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>)
|
||||
fn local_copy(def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>)
|
||||
-> Option<Action<'tcx>> {
|
||||
// The source must be a local.
|
||||
let src_local = match mir.local_index(src_lvalue) {
|
||||
Some(src_local) => src_local,
|
||||
None => {
|
||||
debug!(" Can't copy-propagate local: source is not a local");
|
||||
return None
|
||||
}
|
||||
let src_local = if let Lvalue::Local(local) = *src_lvalue {
|
||||
local
|
||||
} else {
|
||||
debug!(" Can't copy-propagate local: source is not a local");
|
||||
return None;
|
||||
};
|
||||
|
||||
// We're trying to copy propagate a local.
|
||||
|
@ -225,9 +222,9 @@ impl<'tcx> Action<'tcx> {
|
|||
// First, remove all markers.
|
||||
//
|
||||
// FIXME(pcwalton): Don't do this. Merge live ranges instead.
|
||||
debug!(" Replacing all uses of {} with {} (local)",
|
||||
mir.format_local(dest_local),
|
||||
mir.format_local(src_local));
|
||||
debug!(" Replacing all uses of {:?} with {:?} (local)",
|
||||
dest_local,
|
||||
src_local);
|
||||
for lvalue_use in &def_use_analysis.local_info(dest_local).defs_and_uses {
|
||||
if lvalue_use.context.is_storage_marker() {
|
||||
mir.make_statement_nop(lvalue_use.location)
|
||||
|
@ -240,7 +237,7 @@ impl<'tcx> Action<'tcx> {
|
|||
}
|
||||
|
||||
// Replace all uses of the destination local with the source local.
|
||||
let src_lvalue = Lvalue::from_local(mir, src_local);
|
||||
let src_lvalue = Lvalue::Local(src_local);
|
||||
def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue);
|
||||
|
||||
// Finally, zap the now-useless assignment instruction.
|
||||
|
@ -253,8 +250,8 @@ impl<'tcx> Action<'tcx> {
|
|||
// First, remove all markers.
|
||||
//
|
||||
// FIXME(pcwalton): Don't do this. Merge live ranges instead.
|
||||
debug!(" Replacing all uses of {} with {:?} (constant)",
|
||||
mir.format_local(dest_local),
|
||||
debug!(" Replacing all uses of {:?} with {:?} (constant)",
|
||||
dest_local,
|
||||
src_constant);
|
||||
let dest_local_info = def_use_analysis.local_info(dest_local);
|
||||
for lvalue_use in &dest_local_info.defs_and_uses {
|
||||
|
@ -264,8 +261,7 @@ impl<'tcx> Action<'tcx> {
|
|||
}
|
||||
|
||||
// Replace all uses of the destination local with the constant.
|
||||
let mut visitor = ConstantPropagationVisitor::new(MirSummary::new(mir),
|
||||
dest_local,
|
||||
let mut visitor = ConstantPropagationVisitor::new(dest_local,
|
||||
src_constant);
|
||||
for dest_lvalue_use in &dest_local_info.defs_and_uses {
|
||||
visitor.visit_location(mir, dest_lvalue_use.location)
|
||||
|
@ -298,17 +294,15 @@ impl<'tcx> Action<'tcx> {
|
|||
struct ConstantPropagationVisitor<'tcx> {
|
||||
dest_local: Local,
|
||||
constant: Constant<'tcx>,
|
||||
mir_summary: MirSummary,
|
||||
uses_replaced: usize,
|
||||
}
|
||||
|
||||
impl<'tcx> ConstantPropagationVisitor<'tcx> {
|
||||
fn new(mir_summary: MirSummary, dest_local: Local, constant: Constant<'tcx>)
|
||||
fn new(dest_local: Local, constant: Constant<'tcx>)
|
||||
-> ConstantPropagationVisitor<'tcx> {
|
||||
ConstantPropagationVisitor {
|
||||
dest_local: dest_local,
|
||||
constant: constant,
|
||||
mir_summary: mir_summary,
|
||||
uses_replaced: 0,
|
||||
}
|
||||
}
|
||||
|
@ -319,16 +313,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
|
|||
self.super_operand(operand, location);
|
||||
|
||||
match *operand {
|
||||
Operand::Consume(ref lvalue) => {
|
||||
if self.mir_summary.local_index(lvalue) != Some(self.dest_local) {
|
||||
return
|
||||
}
|
||||
}
|
||||
Operand::Constant(_) => return,
|
||||
Operand::Consume(Lvalue::Local(local)) if local == self.dest_local => {}
|
||||
_ => return,
|
||||
}
|
||||
|
||||
*operand = Operand::Constant(self.constant.clone());
|
||||
self.uses_replaced += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,11 +10,12 @@
|
|||
|
||||
//! Performs various peephole optimizations.
|
||||
|
||||
use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue};
|
||||
use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue, Local};
|
||||
use rustc::mir::transform::{MirPass, MirSource, Pass};
|
||||
use rustc::mir::visit::{MutVisitor, Visitor};
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::util::nodemap::FnvHashSet;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use std::mem;
|
||||
|
||||
pub struct InstCombine {
|
||||
|
@ -61,7 +62,8 @@ impl<'tcx> MutVisitor<'tcx> for InstCombine {
|
|||
debug!("Replacing `&*`: {:?}", rvalue);
|
||||
let new_lvalue = match *rvalue {
|
||||
Rvalue::Ref(_, _, Lvalue::Projection(ref mut projection)) => {
|
||||
mem::replace(&mut projection.base, Lvalue::ReturnPointer)
|
||||
// Replace with dummy
|
||||
mem::replace(&mut projection.base, Lvalue::Local(Local::new(0)))
|
||||
}
|
||||
_ => bug!("Detected `&*` but didn't find `&*`!"),
|
||||
};
|
||||
|
@ -107,4 +109,3 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> {
|
|||
struct OptimizationList {
|
||||
and_stars: FnvHashSet<Location>,
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ use syntax_pos::Span;
|
|||
|
||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
use std::usize;
|
||||
|
||||
|
@ -74,15 +75,21 @@ pub enum Candidate {
|
|||
ShuffleIndices(BasicBlock)
|
||||
}
|
||||
|
||||
struct TempCollector {
|
||||
temps: IndexVec<Temp, TempState>,
|
||||
span: Span
|
||||
struct TempCollector<'tcx> {
|
||||
temps: IndexVec<Local, TempState>,
|
||||
span: Span,
|
||||
mir: &'tcx Mir<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for TempCollector {
|
||||
fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) {
|
||||
impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
|
||||
fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext<'tcx>, location: Location) {
|
||||
self.super_lvalue(lvalue, context, location);
|
||||
if let Lvalue::Temp(index) = *lvalue {
|
||||
if let Lvalue::Local(index) = *lvalue {
|
||||
// We're only interested in temporaries
|
||||
if self.mir.local_kind(index) != LocalKind::Temp {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore drops, if the temp gets promoted,
|
||||
// then it's constant and thus drop is noop.
|
||||
// Storage live ranges are also irrelevant.
|
||||
|
@ -126,10 +133,11 @@ impl<'tcx> Visitor<'tcx> for TempCollector {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, TempState> {
|
||||
pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Local, TempState> {
|
||||
let mut collector = TempCollector {
|
||||
temps: IndexVec::from_elem(TempState::Undefined, &mir.temp_decls),
|
||||
span: mir.span
|
||||
temps: IndexVec::from_elem(TempState::Undefined, &mir.local_decls),
|
||||
span: mir.span,
|
||||
mir: mir,
|
||||
};
|
||||
for (bb, data) in rpo {
|
||||
collector.visit_basic_block_data(bb, data);
|
||||
|
@ -140,7 +148,7 @@ pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, Te
|
|||
struct Promoter<'a, 'tcx: 'a> {
|
||||
source: &'a mut Mir<'tcx>,
|
||||
promoted: Mir<'tcx>,
|
||||
temps: &'a mut IndexVec<Temp, TempState>,
|
||||
temps: &'a mut IndexVec<Local, TempState>,
|
||||
|
||||
/// If true, all nested temps are also kept in the
|
||||
/// source MIR, not moved to the promoted MIR.
|
||||
|
@ -177,7 +185,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
|
||||
/// Copy the initialization of this temp to the
|
||||
/// promoted MIR, recursing through temps.
|
||||
fn promote_temp(&mut self, temp: Temp) -> Temp {
|
||||
fn promote_temp(&mut self, temp: Local) -> Local {
|
||||
let old_keep_original = self.keep_original;
|
||||
let (bb, stmt_idx) = match self.temps[temp] {
|
||||
TempState::Defined {
|
||||
|
@ -259,20 +267,19 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
let new_temp = self.promoted.temp_decls.push(TempDecl {
|
||||
ty: self.source.temp_decls[temp].ty
|
||||
});
|
||||
let new_temp = self.promoted.local_decls.push(
|
||||
LocalDecl::new_temp(self.source.local_decls[temp].ty));
|
||||
|
||||
// Inject the Rvalue or Call into the promoted MIR.
|
||||
if stmt_idx < no_stmts {
|
||||
self.assign(Lvalue::Temp(new_temp), rvalue.unwrap(), source_info.span);
|
||||
self.assign(Lvalue::Local(new_temp), rvalue.unwrap(), source_info.span);
|
||||
} else {
|
||||
let last = self.promoted.basic_blocks().last().unwrap();
|
||||
let new_target = self.new_block();
|
||||
let mut call = call.unwrap();
|
||||
match call {
|
||||
TerminatorKind::Call { ref mut destination, ..} => {
|
||||
*destination = Some((Lvalue::Temp(new_temp), new_target));
|
||||
*destination = Some((Lvalue::Local(new_temp), new_target));
|
||||
}
|
||||
_ => bug!()
|
||||
}
|
||||
|
@ -315,11 +322,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
};
|
||||
self.visit_rvalue(&mut rvalue, Location{
|
||||
self.visit_rvalue(&mut rvalue, Location {
|
||||
block: BasicBlock::new(0),
|
||||
statement_index: usize::MAX
|
||||
});
|
||||
self.assign(Lvalue::ReturnPointer, rvalue, span);
|
||||
|
||||
self.assign(Lvalue::Local(RETURN_POINTER), rvalue, span);
|
||||
self.source.promoted.push(self.promoted);
|
||||
}
|
||||
}
|
||||
|
@ -330,8 +338,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
|
|||
lvalue: &mut Lvalue<'tcx>,
|
||||
context: LvalueContext<'tcx>,
|
||||
location: Location) {
|
||||
if let Lvalue::Temp(ref mut temp) = *lvalue {
|
||||
*temp = self.promote_temp(*temp);
|
||||
if let Lvalue::Local(ref mut temp) = *lvalue {
|
||||
if self.source.local_kind(*temp) == LocalKind::Temp {
|
||||
*temp = self.promote_temp(*temp);
|
||||
}
|
||||
}
|
||||
self.super_lvalue(lvalue, context, location);
|
||||
}
|
||||
|
@ -339,7 +349,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
|
|||
|
||||
pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
mut temps: IndexVec<Temp, TempState>,
|
||||
mut temps: IndexVec<Local, TempState>,
|
||||
candidates: Vec<Candidate>) {
|
||||
// Visit candidates in reverse, in case they're nested.
|
||||
for candidate in candidates.into_iter().rev() {
|
||||
|
@ -353,7 +363,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
|||
"expected assignment to promote");
|
||||
}
|
||||
};
|
||||
if let Lvalue::Temp(index) = *dest {
|
||||
if let Lvalue::Local(index) = *dest {
|
||||
if temps[index] == TempState::PromotedOut {
|
||||
// Already promoted.
|
||||
continue;
|
||||
|
@ -376,8 +386,10 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
|||
}
|
||||
};
|
||||
|
||||
// Declare return pointer local
|
||||
let initial_locals = iter::once(LocalDecl::new_return_pointer(ty)).collect();
|
||||
|
||||
let mut promoter = Promoter {
|
||||
source: mir,
|
||||
promoted: Mir::new(
|
||||
IndexVec::new(),
|
||||
Some(VisibilityScopeData {
|
||||
|
@ -386,12 +398,12 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
|||
}).into_iter().collect(),
|
||||
IndexVec::new(),
|
||||
ty,
|
||||
IndexVec::new(),
|
||||
IndexVec::new(),
|
||||
IndexVec::new(),
|
||||
initial_locals,
|
||||
0,
|
||||
vec![],
|
||||
span
|
||||
),
|
||||
source: mir,
|
||||
temps: &mut temps,
|
||||
keep_original: false
|
||||
};
|
||||
|
@ -400,13 +412,13 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
|||
}
|
||||
|
||||
// Eliminate assignments to, and drops of promoted temps.
|
||||
let promoted = |index: Temp| temps[index] == TempState::PromotedOut;
|
||||
let promoted = |index: Local| temps[index] == TempState::PromotedOut;
|
||||
for block in mir.basic_blocks_mut() {
|
||||
block.statements.retain(|statement| {
|
||||
match statement.kind {
|
||||
StatementKind::Assign(Lvalue::Temp(index), _) |
|
||||
StatementKind::StorageLive(Lvalue::Temp(index)) |
|
||||
StatementKind::StorageDead(Lvalue::Temp(index)) => {
|
||||
StatementKind::Assign(Lvalue::Local(index), _) |
|
||||
StatementKind::StorageLive(Lvalue::Local(index)) |
|
||||
StatementKind::StorageDead(Lvalue::Local(index)) => {
|
||||
!promoted(index)
|
||||
}
|
||||
_ => true
|
||||
|
@ -414,7 +426,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
|||
});
|
||||
let terminator = block.terminator_mut();
|
||||
match terminator.kind {
|
||||
TerminatorKind::Drop { location: Lvalue::Temp(index), target, .. } => {
|
||||
TerminatorKind::Drop { location: Lvalue::Local(index), target, .. } => {
|
||||
if promoted(index) {
|
||||
terminator.kind = TerminatorKind::Goto {
|
||||
target: target
|
||||
|
|
|
@ -143,11 +143,11 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
|||
param_env: ty::ParameterEnvironment<'tcx>,
|
||||
qualif_map: &'a mut DefIdMap<Qualif>,
|
||||
mir_map: Option<&'a MirMap<'tcx>>,
|
||||
temp_qualif: IndexVec<Temp, Option<Qualif>>,
|
||||
temp_qualif: IndexVec<Local, Option<Qualif>>,
|
||||
return_qualif: Option<Qualif>,
|
||||
qualif: Qualif,
|
||||
const_fn_arg_vars: BitVector,
|
||||
temp_promotion_state: IndexVec<Temp, TempState>,
|
||||
temp_promotion_state: IndexVec<Local, TempState>,
|
||||
promotion_candidates: Vec<Candidate>
|
||||
}
|
||||
|
||||
|
@ -173,10 +173,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
|||
param_env: param_env,
|
||||
qualif_map: qualif_map,
|
||||
mir_map: mir_map,
|
||||
temp_qualif: IndexVec::from_elem(None, &mir.temp_decls),
|
||||
temp_qualif: IndexVec::from_elem(None, &mir.local_decls),
|
||||
return_qualif: None,
|
||||
qualif: Qualif::empty(),
|
||||
const_fn_arg_vars: BitVector::new(mir.var_decls.len()),
|
||||
const_fn_arg_vars: BitVector::new(mir.local_decls.len()),
|
||||
temp_promotion_state: temps,
|
||||
promotion_candidates: vec![]
|
||||
}
|
||||
|
@ -332,8 +332,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
|||
|
||||
// Only handle promotable temps in non-const functions.
|
||||
if self.mode == Mode::Fn {
|
||||
if let Lvalue::Temp(index) = *dest {
|
||||
if self.temp_promotion_state[index].is_promotable() {
|
||||
if let Lvalue::Local(index) = *dest {
|
||||
if self.mir.local_kind(index) == LocalKind::Temp
|
||||
&& self.temp_promotion_state[index].is_promotable() {
|
||||
debug!("store to promotable temp {:?}", index);
|
||||
store(&mut self.temp_qualif[index]);
|
||||
}
|
||||
}
|
||||
|
@ -341,13 +343,20 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
|
||||
match *dest {
|
||||
Lvalue::Temp(index) => store(&mut self.temp_qualif[index]),
|
||||
Lvalue::ReturnPointer => store(&mut self.return_qualif),
|
||||
Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::Temp => {
|
||||
debug!("store to temp {:?}", index);
|
||||
store(&mut self.temp_qualif[index])
|
||||
}
|
||||
Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::ReturnPointer => {
|
||||
debug!("store to return pointer {:?}", index);
|
||||
store(&mut self.return_qualif)
|
||||
}
|
||||
|
||||
Lvalue::Projection(box Projection {
|
||||
base: Lvalue::Temp(index),
|
||||
base: Lvalue::Local(index),
|
||||
elem: ProjectionElem::Deref
|
||||
}) if self.mir.temp_decls[index].ty.is_unique()
|
||||
}) if self.mir.local_kind(index) == LocalKind::Temp
|
||||
&& self.mir.local_decls[index].ty.is_unique()
|
||||
&& self.temp_qualif[index].map_or(false, |qualif| {
|
||||
qualif.intersects(Qualif::NOT_CONST)
|
||||
}) => {
|
||||
|
@ -366,6 +375,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
|||
|
||||
/// Qualify a whole const, static initializer or const fn.
|
||||
fn qualify_const(&mut self) -> Qualif {
|
||||
debug!("qualifying {} {}", self.mode, self.tcx.item_path_str(self.def_id));
|
||||
|
||||
let mir = self.mir;
|
||||
|
||||
let mut seen_blocks = BitVector::new(mir.basic_blocks().len());
|
||||
|
@ -399,7 +410,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
|||
TerminatorKind::Return => {
|
||||
// Check for unused values. This usually means
|
||||
// there are extra statements in the AST.
|
||||
for temp in mir.temp_decls.indices() {
|
||||
for temp in mir.temp_iter() {
|
||||
if self.temp_qualif[temp].is_none() {
|
||||
continue;
|
||||
}
|
||||
|
@ -424,9 +435,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
|||
|
||||
// Make sure there are no extra unassigned variables.
|
||||
self.qualif = Qualif::NOT_CONST;
|
||||
for index in 0..mir.var_decls.len() {
|
||||
if !self.const_fn_arg_vars.contains(index) {
|
||||
self.assign(&Lvalue::Var(Var::new(index)), Location {
|
||||
for index in mir.var_iter() {
|
||||
if !self.const_fn_arg_vars.contains(index.index()) {
|
||||
debug!("unassigned variable {:?}", index);
|
||||
self.assign(&Lvalue::Local(index), Location {
|
||||
block: bb,
|
||||
statement_index: usize::MAX,
|
||||
});
|
||||
|
@ -480,23 +492,28 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
context: LvalueContext<'tcx>,
|
||||
location: Location) {
|
||||
match *lvalue {
|
||||
Lvalue::Arg(_) => {
|
||||
self.add(Qualif::FN_ARGUMENT);
|
||||
}
|
||||
Lvalue::Var(_) => {
|
||||
self.add(Qualif::NOT_CONST);
|
||||
}
|
||||
Lvalue::Temp(index) => {
|
||||
if !self.temp_promotion_state[index].is_promotable() {
|
||||
self.add(Qualif::NOT_PROMOTABLE);
|
||||
}
|
||||
|
||||
if let Some(qualif) = self.temp_qualif[index] {
|
||||
self.add(qualif);
|
||||
} else {
|
||||
Lvalue::Local(local) => match self.mir.local_kind(local) {
|
||||
LocalKind::ReturnPointer => {
|
||||
self.not_const();
|
||||
}
|
||||
}
|
||||
LocalKind::Arg => {
|
||||
self.add(Qualif::FN_ARGUMENT);
|
||||
}
|
||||
LocalKind::Var => {
|
||||
self.add(Qualif::NOT_CONST);
|
||||
}
|
||||
LocalKind::Temp => {
|
||||
if !self.temp_promotion_state[local].is_promotable() {
|
||||
self.add(Qualif::NOT_PROMOTABLE);
|
||||
}
|
||||
|
||||
if let Some(qualif) = self.temp_qualif[local] {
|
||||
self.add(qualif);
|
||||
} else {
|
||||
self.not_const();
|
||||
}
|
||||
}
|
||||
},
|
||||
Lvalue::Static(_) => {
|
||||
self.add(Qualif::STATIC);
|
||||
if self.mode == Mode::Const || self.mode == Mode::ConstFn {
|
||||
|
@ -505,9 +522,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
a constant instead", self.mode);
|
||||
}
|
||||
}
|
||||
Lvalue::ReturnPointer => {
|
||||
self.not_const();
|
||||
}
|
||||
Lvalue::Projection(ref proj) => {
|
||||
self.nest(|this| {
|
||||
this.super_lvalue(lvalue, context, location);
|
||||
|
@ -685,8 +699,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
if self.mode == Mode::Fn || self.mode == Mode::ConstFn {
|
||||
if !self.qualif.intersects(Qualif::NEVER_PROMOTE) {
|
||||
// We can only promote direct borrows of temps.
|
||||
if let Lvalue::Temp(_) = *lvalue {
|
||||
self.promotion_candidates.push(candidate);
|
||||
if let Lvalue::Local(local) = *lvalue {
|
||||
if self.mir.local_kind(local) == LocalKind::Temp {
|
||||
self.promotion_candidates.push(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -879,17 +895,21 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
self.visit_rvalue(rvalue, location);
|
||||
|
||||
// Check the allowed const fn argument forms.
|
||||
if let (Mode::ConstFn, &Lvalue::Var(index)) = (self.mode, dest) {
|
||||
if self.const_fn_arg_vars.insert(index.index()) {
|
||||
if let (Mode::ConstFn, &Lvalue::Local(index)) = (self.mode, dest) {
|
||||
if self.mir.local_kind(index) == LocalKind::Var &&
|
||||
self.const_fn_arg_vars.insert(index.index()) {
|
||||
|
||||
// Direct use of an argument is permitted.
|
||||
if let Rvalue::Use(Operand::Consume(Lvalue::Arg(_))) = *rvalue {
|
||||
return;
|
||||
if let Rvalue::Use(Operand::Consume(Lvalue::Local(local))) = *rvalue {
|
||||
if self.mir.local_kind(local) == LocalKind::Arg {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid a generic error for other uses of arguments.
|
||||
if self.qualif.intersects(Qualif::FN_ARGUMENT) {
|
||||
let decl = &self.mir.var_decls[index];
|
||||
span_err!(self.tcx.sess, decl.source_info.span, E0022,
|
||||
let decl = &self.mir.local_decls[index];
|
||||
span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022,
|
||||
"arguments of constant functions can only \
|
||||
be immutable by-value bindings");
|
||||
return;
|
||||
|
|
|
@ -90,14 +90,8 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
|
||||
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
|
||||
self.sanitize_type(&"return type", mir.return_ty);
|
||||
for var_decl in &mir.var_decls {
|
||||
self.sanitize_type(var_decl, var_decl.ty);
|
||||
}
|
||||
for (n, arg_decl) in mir.arg_decls.iter().enumerate() {
|
||||
self.sanitize_type(&(n, arg_decl), arg_decl.ty);
|
||||
}
|
||||
for (n, tmp_decl) in mir.temp_decls.iter().enumerate() {
|
||||
self.sanitize_type(&(n, tmp_decl), tmp_decl.ty);
|
||||
for local_decl in &mir.local_decls {
|
||||
self.sanitize_type(local_decl, local_decl.ty);
|
||||
}
|
||||
if self.errors_reported {
|
||||
return;
|
||||
|
@ -131,14 +125,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> {
|
||||
debug!("sanitize_lvalue: {:?}", lvalue);
|
||||
match *lvalue {
|
||||
Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index].ty },
|
||||
Lvalue::Temp(index) => LvalueTy::Ty { ty: self.mir.temp_decls[index].ty },
|
||||
Lvalue::Arg(index) => LvalueTy::Ty { ty: self.mir.arg_decls[index].ty },
|
||||
Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty },
|
||||
Lvalue::Static(def_id) =>
|
||||
LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty },
|
||||
Lvalue::ReturnPointer => {
|
||||
LvalueTy::Ty { ty: self.mir.return_ty }
|
||||
}
|
||||
Lvalue::Projection(ref proj) => {
|
||||
let base_ty = self.sanitize_lvalue(&proj.base, location);
|
||||
if let LvalueTy::Ty { ty } = base_ty {
|
||||
|
@ -380,9 +369,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
StatementKind::StorageLive(ref lv) |
|
||||
StatementKind::StorageDead(ref lv) => {
|
||||
match *lv {
|
||||
Lvalue::Temp(_) | Lvalue::Var(_) => {}
|
||||
Lvalue::Local(_) => {}
|
||||
_ => {
|
||||
span_mirbug!(self, stmt, "bad lvalue: expected temp or var");
|
||||
span_mirbug!(self, stmt, "bad lvalue: expected local");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -711,6 +700,8 @@ impl TypeckMir {
|
|||
impl<'tcx> MirPass<'tcx> for TypeckMir {
|
||||
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
src: MirSource, mir: &mut Mir<'tcx>) {
|
||||
debug!("run_pass: {}", tcx.node_path_str(src.item_id()));
|
||||
|
||||
if tcx.sess.err_count() > 0 {
|
||||
// compiling a broken program can obviously result in a
|
||||
// broken MIR, so try not to report duplicate errors.
|
||||
|
|
|
@ -63,8 +63,9 @@ pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, Mir
|
|||
|
||||
// Find all the scopes with variables defined in them.
|
||||
let mut has_variables = BitVector::new(mir.visibility_scopes.len());
|
||||
for var in &mir.var_decls {
|
||||
has_variables.insert(var.source_info.scope.index());
|
||||
for var in mir.var_iter() {
|
||||
let decl = &mir.local_decls[var];
|
||||
has_variables.insert(decl.source_info.unwrap().scope.index());
|
||||
}
|
||||
|
||||
// Instantiate all scopes.
|
||||
|
|
|
@ -20,7 +20,6 @@ use rustc::mir::visit::{Visitor, LvalueContext};
|
|||
use rustc::mir::traversal;
|
||||
use common::{self, Block, BlockAndBuilder};
|
||||
use glue;
|
||||
use std::iter;
|
||||
use super::rvalue;
|
||||
|
||||
pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
|
||||
|
@ -30,11 +29,7 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
|
|||
|
||||
analyzer.visit_mir(mir);
|
||||
|
||||
let local_types = mir.arg_decls.iter().map(|a| a.ty)
|
||||
.chain(mir.var_decls.iter().map(|v| v.ty))
|
||||
.chain(mir.temp_decls.iter().map(|t| t.ty))
|
||||
.chain(iter::once(mir.return_ty));
|
||||
for (index, ty) in local_types.enumerate() {
|
||||
for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() {
|
||||
let ty = bcx.monomorphize(&ty);
|
||||
debug!("local {} has type {:?}", index, ty);
|
||||
if ty.is_scalar() ||
|
||||
|
@ -80,12 +75,11 @@ impl<'mir, 'bcx, 'tcx> LocalAnalyzer<'mir, 'bcx, 'tcx> {
|
|||
fn new(mir: &'mir mir::Mir<'tcx>,
|
||||
bcx: &'mir BlockAndBuilder<'bcx, 'tcx>)
|
||||
-> LocalAnalyzer<'mir, 'bcx, 'tcx> {
|
||||
let local_count = mir.count_locals();
|
||||
LocalAnalyzer {
|
||||
mir: mir,
|
||||
bcx: bcx,
|
||||
lvalue_locals: BitVector::new(local_count),
|
||||
seen_assigned: BitVector::new(local_count)
|
||||
lvalue_locals: BitVector::new(mir.local_decls.len()),
|
||||
seen_assigned: BitVector::new(mir.local_decls.len())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +103,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
|
|||
location: Location) {
|
||||
debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue);
|
||||
|
||||
if let Some(index) = self.mir.local_index(lvalue) {
|
||||
if let mir::Lvalue::Local(index) = *lvalue {
|
||||
self.mark_assigned(index);
|
||||
if !rvalue::rvalue_creates_operand(self.mir, self.bcx, rvalue) {
|
||||
self.mark_as_lvalue(index);
|
||||
|
@ -153,7 +147,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
|
|||
|
||||
// Allow uses of projections of immediate pair fields.
|
||||
if let mir::Lvalue::Projection(ref proj) = *lvalue {
|
||||
if self.mir.local_index(&proj.base).is_some() {
|
||||
if let mir::Lvalue::Local(_) = proj.base {
|
||||
let ty = proj.base.ty(self.mir, self.bcx.tcx());
|
||||
|
||||
let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx()));
|
||||
|
@ -167,7 +161,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(index) = self.mir.local_index(lvalue) {
|
||||
if let mir::Lvalue::Local(index) = *lvalue {
|
||||
match context {
|
||||
LvalueContext::Call => {
|
||||
self.mark_assigned(index);
|
||||
|
|
|
@ -192,8 +192,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
}
|
||||
|
||||
let llval = if let Some(cast_ty) = ret.cast {
|
||||
let index = mir.local_index(&mir::Lvalue::ReturnPointer).unwrap();
|
||||
let op = match self.locals[index] {
|
||||
let op = match self.locals[mir::RETURN_POINTER] {
|
||||
LocalRef::Operand(Some(op)) => op,
|
||||
LocalRef::Operand(None) => bug!("use of return before def"),
|
||||
LocalRef::Lvalue(tr_lvalue) => {
|
||||
|
@ -218,7 +217,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
}
|
||||
load
|
||||
} else {
|
||||
let op = self.trans_consume(&bcx, &mir::Lvalue::ReturnPointer);
|
||||
let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER));
|
||||
op.pack_if_pair(&bcx).immediate()
|
||||
};
|
||||
bcx.ret(llval);
|
||||
|
@ -844,7 +843,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
if fn_ret_ty.is_ignore() {
|
||||
return ReturnDest::Nothing;
|
||||
}
|
||||
let dest = if let Some(index) = self.mir.local_index(dest) {
|
||||
let dest = if let mir::Lvalue::Local(index) = *dest {
|
||||
let ret_ty = self.monomorphized_lvalue_ty(dest);
|
||||
match self.locals[index] {
|
||||
LocalRef::Lvalue(dest) => dest,
|
||||
|
|
|
@ -221,16 +221,17 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
fn new(ccx: &'a CrateContext<'a, 'tcx>,
|
||||
mir: &'a mir::Mir<'tcx>,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
args: IndexVec<mir::Arg, Const<'tcx>>)
|
||||
args: IndexVec<mir::Local, Const<'tcx>>)
|
||||
-> MirConstContext<'a, 'tcx> {
|
||||
let mut context = MirConstContext {
|
||||
ccx: ccx,
|
||||
mir: mir,
|
||||
substs: substs,
|
||||
locals: (0..mir.count_locals()).map(|_| None).collect(),
|
||||
locals: (0..mir.local_decls.len()).map(|_| None).collect(),
|
||||
};
|
||||
for (i, arg) in args.into_iter().enumerate() {
|
||||
let index = mir.local_index(&mir::Lvalue::Arg(mir::Arg::new(i))).unwrap();
|
||||
// Locals after local0 are the function arguments
|
||||
let index = mir::Local::new(i + 1);
|
||||
context.locals[index] = Some(arg);
|
||||
}
|
||||
context
|
||||
|
@ -238,7 +239,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
|
||||
fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
|
||||
mut instance: Instance<'tcx>,
|
||||
args: IndexVec<mir::Arg, Const<'tcx>>)
|
||||
args: IndexVec<mir::Local, Const<'tcx>>)
|
||||
-> Result<Const<'tcx>, ConstEvalErr> {
|
||||
// Try to resolve associated constants.
|
||||
if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) {
|
||||
|
@ -311,8 +312,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
mir::TerminatorKind::Goto { target } => target,
|
||||
mir::TerminatorKind::Return => {
|
||||
failure?;
|
||||
let index = self.mir.local_index(&mir::Lvalue::ReturnPointer).unwrap();
|
||||
return Ok(self.locals[index].unwrap_or_else(|| {
|
||||
return Ok(self.locals[mir::RETURN_POINTER].unwrap_or_else(|| {
|
||||
span_bug!(span, "no returned value in constant");
|
||||
}));
|
||||
}
|
||||
|
@ -376,7 +376,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) {
|
||||
if let Some(index) = self.mir.local_index(dest) {
|
||||
if let mir::Lvalue::Local(index) = *dest {
|
||||
self.locals[index] = Some(value);
|
||||
} else {
|
||||
span_bug!(span, "assignment to {:?} in constant", dest);
|
||||
|
@ -387,17 +387,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
-> Result<ConstLvalue<'tcx>, ConstEvalErr> {
|
||||
let tcx = self.ccx.tcx();
|
||||
|
||||
if let Some(index) = self.mir.local_index(lvalue) {
|
||||
if let mir::Lvalue::Local(index) = *lvalue {
|
||||
return Ok(self.locals[index].unwrap_or_else(|| {
|
||||
span_bug!(span, "{:?} not initialized", lvalue)
|
||||
}).as_lvalue());
|
||||
}
|
||||
|
||||
let lvalue = match *lvalue {
|
||||
mir::Lvalue::Var(_) |
|
||||
mir::Lvalue::Temp(_) |
|
||||
mir::Lvalue::Arg(_) |
|
||||
mir::Lvalue::ReturnPointer => bug!(), // handled above
|
||||
mir::Lvalue::Local(_) => bug!(), // handled above
|
||||
mir::Lvalue::Static(def_id) => {
|
||||
ConstLvalue {
|
||||
base: Base::Static(consts::get_static(self.ccx, def_id)),
|
||||
|
|
|
@ -91,7 +91,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
let ccx = bcx.ccx();
|
||||
let tcx = bcx.tcx();
|
||||
|
||||
if let Some(index) = self.mir.local_index(lvalue) {
|
||||
if let mir::Lvalue::Local(index) = *lvalue {
|
||||
match self.locals[index] {
|
||||
LocalRef::Lvalue(lvalue) => {
|
||||
return lvalue;
|
||||
|
@ -103,10 +103,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
}
|
||||
|
||||
let result = match *lvalue {
|
||||
mir::Lvalue::Var(_) |
|
||||
mir::Lvalue::Temp(_) |
|
||||
mir::Lvalue::Arg(_) |
|
||||
mir::Lvalue::ReturnPointer => bug!(), // handled above
|
||||
mir::Lvalue::Local(_) => bug!(), // handled above
|
||||
mir::Lvalue::Static(def_id) => {
|
||||
let const_ty = self.monomorphized_lvalue_ty(lvalue);
|
||||
LvalueRef::new_sized(consts::get_static(ccx, def_id),
|
||||
|
@ -235,7 +232,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
lvalue: &mir::Lvalue<'tcx>, f: F) -> U
|
||||
where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
|
||||
{
|
||||
if let Some(index) = self.mir.local_index(lvalue) {
|
||||
if let mir::Lvalue::Local(index) = *lvalue {
|
||||
match self.locals[index] {
|
||||
LocalRef::Lvalue(lvalue) => f(self, lvalue),
|
||||
LocalRef::Operand(None) => {
|
||||
|
|
|
@ -237,51 +237,61 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
|
|||
// Allocate variable and temp allocas
|
||||
mircx.locals = {
|
||||
let args = arg_local_refs(&bcx, &mir, &mircx.scopes, &lvalue_locals);
|
||||
let vars = mir.var_decls.iter().enumerate().map(|(i, decl)| {
|
||||
|
||||
let mut allocate_local = |local| {
|
||||
let decl = &mir.local_decls[local];
|
||||
let ty = bcx.monomorphize(&decl.ty);
|
||||
let debug_scope = mircx.scopes[decl.source_info.scope];
|
||||
let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo;
|
||||
|
||||
let local = mir.local_index(&mir::Lvalue::Var(mir::Var::new(i))).unwrap();
|
||||
if !lvalue_locals.contains(local.index()) && !dbg {
|
||||
return LocalRef::new_operand(bcx.ccx(), ty);
|
||||
}
|
||||
if let Some(name) = decl.name {
|
||||
// User variable
|
||||
let source_info = decl.source_info.unwrap();
|
||||
let debug_scope = mircx.scopes[source_info.scope];
|
||||
let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo;
|
||||
|
||||
let lvalue = LvalueRef::alloca(&bcx, ty, &decl.name.as_str());
|
||||
if dbg {
|
||||
let dbg_loc = mircx.debug_loc(decl.source_info);
|
||||
if let DebugLoc::ScopeAt(scope, span) = dbg_loc {
|
||||
bcx.with_block(|bcx| {
|
||||
declare_local(bcx, decl.name, ty, scope,
|
||||
VariableAccess::DirectVariable { alloca: lvalue.llval },
|
||||
VariableKind::LocalVariable, span);
|
||||
});
|
||||
if !lvalue_locals.contains(local.index()) && !dbg {
|
||||
debug!("alloc: {:?} ({}) -> operand", local, name);
|
||||
return LocalRef::new_operand(bcx.ccx(), ty);
|
||||
}
|
||||
|
||||
debug!("alloc: {:?} ({}) -> lvalue", local, name);
|
||||
let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str());
|
||||
if dbg {
|
||||
let dbg_loc = mircx.debug_loc(source_info);
|
||||
if let DebugLoc::ScopeAt(scope, span) = dbg_loc {
|
||||
bcx.with_block(|bcx| {
|
||||
declare_local(bcx, name, ty, scope,
|
||||
VariableAccess::DirectVariable { alloca: lvalue.llval },
|
||||
VariableKind::LocalVariable, span);
|
||||
});
|
||||
} else {
|
||||
panic!("Unexpected");
|
||||
}
|
||||
}
|
||||
LocalRef::Lvalue(lvalue)
|
||||
} else {
|
||||
// Temporary or return pointer
|
||||
if local == mir::RETURN_POINTER && fcx.fn_ty.ret.is_indirect() {
|
||||
debug!("alloc: {:?} (return pointer) -> lvalue", local);
|
||||
let llretptr = llvm::get_param(fcx.llfn, 0);
|
||||
LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty)))
|
||||
} else if lvalue_locals.contains(local.index()) {
|
||||
debug!("alloc: {:?} -> lvalue", local);
|
||||
LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", local)))
|
||||
} else {
|
||||
panic!("Unexpected");
|
||||
// If this is an immediate local, we do not create an
|
||||
// alloca in advance. Instead we wait until we see the
|
||||
// definition and update the operand there.
|
||||
debug!("alloc: {:?} -> operand", local);
|
||||
LocalRef::new_operand(bcx.ccx(), ty)
|
||||
}
|
||||
}
|
||||
LocalRef::Lvalue(lvalue)
|
||||
});
|
||||
};
|
||||
|
||||
let locals = mir.temp_decls.iter().enumerate().map(|(i, decl)| {
|
||||
(mir::Lvalue::Temp(mir::Temp::new(i)), decl.ty)
|
||||
}).chain(iter::once((mir::Lvalue::ReturnPointer, mir.return_ty)));
|
||||
|
||||
args.into_iter().chain(vars).chain(locals.map(|(lvalue, ty)| {
|
||||
let ty = bcx.monomorphize(&ty);
|
||||
let local = mir.local_index(&lvalue).unwrap();
|
||||
if lvalue == mir::Lvalue::ReturnPointer && fcx.fn_ty.ret.is_indirect() {
|
||||
let llretptr = llvm::get_param(fcx.llfn, 0);
|
||||
LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty)))
|
||||
} else if lvalue_locals.contains(local.index()) {
|
||||
LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", lvalue)))
|
||||
} else {
|
||||
// If this is an immediate local, we do not create an
|
||||
// alloca in advance. Instead we wait until we see the
|
||||
// definition and update the operand there.
|
||||
LocalRef::new_operand(bcx.ccx(), ty)
|
||||
}
|
||||
})).collect()
|
||||
let retptr = allocate_local(mir::RETURN_POINTER);
|
||||
iter::once(retptr)
|
||||
.chain(args.into_iter())
|
||||
.chain(mir.var_and_temp_iter().map(&mut allocate_local))
|
||||
.collect()
|
||||
};
|
||||
|
||||
// Branch to the START block
|
||||
|
@ -346,10 +356,10 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
|||
None
|
||||
};
|
||||
|
||||
mir.arg_decls.iter().enumerate().map(|(arg_index, arg_decl)| {
|
||||
mir.arg_iter().enumerate().map(|(arg_index, local)| {
|
||||
let arg_decl = &mir.local_decls[local];
|
||||
let arg_ty = bcx.monomorphize(&arg_decl.ty);
|
||||
let local = mir.local_index(&mir::Lvalue::Arg(mir::Arg::new(arg_index))).unwrap();
|
||||
if mir.spread_last_arg && arg_index == mir.arg_decls.len() - 1 {
|
||||
if mir.spread_last_arg && arg_index == mir.arg_count - 1 {
|
||||
// This argument (e.g. the last argument in the "rust-call" ABI)
|
||||
// is a tuple that was spread at the ABI level and now we have
|
||||
// to reconstruct it into a tuple local variable, from multiple
|
||||
|
@ -467,8 +477,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
|||
bcx.with_block(|bcx| arg_scope.map(|scope| {
|
||||
// Is this a regular argument?
|
||||
if arg_index > 0 || mir.upvar_decls.is_empty() {
|
||||
declare_local(bcx, arg_decl.debug_name, arg_ty, scope,
|
||||
VariableAccess::DirectVariable { alloca: llval },
|
||||
declare_local(bcx, arg_decl.name.unwrap_or(keywords::Invalid.name()), arg_ty,
|
||||
scope, VariableAccess::DirectVariable { alloca: llval },
|
||||
VariableKind::ArgumentVariable(arg_index + 1),
|
||||
bcx.fcx().span.unwrap_or(DUMMY_SP));
|
||||
return;
|
||||
|
|
|
@ -175,7 +175,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
|
||||
// watch out for locals that do not have an
|
||||
// alloca; they are handled somewhat differently
|
||||
if let Some(index) = self.mir.local_index(lvalue) {
|
||||
if let mir::Lvalue::Local(index) = *lvalue {
|
||||
match self.locals[index] {
|
||||
LocalRef::Operand(Some(o)) => {
|
||||
return o;
|
||||
|
@ -191,7 +191,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
|
||||
// Moves out of pair fields are trivial.
|
||||
if let &mir::Lvalue::Projection(ref proj) = lvalue {
|
||||
if let Some(index) = self.mir.local_index(&proj.base) {
|
||||
if let mir::Lvalue::Local(index) = proj.base {
|
||||
if let LocalRef::Operand(Some(o)) = self.locals[index] {
|
||||
match (o.val, &proj.elem) {
|
||||
(OperandValue::Pair(a, b),
|
||||
|
|
|
@ -30,7 +30,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
debug_loc.apply(bcx.fcx());
|
||||
match statement.kind {
|
||||
mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
|
||||
if let Some(index) = self.mir.local_index(lvalue) {
|
||||
if let mir::Lvalue::Local(index) = *lvalue {
|
||||
match self.locals[index] {
|
||||
LocalRef::Lvalue(tr_dest) => {
|
||||
self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc)
|
||||
|
@ -86,7 +86,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
lvalue: &mir::Lvalue<'tcx>,
|
||||
intrinsic: base::Lifetime)
|
||||
-> BlockAndBuilder<'bcx, 'tcx> {
|
||||
if let Some(index) = self.mir.local_index(lvalue) {
|
||||
if let mir::Lvalue::Local(index) = *lvalue {
|
||||
if let LocalRef::Lvalue(tr_lval) = self.locals[index] {
|
||||
intrinsic.call(&bcx, tr_lval.llval);
|
||||
}
|
||||
|
|
|
@ -23,19 +23,19 @@ fn main() {}
|
|||
// END RUST SOURCE
|
||||
// START rustc.node13.Deaggregator.before.mir
|
||||
// bb0: {
|
||||
// var0 = arg0; // scope 0 at main.rs:8:8: 8:9
|
||||
// tmp0 = var0; // scope 1 at main.rs:9:14: 9:15
|
||||
// return = Baz { x: tmp0, y: const F32(0), z: const false }; // scope ...
|
||||
// local2 = local1; // scope 0 at main.rs:8:8: 8:9
|
||||
// local3 = local2; // scope 1 at main.rs:9:14: 9:15
|
||||
// local0 = Baz { x: local3, y: const F32(0), z: const false }; // scope ...
|
||||
// goto -> bb1; // scope 1 at main.rs:8:1: 10:2
|
||||
// }
|
||||
// END rustc.node13.Deaggregator.before.mir
|
||||
// START rustc.node13.Deaggregator.after.mir
|
||||
// bb0: {
|
||||
// var0 = arg0; // scope 0 at main.rs:8:8: 8:9
|
||||
// tmp0 = var0; // scope 1 at main.rs:9:14: 9:15
|
||||
// (return.0: usize) = tmp0; // scope 1 at main.rs:9:5: 9:34
|
||||
// (return.1: f32) = const F32(0); // scope 1 at main.rs:9:5: 9:34
|
||||
// (return.2: bool) = const false; // scope 1 at main.rs:9:5: 9:34
|
||||
// local2 = local1; // scope 0 at main.rs:8:8: 8:9
|
||||
// local3 = local2; // scope 1 at main.rs:9:14: 9:15
|
||||
// (local0.0: usize) = local3; // scope 1 at main.rs:9:5: 9:34
|
||||
// (local0.1: f32) = const F32(0); // scope 1 at main.rs:9:5: 9:34
|
||||
// (local0.2: bool) = const false; // scope 1 at main.rs:9:5: 9:34
|
||||
// goto -> bb1; // scope 1 at main.rs:8:1: 10:2
|
||||
// }
|
||||
// END rustc.node13.Deaggregator.after.mir
|
||||
// END rustc.node13.Deaggregator.after.mir
|
||||
|
|
|
@ -28,18 +28,18 @@ fn main() {
|
|||
// END RUST SOURCE
|
||||
// START rustc.node10.Deaggregator.before.mir
|
||||
// bb0: {
|
||||
// var0 = arg0; // scope 0 at main.rs:7:8: 7:9
|
||||
// tmp0 = var0; // scope 1 at main.rs:8:19: 8:20
|
||||
// return = Baz::Foo { x: tmp0 }; // scope 1 at main.rs:8:5: 8:21
|
||||
// local2 = local1; // scope 0 at main.rs:7:8: 7:9
|
||||
// local3 = local2; // scope 1 at main.rs:8:19: 8:20
|
||||
// local0 = Baz::Foo { x: local3 }; // scope 1 at main.rs:8:5: 8:21
|
||||
// goto -> bb1; // scope 1 at main.rs:7:1: 9:2
|
||||
// }
|
||||
// END rustc.node10.Deaggregator.before.mir
|
||||
// START rustc.node10.Deaggregator.after.mir
|
||||
// bb0: {
|
||||
// var0 = arg0; // scope 0 at main.rs:7:8: 7:9
|
||||
// tmp0 = var0; // scope 1 at main.rs:8:19: 8:20
|
||||
// ((return as Foo).0: usize) = tmp0; // scope 1 at main.rs:8:5: 8:21
|
||||
// discriminant(return) = 1; // scope 1 at main.rs:8:5: 8:21
|
||||
// local2 = local1; // scope 0 at main.rs:7:8: 7:9
|
||||
// local3 = local2; // scope 1 at main.rs:8:19: 8:20
|
||||
// ((local0 as Foo).0: usize) = local3; // scope 1 at main.rs:8:5: 8:21
|
||||
// discriminant(local0) = 1; // scope 1 at main.rs:8:5: 8:21
|
||||
// goto -> bb1; // scope 1 at main.rs:7:1: 9:2
|
||||
// }
|
||||
// END rustc.node10.Deaggregator.after.mir
|
||||
// END rustc.node10.Deaggregator.after.mir
|
||||
|
|
|
@ -18,27 +18,28 @@ fn main() {
|
|||
let c = 1;
|
||||
}
|
||||
|
||||
// TODO The StorageDead for local1 (a) after local6's (c) is missing!
|
||||
|
||||
// END RUST SOURCE
|
||||
// START rustc.node4.TypeckMir.before.mir
|
||||
// bb0: {
|
||||
// StorageLive(var0); // scope 0 at storage_ranges.rs:14:9: 14:10
|
||||
// var0 = const 0i32; // scope 0 at storage_ranges.rs:14:13: 14:14
|
||||
// StorageLive(var1); // scope 1 at storage_ranges.rs:16:13: 16:14
|
||||
// StorageLive(tmp1); // scope 1 at storage_ranges.rs:16:18: 16:25
|
||||
// StorageLive(tmp2); // scope 1 at storage_ranges.rs:16:23: 16:24
|
||||
// tmp2 = var0; // scope 1 at storage_ranges.rs:16:23: 16:24
|
||||
// tmp1 = std::option::Option<i32>::Some(tmp2,); // scope 1 at storage_ranges.rs:16:18: 16:25
|
||||
// var1 = &tmp1; // scope 1 at storage_ranges.rs:16:17: 16:25
|
||||
// StorageDead(tmp2); // scope 1 at storage_ranges.rs:16:23: 16:24
|
||||
// tmp0 = (); // scope 2 at storage_ranges.rs:15:5: 17:6
|
||||
// StorageDead(tmp1); // scope 1 at storage_ranges.rs:16:18: 16:25
|
||||
// StorageDead(var1); // scope 1 at storage_ranges.rs:16:13: 16:14
|
||||
// StorageLive(var2); // scope 1 at storage_ranges.rs:18:9: 18:10
|
||||
// var2 = const 1i32; // scope 1 at storage_ranges.rs:18:13: 18:14
|
||||
// return = (); // scope 3 at storage_ranges.rs:13:11: 19:2
|
||||
// StorageDead(var2); // scope 1 at storage_ranges.rs:18:9: 18:10
|
||||
// StorageDead(var0); // scope 0 at storage_ranges.rs:14:9: 14:10
|
||||
// goto -> bb1; // scope 0 at storage_ranges.rs:13:1: 19:2
|
||||
// StorageLive(local1); // scope 0 at storage_ranges.rs:12:9: 12:10
|
||||
// local1 = const 0i32; // scope 0 at storage_ranges.rs:12:13: 12:14
|
||||
// StorageLive(local3); // scope 1 at storage_ranges.rs:14:13: 14:14
|
||||
// StorageLive(local4); // scope 1 at storage_ranges.rs:14:18: 14:25
|
||||
// StorageLive(local5); // scope 1 at storage_ranges.rs:14:23: 14:24
|
||||
// local5 = local1; // scope 1 at storage_ranges.rs:14:23: 14:24
|
||||
// local4 = std::option::Option<i32>::Some(local5,); // scope 1 at storage_ranges.rs:14:18: 14:25
|
||||
// local3 = &local4; // scope 1 at storage_ranges.rs:14:17: 14:25
|
||||
// StorageDead(local5); // scope 1 at storage_ranges.rs:14:23: 14:24
|
||||
// local2 = (); // scope 2 at storage_ranges.rs:13:5: 15:6
|
||||
// StorageDead(local4); // scope 1 at storage_ranges.rs:14:18: 14:25
|
||||
// StorageDead(local3); // scope 1 at storage_ranges.rs:14:13: 14:14
|
||||
// StorageLive(local6); // scope 1 at storage_ranges.rs:16:9: 16:10
|
||||
// local6 = const 1i32; // scope 1 at storage_ranges.rs:16:13: 16:14
|
||||
// local0 = (); // scope 3 at storage_ranges.rs:11:11: 17:2
|
||||
// StorageDead(local6); // scope 1 at storage_ranges.rs:16:9: 16:10
|
||||
// goto -> bb1; // scope 0 at storage_ranges.rs:11:1: 17:2
|
||||
// }
|
||||
//
|
||||
// bb1: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue