mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 23:12:02 +00:00
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:
commit
ee00760a14
@ -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
69
src/librustc/mir/cache.rs
Normal 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
|
||||
}
|
@ -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,38 +809,8 @@ 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.
|
||||
pub const ARGUMENT_VISIBILITY_SCOPE: VisibilityScope = VisibilityScope(0);
|
||||
|
||||
impl VisibilityScope {
|
||||
pub fn new(index: usize) -> VisibilityScope {
|
||||
assert!(index < (u32::MAX as usize));
|
||||
VisibilityScope(index as u32)
|
||||
}
|
||||
|
||||
pub fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
newtype_index!(VisibilityScope, "scope");
|
||||
pub const ARGUMENT_VISIBILITY_SCOPE : VisibilityScope = VisibilityScope(0);
|
||||
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct VisibilityScopeData {
|
||||
@ -1080,6 +1082,8 @@ impl<'tcx> Debug for TypedConstVal<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
newtype_index!(Promoted, "promoted");
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub enum Literal<'tcx> {
|
||||
Item {
|
||||
@ -1091,7 +1095,7 @@ pub enum Literal<'tcx> {
|
||||
},
|
||||
Promoted {
|
||||
// Index into the `promoted` vector of `Mir`.
|
||||
index: usize
|
||||
index: Promoted
|
||||
},
|
||||
}
|
||||
|
||||
@ -1115,7 +1119,7 @@ impl<'tcx> Debug for Literal<'tcx> {
|
||||
fmt_const_val(fmt, value)
|
||||
}
|
||||
Promoted { index } => {
|
||||
write!(fmt, "promoted{}", index)
|
||||
write!(fmt, "{:?}", index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 =>
|
||||
|
@ -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.
|
||||
|
@ -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]))
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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" }
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 } |
|
||||
|
@ -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,
|
||||
ref terminator,
|
||||
is_cleanup: _ } = bb_data;
|
||||
let repr::BasicBlockData { ref statements,
|
||||
ref terminator,
|
||||
is_cleanup: _ } = mir[bb];
|
||||
|
||||
let (args, span) = match is_rustc_peek(tcx, terminator) {
|
||||
Some(args_and_span) => args_and_span,
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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] {
|
||||
|
@ -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
|
||||
|
||||
|
228
src/librustc_data_structures/indexed_vec.rs
Normal file
228
src/librustc_data_structures/indexed_vec.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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];
|
||||
|
@ -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};
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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, ") -> ")?;
|
||||
@ -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, ">;")
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {}
|
||||
|
@ -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;
|
||||
|
@ -24,6 +24,7 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
|
||||
TerminatorKind::Goto { .. } |
|
||||
TerminatorKind::Resume |
|
||||
TerminatorKind::Return |
|
||||
TerminatorKind::Unreachable |
|
||||
TerminatorKind::If { .. } |
|
||||
TerminatorKind::Switch { .. } |
|
||||
TerminatorKind::SwitchInt { .. } => {
|
||||
|
@ -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), _) => {
|
||||
|
@ -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();
|
||||
|
@ -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()];
|
||||
}
|
||||
}
|
||||
}
|
63
src/librustc_mir/transform/simplify_branches.rs
Normal file
63
src/librustc_mir/transform/simplify_branches.rs
Normal 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))
|
||||
}
|
||||
}
|
@ -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 {}
|
||||
|
||||
fn merge_consecutive_blocks(mir: &mut Mir) {
|
||||
// Build the precedecessor map for the MIR
|
||||
let mut pred_count = vec![0u32; mir.basic_blocks.len()];
|
||||
for (_, data) in traversal::preorder(mir) {
|
||||
if let Some(ref term) = data.terminator {
|
||||
for &tgt in term.successors().iter() {
|
||||
pred_count[tgt.index()] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
let mut changed = false;
|
||||
let mut seen = BitVector::new(mir.basic_blocks.len());
|
||||
let mut worklist = vec![START_BLOCK];
|
||||
while let Some(bb) = worklist.pop() {
|
||||
// Temporarily take ownership of the terminator we're modifying to keep borrowck happy
|
||||
let mut terminator = mir.basic_block_data_mut(bb).terminator.take()
|
||||
.expect("invalid terminator state");
|
||||
|
||||
// See if we can merge the target block into this one
|
||||
loop {
|
||||
let mut inner_change = false;
|
||||
|
||||
if let TerminatorKind::Goto { target } = terminator.kind {
|
||||
// Don't bother trying to merge a block into itself
|
||||
if target == bb {
|
||||
break;
|
||||
}
|
||||
|
||||
let num_insts = mir.basic_block_data(target).statements.len();
|
||||
match mir.basic_block_data(target).terminator().kind {
|
||||
TerminatorKind::Goto { target: new_target } if num_insts == 0 => {
|
||||
inner_change = true;
|
||||
terminator.kind = TerminatorKind::Goto { target: new_target };
|
||||
pred_count[target.index()] -= 1;
|
||||
pred_count[new_target.index()] += 1;
|
||||
}
|
||||
_ if pred_count[target.index()] == 1 => {
|
||||
inner_change = true;
|
||||
let mut stmts = Vec::new();
|
||||
{
|
||||
let target_data = mir.basic_block_data_mut(target);
|
||||
mem::swap(&mut stmts, &mut target_data.statements);
|
||||
mem::swap(&mut terminator, target_data.terminator_mut());
|
||||
}
|
||||
|
||||
mir.basic_block_data_mut(bb).statements.append(&mut stmts);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
for target in terminator.successors_mut() {
|
||||
let new_target = match final_target(mir, *target) {
|
||||
Some(new_target) => new_target,
|
||||
None if mir.basic_block_data(bb).statements.is_empty() => bb,
|
||||
None => continue
|
||||
};
|
||||
if *target != new_target {
|
||||
inner_change = true;
|
||||
pred_count[target.index()] -= 1;
|
||||
pred_count[new_target.index()] += 1;
|
||||
*target = new_target;
|
||||
}
|
||||
}
|
||||
|
||||
changed |= inner_change;
|
||||
if !inner_change {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
impl<'l> Pass for SimplifyCfg<'l> {
|
||||
fn disambiguator<'a>(&'a self) -> Option<Box<fmt::Display+'a>> {
|
||||
Some(Box::new(self.label))
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
pub struct CfgSimplifier<'a, 'tcx: 'a> {
|
||||
basic_blocks: &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
||||
pred_count: IndexVec<BasicBlock, u32>
|
||||
}
|
||||
|
||||
fn simplify_branches(mir: &mut Mir) {
|
||||
loop {
|
||||
let mut changed = false;
|
||||
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());
|
||||
|
||||
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 }
|
||||
// we can't use mir.predecessors() here because that counts
|
||||
// dead blocks, which we don't want to.
|
||||
for (_, data) in traversal::preorder(mir) {
|
||||
if let Some(ref term) = data.terminator {
|
||||
for &tgt in term.successors().iter() {
|
||||
pred_count[tgt] += 1;
|
||||
}
|
||||
|
||||
TerminatorKind::If { ref targets, cond: Operand::Constant(Constant {
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Bool(cond)
|
||||
}, ..
|
||||
}) } => {
|
||||
changed = true;
|
||||
if cond {
|
||||
TerminatorKind::Goto { target: targets.0 }
|
||||
} else {
|
||||
TerminatorKind::Goto { target: targets.1 }
|
||||
}
|
||||
}
|
||||
|
||||
TerminatorKind::Assert { target, cond: Operand::Constant(Constant {
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Bool(cond)
|
||||
}, ..
|
||||
}), expected, .. } if cond == expected => {
|
||||
changed = true;
|
||||
TerminatorKind::Goto { target: target }
|
||||
}
|
||||
|
||||
TerminatorKind::SwitchInt { ref targets, .. } if targets.len() == 1 => {
|
||||
changed = true;
|
||||
TerminatorKind::Goto { target: targets[0] }
|
||||
}
|
||||
_ => continue
|
||||
}
|
||||
}
|
||||
|
||||
if !changed {
|
||||
break;
|
||||
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;
|
||||
|
||||
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");
|
||||
|
||||
for successor in terminator.successors_mut() {
|
||||
self.collapse_goto_chain(successor, &mut changed);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = match terminator.kind {
|
||||
TerminatorKind::Goto { target }
|
||||
if self.pred_count[target] == 1
|
||||
=> target,
|
||||
_ => return false
|
||||
};
|
||||
|
||||
debug!("merging block {:?} into {:?}", target, terminator);
|
||||
*terminator = match self.basic_blocks[target].terminator.take() {
|
||||
Some(terminator) => terminator,
|
||||
None => {
|
||||
// unreachable loop - this should not be possible, as we
|
||||
// don't strand blocks, but handle it correctly.
|
||||
return false
|
||||
}
|
||||
};
|
||||
new_stmts.extend(self.basic_blocks[target].statements.drain(..));
|
||||
self.pred_count[target] = 0;
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
// turn a branch with all successors identical to a goto
|
||||
fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
|
||||
match terminator.kind {
|
||||
TerminatorKind::If { .. } |
|
||||
TerminatorKind::Switch { .. } |
|
||||
TerminatorKind::SwitchInt { .. } => {},
|
||||
_ => return false
|
||||
};
|
||||
|
||||
let first_succ = {
|
||||
let successors = terminator.successors();
|
||||
if let Some(&first_succ) = terminator.successors().get(0) {
|
||||
if successors.iter().all(|s| *s == first_succ) {
|
||||
self.pred_count[first_succ] -= (successors.len()-1) as u32;
|
||||
first_succ
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
};
|
||||
|
||||
debug!("simplifying branch {:?}", terminator);
|
||||
terminator.kind = TerminatorKind::Goto { target: first_succ };
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_dead_blocks(mir: &mut Mir) {
|
||||
let mut seen = BitVector::new(mir.basic_blocks().len());
|
||||
for (bb, _) in traversal::preorder(mir) {
|
||||
seen.insert(bb.index());
|
||||
}
|
||||
|
||||
let basic_blocks = mir.basic_blocks_mut();
|
||||
|
||||
let num_blocks = basic_blocks.len();
|
||||
let mut replacements : Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
|
||||
let mut used_blocks = 0;
|
||||
for alive_index in seen.iter() {
|
||||
replacements[alive_index] = BasicBlock::new(used_blocks);
|
||||
if alive_index != used_blocks {
|
||||
// Swap the next alive block data with the current available slot. Since alive_index is
|
||||
// non-decreasing this is a valid operation.
|
||||
basic_blocks.raw.swap(alive_index, used_blocks);
|
||||
}
|
||||
used_blocks += 1;
|
||||
}
|
||||
basic_blocks.raw.truncate(used_blocks);
|
||||
|
||||
for block in basic_blocks {
|
||||
for target in block.terminator_mut().successors_mut() {
|
||||
*target = replacements[target.index()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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, &[]);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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(_)) => {
|
||||
|
@ -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|{
|
||||
if bb == mir::START_BLOCK {
|
||||
fcx.new_block("start", None)
|
||||
} else {
|
||||
fcx.new_block(&format!("{:?}", bb), None)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
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();
|
||||
|
||||
// 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 {
|
||||
|
@ -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),
|
||||
|
@ -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
1
src/rustc/Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
@ -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>) {
|
||||
|
Loading…
Reference in New Issue
Block a user