Auto merge of #34149 - arielb1:remove-remove-dead-blocks, r=nikomatsakis

MIR cleanups and predecessor cache

This PR cleans up a few things in MIR and adds a predecessor cache to allow graph algorithms to be run easily.

r? @nikomatsakis
This commit is contained in:
bors 2016-06-09 12:07:38 -07:00 committed by GitHub
commit ee00760a14
54 changed files with 1279 additions and 959 deletions

View File

@ -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;

69
src/librustc/mir/cache.rs Normal file
View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<Option<IndexVec<BasicBlock, Vec<BasicBlock>>>>
}
impl serialize::Encodable for Cache {
fn encode<S: serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
serialize::Encodable::encode(&(), s)
}
}
impl serialize::Decodable for Cache {
fn decode<D: serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
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<IndexVec<BasicBlock, Vec<BasicBlock>>> {
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<BasicBlock, Vec<BasicBlock>> {
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
}

View File

@ -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<BasicBlockData<'tcx>>,
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
/// List of visibility (lexical) scopes; these are referenced by statements
/// and used (eventually) for debuginfo. Indexed by a `VisibilityScope`.
pub visibility_scopes: Vec<VisibilityScopeData>,
pub visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
/// 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<Mir<'tcx>>,
pub promoted: IndexVec<Promoted, Mir<'tcx>>,
/// 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<VarDecl<'tcx>>,
pub var_decls: IndexVec<Var, VarDecl<'tcx>>,
/// Args: these are stack slots corresponding to the input arguments.
pub arg_decls: Vec<ArgDecl<'tcx>>,
pub arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
/// Temp declarations: stack slots that for temporaries created by
/// the compiler. These are assigned once, but they are not SSA
/// values in that it is possible to borrow them and mutate them
/// through the resulting reference.
pub temp_decls: Vec<TempDecl<'tcx>>,
pub temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
/// 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<BasicBlock> {
(0..self.basic_blocks.len())
.map(|i| BasicBlock::new(i))
.collect()
pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
promoted: IndexVec<Promoted, Mir<'tcx>>,
return_ty: FnOutput<'tcx>,
var_decls: IndexVec<Var, VarDecl<'tcx>>,
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
upvar_decls: Vec<UpvarDecl>,
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()
}
}
pub fn basic_block_data(&self, bb: BasicBlock) -> &BasicBlockData<'tcx> {
&self.basic_blocks[bb.index()]
#[inline]
pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
&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 basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
self.cache.invalidate();
&mut self.basic_blocks
}
#[inline]
pub fn predecessors(&self) -> Ref<IndexVec<BasicBlock, Vec<BasicBlock>>> {
self.cache.predecessors(self)
}
#[inline]
pub fn predecessors_for(&self, bb: BasicBlock) -> Ref<Vec<BasicBlock>> {
Ref::map(self.predecessors(), |p| &p[bb])
}
}
@ -89,14 +151,14 @@ impl<'tcx> Index<BasicBlock> for Mir<'tcx> {
#[inline]
fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
self.basic_block_data(index)
&self.basic_blocks()[index]
}
}
impl<'tcx> IndexMut<BasicBlock> 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<Cow<'static, str>> {
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,39 +809,9 @@ impl<'tcx> Debug for Lvalue<'tcx> {
///////////////////////////////////////////////////////////////////////////
// Scopes
impl Index<VisibilityScope> for Vec<VisibilityScopeData> {
type Output = VisibilityScopeData;
#[inline]
fn index(&self, index: VisibilityScope) -> &VisibilityScopeData {
&self[index.index()]
}
}
impl IndexMut<VisibilityScope> for Vec<VisibilityScopeData> {
#[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.
newtype_index!(VisibilityScope, "scope");
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
}
}
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct VisibilityScopeData {
pub span: Span,
@ -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)
}
}
}

View File

@ -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 =>

View File

@ -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<DefId> {
DepNode::MirPass(def_id)
}
fn name(&self) -> &str {
unsafe { ::std::intrinsics::type_name::<Self>() }
}
fn disambiguator<'a>(&'a self) -> Option<Box<fmt::Display+'a>> { 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<for<'s> 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<for<'s> 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<Box<for<'tcx> MirMapPass<'tcx>>>,
pass_hooks: Vec<Box<for<'tcx> MirPassHook<'tcx>>>,
plugin_passes: Vec<Box<for<'tcx> 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<for<'b> MirMapPass<'b>>) {
self.passes.push(pass);
}
/// Pushes a pass hook.
pub fn push_hook(&mut self, hook: Box<for<'b> MirPassHook<'b>>) {
self.pass_hooks.push(hook);
}
}
/// Copies the plugin passes.

View File

@ -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]))
}
}

View File

@ -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,

View File

@ -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" }

View File

@ -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<O: BitDenotation> DataflowState<O> {
@ -126,7 +127,7 @@ pub type Node = BasicBlock;
pub struct Edge { source: BasicBlock, index: usize }
fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
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<Node> {
self.mbcx.mir().all_basic_blocks().into_cow()
self.mbcx.mir()
.basic_blocks()
.indices()
.collect::<Vec<_>>()
.into_cow()
}
fn edges(&self) -> dot::Edges<Edge> {
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]
}
}

View File

@ -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);
}

View File

@ -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<BD::Idx>) {
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 } |

View File

@ -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<Ctxt=MoveDataParamEnv<'tcx>, Idx=MovePathIndex>
{
let move_data = &ctxt.move_data;
let bb_data = mir.basic_block_data(bb);
let &repr::BasicBlockData { ref statements,
let repr::BasicBlockData { ref statements,
ref terminator,
is_cleanup: _ } = bb_data;
is_cleanup: _ } = mir[bb];
let (args, span) = match is_rustc_peek(tcx, terminator) {
Some(args_and_span) => args_and_span,

View File

@ -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<MaybeInitializedLvals<'a, 'tcx>>,
flow_uninits: DataflowResults<MaybeUninitializedLvals<'a, 'tcx>>,
drop_flags: FnvHashMap<MovePathIndex, u32>,
drop_flags: FnvHashMap<MovePathIndex, Temp>,
patch: MirPatch<'tcx>,
}
@ -214,8 +212,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, .. } |
@ -251,8 +248,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();
@ -312,7 +308,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
unwind: Option<BasicBlock>)
{
let bb = loc.block;
let data = self.mir.basic_block_data(bb);
let data = &self.mir[bb];
let terminator = data.terminator();
let assign = Statement {
@ -931,8 +927,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 {
@ -964,8 +959,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);

View File

@ -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<Index> 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<MovePathIndex> 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<MovePathIndex> 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<Option<MovePathIndex>>;
struct MovePathDataBuilder<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
pre_move_paths: Vec<PreMovePath<'tcx>>,
@ -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<Var, Option<MovePathIndex>>,
temps: IndexVec<Temp, Option<MovePathIndex>>,
args: IndexVec<Arg, Option<MovePathIndex>>,
/// 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<T>(LookupKind, T);
impl Lookup<MovePathIndex> {
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<Option<MovePathIndex>>,
idx: u32,
next_index: &mut MovePathIndex) -> Lookup<MovePathIndex> {
let idx = idx as usize;
vec.fill_to_with(idx, None);
fn lookup_or_generate<I: Idx>(vec: &mut IndexVec<I, Option<MovePathIndex>>,
idx: I,
next_index: &mut MovePathIndex)
-> Lookup<MovePathIndex> {
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<MovePathIndex> {
fn lookup_var(&mut self, var_idx: Var) -> Lookup<MovePathIndex> {
Self::lookup_or_generate(&mut self.vars,
var_idx,
&mut self.next_index)
}
fn lookup_temp(&mut self, temp_idx: u32) -> Lookup<MovePathIndex> {
fn lookup_temp(&mut self, temp_idx: Temp) -> Lookup<MovePathIndex> {
Self::lookup_or_generate(&mut self.temps,
temp_idx,
&mut self.next_index)
}
fn lookup_arg(&mut self, arg_idx: u32) -> Lookup<MovePathIndex> {
fn lookup_arg(&mut self, arg_idx: Arg) -> Lookup<MovePathIndex> {
Self::lookup_or_generate(&mut self.args,
arg_idx,
&mut self.next_index)
@ -384,8 +379,8 @@ impl<'tcx> MovePathLookup<'tcx> {
base: MovePathIndex) -> Lookup<MovePathIndex> {
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());

View File

@ -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);
}
@ -327,8 +327,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,
@ -366,8 +366,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);
@ -377,8 +377,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),

View File

@ -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<Option<TerminatorKind<'tcx>>>,
patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>,
new_blocks: Vec<BasicBlockData<'tcx>>,
new_statements: Vec<(Location, StatementKind<'tcx>)>,
new_temps: Vec<TempDecl<'tcx>>,
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)
}

View File

@ -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<T: Idx> IdxSet<T> {
/// 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<T>) -> &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<T>) -> &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] {

View File

@ -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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<I: Idx, T> {
pub raw: Vec<T>,
_marker: PhantomData<Fn(&I)>
}
impl<I: Idx, T: serialize::Encodable> serialize::Encodable for IndexVec<I, T> {
fn encode<S: serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
serialize::Encodable::encode(&self.raw, s)
}
}
impl<I: Idx, T: serialize::Decodable> serialize::Decodable for IndexVec<I, T> {
fn decode<D: serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
serialize::Decodable::decode(d).map(|v| {
IndexVec { raw: v, _marker: PhantomData }
})
}
}
impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexVec<I, T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.raw, fmt)
}
}
pub type Enumerated<I, J> = iter::Map<iter::Enumerate<J>, IntoIdx<I>>;
impl<I: Idx, T> IndexVec<I, T> {
#[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<S>(elem: T, universe: &IndexVec<I, S>) -> 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<T> {
self.raw.into_iter()
}
#[inline]
pub fn into_iter_enumerated(self) -> Enumerated<I, vec::IntoIter<T>>
{
self.raw.into_iter().enumerate().map(IntoIdx { _marker: PhantomData })
}
#[inline]
pub fn iter(&self) -> slice::Iter<T> {
self.raw.iter()
}
#[inline]
pub fn iter_enumerated(&self) -> Enumerated<I, slice::Iter<T>>
{
self.raw.iter().enumerate().map(IntoIdx { _marker: PhantomData })
}
#[inline]
pub fn indices(&self) -> iter::Map<Range<usize>, IntoIdx<I>> {
(0..self.len()).map(IntoIdx { _marker: PhantomData })
}
#[inline]
pub fn iter_mut(&mut self) -> slice::IterMut<T> {
self.raw.iter_mut()
}
#[inline]
pub fn iter_enumerated_mut(&mut self) -> Enumerated<I, slice::IterMut<T>>
{
self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData })
}
#[inline]
pub fn last(&self) -> Option<I> {
self.len().checked_sub(1).map(I::new)
}
}
impl<I: Idx, T> Index<I> for IndexVec<I, T> {
type Output = T;
#[inline]
fn index(&self, index: I) -> &T {
&self.raw[index.index()]
}
}
impl<I: Idx, T> IndexMut<I> for IndexVec<I, T> {
#[inline]
fn index_mut(&mut self, index: I) -> &mut T {
&mut self.raw[index.index()]
}
}
impl<I: Idx, T> Extend<T> for IndexVec<I, T> {
#[inline]
fn extend<J: IntoIterator<Item = T>>(&mut self, iter: J) {
self.raw.extend(iter);
}
}
impl<I: Idx, T> FromIterator<T> for IndexVec<I, T> {
#[inline]
fn from_iter<J>(iter: J) -> Self where J: IntoIterator<Item=T> {
IndexVec { raw: FromIterator::from_iter(iter), _marker: PhantomData }
}
}
impl<I: Idx, T> IntoIterator for IndexVec<I, T> {
type Item = T;
type IntoIter = vec::IntoIter<T>;
#[inline]
fn into_iter(self) -> vec::IntoIter<T> {
self.raw.into_iter()
}
}
impl<'a, I: Idx, T> IntoIterator for &'a IndexVec<I, T> {
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<I, T> {
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<I: Idx> { _marker: PhantomData<fn(&I)> }
impl<I: Idx, T> FnOnce<((usize, T),)> for IntoIdx<I> {
type Output = (I, T);
extern "rust-call" fn call_once(self, ((n, t),): ((usize, T),)) -> Self::Output {
(I::new(n), t)
}
}
impl<I: Idx, T> FnMut<((usize, T),)> for IntoIdx<I> {
extern "rust-call" fn call_mut(&mut self, ((n, t),): ((usize, T),)) -> Self::Output {
(I::new(n), t)
}
}
impl<I: Idx> FnOnce<(usize,)> for IntoIdx<I> {
type Output = I;
extern "rust-call" fn call_once(self, (n,): (usize,)) -> Self::Output {
I::new(n)
}
}
impl<I: Idx> FnMut<(usize,)> for IntoIdx<I> {
extern "rust-call" fn call_mut(&mut self, (n,): (usize,)) -> Self::Output {
I::new(n)
}
}

View File

@ -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;

View File

@ -970,11 +970,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);
});
@ -1040,15 +1042,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);
});

View File

@ -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,

View File

@ -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<M>(&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];

View File

@ -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};

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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<ScopeId, ScopeAuxiliary>,
/// 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<VisibilityScopeData>,
visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
visibility_scope: VisibilityScope,
var_decls: Vec<VarDecl<'tcx>>,
var_indices: FnvHashMap<ast::NodeId, u32>,
temp_decls: Vec<TempDecl<'tcx>>,
var_decls: IndexVec<Var, VarDecl<'tcx>>,
var_indices: NodeMap<Var>,
temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
unit_temp: Option<Lvalue<'tcx>>,
/// 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<BasicBlockData<'tcx>>,
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
}
#[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<ScopeAuxiliary>
}
impl Index<ScopeId> for ScopeAuxiliaryVec {
type Output = ScopeAuxiliary;
#[inline]
fn index(&self, index: ScopeId) -> &ScopeAuxiliary {
&self.vec[index.index()]
}
}
impl IndexMut<ScopeId> for ScopeAuxiliaryVec {
#[inline]
fn index_mut(&mut self, index: ScopeId) -> &mut ScopeAuxiliary {
&mut self.vec[index.index()]
}
}
pub type ScopeAuxiliaryVec = IndexVec<ScopeId, ScopeAuxiliary>;
///////////////////////////////////////////////////////////////////////////
/// 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<UpvarDecl>,
arg_decls: Vec<ArgDecl<'tcx>>,
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
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<A>(&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<Vec<ArgDecl<'tcx>>>
-> BlockAnd<IndexVec<Arg, ArgDecl<'tcx>>>
where A: Iterator<Item=(Ty<'gcx>, 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);

View File

@ -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.

View File

@ -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<Item=(&'a NodeId, &'a Mir<'a>)> {
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<W: Write, INIT, FINI>(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#"<table border="0" cellborder="1" cellspacing="0">"#)?;
@ -105,7 +107,7 @@ fn write_node<W: Write>(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<W: Write>(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, ") -&gt; ")?;
@ -150,13 +152,13 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
write!(w, "mut ")?;
}
write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
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 {:?}: {};<br align="left"/>"#,
Lvalue::Temp(i as u32), escape(&temp.ty))?;
Lvalue::Temp(Temp::new(i)), escape(&temp.ty))?;
}
writeln!(w, ">;")

View File

@ -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;

View File

@ -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;

View File

@ -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};

View File

@ -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<Location, Vec<Annotation>>)
-> 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.

View File

@ -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();
let cur_len = mir.basic_blocks().len();
for &bb in &bbs {
let data = mir.basic_block_data_mut(bb);
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);
}
}

View File

@ -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 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<'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)
}
}
}
impl<'b> Pass for DumpMir<'b> {}
pub struct DumpMir;
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 {}

View File

@ -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;

View File

@ -24,6 +24,7 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
TerminatorKind::Goto { .. } |
TerminatorKind::Resume |
TerminatorKind::Return |
TerminatorKind::Unreachable |
TerminatorKind::If { .. } |
TerminatorKind::Switch { .. } |
TerminatorKind::SwitchInt { .. } => {

View File

@ -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<TempState>,
temps: IndexVec<Temp, TempState>,
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<TempState> {
pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, TempState> {
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<TempState> {
struct Promoter<'a, 'tcx: 'a> {
source: &'a mut Mir<'tcx>,
promoted: Mir<'tcx>,
temps: &'a mut Vec<TempState>,
temps: &'a mut IndexVec<Temp, TempState>,
/// 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<TempState>,
mut temps: IndexVec<Temp, TempState>,
candidates: Vec<Candidate>) {
// 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), _) => {

View File

@ -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<Qualif>,
mir_map: Option<&'a MirMap<'tcx>>,
temp_qualif: Vec<Option<Qualif>>,
temp_qualif: IndexVec<Temp, Option<Qualif>>,
return_qualif: Option<Qualif>,
qualif: Qualif,
const_fn_arg_vars: BitVector,
location: Location,
temp_promotion_state: Vec<TempState>,
temp_promotion_state: IndexVec<Temp, TempState>,
promotion_candidates: Vec<Candidate>
}
@ -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<for<'s> 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();

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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()];
}
}
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<Box<fmt::Display+'a>> {
Some(Box::new(self.label))
}
}

View File

@ -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 std::fmt;
use super::remove_dead_blocks::RemoveDeadBlocks;
pub struct SimplifyCfg<'a> { label: &'a str }
pub struct SimplifyCfg;
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<Box<fmt::Display+'a>> {
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()];
pub struct CfgSimplifier<'a, 'tcx: 'a> {
basic_blocks: &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
pred_count: IndexVec<BasicBlock, u32>
}
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.index()] += 1;
pred_count[tgt] += 1;
}
}
}
let basic_blocks = mir.basic_blocks_mut();
CfgSimplifier {
basic_blocks: basic_blocks,
pred_count: pred_count
}
}
fn simplify(mut self) {
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()
for bb in (0..self.basic_blocks.len()).map(BasicBlock::new) {
if self.pred_count[bb] == 0 {
continue
}
debug!("simplifying {:?}", bb);
let mut terminator = self.basic_blocks[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;
for successor in terminator.successors_mut() {
self.collapse_goto_chain(successor, &mut changed);
}
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;
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;
}
_ if pred_count[target.index()] == 1 => {
inner_change = true;
let mut stmts = Vec::new();
self.basic_blocks[bb].statements.extend(new_stmts);
self.basic_blocks[bb].terminator = Some(terminator);
changed |= inner_changed;
}
if !changed { break }
}
}
// 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
}
_ => unreachable!()
};
self.basic_blocks[*start].terminator = terminator;
debug!("collapsing goto chain from {:?} to {:?}", *start, target);
*changed |= *start != target;
self.pred_count[target] += 1;
self.pred_count[*start] -= 1;
*start = target;
}
// merge a block with 1 `goto` predecessor to its parent
fn merge_successor(&mut self,
new_stmts: &mut Vec<Statement<'tcx>>,
terminator: &mut Terminator<'tcx>)
-> bool
{
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);
}
_ => {}
let target = match terminator.kind {
TerminatorKind::Goto { target }
if self.pred_count[target] == 1
=> target,
_ => return false
};
}
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
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
}
};
if *target != new_target {
inner_change = true;
pred_count[target.index()] -= 1;
pred_count[new_target.index()] += 1;
*target = new_target;
}
new_stmts.extend(self.basic_blocks[target].statements.drain(..));
self.pred_count[target] = 0;
true
}
changed |= inner_change;
if !inner_change {
break;
}
}
// 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
};
mir.basic_block_data_mut(bb).terminator = Some(terminator);
for succ in mir.basic_block_data(bb).terminator().successors().iter() {
if seen.insert(succ.index()) {
worklist.push(*succ);
}
}
}
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<BasicBlock> {
// Keep track of already seen blocks to detect loops
let mut seen: Vec<BasicBlock> = 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;
}
_ => break
}
}
Some(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 }
}
TerminatorKind::If { ref targets, cond: Operand::Constant(Constant {
literal: Literal::Value {
value: ConstVal::Bool(cond)
}, ..
}) } => {
changed = true;
if cond {
TerminatorKind::Goto { target: targets.0 }
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 {
TerminatorKind::Goto { target: targets.1 }
return false
}
} else {
return false
}
};
debug!("simplifying branch {:?}", terminator);
terminator.kind = TerminatorKind::Goto { target: first_succ };
true
}
}
TerminatorKind::Assert { target, cond: Operand::Constant(Constant {
literal: Literal::Value {
value: ConstVal::Bool(cond)
}, ..
}), expected, .. } if cond == expected => {
changed = true;
TerminatorKind::Goto { target: target }
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());
}
TerminatorKind::SwitchInt { ref targets, .. } if targets.len() == 1 => {
changed = true;
TerminatorKind::Goto { target: targets[0] }
}
_ => continue
}
}
let basic_blocks = mir.basic_blocks_mut();
if !changed {
break;
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);
for block in basic_blocks {
for target in block.terminator_mut().successors_mut() {
*target = replacements[target.index()];
}
}
}

View File

@ -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;

View File

@ -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, &[]);

View File

@ -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<DIScope> {
pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, DIScope> {
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<VisibilityScope, DIScope>) {
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,

View File

@ -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<CleanupKind>
-> IndexVec<mir::BasicBlock, CleanupKind>
{
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::BasicBlock, CleanupKind>,
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::BasicBlock, CleanupKind>,
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);

View File

@ -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)
}

View File

@ -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<Const<'tcx>>,
args: IndexVec<mir::Arg, Const<'tcx>>,
/// Variable values - specifically, argument bindings of a const fn.
vars: Vec<Option<Const<'tcx>>>,
vars: IndexVec<mir::Var, Option<Const<'tcx>>>,
/// Temp values.
temps: Vec<Option<Const<'tcx>>>,
temps: IndexVec<mir::Temp, Option<Const<'tcx>>>,
/// Value assigned to Return, which is the resulting constant.
return_value: Option<Const<'tcx>>
@ -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<Const<'tcx>>)
args: IndexVec<mir::Arg, Const<'tcx>>)
-> 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<Const<'tcx>>)
args: IndexVec<mir::Arg, Const<'tcx>>)
-> Result<Const<'tcx>, 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<ConstLvalue<'tcx>, 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<ValueRef, ConstEvalFailure> {
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)
}

View File

@ -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(_)) => {

View File

@ -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<ValueRef>,
/// A `Block` for each MIR `BasicBlock`
blocks: Vec<Block<'bcx, 'tcx>>,
blocks: IndexVec<mir::BasicBlock, Block<'bcx, 'tcx>>,
/// The funclet status of each basic block
cleanup_kinds: Vec<analyze::CleanupKind>,
cleanup_kinds: IndexVec<mir::BasicBlock, analyze::CleanupKind>,
/// This stores the landing-pad block for a given BB, computed lazily on GNU
/// and eagerly on MSVC.
landing_pads: Vec<Option<Block<'bcx, 'tcx>>>,
landing_pads: IndexVec<mir::BasicBlock, Option<Block<'bcx, 'tcx>>>,
/// Cached unreachable block
unreachable_block: Option<Block<'bcx, 'tcx>>,
/// An LLVM alloca for each MIR `VarDecl`
vars: Vec<LvalueRef<'tcx>>,
vars: IndexVec<mir::Var, LvalueRef<'tcx>>,
/// 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<TempRef<'tcx>>,
temps: IndexVec<mir::Temp, TempRef<'tcx>>,
/// 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<LvalueRef<'tcx>>,
args: IndexVec<mir::Arg, LvalueRef<'tcx>>,
/// Debug information for MIR scopes.
scopes: Vec<DIScope>
scopes: IndexVec<mir::VisibilityScope, DIScope>
}
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<Block<'blk,'tcx>> =
mir_blocks.iter()
.map(|&bb|{
let block_bcxs: IndexVec<mir::BasicBlock, Block<'blk,'tcx>> =
mir.basic_blocks().indices().map(|bb| {
if bb == mir::START_BLOCK {
fcx.new_block("start", None)
} else {
fcx.new_block(&format!("{:?}", bb), None)
}
})
.collect();
}).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<LvalueRef<'tcx>> {
scopes: &IndexVec<mir::VisibilityScope, DIScope>)
-> IndexVec<mir::Arg, LvalueRef<'tcx>> {
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 {

View File

@ -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),

View File

@ -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)
}

1
src/rustc/Cargo.lock generated
View File

@ -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",
]

View File

@ -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>) {