diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 301c6e3dd1c4a..fc2d68d7262e6 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -28,6 +28,7 @@ #![feature(box_syntax)] #![feature(collections)] #![feature(const_fn)] +#![feature(core_intrinsics)] #![feature(enumset)] #![feature(iter_arith)] #![feature(libc)] @@ -102,6 +103,7 @@ pub mod middle { } pub mod mir { + mod cache; pub mod repr; pub mod tcx; pub mod visit; diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs new file mode 100644 index 0000000000000..138fed2d64e23 --- /dev/null +++ b/src/librustc/mir/cache.rs @@ -0,0 +1,69 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cell::{Ref, RefCell}; +use rustc_data_structures::indexed_vec::IndexVec; + +use mir::repr::{Mir, BasicBlock}; + +use rustc_serialize as serialize; + +#[derive(Clone)] +pub struct Cache { + predecessors: RefCell>>> +} + + +impl serialize::Encodable for Cache { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + serialize::Encodable::encode(&(), s) + } +} + +impl serialize::Decodable for Cache { + fn decode(d: &mut D) -> Result { + serialize::Decodable::decode(d).map(|_v: ()| Self::new()) + } +} + + +impl Cache { + pub fn new() -> Self { + Cache { + predecessors: RefCell::new(None) + } + } + + pub fn invalidate(&self) { + // FIXME: consider being more fine-grained + *self.predecessors.borrow_mut() = None; + } + + pub fn predecessors(&self, mir: &Mir) -> Ref>> { + if self.predecessors.borrow().is_none() { + *self.predecessors.borrow_mut() = Some(calculate_predecessors(mir)); + } + + Ref::map(self.predecessors.borrow(), |p| p.as_ref().unwrap()) + } +} + +fn calculate_predecessors(mir: &Mir) -> IndexVec> { + let mut result = IndexVec::from_elem(vec![], mir.basic_blocks()); + for (bb, data) in mir.basic_blocks().iter_enumerated() { + if let Some(ref term) = data.terminator { + for &tgt in term.successors().iter() { + result[tgt].push(bb); + } + } + } + + result +} diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 7aaaf38400e87..03ae91fefb925 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -11,6 +11,7 @@ use graphviz::IntoCow; use middle::const_val::ConstVal; use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr}; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use hir::def_id::DefId; use ty::subst::Substs; use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty}; @@ -19,43 +20,70 @@ use rustc_back::slice; use hir::InlineAsm; use std::ascii; use std::borrow::{Cow}; +use std::cell::Ref; use std::fmt::{self, Debug, Formatter, Write}; use std::{iter, u32}; use std::ops::{Index, IndexMut}; use syntax::ast::{self, Name}; use syntax::codemap::Span; +use super::cache::Cache; + +macro_rules! newtype_index { + ($name:ident, $debug_name:expr) => ( + #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, + RustcEncodable, RustcDecodable)] + pub struct $name(u32); + + impl Idx for $name { + fn new(value: usize) -> Self { + assert!(value < (u32::MAX) as usize); + $name(value as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + impl Debug for $name { + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, "{}{}", $debug_name, self.0) + } + } + ) +} + /// Lowered representation of a single function. #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct Mir<'tcx> { /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` /// that indexes into this vector. - pub basic_blocks: Vec>, + basic_blocks: IndexVec>, /// List of visibility (lexical) scopes; these are referenced by statements /// and used (eventually) for debuginfo. Indexed by a `VisibilityScope`. - pub visibility_scopes: Vec, + pub visibility_scopes: IndexVec, /// 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. - pub promoted: Vec>, + pub promoted: IndexVec>, /// Return type of the function. pub return_ty: FnOutput<'tcx>, /// Variables: these are stack slots corresponding to user variables. They may be /// assigned many times. - pub var_decls: Vec>, + pub var_decls: IndexVec>, /// Args: these are stack slots corresponding to the input arguments. - pub arg_decls: Vec>, + pub arg_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: Vec>, + pub temp_decls: IndexVec>, /// Names and capture modes of all the closure upvars, assuming /// the first argument is either the closure or a reference to it. @@ -63,24 +91,58 @@ pub struct Mir<'tcx> { /// A span representing this MIR, for error reporting pub span: Span, + + /// A cache for various calculations + cache: Cache } /// where execution begins pub const START_BLOCK: BasicBlock = BasicBlock(0); impl<'tcx> Mir<'tcx> { - pub fn all_basic_blocks(&self) -> Vec { - (0..self.basic_blocks.len()) - .map(|i| BasicBlock::new(i)) - .collect() + pub fn new(basic_blocks: IndexVec>, + visibility_scopes: IndexVec, + promoted: IndexVec>, + return_ty: FnOutput<'tcx>, + var_decls: IndexVec>, + arg_decls: IndexVec>, + temp_decls: IndexVec>, + upvar_decls: Vec, + span: Span) -> Self + { + 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, + upvar_decls: upvar_decls, + span: span, + cache: Cache::new() + } + } + + #[inline] + pub fn basic_blocks(&self) -> &IndexVec> { + &self.basic_blocks } - pub fn basic_block_data(&self, bb: BasicBlock) -> &BasicBlockData<'tcx> { - &self.basic_blocks[bb.index()] + #[inline] + pub fn basic_blocks_mut(&mut self) -> &mut IndexVec> { + self.cache.invalidate(); + &mut self.basic_blocks } - pub fn basic_block_data_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockData<'tcx> { - &mut self.basic_blocks[bb.index()] + #[inline] + pub fn predecessors(&self) -> Ref>> { + self.cache.predecessors(self) + } + + #[inline] + pub fn predecessors_for(&self, bb: BasicBlock) -> Ref> { + Ref::map(self.predecessors(), |p| &p[bb]) } } @@ -89,14 +151,14 @@ impl<'tcx> Index for Mir<'tcx> { #[inline] fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { - self.basic_block_data(index) + &self.basic_blocks()[index] } } impl<'tcx> IndexMut for Mir<'tcx> { #[inline] fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> { - self.basic_block_data_mut(index) + &mut self.basic_blocks_mut()[index] } } @@ -231,31 +293,7 @@ pub struct UpvarDecl { /////////////////////////////////////////////////////////////////////////// // BasicBlock -/// The index of a particular basic block. The index is into the `basic_blocks` -/// list of the `Mir`. -/// -/// (We use a `u32` internally just to save memory.) -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, - RustcEncodable, RustcDecodable)] -pub struct BasicBlock(u32); - -impl BasicBlock { - pub fn new(index: usize) -> BasicBlock { - assert!(index < (u32::MAX as usize)); - BasicBlock(index as u32) - } - - /// Extract the index. - pub fn index(self) -> usize { - self.0 as usize - } -} - -impl Debug for BasicBlock { - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - write!(fmt, "bb{}", self.0) - } -} +newtype_index!(BasicBlock, "bb"); /////////////////////////////////////////////////////////////////////////// // BasicBlockData and Terminator @@ -336,6 +374,9 @@ pub enum TerminatorKind<'tcx> { /// have been filled in by now. This should occur at most once. Return, + /// Indicates a terminator that can never be reached. + Unreachable, + /// Drop the Lvalue Drop { location: Lvalue<'tcx>, @@ -394,6 +435,7 @@ impl<'tcx> TerminatorKind<'tcx> { SwitchInt { targets: ref b, .. } => b[..].into_cow(), Resume => (&[]).into_cow(), Return => (&[]).into_cow(), + Unreachable => (&[]).into_cow(), Call { destination: Some((_, t)), cleanup: Some(c), .. } => vec![t, c].into_cow(), Call { destination: Some((_, ref t)), cleanup: None, .. } => slice::ref_slice(t).into_cow(), @@ -423,6 +465,7 @@ impl<'tcx> TerminatorKind<'tcx> { SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(), Resume => Vec::new(), Return => Vec::new(), + Unreachable => Vec::new(), Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut c), .. } => vec![t, c], Call { destination: Some((_, ref mut t)), cleanup: None, .. } => vec![t], Call { destination: None, cleanup: Some(ref mut c), .. } => vec![c], @@ -501,6 +544,7 @@ impl<'tcx> TerminatorKind<'tcx> { SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv), Return => write!(fmt, "return"), Resume => write!(fmt, "resume"), + Unreachable => write!(fmt, "unreachable"), Drop { ref location, .. } => write!(fmt, "drop({:?})", location), DropAndReplace { ref location, ref value, .. } => write!(fmt, "replace({:?} <- {:?})", location, value), @@ -544,7 +588,7 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn fmt_successor_labels(&self) -> Vec> { use self::TerminatorKind::*; match *self { - Return | Resume => vec![], + Return | Resume | Unreachable => vec![], Goto { .. } => vec!["".into()], If { .. } => vec!["true".into(), "false".into()], Switch { ref adt_def, .. } => { @@ -616,19 +660,23 @@ impl<'tcx> Debug for Statement<'tcx> { /////////////////////////////////////////////////////////////////////////// // Lvalues +newtype_index!(Var, "var"); +newtype_index!(Temp, "tmp"); +newtype_index!(Arg, "arg"); + /// 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(u32), + Var(Var), /// temporary introduced during lowering into MIR - Temp(u32), + Temp(Temp), /// formal parameter of the function; note that these are NOT the /// bindings that the user declares, which are vars - Arg(u32), + Arg(Arg), /// static or static mut variable Static(DefId), @@ -696,20 +744,7 @@ pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Operand<'tcx>>; /// and the index is an operand. pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Operand<'tcx>>; -/// Index into the list of fields found in a `VariantDef` -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -pub struct Field(u32); - -impl Field { - pub fn new(value: usize) -> Field { - assert!(value < (u32::MAX) as usize); - Field(value as u32) - } - - pub fn index(self) -> usize { - self.0 as usize - } -} +newtype_index!(Field, "field"); impl<'tcx> Lvalue<'tcx> { pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> { @@ -737,12 +772,9 @@ impl<'tcx> Debug for Lvalue<'tcx> { use self::Lvalue::*; match *self { - Var(id) => - write!(fmt, "var{:?}", id), - Arg(id) => - write!(fmt, "arg{:?}", id), - Temp(id) => - write!(fmt, "tmp{:?}", id), + Var(id) => write!(fmt, "{:?}", id), + Arg(id) => write!(fmt, "{:?}", id), + Temp(id) => write!(fmt, "{:?}", id), Static(def_id) => write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))), ReturnPointer => @@ -777,38 +809,8 @@ impl<'tcx> Debug for Lvalue<'tcx> { /////////////////////////////////////////////////////////////////////////// // Scopes -impl Index for Vec { - type Output = VisibilityScopeData; - - #[inline] - fn index(&self, index: VisibilityScope) -> &VisibilityScopeData { - &self[index.index()] - } -} - -impl IndexMut for Vec { - #[inline] - fn index_mut(&mut self, index: VisibilityScope) -> &mut VisibilityScopeData { - &mut self[index.index()] - } -} - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)] -pub struct VisibilityScope(u32); - -/// The visibility scope all arguments go into. -pub const ARGUMENT_VISIBILITY_SCOPE: VisibilityScope = VisibilityScope(0); - -impl VisibilityScope { - pub fn new(index: usize) -> VisibilityScope { - assert!(index < (u32::MAX as usize)); - VisibilityScope(index as u32) - } - - pub fn index(self) -> usize { - self.0 as usize - } -} +newtype_index!(VisibilityScope, "scope"); +pub const ARGUMENT_VISIBILITY_SCOPE : VisibilityScope = VisibilityScope(0); #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct VisibilityScopeData { @@ -1080,6 +1082,8 @@ impl<'tcx> Debug for TypedConstVal<'tcx> { } } +newtype_index!(Promoted, "promoted"); + #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum Literal<'tcx> { Item { @@ -1091,7 +1095,7 @@ pub enum Literal<'tcx> { }, Promoted { // Index into the `promoted` vector of `Mir`. - index: usize + index: Promoted }, } @@ -1115,7 +1119,7 @@ impl<'tcx> Debug for Literal<'tcx> { fmt_const_val(fmt, value) } Promoted { index } => { - write!(fmt, "promoted{}", index) + write!(fmt, "{:?}", index) } } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 270e33c48f1a0..e3905c39daa9c 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -154,11 +154,11 @@ impl<'a, 'gcx, 'tcx> Mir<'tcx> { { match *lvalue { Lvalue::Var(index) => - LvalueTy::Ty { ty: self.var_decls[index as usize].ty }, + LvalueTy::Ty { ty: self.var_decls[index].ty }, Lvalue::Temp(index) => - LvalueTy::Ty { ty: self.temp_decls[index as usize].ty }, + LvalueTy::Ty { ty: self.temp_decls[index].ty }, Lvalue::Arg(index) => - LvalueTy::Ty { ty: self.arg_decls[index as usize].ty }, + LvalueTy::Ty { ty: self.arg_decls[index].ty }, Lvalue::Static(def_id) => LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty }, Lvalue::ReturnPointer => diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 828a48532a2fc..f17984d380459 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -17,6 +17,8 @@ use mir::repr::Mir; use ty::TyCtxt; use syntax::ast::NodeId; +use std::fmt; + /// Where a specific Mir comes from. #[derive(Debug, Copy, Clone)] pub enum MirSource { @@ -70,16 +72,34 @@ impl<'a, 'tcx> MirSource { /// Various information about pass. pub trait Pass { - // fn name() for printouts of various sorts? // fn should_run(Session) to check if pass should run? fn dep_node(&self, def_id: DefId) -> DepNode { DepNode::MirPass(def_id) } + fn name(&self) -> &str { + unsafe { ::std::intrinsics::type_name::() } + } + fn disambiguator<'a>(&'a self) -> Option> { None } } /// A pass which inspects the whole MirMap. pub trait MirMapPass<'tcx>: Pass { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>); + fn run_pass<'a>( + &mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + map: &mut MirMap<'tcx>, + hooks: &mut [Box MirPassHook<'s>>]); +} + +pub trait MirPassHook<'tcx>: Pass { + fn on_mir_pass<'a>( + &mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + pass: &Pass, + is_after: bool + ); } /// A pass which inspects Mir of functions in isolation. @@ -94,16 +114,33 @@ pub trait MirPass<'tcx>: Pass { } impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>) { + fn run_pass<'a>(&mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + map: &mut MirMap<'tcx>, + hooks: &mut [Box MirPassHook<'s>>]) + { for (&id, mir) in &mut map.map { let def_id = tcx.map.local_def_id(id); let _task = tcx.dep_graph.in_task(self.dep_node(def_id)); let src = MirSource::from_node(tcx, id); + + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, mir, self, false); + } MirPass::run_pass(self, tcx, src, mir); + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, mir, self, true); + } for (i, mir) in mir.promoted.iter_mut().enumerate() { + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, mir, self, false); + } self.run_pass_on_promoted(tcx, id, i, mir); + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, mir, self, true); + } } } } @@ -112,6 +149,7 @@ impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T { /// A manager for MIR passes. pub struct Passes { passes: Vec MirMapPass<'tcx>>>, + pass_hooks: Vec MirPassHook<'tcx>>>, plugin_passes: Vec MirMapPass<'tcx>>> } @@ -119,6 +157,7 @@ impl<'a, 'tcx> Passes { pub fn new() -> Passes { let passes = Passes { passes: Vec::new(), + pass_hooks: Vec::new(), plugin_passes: Vec::new() }; passes @@ -126,10 +165,10 @@ impl<'a, 'tcx> Passes { pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>) { for pass in &mut self.plugin_passes { - pass.run_pass(tcx, map); + pass.run_pass(tcx, map, &mut self.pass_hooks); } for pass in &mut self.passes { - pass.run_pass(tcx, map); + pass.run_pass(tcx, map, &mut self.pass_hooks); } } @@ -137,6 +176,11 @@ impl<'a, 'tcx> Passes { pub fn push_pass(&mut self, pass: Box MirMapPass<'b>>) { self.passes.push(pass); } + + /// Pushes a pass hook. + pub fn push_hook(&mut self, hook: Box MirPassHook<'b>>) { + self.pass_hooks.push(hook); + } } /// Copies the plugin passes. diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index c4e4936df9541..1af5123b4df60 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -11,6 +11,7 @@ use std::vec; use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::Idx; use super::repr::*; @@ -44,7 +45,7 @@ impl<'a, 'tcx> Preorder<'a, 'tcx> { Preorder { mir: mir, - visited: BitVector::new(mir.basic_blocks.len()), + visited: BitVector::new(mir.basic_blocks().len()), worklist: worklist } } @@ -63,7 +64,7 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { continue; } - let data = self.mir.basic_block_data(idx); + let data = &self.mir[idx]; if let Some(ref term) = data.terminator { for &succ in term.successors().iter() { @@ -106,12 +107,12 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> { let mut po = Postorder { mir: mir, - visited: BitVector::new(mir.basic_blocks.len()), + visited: BitVector::new(mir.basic_blocks().len()), visit_stack: Vec::new() }; - let data = po.mir.basic_block_data(root); + let data = &po.mir[root]; if let Some(ref term) = data.terminator { po.visited.insert(root.index()); @@ -185,9 +186,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { }; if self.visited.insert(bb.index()) { - let data = self.mir.basic_block_data(bb); - - if let Some(ref term) = data.terminator { + if let Some(ref term) = self.mir[bb].terminator { let succs = term.successors().into_owned().into_iter(); self.visit_stack.push((bb, succs)); } @@ -209,10 +208,7 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { self.traverse_successor(); } - next.map(|(bb, _)| { - let data = self.mir.basic_block_data(bb); - (bb, data) - }) + next.map(|(bb, _)| (bb, &self.mir[bb])) } } @@ -278,9 +274,6 @@ impl<'a, 'tcx> Iterator for ReversePostorder<'a, 'tcx> { if self.idx == 0 { return None; } self.idx -= 1; - self.blocks.get(self.idx).map(|&bb| { - let data = self.mir.basic_block_data(bb); - (bb, data) - }) + self.blocks.get(self.idx).map(|&bb| (bb, &self.mir[bb])) } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 22b3caf6d0c0f..bc45a730c2e21 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -15,6 +15,7 @@ use ty::{ClosureSubsts, FnOutput, Region, Ty}; use mir::repr::*; use rustc_const_math::ConstUsize; use rustc_data_structures::tuple_slice::TupleSlice; +use rustc_data_structures::indexed_vec::Idx; use syntax::codemap::Span; // # The MIR Visitor @@ -251,42 +252,30 @@ macro_rules! make_mir_visitor { fn super_mir(&mut self, mir: & $($mutability)* Mir<'tcx>) { - let Mir { - ref $($mutability)* basic_blocks, - ref $($mutability)* visibility_scopes, - promoted: _, // Visited by passes separately. - ref $($mutability)* return_ty, - ref $($mutability)* var_decls, - ref $($mutability)* arg_decls, - ref $($mutability)* temp_decls, - upvar_decls: _, - ref $($mutability)* span, - } = *mir; - - for (index, data) in basic_blocks.into_iter().enumerate() { + for index in 0..mir.basic_blocks().len() { let block = BasicBlock::new(index); - self.visit_basic_block_data(block, data); + self.visit_basic_block_data(block, &$($mutability)* mir[block]); } - for scope in visibility_scopes { + for scope in &$($mutability)* mir.visibility_scopes { self.visit_visibility_scope_data(scope); } - self.visit_fn_output(return_ty); + self.visit_fn_output(&$($mutability)* mir.return_ty); - for var_decl in var_decls { + for var_decl in &$($mutability)* mir.var_decls { self.visit_var_decl(var_decl); } - for arg_decl in arg_decls { + for arg_decl in &$($mutability)* mir.arg_decls { self.visit_arg_decl(arg_decl); } - for temp_decl in temp_decls { + for temp_decl in &$($mutability)* mir.temp_decls { self.visit_temp_decl(temp_decl); } - self.visit_span(span); + self.visit_span(&$($mutability)* mir.span); } fn super_basic_block_data(&mut self, @@ -397,7 +386,8 @@ macro_rules! make_mir_visitor { } TerminatorKind::Resume | - TerminatorKind::Return => { + TerminatorKind::Return | + TerminatorKind::Unreachable => { } TerminatorKind::Drop { ref $($mutability)* location, diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_borrowck/Cargo.toml index fbc267aaa6a06..c8a71ea350555 100644 --- a/src/librustc_borrowck/Cargo.toml +++ b/src/librustc_borrowck/Cargo.toml @@ -14,4 +14,5 @@ log = { path = "../liblog" } syntax = { path = "../libsyntax" } graphviz = { path = "../libgraphviz" } rustc = { path = "../librustc" } +rustc_data_structures = { path = "../librustc_data_structures" } rustc_mir = { path = "../librustc_mir" } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs index 63c11fb3545b0..91be50d11f952 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs @@ -12,6 +12,7 @@ use syntax::ast::NodeId; use rustc::mir::repr::{BasicBlock, Mir}; +use rustc_data_structures::indexed_vec::Idx; use dot; use dot::IntoCow; @@ -27,7 +28,7 @@ use std::path::Path; use super::super::MoveDataParamEnv; use super::super::MirBorrowckCtxtPreDataflow; use bitslice::bits_to_string; -use indexed_set::{Idx, IdxSet}; +use indexed_set::{IdxSet}; use super::{BitDenotation, DataflowState}; impl DataflowState { @@ -126,7 +127,7 @@ pub type Node = BasicBlock; pub struct Edge { source: BasicBlock, index: usize } fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec { - let succ_len = mir.basic_block_data(bb).terminator().successors().len(); + let succ_len = mir[bb].terminator().successors().len(); (0..succ_len).map(|index| Edge { source: bb, index: index}).collect() } @@ -312,17 +313,20 @@ impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P> type Node = Node; type Edge = Edge; fn nodes(&self) -> dot::Nodes { - self.mbcx.mir().all_basic_blocks().into_cow() + self.mbcx.mir() + .basic_blocks() + .indices() + .collect::>() + .into_cow() } fn edges(&self) -> dot::Edges { let mir = self.mbcx.mir(); - let blocks = mir.all_basic_blocks(); // base initial capacity on assumption every block has at // least one outgoing edge (Which should be true for all // blocks but one, the exit-block). - let mut edges = Vec::with_capacity(blocks.len()); - for bb in blocks { + let mut edges = Vec::with_capacity(mir.basic_blocks().len()); + for bb in mir.basic_blocks().indices() { let outgoing = outgoing(mir, bb); edges.extend(outgoing.into_iter()); } @@ -335,6 +339,6 @@ impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P> fn target(&self, edge: &Edge) -> Node { let mir = self.mbcx.mir(); - mir.basic_block_data(edge.source).terminator().successors()[edge.index] + mir[edge.source].terminator().successors()[edge.index] } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index e3435ed990506..932b748520170 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -10,6 +10,7 @@ use rustc::ty::TyCtxt; use rustc::mir::repr::{self, Mir}; +use rustc_data_structures::indexed_vec::Idx; use super::super::gather_moves::{Location}; use super::super::gather_moves::{MoveOutIndex, MovePathIndex}; @@ -23,7 +24,7 @@ use super::{BitDenotation, BlockSets, DataflowOperator}; use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep. use bitslice::{BitwiseOperator}; -use indexed_set::{Idx, IdxSet}; +use indexed_set::{IdxSet}; // Dataflow analyses are built upon some interpretation of the // bitvectors attached to each basic block, represented via a @@ -425,7 +426,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { bb: repr::BasicBlock, idx: usize) { let (tcx, mir, move_data) = (self.tcx, self.mir, &ctxt.move_data); - let stmt = &mir.basic_block_data(bb).statements[idx]; + let stmt = &mir[bb].statements[idx]; let loc_map = &move_data.loc_map; let path_map = &move_data.path_map; let rev_lookup = &move_data.rev_lookup; @@ -451,7 +452,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { move_data, move_path_index, |mpi| for moi in &path_map[mpi] { - assert!(moi.idx() < bits_per_block); + assert!(moi.index() < bits_per_block); sets.kill_set.add(&moi); }); } @@ -465,14 +466,14 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { statements_len: usize) { let (mir, move_data) = (self.mir, &ctxt.move_data); - let term = mir.basic_block_data(bb).terminator.as_ref().unwrap(); + let term = mir[bb].terminator(); let loc_map = &move_data.loc_map; let loc = Location { block: bb, index: statements_len }; debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}", term, loc, &loc_map[loc]); let bits_per_block = self.bits_per_block(ctxt); for move_index in &loc_map[loc] { - assert!(move_index.idx() < bits_per_block); + assert!(move_index.index() < bits_per_block); zero_to_one(sets.gen_set.words_mut(), *move_index); } } @@ -493,14 +494,14 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { move_data, move_path_index, |mpi| for moi in &path_map[mpi] { - assert!(moi.idx() < bits_per_block); + assert!(moi.index() < bits_per_block); in_out.remove(&moi); }); } } fn zero_to_one(bitvec: &mut [usize], move_index: MoveOutIndex) { - let retval = bitvec.set_bit(move_index.idx()); + let retval = bitvec.set_bit(move_index.index()); assert!(retval); } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 81655b5e386f6..a9b4de450967c 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc_data_structures::indexed_vec::Idx; + use rustc::ty::TyCtxt; use rustc::mir::repr::{self, Mir}; @@ -21,7 +23,7 @@ use super::MirBorrowckCtxtPreDataflow; use super::MoveDataParamEnv; use bitslice::{bitwise, BitwiseOperator}; -use indexed_set::{Idx, IdxSet, IdxSetBuf}; +use indexed_set::{IdxSet, IdxSetBuf}; pub use self::sanity_check::sanity_check_via_rustc_peek; pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals}; @@ -81,11 +83,10 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> self.flow_state.operator.start_block_effect(&self.ctxt, sets); } - for bb in self.mir.all_basic_blocks() { + for (bb, data) in self.mir.basic_blocks().iter_enumerated() { let &repr::BasicBlockData { ref statements, ref terminator, - is_cleanup: _ } = - self.mir.basic_block_data(bb); + is_cleanup: _ } = data; let sets = &mut self.flow_state.sets.for_block(bb.index()); for j_stmt in 0..statements.len() { @@ -112,7 +113,7 @@ impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> fn walk_cfg(&mut self, in_out: &mut IdxSet) { let mir = self.builder.mir; - for (bb_idx, bb_data) in mir.basic_blocks.iter().enumerate() { + for (bb_idx, bb_data) in mir.basic_blocks().iter().enumerate() { let builder = &mut self.builder; { let sets = builder.flow_state.sets.for_block(bb_idx); @@ -396,7 +397,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> // (now rounded up to multiple of word size) let bits_per_block = words_per_block * usize_bits; - let num_blocks = mir.basic_blocks.len(); + let num_blocks = mir.basic_blocks().len(); let num_overall = num_blocks * bits_per_block; let zeroes = Bits::new(IdxSetBuf::new_empty(num_overall)); @@ -448,7 +449,8 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> { match bb_data.terminator().kind { repr::TerminatorKind::Return | - repr::TerminatorKind::Resume => {} + repr::TerminatorKind::Resume | + repr::TerminatorKind::Unreachable => {} repr::TerminatorKind::Goto { ref target } | repr::TerminatorKind::Assert { ref target, cleanup: None, .. } | repr::TerminatorKind::Drop { ref target, location: _, unwind: None } | diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 8c528f10b57ba..c8d3ff01b6c1a 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -14,6 +14,7 @@ use syntax::codemap::Span; use rustc::ty::{self, TyCtxt}; use rustc::mir::repr::{self, Mir}; +use rustc_data_structures::indexed_vec::Idx; use super::super::gather_moves::{MovePathIndex}; use super::super::MoveDataParamEnv; @@ -49,8 +50,7 @@ pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // `dataflow::build_sets`. (But note it is doing non-standard // stuff, so such generalization may not be realistic.) - let blocks = mir.all_basic_blocks(); - 'next_block: for bb in blocks { + for bb in mir.basic_blocks().indices() { each_block(tcx, mir, flow_ctxt, results, bb); } } @@ -63,10 +63,9 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, O: BitDenotation, Idx=MovePathIndex> { let move_data = &ctxt.move_data; - let bb_data = mir.basic_block_data(bb); - let &repr::BasicBlockData { ref statements, - ref terminator, - is_cleanup: _ } = bb_data; + let repr::BasicBlockData { ref statements, + ref terminator, + is_cleanup: _ } = mir[bb]; let (args, span) = match is_rustc_peek(tcx, terminator) { Some(args_and_span) => args_and_span, diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index b09db70e7b88a..362d6ce2acafc 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -22,7 +22,7 @@ use rustc::mir::transform::{Pass, MirPass, MirSource}; use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; use rustc::util::nodemap::FnvHashMap; -use rustc_mir::pretty; +use rustc_data_structures::indexed_vec::Idx; use syntax::codemap::Span; use std::fmt; @@ -65,9 +65,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { patch: MirPatch::new(mir), }.elaborate() }; - pretty::dump_mir(tcx, "elaborate_drops", &0, src, mir, None); elaborate_patch.apply(mir); - pretty::dump_mir(tcx, "elaborate_drops", &1, src, mir, None); } } @@ -118,7 +116,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>, } @@ -224,8 +222,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn collect_drop_flags(&mut self) { - for bb in self.mir.all_basic_blocks() { - let data = self.mir.basic_block_data(bb); + for (bb, data) in self.mir.basic_blocks().iter_enumerated() { let terminator = data.terminator(); let location = match terminator.kind { TerminatorKind::Drop { ref location, .. } | @@ -261,8 +258,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn elaborate_drops(&mut self) { - for bb in self.mir.all_basic_blocks() { - let data = self.mir.basic_block_data(bb); + for (bb, data) in self.mir.basic_blocks().iter_enumerated() { let loc = Location { block: bb, index: data.statements.len() }; let terminator = data.terminator(); @@ -322,7 +318,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { unwind: Option) { let bb = loc.block; - let data = self.mir.basic_block_data(bb); + let data = &self.mir[bb]; let terminator = data.terminator(); let assign = Statement { @@ -941,8 +937,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn drop_flags_for_fn_rets(&mut self) { - for bb in self.mir.all_basic_blocks() { - let data = self.mir.basic_block_data(bb); + for (bb, data) in self.mir.basic_blocks().iter_enumerated() { if let TerminatorKind::Call { destination: Some((ref lv, tgt)), cleanup: Some(_), .. } = data.terminator().kind { @@ -974,8 +969,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { // drop flags by themselves, to avoid the drop flags being // clobbered before they are read. - for bb in self.mir.all_basic_blocks() { - let data = self.mir.basic_block_data(bb); + for (bb, data) in self.mir.basic_blocks().iter_enumerated() { debug!("drop_flags_for_locs({:?})", data); for i in 0..(data.statements.len()+1) { debug!("drop_flag_for_locs: stmt {}", i); diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 1acee8e64a9af..05412216d487c 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -12,6 +12,7 @@ use rustc::ty::{FnOutput, TyCtxt}; use rustc::mir::repr::*; use rustc::util::nodemap::FnvHashMap; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use std::cell::{Cell}; use std::collections::hash_map::Entry; @@ -20,7 +21,6 @@ use std::iter; use std::ops::Index; use super::abs_domain::{AbstractElem, Lift}; -use indexed_set::{Idx}; // This submodule holds some newtype'd Index wrappers that are using // NonZero to ensure that Option occupies only a single word. @@ -29,7 +29,7 @@ use indexed_set::{Idx}; // (which is likely to yield a subtle off-by-one error). mod indexes { use core::nonzero::NonZero; - use indexed_set::Idx; + use rustc_data_structures::indexed_vec::Idx; macro_rules! new_index { ($Index:ident) => { @@ -43,7 +43,7 @@ mod indexes { fn new(idx: usize) -> Self { unsafe { $Index(NonZero::new(idx + 1)) } } - fn idx(&self) -> usize { + fn index(self) -> usize { *self.0 - 1 } } @@ -62,7 +62,7 @@ pub use self::indexes::MoveOutIndex; impl self::indexes::MoveOutIndex { pub fn move_path_index(&self, move_data: &MoveData) -> MovePathIndex { - move_data.moves[self.idx()].path + move_data.moves[self.index()].path } } @@ -176,7 +176,7 @@ pub struct PathMap { impl Index for PathMap { type Output = [MoveOutIndex]; fn index(&self, index: MovePathIndex) -> &Self::Output { - &self.map[index.idx()] + &self.map[index.index()] } } @@ -196,7 +196,7 @@ pub struct MoveOut { impl fmt::Debug for MoveOut { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "p{}@{:?}", self.path.idx(), self.source) + write!(fmt, "p{}@{:?}", self.path.index(), self.source) } } @@ -227,14 +227,10 @@ impl<'tcx> MovePathData<'tcx> { impl<'tcx> Index for MovePathData<'tcx> { type Output = MovePath<'tcx>; fn index(&self, i: MovePathIndex) -> &MovePath<'tcx> { - &self.move_paths[i.idx()] + &self.move_paths[i.index()] } } -/// MovePathInverseMap maps from a uint in an lvalue-category to the -/// MovePathIndex for the MovePath for that lvalue. -type MovePathInverseMap = Vec>; - struct MovePathDataBuilder<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, pre_move_paths: Vec>, @@ -244,9 +240,9 @@ struct MovePathDataBuilder<'a, 'tcx: 'a> { /// Tables mapping from an l-value to its MovePathIndex. #[derive(Debug)] pub struct MovePathLookup<'tcx> { - vars: MovePathInverseMap, - temps: MovePathInverseMap, - args: MovePathInverseMap, + 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. @@ -295,15 +291,15 @@ enum LookupKind { Generate, Reuse } struct Lookup(LookupKind, T); impl Lookup { - fn idx(&self) -> usize { (self.1).idx() } + fn index(&self) -> usize { (self.1).index() } } impl<'tcx> MovePathLookup<'tcx> { - fn new() -> Self { + fn new(mir: &Mir) -> Self { MovePathLookup { - vars: vec![], - temps: vec![], - args: vec![], + vars: IndexVec::from_elem(None, &mir.var_decls), + temps: IndexVec::from_elem(None, &mir.temp_decls), + args: IndexVec::from_elem(None, &mir.arg_decls), statics: None, return_ptr: None, projections: vec![], @@ -313,15 +309,14 @@ impl<'tcx> MovePathLookup<'tcx> { fn next_index(next: &mut MovePathIndex) -> MovePathIndex { let i = *next; - *next = MovePathIndex::new(i.idx() + 1); + *next = MovePathIndex::new(i.index() + 1); i } - fn lookup_or_generate(vec: &mut Vec>, - idx: u32, - next_index: &mut MovePathIndex) -> Lookup { - let idx = idx as usize; - vec.fill_to_with(idx, None); + fn lookup_or_generate(vec: &mut IndexVec>, + idx: I, + next_index: &mut MovePathIndex) + -> Lookup { let entry = &mut vec[idx]; match *entry { None => { @@ -335,19 +330,19 @@ impl<'tcx> MovePathLookup<'tcx> { } } - fn lookup_var(&mut self, var_idx: u32) -> Lookup { + fn lookup_var(&mut self, var_idx: Var) -> Lookup { Self::lookup_or_generate(&mut self.vars, var_idx, &mut self.next_index) } - fn lookup_temp(&mut self, temp_idx: u32) -> Lookup { + fn lookup_temp(&mut self, temp_idx: Temp) -> Lookup { Self::lookup_or_generate(&mut self.temps, temp_idx, &mut self.next_index) } - fn lookup_arg(&mut self, arg_idx: u32) -> Lookup { + fn lookup_arg(&mut self, arg_idx: Arg) -> Lookup { Self::lookup_or_generate(&mut self.args, arg_idx, &mut self.next_index) @@ -384,8 +379,8 @@ impl<'tcx> MovePathLookup<'tcx> { base: MovePathIndex) -> Lookup { let MovePathLookup { ref mut projections, ref mut next_index, .. } = *self; - projections.fill_to(base.idx()); - match projections[base.idx()].entry(proj.elem.lift()) { + projections.fill_to(base.index()); + match projections[base.index()].entry(proj.elem.lift()) { Entry::Occupied(ent) => { Lookup(LookupKind::Reuse, *ent.get()) } @@ -404,14 +399,14 @@ impl<'tcx> MovePathLookup<'tcx> { // unknown l-value; it will simply panic. pub fn find(&self, lval: &Lvalue<'tcx>) -> MovePathIndex { match *lval { - Lvalue::Var(var_idx) => self.vars[var_idx as usize].unwrap(), - Lvalue::Temp(temp_idx) => self.temps[temp_idx as usize].unwrap(), - Lvalue::Arg(arg_idx) => self.args[arg_idx as usize].unwrap(), + Lvalue::Var(var) => self.vars[var].unwrap(), + Lvalue::Temp(temp) => self.temps[temp].unwrap(), + Lvalue::Arg(arg) => self.args[arg].unwrap(), Lvalue::Static(ref _def_id) => self.statics.unwrap(), Lvalue::ReturnPointer => self.return_ptr.unwrap(), Lvalue::Projection(ref proj) => { let base_index = self.find(&proj.base); - self.projections[base_index.idx()][&proj.elem.lift()] + self.projections[base_index.index()][&proj.elem.lift()] } } } @@ -451,7 +446,7 @@ impl<'a, 'tcx> MovePathDataBuilder<'a, 'tcx> { // `lookup` is either the previously assigned index or a // newly-allocated one. - debug_assert!(lookup.idx() <= self.pre_move_paths.len()); + debug_assert!(lookup.index() <= self.pre_move_paths.len()); if let Lookup(LookupKind::Generate, mpi) = lookup { let parent; @@ -482,7 +477,7 @@ impl<'a, 'tcx> MovePathDataBuilder<'a, 'tcx> { let idx = self.move_path_for(&proj.base); parent = Some(idx); - let parent_move_path = &mut self.pre_move_paths[idx.idx()]; + let parent_move_path = &mut self.pre_move_paths[idx.index()]; // At last: Swap in the new first_child. sibling = parent_move_path.first_child.get(); @@ -524,9 +519,9 @@ enum StmtKind { fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveData<'tcx> { use self::StmtKind as SK; - let bbs = mir.all_basic_blocks(); - let mut moves = Vec::with_capacity(bbs.len()); - let mut loc_map: Vec<_> = iter::repeat(Vec::new()).take(bbs.len()).collect(); + let bb_count = mir.basic_blocks().len(); + let mut moves = vec![]; + let mut loc_map: Vec<_> = iter::repeat(Vec::new()).take(bb_count).collect(); let mut path_map = Vec::new(); // this is mutable only because we will move it to and fro' the @@ -535,7 +530,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD let mut builder = MovePathDataBuilder { mir: mir, pre_move_paths: Vec::new(), - rev_lookup: MovePathLookup::new(), + rev_lookup: MovePathLookup::new(mir), }; // Before we analyze the program text, we create the MovePath's @@ -546,22 +541,21 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD assert!(mir.var_decls.len() <= ::std::u32::MAX as usize); assert!(mir.arg_decls.len() <= ::std::u32::MAX as usize); assert!(mir.temp_decls.len() <= ::std::u32::MAX as usize); - for var_idx in 0..mir.var_decls.len() { - let path_idx = builder.move_path_for(&Lvalue::Var(var_idx as u32)); - path_map.fill_to(path_idx.idx()); + for var in mir.var_decls.indices() { + let path_idx = builder.move_path_for(&Lvalue::Var(var)); + path_map.fill_to(path_idx.index()); } - for arg_idx in 0..mir.arg_decls.len() { - let path_idx = builder.move_path_for(&Lvalue::Arg(arg_idx as u32)); - path_map.fill_to(path_idx.idx()); + for arg in mir.arg_decls.indices() { + let path_idx = builder.move_path_for(&Lvalue::Arg(arg)); + path_map.fill_to(path_idx.index()); } - for temp_idx in 0..mir.temp_decls.len() { - let path_idx = builder.move_path_for(&Lvalue::Temp(temp_idx as u32)); - path_map.fill_to(path_idx.idx()); + for temp in mir.temp_decls.indices() { + let path_idx = builder.move_path_for(&Lvalue::Temp(temp)); + path_map.fill_to(path_idx.index()); } - for bb in bbs { + for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { let loc_map_bb = &mut loc_map[bb.index()]; - let bb_data = mir.basic_block_data(bb); debug_assert!(loc_map_bb.len() == 0); let len = bb_data.statements.len(); @@ -585,7 +579,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD // Ensure that the path_map contains entries even // if the lvalue is assigned and never read. let assigned_path = bb_ctxt.builder.move_path_for(lval); - bb_ctxt.path_map.fill_to(assigned_path.idx()); + bb_ctxt.path_map.fill_to(assigned_path.index()); match *rval { Rvalue::Use(ref operand) => { @@ -627,7 +621,9 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD debug!("gather_moves({:?})", bb_data.terminator()); match bb_data.terminator().kind { - TerminatorKind::Goto { target: _ } | TerminatorKind::Resume => { } + TerminatorKind::Goto { target: _ } | + TerminatorKind::Resume | + TerminatorKind::Unreachable => { } TerminatorKind::Return => { let source = Location { block: bb, @@ -679,7 +675,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD } TerminatorKind::DropAndReplace { ref location, ref value, .. } => { let assigned_path = bb_ctxt.builder.move_path_for(location); - bb_ctxt.path_map.fill_to(assigned_path.idx()); + bb_ctxt.path_map.fill_to(assigned_path.index()); let source = Location { block: bb, index: bb_data.statements.len() }; @@ -699,7 +695,7 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD // Ensure that the path_map contains entries even // if the lvalue is assigned and never read. let assigned_path = bb_ctxt.builder.move_path_for(destination); - bb_ctxt.path_map.fill_to(assigned_path.idx()); + bb_ctxt.path_map.fill_to(assigned_path.index()); bb_ctxt.builder.create_move_path(destination); } @@ -729,8 +725,8 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD let mut seen: Vec<_> = move_paths.iter().map(|_| false).collect(); for (j, &MoveOut { ref path, ref source }) in moves.iter().enumerate() { debug!("MovePathData moves[{}]: MoveOut {{ path: {:?} = {:?}, source: {:?} }}", - j, path, move_paths[path.idx()], source); - seen[path.idx()] = true; + j, path, move_paths[path.index()], source); + seen[path.index()] = true; } for (j, path) in move_paths.iter().enumerate() { if !seen[j] { @@ -767,7 +763,7 @@ impl<'b, 'a: 'b, 'tcx: 'a> BlockContext<'b, 'a, 'tcx> { let path = self.builder.move_path_for(lval); self.moves.push(MoveOut { path: path, source: source.clone() }); - self.path_map.fill_to(path.idx()); + self.path_map.fill_to(path.index()); debug!("ctxt: {:?} add consume of lval: {:?} \ at index: {:?} \ @@ -775,12 +771,12 @@ impl<'b, 'a: 'b, 'tcx: 'a> BlockContext<'b, 'a, 'tcx> { to loc_map for loc: {:?}", stmt_kind, lval, index, path, source); - debug_assert!(path.idx() < self.path_map.len()); + debug_assert!(path.index() < self.path_map.len()); // this is actually a questionable assert; at the very // least, incorrect input code can probably cause it to // fire. - assert!(self.path_map[path.idx()].iter().find(|idx| **idx == index).is_none()); - self.path_map[path.idx()].push(index); + assert!(self.path_map[path.index()].iter().find(|idx| **idx == index).is_none()); + self.path_map[path.index()].push(index); debug_assert!(i < self.loc_map_bb.len()); debug_assert!(self.loc_map_bb[i].iter().find(|idx| **idx == index).is_none()); diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 007cde156f40f..270b16fcf49fe 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -111,7 +111,7 @@ pub fn borrowck_mir<'a, 'tcx: 'a>( flow_uninits: flow_uninits, }; - for bb in mir.all_basic_blocks() { + for bb in mir.basic_blocks().indices() { mbcx.process_basic_block(bb); } @@ -180,8 +180,8 @@ pub struct MirBorrowckCtxt<'b, 'a: 'b, 'tcx: 'a> { impl<'b, 'a: 'b, 'tcx: 'a> MirBorrowckCtxt<'b, 'a, 'tcx> { fn process_basic_block(&mut self, bb: BasicBlock) { - let &BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = - self.mir.basic_block_data(bb); + let BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = + self.mir[bb]; for stmt in statements { self.process_statement(bb, stmt); } @@ -298,8 +298,8 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( where F: FnMut(MovePathIndex, DropFlagState) { let move_data = &ctxt.move_data; - for i in 0..(mir.arg_decls.len() as u32) { - let lvalue = repr::Lvalue::Arg(i); + for (arg, _) in mir.arg_decls.iter_enumerated() { + let lvalue = repr::Lvalue::Arg(arg); let move_path_index = move_data.rev_lookup.find(&lvalue); on_all_children_bits(tcx, mir, move_data, move_path_index, @@ -337,8 +337,8 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( |moi| callback(moi, DropFlagState::Absent)) } - let bb = mir.basic_block_data(loc.block); - match bb.statements.get(loc.index) { + let block = &mir[loc.block]; + match block.statements.get(loc.index) { Some(stmt) => match stmt.kind { repr::StatementKind::Assign(ref lvalue, _) => { debug!("drop_flag_effects: assignment {:?}", stmt); @@ -348,8 +348,8 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( } }, None => { - debug!("drop_flag_effects: replace {:?}", bb.terminator()); - match bb.terminator().kind { + debug!("drop_flag_effects: replace {:?}", block.terminator()); + match block.terminator().kind { repr::TerminatorKind::DropAndReplace { ref location, .. } => { on_all_children_bits(tcx, mir, move_data, move_data.rev_lookup.find(location), diff --git a/src/librustc_borrowck/borrowck/mir/patch.rs b/src/librustc_borrowck/borrowck/mir/patch.rs index b838881251da3..417e719a9dcb9 100644 --- a/src/librustc_borrowck/borrowck/mir/patch.rs +++ b/src/librustc_borrowck/borrowck/mir/patch.rs @@ -11,31 +11,28 @@ use super::gather_moves::Location; use rustc::ty::Ty; use rustc::mir::repr::*; - -use std::iter; -use std::u32; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; /// This struct represents a patch to MIR, which can add /// new statements and basic blocks and patch over block /// terminators. pub struct MirPatch<'tcx> { - patch_map: Vec>>, + patch_map: IndexVec>>, new_blocks: Vec>, new_statements: Vec<(Location, StatementKind<'tcx>)>, new_temps: Vec>, resume_block: BasicBlock, - next_temp: u32, + next_temp: usize, } impl<'tcx> MirPatch<'tcx> { pub fn new(mir: &Mir<'tcx>) -> Self { let mut result = MirPatch { - patch_map: iter::repeat(None) - .take(mir.basic_blocks.len()).collect(), + patch_map: IndexVec::from_elem(None, mir.basic_blocks()), new_blocks: vec![], new_temps: vec![], new_statements: vec![], - next_temp: mir.temp_decls.len() as u32, + next_temp: mir.temp_decls.len(), resume_block: START_BLOCK }; @@ -46,13 +43,12 @@ impl<'tcx> MirPatch<'tcx> { let mut resume_block = None; let mut resume_stmt_block = None; - for block in mir.all_basic_blocks() { - let data = mir.basic_block_data(block); - if let TerminatorKind::Resume = data.terminator().kind { - if data.statements.len() > 0 { - resume_stmt_block = Some(block); + for (bb, block) in mir.basic_blocks().iter_enumerated() { + if let TerminatorKind::Resume = block.terminator().kind { + if block.statements.len() > 0 { + resume_stmt_block = Some(bb); } else { - resume_block = Some(block); + resume_block = Some(bb); } break } @@ -83,13 +79,13 @@ impl<'tcx> MirPatch<'tcx> { } pub fn is_patched(&self, bb: BasicBlock) -> bool { - self.patch_map[bb.index()].is_some() + self.patch_map[bb].is_some() } pub fn terminator_loc(&self, mir: &Mir<'tcx>, bb: BasicBlock) -> Location { - let offset = match bb.index().checked_sub(mir.basic_blocks.len()) { + let offset = match bb.index().checked_sub(mir.basic_blocks().len()) { Some(index) => self.new_blocks[index].statements.len(), - None => mir.basic_block_data(bb).statements.len() + None => mir[bb].statements.len() }; Location { block: bb, @@ -97,12 +93,11 @@ impl<'tcx> MirPatch<'tcx> { } } - pub fn new_temp(&mut self, ty: Ty<'tcx>) -> u32 { + pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Temp { let index = self.next_temp; - assert!(self.next_temp < u32::MAX); self.next_temp += 1; self.new_temps.push(TempDecl { ty: ty }); - index + Temp::new(index as usize) } pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { @@ -114,9 +109,9 @@ impl<'tcx> MirPatch<'tcx> { } pub fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) { - assert!(self.patch_map[block.index()].is_none()); + assert!(self.patch_map[block].is_none()); debug!("MirPatch: patch_terminator({:?}, {:?})", block, new); - self.patch_map[block.index()] = Some(new); + self.patch_map[block] = Some(new); } pub fn add_statement(&mut self, loc: Location, stmt: StatementKind<'tcx>) { @@ -132,13 +127,13 @@ impl<'tcx> MirPatch<'tcx> { debug!("MirPatch: {:?} new temps, starting from index {}: {:?}", self.new_temps.len(), mir.temp_decls.len(), self.new_temps); debug!("MirPatch: {} new blocks, starting from index {}", - self.new_blocks.len(), mir.basic_blocks.len()); - mir.basic_blocks.extend(self.new_blocks); + self.new_blocks.len(), mir.basic_blocks().len()); + mir.basic_blocks_mut().extend(self.new_blocks); mir.temp_decls.extend(self.new_temps); - for (src, patch) in self.patch_map.into_iter().enumerate() { + for (src, patch) in self.patch_map.into_iter_enumerated() { if let Some(patch) = patch { debug!("MirPatch: patching block {:?}", src); - mir.basic_blocks[src].terminator_mut().kind = patch; + mir[src].terminator_mut().kind = patch; } } @@ -156,9 +151,9 @@ impl<'tcx> MirPatch<'tcx> { stmt, loc, delta); loc.index += delta; let source_info = Self::source_info_for_index( - mir.basic_block_data(loc.block), loc + &mir[loc.block], loc ); - mir.basic_block_data_mut(loc.block).statements.insert( + mir[loc.block].statements.insert( loc.index, Statement { source_info: source_info, kind: stmt @@ -175,9 +170,9 @@ impl<'tcx> MirPatch<'tcx> { } pub fn source_info_for_location(&self, mir: &Mir, loc: Location) -> SourceInfo { - let data = match loc.block.index().checked_sub(mir.basic_blocks.len()) { + let data = match loc.block.index().checked_sub(mir.basic_blocks().len()) { Some(new) => &self.new_blocks[new], - None => mir.basic_block_data(loc.block) + None => &mir[loc.block] }; Self::source_info_for_index(data, loc) } diff --git a/src/librustc_borrowck/indexed_set.rs b/src/librustc_borrowck/indexed_set.rs index 3fee1dbc05660..671aff97d20aa 100644 --- a/src/librustc_borrowck/indexed_set.rs +++ b/src/librustc_borrowck/indexed_set.rs @@ -17,13 +17,7 @@ use std::ops::{Deref, DerefMut, Range}; use bitslice::{BitSlice, Word}; use bitslice::{bitwise, Union, Subtract}; -/// Represents some newtyped `usize` wrapper. -/// -/// (purpose: avoid mixing indexes for different bitvector domains.) -pub trait Idx: 'static { - fn new(usize) -> Self; - fn idx(&self) -> usize; -} +use rustc_data_structures::indexed_vec::Idx; /// Represents a set (or packed family of sets), of some element type /// E, where each E is identified by some unique index type `T`. @@ -120,27 +114,27 @@ impl IdxSet { /// Removes `elem` from the set `self`; returns true iff this changed `self`. pub fn remove(&mut self, elem: &T) -> bool { - self.bits.clear_bit(elem.idx()) + self.bits.clear_bit(elem.index()) } /// Adds `elem` to the set `self`; returns true iff this changed `self`. pub fn add(&mut self, elem: &T) -> bool { - self.bits.set_bit(elem.idx()) + self.bits.set_bit(elem.index()) } pub fn range(&self, elems: &Range) -> &Self { - let elems = elems.start.idx()..elems.end.idx(); + let elems = elems.start.index()..elems.end.index(); unsafe { Self::from_slice(&self.bits[elems]) } } pub fn range_mut(&mut self, elems: &Range) -> &mut Self { - let elems = elems.start.idx()..elems.end.idx(); + let elems = elems.start.index()..elems.end.index(); unsafe { Self::from_slice_mut(&mut self.bits[elems]) } } /// Returns true iff set `self` contains `elem`. pub fn contains(&self, elem: &T) -> bool { - self.bits.get_bit(elem.idx()) + self.bits.get_bit(elem.index()) } pub fn words(&self) -> &[Word] { diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index cc694c59245f7..f3c39bd5fd165 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -34,6 +34,7 @@ extern crate graphviz as dot; #[macro_use] extern crate rustc; +extern crate rustc_data_structures; extern crate rustc_mir; extern crate core; // for NonZero diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs new file mode 100644 index 0000000000000..db054477f75a1 --- /dev/null +++ b/src/librustc_data_structures/indexed_vec.rs @@ -0,0 +1,228 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::iter::{self, FromIterator}; +use std::slice; +use std::marker::PhantomData; +use std::ops::{Index, IndexMut, Range}; +use std::fmt; +use std::vec; + +use rustc_serialize as serialize; + +/// Represents some newtyped `usize` wrapper. +/// +/// (purpose: avoid mixing indexes for different bitvector domains.) +pub trait Idx: Copy + 'static { + fn new(usize) -> Self; + fn index(self) -> usize; +} + +impl Idx for usize { + fn new(idx: usize) -> Self { idx } + fn index(self) -> usize { self } +} + +#[derive(Clone)] +pub struct IndexVec { + pub raw: Vec, + _marker: PhantomData +} + +impl serialize::Encodable for IndexVec { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + serialize::Encodable::encode(&self.raw, s) + } +} + +impl serialize::Decodable for IndexVec { + fn decode(d: &mut D) -> Result { + serialize::Decodable::decode(d).map(|v| { + IndexVec { raw: v, _marker: PhantomData } + }) + } +} + +impl fmt::Debug for IndexVec { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.raw, fmt) + } +} + +pub type Enumerated = iter::Map, IntoIdx>; + +impl IndexVec { + #[inline] + pub fn new() -> Self { + IndexVec { raw: Vec::new(), _marker: PhantomData } + } + + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + IndexVec { raw: Vec::with_capacity(capacity), _marker: PhantomData } + } + + #[inline] + pub fn from_elem(elem: T, universe: &IndexVec) -> Self + where T: Clone + { + IndexVec { raw: vec![elem; universe.len()], _marker: PhantomData } + } + + #[inline] + pub fn push(&mut self, d: T) -> I { + let idx = I::new(self.len()); + self.raw.push(d); + idx + } + + #[inline] + pub fn len(&self) -> usize { + self.raw.len() + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.raw.is_empty() + } + + #[inline] + pub fn into_iter(self) -> vec::IntoIter { + self.raw.into_iter() + } + + #[inline] + pub fn into_iter_enumerated(self) -> Enumerated> + { + self.raw.into_iter().enumerate().map(IntoIdx { _marker: PhantomData }) + } + + #[inline] + pub fn iter(&self) -> slice::Iter { + self.raw.iter() + } + + #[inline] + pub fn iter_enumerated(&self) -> Enumerated> + { + self.raw.iter().enumerate().map(IntoIdx { _marker: PhantomData }) + } + + #[inline] + pub fn indices(&self) -> iter::Map, IntoIdx> { + (0..self.len()).map(IntoIdx { _marker: PhantomData }) + } + + #[inline] + pub fn iter_mut(&mut self) -> slice::IterMut { + self.raw.iter_mut() + } + + #[inline] + pub fn iter_enumerated_mut(&mut self) -> Enumerated> + { + self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData }) + } + + #[inline] + pub fn last(&self) -> Option { + self.len().checked_sub(1).map(I::new) + } +} + +impl Index for IndexVec { + type Output = T; + + #[inline] + fn index(&self, index: I) -> &T { + &self.raw[index.index()] + } +} + +impl IndexMut for IndexVec { + #[inline] + fn index_mut(&mut self, index: I) -> &mut T { + &mut self.raw[index.index()] + } +} + +impl Extend for IndexVec { + #[inline] + fn extend>(&mut self, iter: J) { + self.raw.extend(iter); + } +} + +impl FromIterator for IndexVec { + #[inline] + fn from_iter(iter: J) -> Self where J: IntoIterator { + IndexVec { raw: FromIterator::from_iter(iter), _marker: PhantomData } + } +} + +impl IntoIterator for IndexVec { + type Item = T; + type IntoIter = vec::IntoIter; + + #[inline] + fn into_iter(self) -> vec::IntoIter { + self.raw.into_iter() + } + +} + +impl<'a, I: Idx, T> IntoIterator for &'a IndexVec { + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + + #[inline] + fn into_iter(self) -> slice::Iter<'a, T> { + self.raw.iter() + } +} + +impl<'a, I: Idx, T> IntoIterator for &'a mut IndexVec { + type Item = &'a mut T; + type IntoIter = slice::IterMut<'a, T>; + + #[inline] + fn into_iter(mut self) -> slice::IterMut<'a, T> { + self.raw.iter_mut() + } +} + +pub struct IntoIdx { _marker: PhantomData } +impl FnOnce<((usize, T),)> for IntoIdx { + type Output = (I, T); + + extern "rust-call" fn call_once(self, ((n, t),): ((usize, T),)) -> Self::Output { + (I::new(n), t) + } +} + +impl FnMut<((usize, T),)> for IntoIdx { + extern "rust-call" fn call_mut(&mut self, ((n, t),): ((usize, T),)) -> Self::Output { + (I::new(n), t) + } +} + +impl FnOnce<(usize,)> for IntoIdx { + type Output = I; + + extern "rust-call" fn call_once(self, (n,): (usize,)) -> Self::Output { + I::new(n) + } +} + +impl FnMut<(usize,)> for IntoIdx { + extern "rust-call" fn call_mut(&mut self, (n,): (usize,)) -> Self::Output { + I::new(n) + } +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 00f797d1b9022..9370ad016ef1e 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -41,6 +41,7 @@ extern crate serialize as rustc_serialize; // used by deriving pub mod bitvec; pub mod graph; pub mod ivar; +pub mod indexed_vec; pub mod obligation_forest; pub mod snapshot_map; pub mod snapshot_vec; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c63122948ff3a..1205d688b85a8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -976,11 +976,13 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, time(time_passes, "MIR passes", || { let mut passes = sess.mir_passes.borrow_mut(); // Push all the built-in passes. - passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks); + passes.push_hook(box mir::transform::dump_mir::DumpMir); + passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("initial")); passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants); passes.push_pass(box mir::transform::type_check::TypeckMir); - passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg); - passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks); + passes.push_pass( + box mir::transform::simplify_branches::SimplifyBranches::new("initial")); + passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("qualify-consts")); // And run everything. passes.run_passes(tcx, &mut mir_map); }); @@ -1046,15 +1048,20 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // to LLVM code. time(time_passes, "Prepare MIR codegen passes", || { let mut passes = ::rustc::mir::transform::Passes::new(); + passes.push_hook(box mir::transform::dump_mir::DumpMir); passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); - passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks); + passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("no-landing-pads")); + passes.push_pass(box mir::transform::erase_regions::EraseRegions); + passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); passes.push_pass(box borrowck::ElaborateDrops); passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); - passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg); + passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("elaborate-drops")); + passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); - passes.push_pass(box mir::transform::dump_mir::DumpMir("pre_trans")); + passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans")); + passes.run_passes(tcx, &mut mir_map); }); diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 95f87bf832614..83f8c3b42c850 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -18,17 +18,15 @@ use rustc::mir::repr::*; impl<'tcx> CFG<'tcx> { pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> { - &self.basic_blocks[blk.index()] + &self.basic_blocks[blk] } pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> { - &mut self.basic_blocks[blk.index()] + &mut self.basic_blocks[blk] } pub fn start_new_block(&mut self) -> BasicBlock { - let node_index = self.basic_blocks.len(); - self.basic_blocks.push(BasicBlockData::new(None)); - BasicBlock::new(node_index) + self.basic_blocks.push(BasicBlockData::new(None)) } pub fn start_new_cleanup_block(&mut self) -> BasicBlock { @@ -80,8 +78,11 @@ impl<'tcx> CFG<'tcx> { block: BasicBlock, source_info: SourceInfo, kind: TerminatorKind<'tcx>) { + debug!("terminating block {:?} <- {:?}", block, kind); debug_assert!(self.block_data(block).terminator.is_none(), - "terminate: block {:?} already has a terminator set", block); + "terminate: block {:?}={:?} already has a terminator set", + block, + self.block_data(block)); self.block_data_mut(block).terminator = Some(Terminator { source_info: source_info, kind: kind, diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 8e33cfa9b0b52..dd6c9c02f5644 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -15,6 +15,8 @@ use build::expr::category::Category; use hair::*; use rustc::mir::repr::*; +use rustc_data_structures::indexed_vec::Idx; + impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr`, yielding an lvalue that we can move from etc. pub fn as_lvalue(&mut self, @@ -75,7 +77,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { success.and(slice.index(idx)) } ExprKind::SelfRef => { - block.and(Lvalue::Arg(0)) + block.and(Lvalue::Arg(Arg::new(0))) } ExprKind::VarRef { id } => { let index = this.var_indices[&id]; diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 6524124c13b06..c0c27ac5943aa 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -14,6 +14,7 @@ use std; use rustc_const_math::{ConstMathErr, Op}; use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::indexed_vec::Idx; use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::{Category, RvalueFunc}; diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 14b4dbdd9cff4..b3315ab7d290f 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -78,12 +78,21 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // branch to the appropriate arm block let otherwise = self.match_candidates(span, &mut arm_blocks, candidates, block); - // because all matches are exhaustive, in principle we expect - // an empty vector to be returned here, but the algorithm is - // not entirely precise if !otherwise.is_empty() { - let join_block = self.join_otherwise_blocks(span, otherwise); - self.panic(join_block, "something about matches algorithm not being precise", span); + // All matches are exhaustive. However, because some matches + // only have exponentially-large exhaustive decision trees, we + // sometimes generate an inexhaustive decision tree. + // + // In that case, the inexhaustive tips of the decision tree + // can't be reached - terminate them with an `unreachable`. + let source_info = self.source_info(span); + + let mut otherwise = otherwise; + otherwise.sort(); + otherwise.dedup(); // variant switches can introduce duplicate target blocks + for block in otherwise { + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + } } // all the arm blocks will rejoin here @@ -667,25 +676,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { name: Name, var_id: NodeId, var_ty: Ty<'tcx>) - -> u32 + -> Var { debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, source_info={:?})", var_id, name, var_ty, source_info); - let index = self.var_decls.len(); - self.var_decls.push(VarDecl::<'tcx> { + let var = self.var_decls.push(VarDecl::<'tcx> { source_info: source_info, mutability: mutability, name: name, ty: var_ty.clone(), }); - let index = index as u32; let extent = self.extent_of_innermost_scope(); - self.schedule_drop(source_info.span, extent, &Lvalue::Var(index), var_ty); - self.var_indices.insert(var_id, index); + self.schedule_drop(source_info.span, extent, &Lvalue::Var(var), var_ty); + self.var_indices.insert(var_id, var); - debug!("declare_binding: index={:?}", index); + debug!("declare_binding: var={:?}", var); - index + var } } diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index a9d5c0c4f85c3..0d7a502834881 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -18,7 +18,6 @@ use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; use rustc::mir::repr::*; -use std::u32; use syntax::ast; use syntax::codemap::Span; @@ -29,12 +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 index = self.temp_decls.len(); - self.temp_decls.push(TempDecl { ty: ty }); - assert!(index < (u32::MAX) as usize); - let lvalue = Lvalue::Temp(index as u32); + let temp = self.temp_decls.push(TempDecl { ty: ty }); + let lvalue = Lvalue::Temp(temp); debug!("temp: created temp {:?} with type {:?}", - lvalue, self.temp_decls.last().unwrap().ty); + lvalue, self.temp_decls[temp].ty); lvalue } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 9c1b9fa4437e0..2626a02281f7d 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -12,15 +12,17 @@ use hair::cx::Cx; use rustc::middle::region::{CodeExtent, CodeExtentData, ROOT_CODE_EXTENT}; use rustc::ty::{self, Ty}; use rustc::mir::repr::*; -use rustc_data_structures::fnv::FnvHashMap; +use rustc::util::nodemap::NodeMap; use rustc::hir; -use std::ops::{Index, IndexMut}; -use std::u32; use syntax::abi::Abi; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token::keywords; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; + +use std::u32; + pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { hir: Cx<'a, 'gcx, 'tcx>, cfg: CFG<'tcx>, @@ -36,7 +38,7 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// but these are liable to get out of date once optimization /// begins. They are also hopefully temporary, and will be /// no longer needed when we adopt graph-based regions. - scope_auxiliary: ScopeAuxiliaryVec, + scope_auxiliary: IndexVec, /// the current set of loops; see the `scope` module for more /// details @@ -44,12 +46,12 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// the vector of all scopes that we have created thus far; /// we track this for debuginfo later - visibility_scopes: Vec, + visibility_scopes: IndexVec, visibility_scope: VisibilityScope, - var_decls: Vec>, - var_indices: FnvHashMap, - temp_decls: Vec>, + var_decls: IndexVec>, + var_indices: NodeMap, + temp_decls: IndexVec>, unit_temp: Option>, /// cached block with the RESUME terminator; this is created @@ -60,19 +62,19 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { } struct CFG<'tcx> { - basic_blocks: Vec>, + basic_blocks: IndexVec>, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct ScopeId(u32); -impl ScopeId { - pub fn new(index: usize) -> ScopeId { +impl Idx for ScopeId { + fn new(index: usize) -> ScopeId { assert!(index < (u32::MAX as usize)); ScopeId(index as u32) } - pub fn index(self) -> usize { + fn index(self) -> usize { self.0 as usize } } @@ -109,25 +111,7 @@ pub struct Location { pub statement_index: usize, } -pub struct ScopeAuxiliaryVec { - pub vec: Vec -} - -impl Index for ScopeAuxiliaryVec { - type Output = ScopeAuxiliary; - - #[inline] - fn index(&self, index: ScopeId) -> &ScopeAuxiliary { - &self.vec[index.index()] - } -} - -impl IndexMut for ScopeAuxiliaryVec { - #[inline] - fn index_mut(&mut self, index: ScopeId) -> &mut ScopeAuxiliary { - &mut self.vec[index.index()] - } -} +pub type ScopeAuxiliaryVec = IndexVec; /////////////////////////////////////////////////////////////////////////// /// The `BlockAnd` "monad" packages up the new basic block along with a @@ -213,8 +197,8 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, 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(arg_decl) = arg_decls.last_mut() { - arg_decl.spread = true; + if let Some(last_arg) = arg_decls.last() { + arg_decls[last_arg].spread = true; } } _ => {} @@ -271,23 +255,23 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, }); let ty = tcx.expr_ty_adjusted(ast_expr); - builder.finish(vec![], vec![], ty::FnConverging(ty)) + builder.finish(vec![], IndexVec::new(), ty::FnConverging(ty)) } impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span) -> Builder<'a, 'gcx, 'tcx> { let mut builder = Builder { hir: hir, - cfg: CFG { basic_blocks: vec![] }, + cfg: CFG { basic_blocks: IndexVec::new() }, fn_span: span, scopes: vec![], - visibility_scopes: vec![], + visibility_scopes: IndexVec::new(), visibility_scope: ARGUMENT_VISIBILITY_SCOPE, - scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] }, + scope_auxiliary: IndexVec::new(), loop_scopes: vec![], - temp_decls: vec![], - var_decls: vec![], - var_indices: FnvHashMap(), + temp_decls: IndexVec::new(), + var_decls: IndexVec::new(), + var_indices: NodeMap(), unit_temp: None, cached_resume_block: None, cached_return_block: None @@ -302,7 +286,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn finish(self, upvar_decls: Vec, - arg_decls: Vec>, + arg_decls: IndexVec>, return_ty: ty::FnOutput<'tcx>) -> (Mir<'tcx>, ScopeAuxiliaryVec) { for (index, block) in self.cfg.basic_blocks.iter().enumerate() { @@ -311,17 +295,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - (Mir { - basic_blocks: self.cfg.basic_blocks, - visibility_scopes: self.visibility_scopes, - promoted: vec![], - var_decls: self.var_decls, - arg_decls: arg_decls, - temp_decls: self.temp_decls, - upvar_decls: upvar_decls, - return_ty: return_ty, - span: self.fn_span - }, self.scope_auxiliary) + (Mir::new(self.cfg.basic_blocks, + self.visibility_scopes, + IndexVec::new(), + return_ty, + self.var_decls, + arg_decls, + self.temp_decls, + upvar_decls, + self.fn_span + ), self.scope_auxiliary) } fn args_and_body(&mut self, @@ -330,13 +313,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { arguments: A, argument_extent: CodeExtent, ast_block: &'gcx hir::Block) - -> BlockAnd>> + -> BlockAnd>> where A: Iterator, Option<&'gcx hir::Pat>)> { // to start, translate the argument patterns and collect the argument types. let mut scope = None; let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| { - let lvalue = Lvalue::Arg(index as u32); + let lvalue = Lvalue::Arg(Arg::new(index)); if let Some(pattern) = pattern { let pattern = self.hir.irrefutable_pat(pattern); scope = self.declare_bindings(scope, ast_block.span, &pattern); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 2b7efa52cbd05..9cc6b60eec005 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -90,12 +90,10 @@ use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId}; use rustc::middle::region::{CodeExtent, CodeExtentData}; use rustc::middle::lang_items; use rustc::ty::subst::{Substs, Subst, VecPerParamSpace}; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{Ty, TyCtxt}; use rustc::mir::repr::*; -use syntax::codemap::{Span, DUMMY_SP}; -use syntax::parse::token::intern_and_get_ident; -use rustc::middle::const_val::ConstVal; -use rustc_const_math::ConstInt; +use syntax::codemap::Span; +use rustc_data_structures::indexed_vec::Idx; pub struct Scope<'tcx> { /// the scope-id within the scope_auxiliary @@ -264,7 +262,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// wrapper maybe preferable. pub fn push_scope(&mut self, extent: CodeExtent, entry: BasicBlock) { debug!("push_scope({:?})", extent); - let id = ScopeId::new(self.scope_auxiliary.vec.len()); + let id = ScopeId::new(self.scope_auxiliary.len()); let vis_scope = self.visibility_scope; self.scopes.push(Scope { id: id, @@ -274,7 +272,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { free: None, cached_block: None, }); - self.scope_auxiliary.vec.push(ScopeAuxiliary { + self.scope_auxiliary.push(ScopeAuxiliary { extent: extent, dom: self.cfg.current_location(entry), postdoms: vec![] @@ -555,50 +553,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { next_target.unit() } - /// Create diverge cleanup and branch to it from `block`. - // FIXME: Remove this (used only for unreachable cases in match). - pub fn panic(&mut self, block: BasicBlock, msg: &'static str, span: Span) { - // fn(&(msg: &'static str filename: &'static str, line: u32)) -> ! - let region = ty::ReStatic; // FIXME(mir-borrowck): use a better region? - let func = self.lang_function(lang_items::PanicFnLangItem); - let args = self.hir.tcx().replace_late_bound_regions(&func.ty.fn_args(), |_| region).0; - - let ref_ty = args[0]; - let tup_ty = if let ty::TyRef(_, tyandmut) = ref_ty.sty { - tyandmut.ty - } else { - span_bug!(span, "unexpected panic type: {:?}", func.ty); - }; - - let (tuple, tuple_ref) = (self.temp(tup_ty), self.temp(ref_ty)); - let (file, line) = self.span_to_fileline_args(span); - let message = Constant { - span: span, - ty: self.hir.tcx().mk_static_str(), - literal: self.hir.str_literal(intern_and_get_ident(msg)) - }; - let elems = vec![Operand::Constant(message), - Operand::Constant(file), - Operand::Constant(line)]; - let source_info = self.source_info(span); - // FIXME: We should have this as a constant, rather than a stack variable (to not pollute - // icache with cold branch code), however to achieve that we either have to rely on rvalue - // promotion or have some way, in MIR, to create constants. - self.cfg.push_assign(block, source_info, &tuple, // [1] - Rvalue::Aggregate(AggregateKind::Tuple, elems)); - // [1] tuple = (message_arg, file_arg, line_arg); - // FIXME: is this region really correct here? - self.cfg.push_assign(block, source_info, &tuple_ref, // tuple_ref = &tuple; - Rvalue::Ref(region, BorrowKind::Shared, tuple)); - let cleanup = self.diverge_cleanup(); - self.cfg.terminate(block, source_info, TerminatorKind::Call { - func: Operand::Constant(func), - args: vec![Operand::Consume(tuple_ref)], - cleanup: cleanup, - destination: None, - }); - } - /// Create an Assert terminator and return the success block. /// If the boolean condition operand is not the expected value, /// a runtime panic will be caused with the given message. @@ -624,39 +578,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { success_block } - - fn lang_function(&mut self, lang_item: lang_items::LangItem) -> Constant<'tcx> { - let funcdid = match self.hir.tcx().lang_items.require(lang_item) { - Ok(d) => d, - Err(m) => { - self.hir.tcx().sess.fatal(&m) - } - }; - Constant { - span: DUMMY_SP, - ty: self.hir.tcx().lookup_item_type(funcdid).ty, - literal: Literal::Item { - def_id: funcdid, - substs: self.hir.tcx().mk_substs(Substs::empty()) - } - } - } - - fn span_to_fileline_args(&mut self, span: Span) -> (Constant<'tcx>, Constant<'tcx>) { - let span_lines = self.hir.tcx().sess.codemap().lookup_char_pos(span.lo); - (Constant { - span: span, - ty: self.hir.tcx().mk_static_str(), - literal: self.hir.str_literal(intern_and_get_ident(&span_lines.file.name)) - }, Constant { - span: span, - ty: self.hir.tcx().types.u32, - literal: Literal::Value { - value: ConstVal::Integral(ConstInt::U32(span_lines.line as u32)), - }, - }) - } - } /// Builds drops for pop_scope and exit_scope. diff --git a/src/librustc_mir/graphviz.rs b/src/librustc_mir/graphviz.rs index 6a34d9ff0b4c4..fdfa872b0b698 100644 --- a/src/librustc_mir/graphviz.rs +++ b/src/librustc_mir/graphviz.rs @@ -15,6 +15,8 @@ use std::fmt::Debug; use std::io::{self, Write}; use syntax::ast::NodeId; +use rustc_data_structures::indexed_vec::Idx; + /// Write a graphviz DOT graph of a list of MIRs. pub fn write_mir_graphviz<'a, 'b, 'tcx, W, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>, iter: I, w: &mut W) @@ -32,12 +34,12 @@ where W: Write, I: Iterator)> { write_graph_label(tcx, nodeid, mir, w)?; // Nodes - for block in mir.all_basic_blocks() { + for (block, _) in mir.basic_blocks().iter_enumerated() { write_node(block, mir, w)?; } // Edges - for source in mir.all_basic_blocks() { + for (source, _) in mir.basic_blocks().iter_enumerated() { write_edges(source, mir, w)?; } writeln!(w, "}}")? @@ -61,7 +63,7 @@ pub fn write_node_label(block: BasicBlock, where INIT: Fn(&mut W) -> io::Result<()>, FINI: Fn(&mut W) -> io::Result<()> { - let data = mir.basic_block_data(block); + let data = &mir[block]; write!(w, r#""#)?; @@ -105,7 +107,7 @@ fn write_node(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<( /// Write graphviz DOT edges with labels between the given basic block and all of its successors. fn write_edges(source: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> { - let terminator = &mir.basic_block_data(source).terminator(); + let terminator = mir[source].terminator(); let labels = terminator.kind.fmt_successor_labels(); for (&target, label) in terminator.successors().iter().zip(labels) { @@ -130,7 +132,7 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if i > 0 { write!(w, ", ")?; } - write!(w, "{:?}: {}", Lvalue::Arg(i as u32), escape(&arg.ty))?; + write!(w, "{:?}: {}", Lvalue::Arg(Arg::new(i)), escape(&arg.ty))?; } write!(w, ") -> ")?; @@ -150,13 +152,13 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>, write!(w, "mut ")?; } write!(w, r#"{:?}: {}; // {}
"#, - Lvalue::Var(i as u32), escape(&var.ty), var.name)?; + 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(i as u32), escape(&temp.ty))?; + Lvalue::Temp(Temp::new(i)), escape(&temp.ty))?; } writeln!(w, ">;") diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 1f560672b62a8..cebdaad13db48 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -10,6 +10,7 @@ use hair::*; use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::indexed_vec::Idx; use rustc_const_math::ConstInt; use hair::cx::Cx; use hair::cx::block; diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 25860ae7ef1ee..81b098281d6a1 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -21,6 +21,7 @@ use rustc::mir::transform::MirSource; use rustc::middle::const_val::ConstVal; use rustc_const_eval as const_eval; +use rustc_data_structures::indexed_vec::Idx; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::FnKind; use rustc::hir::map::blocks::FnLikeNode; diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index acde81979f927..d527936c8993f 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -11,6 +11,7 @@ use hair::*; use hair::cx::Cx; use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::indexed_vec::Idx; use rustc_const_eval as const_eval; use rustc::hir::def::Def; use rustc::hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const}; diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index 8c21928c2513b..856d6cda5af0f 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -14,6 +14,7 @@ use rustc::mir::repr::*; use rustc::mir::transform::MirSource; use rustc::ty::{self, TyCtxt}; use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::indexed_vec::{Idx}; use std::fmt::Display; use std::fs; use std::io::{self, Write}; @@ -111,9 +112,7 @@ fn scope_entry_exit_annotations(auxiliary: Option<&ScopeAuxiliaryVec>) // compute scope/entry exit annotations let mut annotations = FnvHashMap(); if let Some(auxiliary) = auxiliary { - for (index, auxiliary) in auxiliary.vec.iter().enumerate() { - let scope_id = ScopeId::new(index); - + for (scope_id, auxiliary) in auxiliary.iter_enumerated() { annotations.entry(auxiliary.dom) .or_insert(vec![]) .push(Annotation::EnterScope(scope_id)); @@ -136,9 +135,9 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> io::Result<()> { let annotations = scope_entry_exit_annotations(auxiliary); write_mir_intro(tcx, src, mir, w)?; - for block in mir.all_basic_blocks() { + for block in mir.basic_blocks().indices() { write_basic_block(tcx, block, mir, w, &annotations)?; - if block.index() + 1 != mir.basic_blocks.len() { + if block.index() + 1 != mir.basic_blocks().len() { writeln!(w, "")?; } } @@ -154,7 +153,7 @@ fn write_basic_block(tcx: TyCtxt, w: &mut Write, annotations: &FnvHashMap>) -> io::Result<()> { - let data = mir.basic_block_data(block); + let data = &mir[block]; // Basic block label at the top. writeln!(w, "{}{:?}: {{", INDENT, block)?; @@ -218,7 +217,7 @@ 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 (i, var) in mir.var_decls.iter().enumerate() { + for (id, var) in mir.var_decls.iter_enumerated() { // Skip if not declared in this scope. if var.source_info.scope != child { continue; @@ -235,7 +234,7 @@ fn write_scope_tree(tcx: TyCtxt, INDENT, indent, mut_str, - Lvalue::Var(i as u32), + id, var.ty); writeln!(w, "{0:1$} // \"{2}\" in {3}", indented_var, @@ -297,11 +296,11 @@ 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().enumerate() { - if i > 0 { + for (i, arg) in mir.arg_decls.iter_enumerated() { + if i.index() != 0 { write!(w, ", ")?; } - write!(w, "{:?}: {}", Lvalue::Arg(i as u32), arg.ty)?; + write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?; } write!(w, ") -> ")?; @@ -319,8 +318,8 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> { // Compiler-introduced temporary types. - for (i, temp) in mir.temp_decls.iter().enumerate() { - writeln!(w, "{}let mut {:?}: {};", INDENT, Lvalue::Temp(i as u32), temp.ty)?; + 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. diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index 987f12ab71b4a..63e975128c792 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -11,7 +11,8 @@ use rustc::ty::TyCtxt; use rustc::mir::repr::*; use rustc::mir::transform::{MirPass, MirSource, Pass}; -use rustc::mir::traversal; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; + use pretty; pub struct AddCallGuards; @@ -38,38 +39,27 @@ pub struct AddCallGuards; impl<'tcx> MirPass<'tcx> for AddCallGuards { fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { - let mut pred_count = vec![0u32; mir.basic_blocks.len()]; - - // Build the precedecessor map for the MIR - for (_, data) in traversal::preorder(mir) { - if let Some(ref term) = data.terminator { - for &tgt in term.successors().iter() { - pred_count[tgt.index()] += 1; - } - } - } + let pred_count: IndexVec<_, _> = + mir.predecessors().iter().map(|ps| ps.len()).collect(); // We need a place to store the new blocks generated let mut new_blocks = Vec::new(); - let bbs = mir.all_basic_blocks(); - let cur_len = mir.basic_blocks.len(); - - for &bb in &bbs { - let data = mir.basic_block_data_mut(bb); + let cur_len = mir.basic_blocks().len(); - match data.terminator { + for block in mir.basic_blocks_mut() { + match block.terminator { Some(Terminator { kind: TerminatorKind::Call { destination: Some((_, ref mut destination)), cleanup: Some(_), .. }, source_info - }) if pred_count[destination.index()] > 1 => { + }) if pred_count[*destination] > 1 => { // It's a critical edge, break it let call_guard = BasicBlockData { statements: vec![], - is_cleanup: data.is_cleanup, + is_cleanup: block.is_cleanup, terminator: Some(Terminator { source_info: source_info, kind: TerminatorKind::Goto { target: *destination } @@ -88,7 +78,7 @@ impl<'tcx> MirPass<'tcx> for AddCallGuards { pretty::dump_mir(tcx, "break_cleanup_edges", &0, src, mir, None); debug!("Broke {} N edges", new_blocks.len()); - mir.basic_blocks.extend_from_slice(&new_blocks); + mir.basic_blocks_mut().extend(new_blocks); } } diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index fb49f951ecd58..642adeee5cd63 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -10,18 +10,64 @@ //! This pass just dumps MIR at a specified point. +use std::fmt; + use rustc::ty::TyCtxt; use rustc::mir::repr::*; -use rustc::mir::transform::{Pass, MirPass, MirSource}; +use rustc::mir::transform::{Pass, MirPass, MirPassHook, MirSource}; use pretty; -pub struct DumpMir<'a>(pub &'a str); +pub struct Marker<'a>(pub &'a str); + +impl<'b, 'tcx> MirPass<'tcx> for Marker<'b> { + fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, + _src: MirSource, _mir: &mut Mir<'tcx>) + {} +} + +impl<'b> Pass for Marker<'b> { + fn name(&self) -> &str { self.0 } +} + +pub struct Disambiguator<'a> { + pass: &'a Pass, + is_after: bool +} + +impl<'a> fmt::Display for Disambiguator<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let title = if self.is_after { "after" } else { "before" }; + if let Some(fmt) = self.pass.disambiguator() { + write!(formatter, "{}-{}", fmt, title) + } else { + write!(formatter, "{}", title) + } + } +} + +pub struct DumpMir; -impl<'b, 'tcx> MirPass<'tcx> for DumpMir<'b> { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, mir: &mut Mir<'tcx>) { - pretty::dump_mir(tcx, self.0, &0, src, mir, None); +impl<'tcx> MirPassHook<'tcx> for DumpMir { + fn on_mir_pass<'a>( + &mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + pass: &Pass, + is_after: bool) + { + pretty::dump_mir( + tcx, + pass.name(), + &Disambiguator { + pass: pass, + is_after: is_after + }, + src, + mir, + None + ); } } -impl<'b> Pass for DumpMir<'b> {} +impl<'b> Pass for DumpMir {} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 339dcdec06080..7b707b4adb69a 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub mod remove_dead_blocks; +pub mod simplify_branches; pub mod simplify_cfg; pub mod erase_regions; pub mod no_landing_pads; diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 590106e0a225b..818f060ed445c 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -24,6 +24,7 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { TerminatorKind::Goto { .. } | TerminatorKind::Resume | TerminatorKind::Return | + TerminatorKind::Unreachable | TerminatorKind::If { .. } | TerminatorKind::Switch { .. } | TerminatorKind::SwitchInt { .. } => { diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 985bc9ac2d8d7..3ebfef10d4311 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -30,6 +30,8 @@ use syntax::codemap::Span; use build::Location; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; + use std::mem; /// State of a temporary during collection and promotion. @@ -74,7 +76,7 @@ pub enum Candidate { } struct TempCollector { - temps: Vec, + temps: IndexVec, location: Location, span: Span } @@ -89,7 +91,7 @@ impl<'tcx> Visitor<'tcx> for TempCollector { return; } - let temp = &mut self.temps[index as usize]; + let temp = &mut self.temps[index]; if *temp == TempState::Undefined { match context { LvalueContext::Store | @@ -134,9 +136,9 @@ impl<'tcx> Visitor<'tcx> for TempCollector { } } -pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> Vec { +pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec { let mut collector = TempCollector { - temps: vec![TempState::Undefined; mir.temp_decls.len()], + temps: IndexVec::from_elem(TempState::Undefined, &mir.temp_decls), location: Location { block: START_BLOCK, statement_index: 0 @@ -152,7 +154,7 @@ pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> Vec { struct Promoter<'a, 'tcx: 'a> { source: &'a mut Mir<'tcx>, promoted: Mir<'tcx>, - temps: &'a mut Vec, + temps: &'a mut IndexVec, /// If true, all nested temps are also kept in the /// source MIR, not moved to the promoted MIR. @@ -161,23 +163,23 @@ struct Promoter<'a, 'tcx: 'a> { impl<'a, 'tcx> Promoter<'a, 'tcx> { fn new_block(&mut self) -> BasicBlock { - let index = self.promoted.basic_blocks.len(); - self.promoted.basic_blocks.push(BasicBlockData { + let span = self.promoted.span; + self.promoted.basic_blocks_mut().push(BasicBlockData { statements: vec![], terminator: Some(Terminator { source_info: SourceInfo { - span: self.promoted.span, + span: span, scope: ARGUMENT_VISIBILITY_SCOPE }, kind: TerminatorKind::Return }), is_cleanup: false - }); - BasicBlock::new(index) + }) } fn assign(&mut self, dest: Lvalue<'tcx>, rvalue: Rvalue<'tcx>, span: Span) { - let data = self.promoted.basic_blocks.last_mut().unwrap(); + let last = self.promoted.basic_blocks().last().unwrap(); + let data = &mut self.promoted[last]; data.statements.push(Statement { source_info: SourceInfo { span: span, @@ -189,10 +191,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { /// Copy the initialization of this temp to the /// promoted MIR, recursing through temps. - fn promote_temp(&mut self, index: u32) -> u32 { - let index = index as usize; + fn promote_temp(&mut self, temp: Temp) -> Temp { let old_keep_original = self.keep_original; - let (bb, stmt_idx) = match self.temps[index] { + let (bb, stmt_idx) = match self.temps[temp] { TempState::Defined { location: Location { block, statement_index }, uses @@ -202,13 +203,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { } (block, statement_index) } - temp => { - span_bug!(self.promoted.span, "tmp{} not promotable: {:?}", - index, temp); + state => { + span_bug!(self.promoted.span, "{:?} not promotable: {:?}", + temp, state); } }; if !self.keep_original { - self.temps[index] = TempState::PromotedOut; + self.temps[temp] = TempState::PromotedOut; } let no_stmts = self.source[bb].statements.len(); @@ -260,26 +261,24 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { self.visit_terminator_kind(bb, call.as_mut().unwrap()); } - let new_index = self.promoted.temp_decls.len() as u32; - let new_temp = Lvalue::Temp(new_index); - self.promoted.temp_decls.push(TempDecl { - ty: self.source.temp_decls[index].ty + let new_temp = self.promoted.temp_decls.push(TempDecl { + ty: self.source.temp_decls[temp].ty }); // Inject the Rvalue or Call into the promoted MIR. if stmt_idx < no_stmts { - self.assign(new_temp, rvalue.unwrap(), source_info.span); + self.assign(Lvalue::Temp(new_temp), rvalue.unwrap(), source_info.span); } else { - let last = self.promoted.basic_blocks.len() - 1; + 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((new_temp, new_target)); + *destination = Some((Lvalue::Temp(new_temp), new_target)); } _ => bug!() } - let terminator = &mut self.promoted.basic_blocks[last].terminator_mut(); + let terminator = self.promoted[last].terminator_mut(); terminator.source_info.span = source_info.span; terminator.kind = call; } @@ -287,7 +286,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { // Restore the old duplication state. self.keep_original = old_keep_original; - new_index + new_temp } fn promote_candidate(mut self, candidate: Candidate) { @@ -296,7 +295,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { span: span, ty: self.promoted.return_ty.unwrap(), literal: Literal::Promoted { - index: self.source.promoted.len() + index: Promoted::new(self.source.promoted.len()) } }); let mut rvalue = match candidate { @@ -325,8 +324,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { /// Replaces all temporaries with their promoted counterparts. impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { fn visit_lvalue(&mut self, lvalue: &mut Lvalue<'tcx>, context: LvalueContext) { - if let Lvalue::Temp(ref mut index) = *lvalue { - *index = self.promote_temp(*index); + if let Lvalue::Temp(ref mut temp) = *lvalue { + *temp = self.promote_temp(*temp); } self.super_lvalue(lvalue, context); } @@ -334,7 +333,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: Vec, + mut temps: IndexVec, candidates: Vec) { // Visit candidates in reverse, in case they're nested. for candidate in candidates.into_iter().rev() { @@ -343,7 +342,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, let statement = &mir[bb].statements[stmt_idx]; let StatementKind::Assign(ref dest, _) = statement.kind; if let Lvalue::Temp(index) = *dest { - if temps[index as usize] == TempState::PromotedOut { + if temps[index] == TempState::PromotedOut { // Already promoted. continue; } @@ -367,20 +366,20 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, let mut promoter = Promoter { source: mir, - promoted: Mir { - basic_blocks: vec![], - visibility_scopes: vec![VisibilityScopeData { + promoted: Mir::new( + IndexVec::new(), + Some(VisibilityScopeData { span: span, parent_scope: None - }], - promoted: vec![], - return_ty: ty::FnConverging(ty), - var_decls: vec![], - arg_decls: vec![], - temp_decls: vec![], - upvar_decls: vec![], - span: span - }, + }).into_iter().collect(), + IndexVec::new(), + ty::FnConverging(ty), + IndexVec::new(), + IndexVec::new(), + IndexVec::new(), + vec![], + span + ), temps: &mut temps, keep_original: false }; @@ -389,8 +388,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, } // Eliminate assignments to, and drops of promoted temps. - let promoted = |index: u32| temps[index as usize] == TempState::PromotedOut; - for block in &mut mir.basic_blocks { + let promoted = |index: Temp| temps[index] == TempState::PromotedOut; + for block in mir.basic_blocks_mut() { block.statements.retain(|statement| { match statement.kind { StatementKind::Assign(Lvalue::Temp(index), _) => { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 3fdf492611d46..784ddc1ede4f1 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -15,6 +15,7 @@ //! diagnostics as to why a constant rvalue wasn't promoted. use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::FnKind; @@ -24,8 +25,8 @@ use rustc::ty::{self, TyCtxt, Ty}; use rustc::ty::cast::CastTy; use rustc::mir::repr::*; use rustc::mir::mir_map::MirMap; -use rustc::mir::transform::{Pass, MirMapPass, MirSource}; use rustc::mir::traversal::{self, ReversePostorder}; +use rustc::mir::transform::{Pass, MirMapPass, MirPassHook, MirSource}; use rustc::mir::visit::{LvalueContext, Visitor}; use rustc::util::nodemap::DefIdMap; use syntax::abi::Abi; @@ -141,12 +142,12 @@ 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: Vec>, + temp_qualif: IndexVec>, return_qualif: Option, qualif: Qualif, const_fn_arg_vars: BitVector, location: Location, - temp_promotion_state: Vec, + temp_promotion_state: IndexVec, promotion_candidates: Vec } @@ -172,7 +173,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { param_env: param_env, qualif_map: qualif_map, mir_map: mir_map, - temp_qualif: vec![None; mir.temp_decls.len()], + temp_qualif: IndexVec::from_elem(None, &mir.temp_decls), return_qualif: None, qualif: Qualif::empty(), const_fn_arg_vars: BitVector::new(mir.var_decls.len()), @@ -301,22 +302,22 @@ 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 as usize].is_promotable() { - store(&mut self.temp_qualif[index as usize]); + if self.temp_promotion_state[index].is_promotable() { + store(&mut self.temp_qualif[index]); } } return; } match *dest { - Lvalue::Temp(index) => store(&mut self.temp_qualif[index as usize]), + Lvalue::Temp(index) => store(&mut self.temp_qualif[index]), Lvalue::ReturnPointer => store(&mut self.return_qualif), Lvalue::Projection(box Projection { base: Lvalue::Temp(index), elem: ProjectionElem::Deref - }) if self.mir.temp_decls[index as usize].ty.is_unique() - && self.temp_qualif[index as usize].map_or(false, |qualif| { + }) if self.mir.temp_decls[index].ty.is_unique() + && self.temp_qualif[index].map_or(false, |qualif| { qualif.intersects(Qualif::NOT_CONST) }) => { // Part of `box expr`, we should've errored @@ -336,7 +337,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { fn qualify_const(&mut self) -> Qualif { let mir = self.mir; - let mut seen_blocks = BitVector::new(mir.basic_blocks.len()); + let mut seen_blocks = BitVector::new(mir.basic_blocks().len()); let mut bb = START_BLOCK; loop { seen_blocks.insert(bb.index()); @@ -361,17 +362,18 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { TerminatorKind::Switch {..} | TerminatorKind::SwitchInt {..} | TerminatorKind::DropAndReplace { .. } | - TerminatorKind::Resume => None, + TerminatorKind::Resume | + TerminatorKind::Unreachable => None, TerminatorKind::Return => { // Check for unused values. This usually means // there are extra statements in the AST. - for i in 0..mir.temp_decls.len() { - if self.temp_qualif[i].is_none() { + for temp in mir.temp_decls.indices() { + if self.temp_qualif[temp].is_none() { continue; } - let state = self.temp_promotion_state[i]; + let state = self.temp_promotion_state[temp]; if let TempState::Defined { location, uses: 0 } = state { let data = &mir[location.block]; let stmt_idx = location.statement_index; @@ -393,7 +395,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { 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(index as u32)); + self.assign(&Lvalue::Var(Var::new(index))); } } @@ -448,11 +450,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.add(Qualif::NOT_CONST); } Lvalue::Temp(index) => { - if !self.temp_promotion_state[index as usize].is_promotable() { + if !self.temp_promotion_state[index].is_promotable() { self.add(Qualif::NOT_PROMOTABLE); } - if let Some(qualif) = self.temp_qualif[index as usize] { + if let Some(qualif) = self.temp_qualif[index] { self.add(qualif); } else { self.not_const(); @@ -822,7 +824,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // 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 as usize) { + if 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; @@ -830,7 +832,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Avoid a generic error for other uses of arguments. if self.qualif.intersects(Qualif::FN_ARGUMENT) { - let decl = &self.mir.var_decls[index as usize]; + let decl = &self.mir.var_decls[index]; span_err!(self.tcx.sess, decl.source_info.span, E0022, "arguments of constant functions can only \ be immutable by-value bindings"); @@ -907,7 +909,10 @@ pub struct QualifyAndPromoteConstants; impl Pass for QualifyAndPromoteConstants {} impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>) { + fn run_pass<'a>(&mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + map: &mut MirMap<'tcx>, + hooks: &mut [Box MirPassHook<'s>>]) { let mut qualif_map = DefIdMap(); // First, visit `const` items, potentially recursing, to get @@ -943,6 +948,10 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { }; let param_env = ty::ParameterEnvironment::for_item(tcx, id); + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, mir, self, false); + } + if mode == Mode::Fn || mode == Mode::ConstFn { // This is ugly because Qualifier holds onto mir, // which can't be mutated until its scope ends. @@ -970,6 +979,10 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { qualifier.qualify_const(); } + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, mir, self, true); + } + // Statics must be Sync. if mode == Mode::Static { let ty = mir.return_ty.unwrap(); diff --git a/src/librustc_mir/transform/remove_dead_blocks.rs b/src/librustc_mir/transform/remove_dead_blocks.rs deleted file mode 100644 index 44f3ce7361cf4..0000000000000 --- a/src/librustc_mir/transform/remove_dead_blocks.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A pass that erases the contents of dead blocks. This pass must -//! run before any analysis passes because some of the dead blocks -//! can be ill-typed. -//! -//! The main problem is that typeck lets most blocks whose end is not -//! reachable have an arbitrary return type, rather than having the -//! usual () return type (as a note, typeck's notion of reachability -//! is in fact slightly weaker than MIR CFG reachability - see #31617). -//! -//! A standard example of the situation is: -//! ```rust -//! fn example() { -//! let _a: char = { return; }; -//! } -//! ``` -//! -//! Here the block (`{ return; }`) has the return type `char`, -//! rather than `()`, but the MIR we naively generate still contains -//! the `_a = ()` write in the unreachable block "after" the return. -//! -//! As we have to run this pass even when we want to debug the MIR, -//! this pass just replaces the blocks with empty "return" blocks -//! and does not renumber anything. - -use rustc_data_structures::bitvec::BitVector; -use rustc::ty::TyCtxt; -use rustc::mir::repr::*; -use rustc::mir::transform::{Pass, MirPass, MirSource}; - -pub struct RemoveDeadBlocks; - -impl<'tcx> MirPass<'tcx> for RemoveDeadBlocks { - fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource, mir: &mut Mir<'tcx>) { - let mut seen = BitVector::new(mir.basic_blocks.len()); - // This block is always required. - seen.insert(START_BLOCK.index()); - - let mut worklist = Vec::with_capacity(4); - worklist.push(START_BLOCK); - while let Some(bb) = worklist.pop() { - for succ in mir.basic_block_data(bb).terminator().successors().iter() { - if seen.insert(succ.index()) { - worklist.push(*succ); - } - } - } - retain_basic_blocks(mir, &seen); - } -} - -impl Pass for RemoveDeadBlocks {} - -/// Mass removal of basic blocks to keep the ID-remapping cheap. -fn retain_basic_blocks(mir: &mut Mir, keep: &BitVector) { - let num_blocks = mir.basic_blocks.len(); - - let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); - let mut used_blocks = 0; - for alive_index in keep.iter() { - replacements[alive_index] = BasicBlock::new(used_blocks); - if alive_index != used_blocks { - // Swap the next alive block data with the current available slot. Since alive_index is - // non-decreasing this is a valid operation. - mir.basic_blocks.swap(alive_index, used_blocks); - } - used_blocks += 1; - } - mir.basic_blocks.truncate(used_blocks); - - for bb in mir.all_basic_blocks() { - for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() { - *target = replacements[target.index()]; - } - } -} diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs new file mode 100644 index 0000000000000..f93de6ca382bb --- /dev/null +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -0,0 +1,63 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A pass that simplifies branches when their condition is known. + +use rustc::ty::TyCtxt; +use rustc::middle::const_val::ConstVal; +use rustc::mir::transform::{MirPass, MirSource, Pass}; +use rustc::mir::repr::*; + +use std::fmt; + +pub struct SimplifyBranches<'a> { label: &'a str } + +impl<'a> SimplifyBranches<'a> { + pub fn new(label: &'a str) -> Self { + SimplifyBranches { label: label } + } +} + +impl<'l, 'tcx> MirPass<'tcx> for SimplifyBranches<'l> { + fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) { + for block in mir.basic_blocks_mut() { + let terminator = block.terminator_mut(); + terminator.kind = match terminator.kind { + TerminatorKind::If { ref targets, cond: Operand::Constant(Constant { + literal: Literal::Value { + value: ConstVal::Bool(cond) + }, .. + }) } => { + if cond { + TerminatorKind::Goto { target: targets.0 } + } else { + TerminatorKind::Goto { target: targets.1 } + } + } + + TerminatorKind::Assert { target, cond: Operand::Constant(Constant { + literal: Literal::Value { + value: ConstVal::Bool(cond) + }, .. + }), expected, .. } if cond == expected => { + TerminatorKind::Goto { target: target } + } + + _ => continue + }; + } + } +} + +impl<'l> Pass for SimplifyBranches<'l> { + fn disambiguator<'a>(&'a self) -> Option> { + Some(Box::new(self.label)) + } +} diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index 3a0055c564feb..8bbcc3fe2d70f 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -8,197 +8,239 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! A pass that removes various redundancies in the CFG. It should be +//! called after every significant CFG modification to tidy things +//! up. +//! +//! This pass must also be run before any analysis passes because it removes +//! dead blocks, and some of these can be ill-typed. +//! +//! The cause of that is that typeck lets most blocks whose end is not +//! reachable have an arbitrary return type, rather than having the +//! usual () return type (as a note, typeck's notion of reachability +//! is in fact slightly weaker than MIR CFG reachability - see #31617). +//! +//! A standard example of the situation is: +//! ```rust +//! fn example() { +//! let _a: char = { return; }; +//! } +//! ``` +//! +//! Here the block (`{ return; }`) has the return type `char`, +//! rather than `()`, but the MIR we naively generate still contains +//! the `_a = ()` write in the unreachable block "after" the return. + + use rustc_data_structures::bitvec::BitVector; -use rustc::middle::const_val::ConstVal; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::ty::TyCtxt; use rustc::mir::repr::*; use rustc::mir::transform::{MirPass, MirSource, Pass}; use rustc::mir::traversal; -use pretty; -use std::mem; - -use super::remove_dead_blocks::RemoveDeadBlocks; +use std::fmt; -pub struct SimplifyCfg; +pub struct SimplifyCfg<'a> { label: &'a str } -impl SimplifyCfg { - pub fn new() -> SimplifyCfg { - SimplifyCfg +impl<'a> SimplifyCfg<'a> { + pub fn new(label: &'a str) -> Self { + SimplifyCfg { label: label } } } -impl<'tcx> MirPass<'tcx> for SimplifyCfg { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { - simplify_branches(mir); - RemoveDeadBlocks.run_pass(tcx, src, mir); - merge_consecutive_blocks(mir); - RemoveDeadBlocks.run_pass(tcx, src, mir); - pretty::dump_mir(tcx, "simplify_cfg", &0, src, mir, None); +impl<'l, 'tcx> MirPass<'tcx> for SimplifyCfg<'l> { + fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) { + CfgSimplifier::new(mir).simplify(); + remove_dead_blocks(mir); // FIXME: Should probably be moved into some kind of pass manager - mir.basic_blocks.shrink_to_fit(); + mir.basic_blocks_mut().raw.shrink_to_fit(); } } -impl Pass for SimplifyCfg {} +impl<'l> Pass for SimplifyCfg<'l> { + fn disambiguator<'a>(&'a self) -> Option> { + Some(Box::new(self.label)) + } +} -fn merge_consecutive_blocks(mir: &mut Mir) { - // Build the precedecessor map for the MIR - let mut pred_count = vec![0u32; mir.basic_blocks.len()]; - for (_, data) in traversal::preorder(mir) { - if let Some(ref term) = data.terminator { - for &tgt in term.successors().iter() { - pred_count[tgt.index()] += 1; +pub struct CfgSimplifier<'a, 'tcx: 'a> { + basic_blocks: &'a mut IndexVec>, + pred_count: IndexVec +} + +impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { + fn new(mir: &'a mut Mir<'tcx>) -> Self { + let mut pred_count = IndexVec::from_elem(0u32, mir.basic_blocks()); + + // we can't use mir.predecessors() here because that counts + // dead blocks, which we don't want to. + for (_, data) in traversal::preorder(mir) { + if let Some(ref term) = data.terminator { + for &tgt in term.successors().iter() { + pred_count[tgt] += 1; + } } } + + let basic_blocks = mir.basic_blocks_mut(); + + CfgSimplifier { + basic_blocks: basic_blocks, + pred_count: pred_count + } } - loop { - let mut changed = false; - let mut seen = BitVector::new(mir.basic_blocks.len()); - let mut worklist = vec![START_BLOCK]; - while let Some(bb) = worklist.pop() { - // Temporarily take ownership of the terminator we're modifying to keep borrowck happy - let mut terminator = mir.basic_block_data_mut(bb).terminator.take() - .expect("invalid terminator state"); - - // See if we can merge the target block into this one - loop { - let mut inner_change = false; - - if let TerminatorKind::Goto { target } = terminator.kind { - // Don't bother trying to merge a block into itself - if target == bb { - break; - } - - let num_insts = mir.basic_block_data(target).statements.len(); - match mir.basic_block_data(target).terminator().kind { - TerminatorKind::Goto { target: new_target } if num_insts == 0 => { - inner_change = true; - terminator.kind = TerminatorKind::Goto { target: new_target }; - pred_count[target.index()] -= 1; - pred_count[new_target.index()] += 1; - } - _ if pred_count[target.index()] == 1 => { - inner_change = true; - let mut stmts = Vec::new(); - { - let target_data = mir.basic_block_data_mut(target); - mem::swap(&mut stmts, &mut target_data.statements); - mem::swap(&mut terminator, target_data.terminator_mut()); - } - - mir.basic_block_data_mut(bb).statements.append(&mut stmts); - } - _ => {} - }; + fn simplify(mut self) { + loop { + let mut changed = false; + + for bb in (0..self.basic_blocks.len()).map(BasicBlock::new) { + if self.pred_count[bb] == 0 { + continue } - for target in terminator.successors_mut() { - let new_target = match final_target(mir, *target) { - Some(new_target) => new_target, - None if mir.basic_block_data(bb).statements.is_empty() => bb, - None => continue - }; - if *target != new_target { - inner_change = true; - pred_count[target.index()] -= 1; - pred_count[new_target.index()] += 1; - *target = new_target; - } + debug!("simplifying {:?}", bb); + + let mut terminator = self.basic_blocks[bb].terminator.take() + .expect("invalid terminator state"); + + for successor in terminator.successors_mut() { + self.collapse_goto_chain(successor, &mut changed); } - changed |= inner_change; - if !inner_change { - break; + let mut new_stmts = vec![]; + let mut inner_changed = true; + while inner_changed { + inner_changed = false; + inner_changed |= self.simplify_branch(&mut terminator); + inner_changed |= self.merge_successor(&mut new_stmts, &mut terminator); + changed |= inner_changed; } - } - mir.basic_block_data_mut(bb).terminator = Some(terminator); + self.basic_blocks[bb].statements.extend(new_stmts); + self.basic_blocks[bb].terminator = Some(terminator); - for succ in mir.basic_block_data(bb).terminator().successors().iter() { - if seen.insert(succ.index()) { - worklist.push(*succ); - } + changed |= inner_changed; } - } - if !changed { - break; + if !changed { break } } } -} -// Find the target at the end of the jump chain, return None if there is a loop -fn final_target(mir: &Mir, mut target: BasicBlock) -> Option { - // Keep track of already seen blocks to detect loops - let mut seen: Vec = Vec::with_capacity(8); - - while mir.basic_block_data(target).statements.is_empty() { - // NB -- terminator may have been swapped with `None` in - // merge_consecutive_blocks, in which case we have a cycle and just want - // to stop - match mir.basic_block_data(target).terminator { - Some(Terminator { kind: TerminatorKind::Goto { target: next }, .. }) => { - if seen.contains(&next) { - return None; - } - seen.push(next); - target = next; + // Collapse a goto chain starting from `start` + fn collapse_goto_chain(&mut self, start: &mut BasicBlock, changed: &mut bool) { + let mut terminator = match self.basic_blocks[*start] { + BasicBlockData { + ref statements, + terminator: ref mut terminator @ Some(Terminator { + kind: TerminatorKind::Goto { .. }, .. + }), .. + } if statements.is_empty() => terminator.take(), + // if `terminator` is None, this means we are in a loop. In that + // case, let all the loop collapse to its entry. + _ => return + }; + + let target = match terminator { + Some(Terminator { kind: TerminatorKind::Goto { ref mut target }, .. }) => { + self.collapse_goto_chain(target, changed); + *target } - _ => break - } - } + _ => unreachable!() + }; + self.basic_blocks[*start].terminator = terminator; - Some(target) -} + debug!("collapsing goto chain from {:?} to {:?}", *start, target); -fn simplify_branches(mir: &mut Mir) { - loop { - let mut changed = false; - - for bb in mir.all_basic_blocks() { - let basic_block = mir.basic_block_data_mut(bb); - let mut terminator = basic_block.terminator_mut(); - terminator.kind = match terminator.kind { - TerminatorKind::If { ref targets, .. } if targets.0 == targets.1 => { - changed = true; - TerminatorKind::Goto { target: targets.0 } - } + *changed |= *start != target; + self.pred_count[target] += 1; + self.pred_count[*start] -= 1; + *start = target; + } - TerminatorKind::If { ref targets, cond: Operand::Constant(Constant { - literal: Literal::Value { - value: ConstVal::Bool(cond) - }, .. - }) } => { - changed = true; - if cond { - TerminatorKind::Goto { target: targets.0 } - } else { - TerminatorKind::Goto { target: targets.1 } - } - } + // merge a block with 1 `goto` predecessor to its parent + fn merge_successor(&mut self, + new_stmts: &mut Vec>, + terminator: &mut Terminator<'tcx>) + -> bool + { + let target = match terminator.kind { + TerminatorKind::Goto { target } + if self.pred_count[target] == 1 + => target, + _ => return false + }; + + debug!("merging block {:?} into {:?}", target, terminator); + *terminator = match self.basic_blocks[target].terminator.take() { + Some(terminator) => terminator, + None => { + // unreachable loop - this should not be possible, as we + // don't strand blocks, but handle it correctly. + return false + } + }; + new_stmts.extend(self.basic_blocks[target].statements.drain(..)); + self.pred_count[target] = 0; - TerminatorKind::Assert { target, cond: Operand::Constant(Constant { - literal: Literal::Value { - value: ConstVal::Bool(cond) - }, .. - }), expected, .. } if cond == expected => { - changed = true; - TerminatorKind::Goto { target: target } - } + true + } - TerminatorKind::SwitchInt { ref targets, .. } if targets.len() == 1 => { - changed = true; - TerminatorKind::Goto { target: targets[0] } + // turn a branch with all successors identical to a goto + fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool { + match terminator.kind { + TerminatorKind::If { .. } | + TerminatorKind::Switch { .. } | + TerminatorKind::SwitchInt { .. } => {}, + _ => return false + }; + + let first_succ = { + let successors = terminator.successors(); + if let Some(&first_succ) = terminator.successors().get(0) { + if successors.iter().all(|s| *s == first_succ) { + self.pred_count[first_succ] -= (successors.len()-1) as u32; + first_succ + } else { + return false } - _ => continue + } else { + return false } + }; + + debug!("simplifying branch {:?}", terminator); + terminator.kind = TerminatorKind::Goto { target: first_succ }; + true + } +} + +fn remove_dead_blocks(mir: &mut Mir) { + let mut seen = BitVector::new(mir.basic_blocks().len()); + for (bb, _) in traversal::preorder(mir) { + seen.insert(bb.index()); + } + + let basic_blocks = mir.basic_blocks_mut(); + + let num_blocks = basic_blocks.len(); + let mut replacements : Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); + let mut used_blocks = 0; + for alive_index in seen.iter() { + replacements[alive_index] = BasicBlock::new(used_blocks); + if alive_index != used_blocks { + // Swap the next alive block data with the current available slot. Since alive_index is + // non-decreasing this is a valid operation. + basic_blocks.raw.swap(alive_index, used_blocks); } + used_blocks += 1; + } + basic_blocks.raw.truncate(used_blocks); - if !changed { - break; + for block in basic_blocks { + for target in block.terminator_mut().successors_mut() { + *target = replacements[target.index()]; } } } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index c38f1f1e6c0fa..e4398fcab3163 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -24,6 +24,8 @@ use rustc::mir::visit::{self, Visitor}; use std::fmt; use syntax::codemap::{Span, DUMMY_SP}; +use rustc_data_structures::indexed_vec::Idx; + macro_rules! span_mirbug { ($context:expr, $elem:expr, $($message:tt)*) => ({ $context.tcx().sess.span_warn( @@ -129,11 +131,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>) -> LvalueTy<'tcx> { debug!("sanitize_lvalue: {:?}", lvalue); match *lvalue { - Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index as usize].ty }, - Lvalue::Temp(index) => - LvalueTy::Ty { ty: self.mir.temp_decls[index as usize].ty }, - Lvalue::Arg(index) => - LvalueTy::Ty { ty: self.mir.arg_decls[index as usize].ty }, + 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::Static(def_id) => LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty }, Lvalue::ReturnPointer => { @@ -379,6 +379,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { TerminatorKind::Goto { .. } | TerminatorKind::Resume | TerminatorKind::Return | + TerminatorKind::Unreachable | TerminatorKind::Drop { .. } => { // no checks needed for these } @@ -595,6 +596,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { span_mirbug!(self, block, "return on cleanup block") } } + TerminatorKind::Unreachable => {} TerminatorKind::Drop { target, unwind, .. } | TerminatorKind::DropAndReplace { target, unwind, .. } | TerminatorKind::Assert { target, cleanup: unwind, .. } => { @@ -626,7 +628,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { bb: BasicBlock, iscleanuppad: bool) { - if mir.basic_block_data(bb).is_cleanup != iscleanuppad { + if mir[bb].is_cleanup != iscleanuppad { span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}", bb, iscleanuppad); } @@ -635,7 +637,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn typeck_mir(&mut self, mir: &Mir<'tcx>) { self.last_span = mir.span; debug!("run_on_mir: {:?}", mir.span); - for block in &mir.basic_blocks { + for block in mir.basic_blocks() { for stmt in &block.statements { if stmt.source_info.span != DUMMY_SP { self.last_span = stmt.source_info.span; diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index b7e8e618abbc4..381bd24d9a4ae 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1844,7 +1844,10 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, attributes::emit_uwtable(llfndecl, true); } - debug!("trans_closure(..., {})", instance); + // this is an info! to allow collecting monomorphization statistics + // and to allow finding the last function before LLVM aborts from + // release builds. + info!("trans_closure(..., {})", instance); let fn_ty = FnType::new(ccx, abi, sig, &[]); diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index f75f973f68aab..f1d9e2c5a5710 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -26,6 +26,7 @@ use syntax::codemap::{Span, Pos}; use syntax::{ast, codemap}; use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::hir::{self, PatKind}; // This procedure builds the *scope map* for a given function, which maps any @@ -69,9 +70,9 @@ pub fn create_scope_map(cx: &CrateContext, /// Produce DIScope DIEs for each MIR Scope which has variables defined in it. /// If debuginfo is disabled, the returned vector is empty. -pub fn create_mir_scopes(fcx: &FunctionContext) -> Vec { +pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec { let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn"); - let mut scopes = vec![ptr::null_mut(); mir.visibility_scopes.len()]; + let mut scopes = IndexVec::from_elem(ptr::null_mut(), &mir.visibility_scopes); let fn_metadata = match fcx.debug_context { FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata, @@ -101,23 +102,22 @@ fn make_mir_scope(ccx: &CrateContext, has_variables: &BitVector, fn_metadata: DISubprogram, scope: VisibilityScope, - scopes: &mut [DIScope]) { - let idx = scope.index(); - if !scopes[idx].is_null() { + scopes: &mut IndexVec) { + if !scopes[scope].is_null() { return; } let scope_data = &mir.visibility_scopes[scope]; let parent_scope = if let Some(parent) = scope_data.parent_scope { make_mir_scope(ccx, mir, has_variables, fn_metadata, parent, scopes); - scopes[parent.index()] + scopes[parent] } else { // The root is the function itself. - scopes[idx] = fn_metadata; + scopes[scope] = fn_metadata; return; }; - if !has_variables.contains(idx) { + if !has_variables.contains(scope.index()) { // Do not create a DIScope if there are no variables // defined in this MIR Scope, to avoid debuginfo bloat. @@ -125,14 +125,14 @@ fn make_mir_scope(ccx: &CrateContext, // our parent is the root, because we might want to // put arguments in the root and not have shadowing. if parent_scope != fn_metadata { - scopes[idx] = parent_scope; + scopes[scope] = parent_scope; return; } } let loc = span_start(ccx, scope_data.span); let file_metadata = file_metadata(ccx, &loc.file.name); - scopes[idx] = unsafe { + scopes[scope] = unsafe { llvm::LLVMDIBuilderCreateLexicalBlock( DIB(ccx), parent_scope, diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 4476163a7f108..d1c1053ac46b2 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -12,6 +12,7 @@ //! which do not. use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::mir::repr as mir; use rustc::mir::repr::TerminatorKind; use rustc::mir::visit::{Visitor, LvalueContext}; @@ -94,10 +95,10 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for TempAnalyzer<'mir, 'bcx, 'tcx> { debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue); match *lvalue { - mir::Lvalue::Temp(index) => { - self.mark_assigned(index as usize); + mir::Lvalue::Temp(temp) => { + self.mark_assigned(temp.index()); if !rvalue::rvalue_creates_operand(self.mir, self.bcx, rvalue) { - self.mark_as_lvalue(index as usize); + self.mark_as_lvalue(temp.index()); } } _ => { @@ -115,8 +116,8 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for TempAnalyzer<'mir, 'bcx, 'tcx> { // Allow uses of projections of immediate pair fields. if let mir::Lvalue::Projection(ref proj) = *lvalue { - if let mir::Lvalue::Temp(index) = proj.base { - let ty = self.mir.temp_decls[index as usize].ty; + if let mir::Lvalue::Temp(temp) = proj.base { + let ty = self.mir.temp_decls[temp].ty; let ty = self.bcx.monomorphize(&ty); if common::type_is_imm_pair(self.bcx.ccx(), ty) { if let mir::ProjectionElem::Field(..) = proj.elem { @@ -129,10 +130,10 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for TempAnalyzer<'mir, 'bcx, 'tcx> { } match *lvalue { - mir::Lvalue::Temp(index) => { + mir::Lvalue::Temp(temp) => { match context { LvalueContext::Call => { - self.mark_assigned(index as usize); + self.mark_assigned(temp.index()); } LvalueContext::Consume => { } @@ -142,7 +143,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for TempAnalyzer<'mir, 'bcx, 'tcx> { LvalueContext::Borrow { .. } | LvalueContext::Slice { .. } | LvalueContext::Projection => { - self.mark_as_lvalue(index as usize); + self.mark_as_lvalue(temp.index()); } } } @@ -163,15 +164,16 @@ pub enum CleanupKind { pub fn cleanup_kinds<'bcx,'tcx>(_bcx: Block<'bcx,'tcx>, mir: &mir::Mir<'tcx>) - -> Vec + -> IndexVec { - fn discover_masters<'tcx>(result: &mut [CleanupKind], mir: &mir::Mir<'tcx>) { - for bb in mir.all_basic_blocks() { - let data = mir.basic_block_data(bb); + fn discover_masters<'tcx>(result: &mut IndexVec, + mir: &mir::Mir<'tcx>) { + for (bb, data) in mir.basic_blocks().iter_enumerated() { match data.terminator().kind { TerminatorKind::Goto { .. } | TerminatorKind::Resume | TerminatorKind::Return | + TerminatorKind::Unreachable | TerminatorKind::If { .. } | TerminatorKind::Switch { .. } | TerminatorKind::SwitchInt { .. } => { @@ -184,19 +186,19 @@ pub fn cleanup_kinds<'bcx,'tcx>(_bcx: Block<'bcx,'tcx>, if let Some(unwind) = unwind { debug!("cleanup_kinds: {:?}/{:?} registering {:?} as funclet", bb, data, unwind); - result[unwind.index()] = CleanupKind::Funclet; + result[unwind] = CleanupKind::Funclet; } } } } } - fn propagate<'tcx>(result: &mut [CleanupKind], mir: &mir::Mir<'tcx>) { - let mut funclet_succs : Vec<_> = - mir.all_basic_blocks().iter().map(|_| None).collect(); + fn propagate<'tcx>(result: &mut IndexVec, + mir: &mir::Mir<'tcx>) { + let mut funclet_succs = IndexVec::from_elem(None, mir.basic_blocks()); let mut set_successor = |funclet: mir::BasicBlock, succ| { - match funclet_succs[funclet.index()] { + match funclet_succs[funclet] { ref mut s @ None => { debug!("set_successor: updating successor of {:?} to {:?}", funclet, succ); @@ -210,22 +212,22 @@ pub fn cleanup_kinds<'bcx,'tcx>(_bcx: Block<'bcx,'tcx>, }; for (bb, data) in traversal::reverse_postorder(mir) { - let funclet = match result[bb.index()] { + let funclet = match result[bb] { CleanupKind::NotCleanup => continue, CleanupKind::Funclet => bb, CleanupKind::Internal { funclet } => funclet, }; debug!("cleanup_kinds: {:?}/{:?}/{:?} propagating funclet {:?}", - bb, data, result[bb.index()], funclet); + bb, data, result[bb], funclet); for &succ in data.terminator().successors().iter() { - let kind = result[succ.index()]; + let kind = result[succ]; debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}", funclet, succ, kind); match kind { CleanupKind::NotCleanup => { - result[succ.index()] = CleanupKind::Internal { funclet: funclet }; + result[succ] = CleanupKind::Internal { funclet: funclet }; } CleanupKind::Funclet => { set_successor(funclet, succ); @@ -237,7 +239,7 @@ pub fn cleanup_kinds<'bcx,'tcx>(_bcx: Block<'bcx,'tcx>, debug!("promoting {:?} to a funclet and updating {:?}", succ, succ_funclet); - result[succ.index()] = CleanupKind::Funclet; + result[succ] = CleanupKind::Funclet; set_successor(succ_funclet, succ); set_successor(funclet, succ); } @@ -247,8 +249,7 @@ pub fn cleanup_kinds<'bcx,'tcx>(_bcx: Block<'bcx,'tcx>, } } - let mut result : Vec<_> = - mir.all_basic_blocks().iter().map(|_| CleanupKind::NotCleanup).collect(); + let mut result = IndexVec::from_elem(CleanupKind::NotCleanup, mir.basic_blocks()); discover_masters(&mut result, mir); propagate(&mut result, mir); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 88c3fede1e1ed..bdcf3dd8cd418 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -43,7 +43,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_block(&mut self, bb: mir::BasicBlock) { let mut bcx = self.bcx(bb); let mir = self.mir.clone(); - let data = mir.basic_block_data(bb); + let data = &mir[bb]; debug!("trans_block({:?}={:?})", bb, data); @@ -52,9 +52,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let cleanup_bundle = bcx.lpad().and_then(|l| l.bundle()); let funclet_br = |this: &Self, bcx: BlockAndBuilder, bb: mir::BasicBlock| { - let lltarget = this.blocks[bb.index()].llbb; + let lltarget = this.blocks[bb].llbb; if let Some(cp) = cleanup_pad { - match this.cleanup_kind(bb) { + match this.cleanup_kinds[bb] { CleanupKind::Funclet => { // micro-optimization: generate a `ret` rather than a jump // to a return block @@ -69,10 +69,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { }; let llblock = |this: &mut Self, target: mir::BasicBlock| { - let lltarget = this.blocks[target.index()].llbb; + let lltarget = this.blocks[target].llbb; if let Some(cp) = cleanup_pad { - match this.cleanup_kind(target) { + match this.cleanup_kinds[target] { CleanupKind::Funclet => { // MSVC cross-funclet jump - need a trampoline @@ -89,7 +89,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } else { if let (CleanupKind::NotCleanup, CleanupKind::Funclet) = - (this.cleanup_kind(bb), this.cleanup_kind(target)) + (this.cleanup_kinds[bb], this.cleanup_kinds[target]) { // jump *into* cleanup - need a landing pad if GNU this.landing_pad_to(target).llbb @@ -191,6 +191,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { }) } + mir::TerminatorKind::Unreachable => { + bcx.unreachable(); + } + mir::TerminatorKind::Drop { ref location, target, unwind } => { let lvalue = self.trans_lvalue(&bcx, location); let ty = lvalue.ty.to_ty(bcx.tcx()); @@ -209,7 +213,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { if let Some(unwind) = unwind { bcx.invoke(drop_fn, &[llvalue], - self.blocks[target.index()].llbb, + self.blocks[target].llbb, llblock(self, unwind), cleanup_bundle); } else { @@ -488,7 +492,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // Many different ways to call a function handled here if let &Some(cleanup) = cleanup { let ret_bcx = if let Some((_, target)) = *destination { - self.blocks[target.index()] + self.blocks[target] } else { self.unreachable_block() }; @@ -693,27 +697,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } - fn cleanup_kind(&self, bb: mir::BasicBlock) -> CleanupKind { - self.cleanup_kinds[bb.index()] - } - /// Return the landingpad wrapper around the given basic block /// /// No-op in MSVC SEH scheme. fn landing_pad_to(&mut self, target_bb: mir::BasicBlock) -> Block<'bcx, 'tcx> { - if let Some(block) = self.landing_pads[target_bb.index()] { + if let Some(block) = self.landing_pads[target_bb] { return block; } if base::wants_msvc_seh(self.fcx.ccx.sess()) { - return self.blocks[target_bb.index()]; + return self.blocks[target_bb]; } let target = self.bcx(target_bb); let block = self.fcx.new_block("cleanup", None); - self.landing_pads[target_bb.index()] = Some(block); + self.landing_pads[target_bb] = Some(block); let bcx = block.build(); let ccx = bcx.ccx(); @@ -729,10 +729,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn init_cpad(&mut self, bb: mir::BasicBlock) { let bcx = self.bcx(bb); - let data = self.mir.basic_block_data(bb); + let data = &self.mir[bb]; debug!("init_cpad({:?})", data); - match self.cleanup_kinds[bb.index()] { + match self.cleanup_kinds[bb] { CleanupKind::NotCleanup => { bcx.set_lpad(None) } @@ -763,7 +763,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } fn bcx(&self, bb: mir::BasicBlock) -> BlockAndBuilder<'bcx, 'tcx> { - self.blocks[bb.index()].build() + self.blocks[bb].build() } fn make_return_dest(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>, @@ -776,7 +776,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let dest = match *dest { mir::Lvalue::Temp(idx) => { let ret_ty = self.lvalue_ty(dest); - match self.temps[idx as usize] { + match self.temps[idx] { TempRef::Lvalue(dest) => dest, TempRef::Operand(None) => { // Handle temporary lvalues, specifically Operand ones, as @@ -838,6 +838,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { self.store_operand(bcx, cast_ptr, val); } + // Stores the return value of a function call into it's final location. fn store_return(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>, @@ -851,7 +852,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { Store(dst) => ret_ty.store(bcx, op.immediate(), dst), IndirectOperand(tmp, idx) => { let op = self.trans_load(bcx, tmp, op.ty); - self.temps[idx as usize] = TempRef::Operand(Some(op)); + self.temps[idx] = TempRef::Operand(Some(op)); } DirectOperand(idx) => { // If there is a cast, we have to store and reload. @@ -864,7 +865,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } else { op.unpack_if_pair(bcx) }; - self.temps[idx as usize] = TempRef::Operand(Some(op)); + self.temps[idx] = TempRef::Operand(Some(op)); } } } @@ -876,7 +877,7 @@ enum ReturnDest { // Store the return value to the pointer Store(ValueRef), // Stores an indirect return value to an operand temporary lvalue - IndirectOperand(ValueRef, u32), + IndirectOperand(ValueRef, mir::Temp), // Stores a direct return value to an operand temporary lvalue - DirectOperand(u32) + DirectOperand(mir::Temp) } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 4e0cf729d4cd6..316c7341ef142 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -22,6 +22,7 @@ use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::cast::{CastTy, IntTy}; use rustc::ty::subst::Substs; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use {abi, adt, base, Disr}; use callee::Callee; use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty}; @@ -203,13 +204,13 @@ struct MirConstContext<'a, 'tcx: 'a> { substs: &'tcx Substs<'tcx>, /// Arguments passed to a const fn. - args: Vec>, + args: IndexVec>, /// Variable values - specifically, argument bindings of a const fn. - vars: Vec>>, + vars: IndexVec>>, /// Temp values. - temps: Vec>>, + temps: IndexVec>>, /// Value assigned to Return, which is the resulting constant. return_value: Option> @@ -220,22 +221,22 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn new(ccx: &'a CrateContext<'a, 'tcx>, mir: &'a mir::Mir<'tcx>, substs: &'tcx Substs<'tcx>, - args: Vec>) + args: IndexVec>) -> MirConstContext<'a, 'tcx> { MirConstContext { ccx: ccx, mir: mir, substs: substs, args: args, - vars: vec![None; mir.var_decls.len()], - temps: vec![None; mir.temp_decls.len()], + vars: IndexVec::from_elem(None, &mir.var_decls), + temps: IndexVec::from_elem(None, &mir.temp_decls), return_value: None } } fn trans_def(ccx: &'a CrateContext<'a, 'tcx>, mut instance: Instance<'tcx>, - args: Vec>) + args: IndexVec>) -> Result, ConstEvalFailure> { // Try to resolve associated constants. if instance.substs.self_ty().is_some() { @@ -279,7 +280,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let mut failure = Ok(()); loop { - let data = self.mir.basic_block_data(bb); + let data = &self.mir[bb]; for statement in &data.statements { let span = statement.source_info.span; match statement.kind { @@ -342,10 +343,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { func, fn_ty) }; - let mut const_args = Vec::with_capacity(args.len()); + let mut const_args = IndexVec::with_capacity(args.len()); for arg in args { match self.const_operand(arg, span) { - Ok(arg) => const_args.push(arg), + Ok(arg) => { const_args.push(arg); }, Err(err) => if failure.is_ok() { failure = Err(err); } } } @@ -366,8 +367,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) { let dest = match *dest { - mir::Lvalue::Var(index) => &mut self.vars[index as usize], - mir::Lvalue::Temp(index) => &mut self.temps[index as usize], + mir::Lvalue::Var(var) => &mut self.vars[var], + mir::Lvalue::Temp(temp) => &mut self.temps[temp], mir::Lvalue::ReturnPointer => &mut self.return_value, _ => span_bug!(span, "assignment to {:?} in constant", dest) }; @@ -378,17 +379,17 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { -> Result, ConstEvalFailure> { let tcx = self.ccx.tcx(); let lvalue = match *lvalue { - mir::Lvalue::Var(index) => { - self.vars[index as usize].unwrap_or_else(|| { - span_bug!(span, "var{} not initialized", index) + mir::Lvalue::Var(var) => { + self.vars[var].unwrap_or_else(|| { + span_bug!(span, "{:?} not initialized", var) }).as_lvalue() } - mir::Lvalue::Temp(index) => { - self.temps[index as usize].unwrap_or_else(|| { - span_bug!(span, "tmp{} not initialized", index) + mir::Lvalue::Temp(temp) => { + self.temps[temp].unwrap_or_else(|| { + span_bug!(span, "{:?} not initialized", temp) }).as_lvalue() } - mir::Lvalue::Arg(index) => self.args[index as usize].as_lvalue(), + mir::Lvalue::Arg(arg) => self.args[arg].as_lvalue(), mir::Lvalue::Static(def_id) => { ConstLvalue { base: Base::Static(consts::get_static(self.ccx, def_id).val), @@ -489,11 +490,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let substs = self.monomorphize(&substs); let instance = Instance::new(def_id, substs); - MirConstContext::trans_def(self.ccx, instance, vec![]) + MirConstContext::trans_def(self.ccx, instance, IndexVec::new()) } mir::Literal::Promoted { index } => { let mir = &self.mir.promoted[index]; - MirConstContext::new(self.ccx, mir, self.substs, vec![]).trans() + MirConstContext::new(self.ccx, mir, self.substs, IndexVec::new()).trans() } mir::Literal::Value { value } => { Ok(Const::from_constval(self.ccx, value, ty)) @@ -914,11 +915,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let substs = bcx.monomorphize(&substs); let instance = Instance::new(def_id, substs); - MirConstContext::trans_def(bcx.ccx(), instance, vec![]) + MirConstContext::trans_def(bcx.ccx(), instance, IndexVec::new()) } mir::Literal::Promoted { index } => { let mir = &self.mir.promoted[index]; - MirConstContext::new(bcx.ccx(), mir, bcx.fcx().param_substs, vec![]).trans() + MirConstContext::new(bcx.ccx(), mir, bcx.fcx().param_substs, + IndexVec::new()).trans() } mir::Literal::Value { value } => { Ok(Const::from_constval(bcx.ccx(), value, ty)) @@ -945,5 +947,5 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId) -> Result { let instance = Instance::mono(ccx.shared(), def_id); - MirConstContext::trans_def(ccx, instance, vec![]).map(|c| c.llval) + MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval) } diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 523dfef5a2409..0a66a147568e6 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -12,6 +12,7 @@ use llvm::ValueRef; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::mir::repr as mir; use rustc::mir::tcx::LvalueTy; +use rustc_data_structures::indexed_vec::Idx; use abi; use adt; use base; @@ -90,14 +91,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let ccx = bcx.ccx(); let tcx = bcx.tcx(); let result = match *lvalue { - mir::Lvalue::Var(index) => self.vars[index as usize], - mir::Lvalue::Temp(index) => match self.temps[index as usize] { + mir::Lvalue::Var(var) => self.vars[var], + mir::Lvalue::Temp(temp) => match self.temps[temp] { TempRef::Lvalue(lvalue) => lvalue, TempRef::Operand(..) => bug!("using operand temp {:?} as lvalue", lvalue), }, - mir::Lvalue::Arg(index) => self.args[index as usize], + mir::Lvalue::Arg(arg) => self.args[arg], mir::Lvalue::Static(def_id) => { let const_ty = self.lvalue_ty(lvalue); LvalueRef::new_sized(consts::get_static(ccx, def_id).val, @@ -233,8 +234,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U { match *lvalue { - mir::Lvalue::Temp(idx) => { - match self.temps[idx as usize] { + mir::Lvalue::Temp(temp) => { + match self.temps[temp] { TempRef::Lvalue(lvalue) => f(self, lvalue), TempRef::Operand(None) => { let lvalue_ty = self.lvalue_ty(lvalue); @@ -243,7 +244,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { "lvalue_temp"); let ret = f(self, lvalue); let op = self.trans_load(bcx, lvalue.llval, lvalue_ty); - self.temps[idx as usize] = TempRef::Operand(Some(op)); + self.temps[temp] = TempRef::Operand(Some(op)); ret } TempRef::Operand(Some(_)) => { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index e1fa08fd8b307..1932a2023fac8 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -30,6 +30,7 @@ use std::rc::Rc; use basic_block::BasicBlock; use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; pub use self::constant::trans_static_initializer; @@ -71,20 +72,20 @@ pub struct MirContext<'bcx, 'tcx:'bcx> { llpersonalityslot: Option, /// A `Block` for each MIR `BasicBlock` - blocks: Vec>, + blocks: IndexVec>, /// The funclet status of each basic block - cleanup_kinds: Vec, + cleanup_kinds: IndexVec, /// This stores the landing-pad block for a given BB, computed lazily on GNU /// and eagerly on MSVC. - landing_pads: Vec>>, + landing_pads: IndexVec>>, /// Cached unreachable block unreachable_block: Option>, /// An LLVM alloca for each MIR `VarDecl` - vars: Vec>, + vars: IndexVec>, /// The location where each MIR `TempDecl` is stored. This is /// usually an `LvalueRef` representing an alloca, but not always: @@ -101,20 +102,20 @@ pub struct MirContext<'bcx, 'tcx:'bcx> { /// /// Avoiding allocs can also be important for certain intrinsics, /// notably `expect`. - temps: Vec>, + temps: IndexVec>, /// The arguments to the function; as args are lvalues, these are /// always indirect, though we try to avoid creating an alloca /// when we can (and just reuse the pointer the caller provided). - args: Vec>, + args: IndexVec>, /// Debug information for MIR scopes. - scopes: Vec + scopes: IndexVec } impl<'blk, 'tcx> MirContext<'blk, 'tcx> { pub fn debug_loc(&self, source_info: mir::SourceInfo) -> DebugLoc { - DebugLoc::ScopeAt(self.scopes[source_info.scope.index()], source_info.span) + DebugLoc::ScopeAt(self.scopes[source_info.scope], source_info.span) } } @@ -154,8 +155,6 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { let bcx = fcx.init(false, None).build(); let mir = bcx.mir(); - let mir_blocks = mir.all_basic_blocks(); - // Analyze the temps to determine which must be lvalues // FIXME let (lvalue_temps, cleanup_kinds) = bcx.with_block(|bcx| { @@ -173,7 +172,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { .map(|(mty, decl)| { let lvalue = LvalueRef::alloca(&bcx, mty, &decl.name.as_str()); - let scope = scopes[decl.source_info.scope.index()]; + let scope = scopes[decl.source_info.scope]; if !scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo { bcx.with_block(|bcx| { declare_local(bcx, decl.name, mty, scope, @@ -200,19 +199,17 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { .collect(); // Allocate a `Block` for every basic block - let block_bcxs: Vec> = - mir_blocks.iter() - .map(|&bb|{ - if bb == mir::START_BLOCK { - fcx.new_block("start", None) - } else { - fcx.new_block(&format!("{:?}", bb), None) - } - }) - .collect(); + let block_bcxs: IndexVec> = + mir.basic_blocks().indices().map(|bb| { + if bb == mir::START_BLOCK { + fcx.new_block("start", None) + } else { + fcx.new_block(&format!("{:?}", bb), None) + } + }).collect(); // Branch to the START block - let start_bcx = block_bcxs[mir::START_BLOCK.index()]; + let start_bcx = block_bcxs[mir::START_BLOCK]; bcx.br(start_bcx.llbb); // Up until here, IR instructions for this function have explicitly not been annotated with @@ -227,14 +224,14 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { blocks: block_bcxs, unreachable_block: None, cleanup_kinds: cleanup_kinds, - landing_pads: mir_blocks.iter().map(|_| None).collect(), + landing_pads: IndexVec::from_elem(None, mir.basic_blocks()), vars: vars, temps: temps, args: args, scopes: scopes }; - let mut visited = BitVector::new(mir_blocks.len()); + let mut visited = BitVector::new(mir.basic_blocks().len()); let mut rpo = traversal::reverse_postorder(&mir); @@ -252,8 +249,8 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { // Remove blocks that haven't been visited, or have no // predecessors. - for &bb in &mir_blocks { - let block = mircx.blocks[bb.index()]; + for bb in mir.basic_blocks().indices() { + let block = mircx.blocks[bb]; let block = BasicBlock(block.llbb); // Unreachable block if !visited.contains(bb.index()) { @@ -271,15 +268,15 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { /// indirect. fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, mir: &mir::Mir<'tcx>, - scopes: &[DIScope]) - -> Vec> { + scopes: &IndexVec) + -> IndexVec> { let fcx = bcx.fcx(); let tcx = bcx.tcx(); let mut idx = 0; let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize; // Get the argument scope, if it exists and if we need it. - let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE.index()]; + let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE]; let arg_scope = if !arg_scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo { Some(arg_scope) } else { diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index c21f112b5f603..80ff0a92d8d46 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -11,6 +11,8 @@ use llvm::ValueRef; use rustc::ty::Ty; use rustc::mir::repr as mir; +use rustc_data_structures::indexed_vec::Idx; + use base; use common::{self, Block, BlockAndBuilder}; use value::Value; @@ -174,7 +176,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // watch out for temporaries that do not have an // alloca; they are handled somewhat differently if let &mir::Lvalue::Temp(index) = lvalue { - match self.temps[index as usize] { + match self.temps[index] { TempRef::Operand(Some(o)) => { return o; } @@ -190,7 +192,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // Moves out of pair fields are trivial. if let &mir::Lvalue::Projection(ref proj) = lvalue { if let mir::Lvalue::Temp(index) = proj.base { - let temp_ref = &self.temps[index as usize]; + let temp_ref = &self.temps[index]; if let &TempRef::Operand(Some(o)) = temp_ref { 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 63472d582330f..d592f5ee1b936 100644 --- a/src/librustc_trans/mir/statement.rs +++ b/src/librustc_trans/mir/statement.rs @@ -9,6 +9,7 @@ // except according to those terms. use rustc::mir::repr as mir; + use common::{self, BlockAndBuilder}; use super::MirContext; @@ -28,8 +29,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::StatementKind::Assign(ref lvalue, ref rvalue) => { match *lvalue { mir::Lvalue::Temp(index) => { - let index = index as usize; - match self.temps[index as usize] { + match self.temps[index] { TempRef::Lvalue(tr_dest) => { self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc) } diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 50d9f61e2c160..3e8277e28ba73 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -87,6 +87,7 @@ dependencies = [ "graphviz 0.0.0", "log 0.0.0", "rustc 0.0.0", + "rustc_data_structures 0.0.0", "rustc_mir 0.0.0", "syntax 0.0.0", ] diff --git a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs index 0abf71ba444ae..604933d40a12c 100644 --- a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs +++ b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs @@ -29,6 +29,7 @@ use rustc_plugin::Registry; struct Pass; impl transform::Pass for Pass {} + impl<'tcx> MirPass<'tcx> for Pass { fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) {