diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 70b0b810c6c48..5da2e2f6fda54 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -70,29 +70,37 @@ 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>, /// 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>, - - /// Args: these are stack slots corresponding to the input arguments. - pub arg_decls: IndexVec>, + /// 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>, - /// 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>, + /// Number of arguments this function takes. + /// + /// Starting at local 1, `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. pub upvar_decls: Vec, + /// Mark an argument local (which must be a tuple) as getting passed as + /// its individual components at the LLVM level. + /// + /// This is used for the "rust-call" ABI. + pub spread_arg: Option, + /// A span representing this MIR, for error reporting pub span: Span, @@ -108,21 +116,25 @@ impl<'tcx> Mir<'tcx> { visibility_scopes: IndexVec, promoted: IndexVec>, return_ty: Ty<'tcx>, - var_decls: IndexVec>, - arg_decls: IndexVec>, - temp_decls: IndexVec>, + local_decls: IndexVec>, + arg_count: usize, upvar_decls: Vec, 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_arg: None, span: span, cache: Cache::new() } @@ -154,56 +166,66 @@ 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 { - 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() + #[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 + } + } + + /// Returns an iterator over all temporaries. + #[inline] + pub fn temps_iter<'a>(&'a self) -> impl Iterator + '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 } - Lvalue::ReturnPointer => { - self.arg_decls.len() + - self.var_decls.len() + - self.temp_decls.len() + }) + } + + /// Returns an iterator over all user-declared locals. + #[inline] + pub fn vars_iter<'a>(&'a self) -> impl Iterator + '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) } - Lvalue::Static(_) | - Lvalue::Projection(_) => return None - }; - Some(Local::new(idx)) + }) } - /// 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 function arguments. + #[inline] + pub fn args_iter(&self) -> impl Iterator { + let arg_count = self.arg_count; + (1..arg_count+1).map(Local::new) } - 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-defined variables and compiler-generated temporaries (all + /// locals that are neither arguments nor the return pointer). + #[inline] + pub fn vars_and_temps_iter(&self) -> impl Iterator { + let arg_count = self.arg_count; + let local_count = self.local_decls.len(); + (arg_count+1..local_count).map(Local::new) } /// Changes a statement to a nop. This is both faster than deleting instructions and avoids @@ -301,53 +323,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. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct VarDecl<'tcx> { - /// `let mut x` vs `let x` - pub mutability: Mutability, - - /// name that user gave the variable; not that, internally, - /// mir references variables by index - pub name: Name, +newtype_index!(Local, "_"); - /// type inferred for this variable (`let x: ty = ...`) - pub ty: Ty<'tcx>, +pub const RETURN_POINTER: Local = Local(0); - /// source information (span, scope, etc.) for the declaration - pub source_info: 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>, +/// 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 "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)) { ... } -/// ``` +/// A MIR local. /// -/// there is only one argument, of type `(i32, u32)`, but two bindings -/// (`x` and `y`). +/// 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 ArgDecl<'tcx> { +pub struct LocalDecl<'tcx> { + /// `let mut x` vs `let x`. + /// + /// Temporaries and the return pointer are always mutable. + pub mutability: Mutability, + + /// Type of this local. pub ty: Ty<'tcx>, - /// If true, this argument is a tuple after monomorphization, - /// and has to be collected from multiple actual arguments. - pub spread: bool, + /// 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, - /// Either keywords::Invalid or the name of a single-binding - /// pattern associated with this argument. Useful for debuginfo. - pub debug_name: 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, +} + +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, + } + } + + /// 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. @@ -439,7 +484,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, @@ -756,31 +801,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>), } @@ -862,24 +892,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> { @@ -887,13 +899,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) => diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 74ad6c602f6cd..19e980ec73eb1 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -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), } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 2c58d35973e73..9e0bafa4e310f 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -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,37 +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: _, - name: _, ref $($mutability)* ty, + name: _, 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, - spread: _, - 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, diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index aeb91f06a9aa4..5e22d477c5185 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -73,11 +73,13 @@ 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::Constant(_) => { + repr::Operand::Consume(ref lval @ repr::Lvalue::Local(_)) => Some(lval), + _ => 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; diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 96702b209a1f5..188fce467be52 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -118,7 +118,7 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> { env: &'a MoveDataParamEnv<'tcx>, flow_inits: DataflowResults>, flow_uninits: DataflowResults>, - drop_flags: FnvHashMap, + drop_flags: FnvHashMap, patch: MirPatch<'tcx>, } @@ -164,7 +164,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn drop_flag(&mut self, index: MovePathIndex) -> Option> { - 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()); } } diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 6346c1e58897e..16e25d2b77258 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -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, - temps: IndexVec, - args: IndexVec, - - /// The move path representing the return value is constructed - /// lazily when we first encounter it in the input MIR. - return_ptr: Option, + locals: IndexVec, /// 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 { .. } | diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index f26afdc2b8572..2a3c602b134e7 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -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.args_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, diff --git a/src/librustc_borrowck/borrowck/mir/patch.rs b/src/librustc_borrowck/borrowck/mir/patch.rs index 52cd1a9f949bf..5d018c98684e3 100644 --- a/src/librustc_borrowck/borrowck/mir/patch.rs +++ b/src/librustc_borrowck/borrowck/mir/patch.rs @@ -19,9 +19,9 @@ pub struct MirPatch<'tcx> { patch_map: IndexVec>>, new_blocks: Vec>, new_statements: Vec<(Location, StatementKind<'tcx>)>, - new_temps: Vec>, + new_locals: Vec>, 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); diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index ae5ccbfd82099..a9dfc6ea651e4 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -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)) diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 8ae23c9103b02..9448527e6e65f 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -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 } }; diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 1b64b4d0b5317..a9ea82140b536 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -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); diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 79a4cf73041d7..4bc51c3a6252d 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -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 } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 23591f05b8774..353aaaa45e18b 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -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, visibility_scope: VisibilityScope, - var_decls: IndexVec>, - var_indices: NodeMap, - temp_decls: IndexVec>, + /// Maps node ids of variable bindings to the `Local`s created for them. + var_indices: NodeMap, + local_decls: IndexVec>, unit_temp: Option>, /// 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, 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 mut 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,16 +183,15 @@ 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()); + let mut spread_arg = None; match tcx.node_id_to_type(fn_id).sty { ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => { // RustCall pseudo-ABI untuples the last argument. - if let Some(last_arg) = arg_decls.last() { - arg_decls[last_arg].spread = true; - } + spread_arg = Some(Local::new(arguments.len())); } _ => {} } @@ -218,7 +220,9 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, }).collect() }); - builder.finish(upvar_decls, arg_decls, return_ty) + let (mut mir, aux) = builder.finish(upvar_decls, return_ty); + mir.spread_arg = spread_arg; + (mir, aux) } pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, @@ -226,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(); @@ -246,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, @@ -278,7 +286,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn finish(self, upvar_decls: Vec, - arg_decls: IndexVec>, return_ty: Ty<'tcx>) -> (Mir<'tcx>, ScopeAuxiliaryVec) { for (index, block) in self.cfg.basic_blocks.iter().enumerate() { @@ -291,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(&mut self, - mut block: BasicBlock, - return_ty: Ty<'tcx>, - arguments: A, - argument_extent: CodeExtent, - ast_block: &'gcx hir::Block) - -> BlockAnd>> - where A: Iterator, 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); @@ -322,19 +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, - spread: false, - 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> { diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 0b33e5a145083..01cce3c7dd794 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -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 => 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 } diff --git a/src/librustc_mir/def_use.rs b/src/librustc_mir/def_use.rs index 11b4441c8460a..343d802119ea0 100644 --- a/src/librustc_mir/def_use.rs +++ b/src/librustc_mir/def_use.rs @@ -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>, - 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>, - 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) - } - 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 { - 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)) + if let Lvalue::Local(local) = *lvalue { + if local == self.query { + (self.callback)(lvalue, context, location) } - Lvalue::ReturnPointer => { - Some(Local::new(self.arg_count + self.var_count + self.temp_count)) - } - _ => None, } + self.super_lvalue(lvalue, context, location) } } - diff --git a/src/librustc_mir/graphviz.rs b/src/librustc_mir/graphviz.rs index 72b6d7f0e5aa5..1c1f0ca790267 100644 --- a/src/librustc_mir/graphviz.rs +++ b/src/librustc_mir/graphviz.rs @@ -136,30 +136,31 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>, write!(w, " label= 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#"
"#)?; - // User variable types (including the user's name in a comment). - for (i, var) in mir.var_decls.iter().enumerate() { + for local in mir.vars_and_temps_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#"{:?}: {}; // {}
"#, - 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 {:?}: {};
"#, - Lvalue::Temp(Temp::new(i)), escape(&temp.ty))?; + if let Some(name) = decl.name { + write!(w, r#"{:?}: {}; // {}
"#, + Lvalue::Local(local), escape(&decl.ty), name)?; + } else { + write!(w, r#"let mut {:?}: {};
"#, + Lvalue::Local(local), escape(&decl.ty))?; + } } writeln!(w, ">;") diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index 01e2c6308ba01..5c88c89862126 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -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>, @@ -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.vars_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,29 +333,24 @@ 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.args_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.temps_iter() { + writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[temp].ty)?; } Ok(()) diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 79fd16012d9ee..783162cd5588f 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -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> { // 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 } } - diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index a0331f03b0197..b4159af6f071d 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -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, } - diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 57de68fce1d1a..9afc97d1e319a 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -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,24 @@ pub enum Candidate { ShuffleIndices(BasicBlock) } -struct TempCollector { - temps: IndexVec, - span: Span +struct TempCollector<'tcx> { + temps: IndexVec, + 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 +136,11 @@ impl<'tcx> Visitor<'tcx> for TempCollector { } } -pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec { +pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec { 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 +151,7 @@ pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec { source: &'a mut Mir<'tcx>, promoted: Mir<'tcx>, - temps: &'a mut IndexVec, + temps: &'a mut IndexVec, /// If true, all nested temps are also kept in the /// source MIR, not moved to the promoted MIR. @@ -163,7 +174,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { }) } - fn assign(&mut self, dest: Lvalue<'tcx>, rvalue: Rvalue<'tcx>, span: Span) { + fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) { let last = self.promoted.basic_blocks().last().unwrap(); let data = &mut self.promoted[last]; data.statements.push(Statement { @@ -171,13 +182,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { span: span, scope: ARGUMENT_VISIBILITY_SCOPE }, - kind: StatementKind::Assign(dest, rvalue) + kind: StatementKind::Assign(Lvalue::Local(dest), rvalue) }); } /// 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 +270,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(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 +325,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(RETURN_POINTER, rvalue, span); self.source.promoted.push(self.promoted); } } @@ -330,8 +341,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 +352,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, + mut temps: IndexVec, candidates: Vec) { // Visit candidates in reverse, in case they're nested. for candidate in candidates.into_iter().rev() { @@ -353,7 +366,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 +389,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 +401,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 +415,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 +429,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 diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 2c03af2c8e97a..b00a88093d726 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -143,11 +143,11 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { param_env: ty::ParameterEnvironment<'tcx>, qualif_map: &'a mut DefIdMap, mir_map: Option<&'a MirMap<'tcx>>, - temp_qualif: IndexVec>, + temp_qualif: IndexVec>, return_qualif: Option, qualif: Qualif, const_fn_arg_vars: BitVector, - temp_promotion_state: IndexVec, + temp_promotion_state: IndexVec, promotion_candidates: Vec } @@ -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.temps_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.vars_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); + 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[index] { - self.add(qualif); - } else { - self.not_const(); + 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; diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 7b6a2f5580819..7a68229242954 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -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. diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index 21716d55ac6fa..1d7e4991aa847 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -63,8 +63,9 @@ pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec(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); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 003830123ff3b..9e2d947c5e563 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -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, diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index b74d56ce368a9..c0e7af845ec4f 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -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>) + args: IndexVec>) -> 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 local 0 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>) + args: IndexVec>) -> Result, 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, 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)), diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 0ce5544c3bfc5..7102bd81caf36 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -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) => { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 1934f7b870d18..fe71023ea34de 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -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); - }); - } else { - panic!("Unexpected"); + if !lvalue_locals.contains(local.index()) && !dbg { + debug!("alloc: {:?} ({}) -> operand", local, name); + return 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))) + + 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 { - // 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) + // 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 { + // 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) + } } - })).collect() + }; + + let retptr = allocate_local(mir::RETURN_POINTER); + iter::once(retptr) + .chain(args.into_iter()) + .chain(mir.vars_and_temps_iter().map(allocate_local)) + .collect() }; // Branch to the START block @@ -346,10 +356,11 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, None }; - mir.arg_decls.iter().enumerate().map(|(arg_index, arg_decl)| { + mir.args_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 arg_decl.spread { + + if Some(local) == mir.spread_arg { // 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 +478,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; diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 270033be9375c..4f1ec40398ca9 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -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), diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs index 9943acbc88e6d..3d6aad37ed571 100644 --- a/src/librustc_trans/mir/statement.rs +++ b/src/librustc_trans/mir/statement.rs @@ -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); } diff --git a/src/test/codegen/lifetime_start_end.rs b/src/test/codegen/lifetime_start_end.rs index cf91e7a8bcb66..81f6cf309da50 100644 --- a/src/test/codegen/lifetime_start_end.rs +++ b/src/test/codegen/lifetime_start_end.rs @@ -30,11 +30,11 @@ pub fn test() { // CHECK: [[S_b:%[0-9]+]] = bitcast %"2.std::option::Option"** %b to i8* // CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_b]]) -// CHECK: [[S_tmp2:%[0-9]+]] = bitcast %"2.std::option::Option"* %tmp2 to i8* -// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_tmp2]]) +// CHECK: [[S__5:%[0-9]+]] = bitcast %"2.std::option::Option"* %_5 to i8* +// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S__5]]) -// CHECK: [[E_tmp2:%[0-9]+]] = bitcast %"2.std::option::Option"* %tmp2 to i8* -// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_tmp2]]) +// CHECK: [[E__5:%[0-9]+]] = bitcast %"2.std::option::Option"* %_5 to i8* +// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E__5]]) // CHECK: [[E_b:%[0-9]+]] = bitcast %"2.std::option::Option"** %b to i8* // CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_b]]) diff --git a/src/test/mir-opt/deaggregator_test.rs b/src/test/mir-opt/deaggregator_test.rs index e57a9674cf683..3304a66773ad2 100644 --- a/src/test/mir-opt/deaggregator_test.rs +++ b/src/test/mir-opt/deaggregator_test.rs @@ -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 ... -// goto -> bb1; // scope 1 at main.rs:8:1: 10:2 +// _2 = _1; +// _3 = _2; +// _0 = Baz { x: _3, y: const F32(0), z: const false }; +// goto -> bb1; // } // 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 -// goto -> bb1; // scope 1 at main.rs:8:1: 10:2 +// _2 = _1; +// _3 = _2; +// (_0.0: usize) = _3; +// (_0.1: f32) = const F32(0); +// (_0.2: bool) = const false; +// goto -> bb1; // } -// END rustc.node13.Deaggregator.after.mir \ No newline at end of file +// END rustc.node13.Deaggregator.after.mir diff --git a/src/test/mir-opt/deaggregator_test_enum.rs b/src/test/mir-opt/deaggregator_test_enum.rs index ccfa760a28c76..a6f12886f5527 100644 --- a/src/test/mir-opt/deaggregator_test_enum.rs +++ b/src/test/mir-opt/deaggregator_test_enum.rs @@ -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 -// goto -> bb1; // scope 1 at main.rs:7:1: 9:2 +// _2 = _1; +// _3 = _2; +// _0 = Baz::Foo { x: _3 }; +// goto -> bb1; // } // 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 -// goto -> bb1; // scope 1 at main.rs:7:1: 9:2 +// _2 = _1; +// _3 = _2; +// ((_0 as Foo).0: usize) = _3; +// discriminant(_0) = 1; +// goto -> bb1; // } -// END rustc.node10.Deaggregator.after.mir \ No newline at end of file +// END rustc.node10.Deaggregator.after.mir diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index dd6a857960432..7239e32357b95 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -17,11 +17,11 @@ fn main() { // END RUST SOURCE // START rustc.node4.SimplifyBranches.initial-before.mir // bb0: { -// if(const false) -> [true: bb1, false: bb2]; // scope 0 at simplify_if.rs:12:5: 14:6 +// if(const false) -> [true: bb1, false: bb2]; // } // END rustc.node4.SimplifyBranches.initial-before.mir // START rustc.node4.SimplifyBranches.initial-after.mir // bb0: { -// goto -> bb2; // scope 0 at simplify_if.rs:12:5: 14:6 +// goto -> bb2; // } -// END rustc.node4.SimplifyBranches.initial-after.mir \ No newline at end of file +// END rustc.node4.SimplifyBranches.initial-after.mir diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs index 4ed0c8bc9ffa4..3885b233fd296 100644 --- a/src/test/mir-opt/storage_ranges.rs +++ b/src/test/mir-opt/storage_ranges.rs @@ -21,27 +21,27 @@ fn main() { // 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::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(_1); +// _1 = const 0i32; +// StorageLive(_3); +// StorageLive(_4); +// StorageLive(_5); +// _5 = _1; +// _4 = std::option::Option::Some(_5,); +// _3 = &_4; +// StorageDead(_5); +// _2 = (); +// StorageDead(_4); +// StorageDead(_3); +// StorageLive(_6); +// _6 = const 1i32; +// _0 = (); +// StorageDead(_6); +// StorageDead(_1); +// goto -> bb1; // } // // bb1: { -// return; // scope 0 at storage_ranges.rs:13:1: 19:2 +// return; // } // END rustc.node4.TypeckMir.before.mir