diff --git a/src/Cargo.lock b/src/Cargo.lock index 26be463f6bb6f..77e33855f2344 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1668,6 +1668,7 @@ dependencies = [ "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 2d2558fd815c4..cb4126245afae 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -406,7 +406,7 @@ impl DepGraph { for (current_dep_node_index, edges) in current_dep_graph.edges.iter_enumerated() { let start = edge_list_data.len() as u32; // This should really just be a memcpy :/ - edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex(i.index))); + edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex::new(i.index()))); let end = edge_list_data.len() as u32; debug_assert_eq!(current_dep_node_index.index(), edge_list_indices.len()); diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc/dep_graph/serialized.rs index 7275a740e76f8..c96040ab9b6e3 100644 --- a/src/librustc/dep_graph/serialized.rs +++ b/src/librustc/dep_graph/serialized.rs @@ -14,23 +14,7 @@ use dep_graph::DepNode; use ich::Fingerprint; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -/// The index of a DepNode in the SerializedDepGraph::nodes array. -#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, - RustcEncodable, RustcDecodable)] -pub struct SerializedDepNodeIndex(pub u32); - -impl Idx for SerializedDepNodeIndex { - #[inline] - fn new(idx: usize) -> Self { - assert!(idx <= ::std::u32::MAX as usize); - SerializedDepNodeIndex(idx as u32) - } - - #[inline] - fn index(self) -> usize { - self.0 as usize - } -} +newtype_index!(SerializedDepNodeIndex); /// Data for use when recompiling the **current crate**. #[derive(Debug, RustcEncodable, RustcDecodable)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 1e90aa47267ff..015dbbb7affa9 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -43,6 +43,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] +#![feature(const_fn)] #![feature(core_intrinsics)] #![feature(i128_type)] #![cfg_attr(windows, feature(libc))] @@ -71,7 +72,7 @@ extern crate graphviz; extern crate libc; extern crate owning_ref; extern crate rustc_back; -extern crate rustc_data_structures; +#[macro_use] extern crate rustc_data_structures; extern crate serialize; extern crate rustc_const_math; extern crate rustc_errors as errors; diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index ba221ef6ae10b..b909269e1538e 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -43,30 +43,6 @@ pub mod visit; pub mod transform; pub mod traversal; -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) - } - } - ) -} - /// Types for locals type LocalDecls<'tcx> = IndexVec>; diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 1d0e88ee32855..4b7f55eba06be 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -38,6 +38,43 @@ impl Idx for u32 { fn index(self) -> usize { self as usize } } +#[macro_export] +macro_rules! newtype_index { + ($name:ident) => ( + newtype_index!($name, unsafe { ::std::intrinsics::type_name::<$name>() }); + ); + + ($name:ident, $debug_name:expr) => ( + #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, + RustcEncodable, RustcDecodable)] + pub struct $name(u32); + + impl $name { + // HACK use for constants + #[allow(unused)] + const fn const_new(x: u32) -> Self { + $name(x) + } + } + + impl Idx for $name { + fn new(value: usize) -> Self { + assert!(value < (::std::u32::MAX) as usize); + $name(value as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + impl ::std::fmt::Debug for $name { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(fmt, "{}{}", $debug_name, self.0) + } + } + ) +} + #[derive(Clone, PartialEq, Eq)] pub struct IndexVec { pub raw: Vec, diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 936fd5a774d3c..b7a576babeb67 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -17,5 +17,6 @@ rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } +serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 68ef646184c2c..b8bb2a404620e 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -149,7 +149,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t mem::transmute::>(mir) }; - mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); + mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir, |_, _| Ok(()) ); mir }) @@ -227,7 +227,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mem::transmute::>(mir) }; - mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir); + mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir, |_, _| Ok(()) ); mir }) @@ -311,19 +311,7 @@ struct CFG<'tcx> { basic_blocks: IndexVec>, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct ScopeId(u32); - -impl Idx for ScopeId { - fn new(index: usize) -> ScopeId { - assert!(index < (u32::MAX as usize)); - ScopeId(index as u32) - } - - fn index(self) -> usize { - self.0 as usize - } -} +newtype_index!(ScopeId); /////////////////////////////////////////////////////////////////////////// /// The `BlockAnd` "monad" packages up the new basic block along with a diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index d0b9849986b82..7e4206e14c561 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -18,6 +18,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(const_fn)] +#![feature(core_intrinsics)] #![feature(i128_type)] #![feature(rustc_diagnostic_macros)] #![feature(placement_in_syntax)] @@ -30,7 +32,8 @@ extern crate bitflags; extern crate graphviz as dot; #[macro_use] extern crate rustc; -extern crate rustc_data_structures; +#[macro_use] extern crate rustc_data_structures; +extern crate serialize as rustc_serialize; extern crate rustc_errors; #[macro_use] extern crate syntax; diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 67a3281dba48b..cea66837d9aaf 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -65,7 +65,18 @@ impl PassHook for DumpMir { pass_name, &Disambiguator { is_after }, source, - mir); + mir, + |_, _| Ok(()) ); + for (index, promoted_mir) in mir.promoted.iter_enumerated() { + let promoted_source = MirSource::Promoted(source.item_id(), index); + mir_util::dump_mir(tcx, + Some((suite, pass_num)), + pass_name, + &Disambiguator { is_after }, + promoted_source, + promoted_mir, + |_, _| Ok(()) ); + } } } } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 729fe46ef37ec..7d0814b67fba5 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -587,7 +587,7 @@ fn create_generator_drop_shim<'a, 'tcx>( // unrelated code from the resume part of the function simplify::remove_dead_blocks(&mut mir); - dump_mir(tcx, None, "generator_drop", &0, source, &mut mir); + dump_mir(tcx, None, "generator_drop", &0, source, &mut mir, |_, _| Ok(()) ); mir } @@ -673,7 +673,7 @@ fn create_generator_resume_function<'a, 'tcx>( // unrelated code from the drop part of the function simplify::remove_dead_blocks(mir); - dump_mir(tcx, None, "generator_resume", &0, source, mir); + dump_mir(tcx, None, "generator_resume", &0, source, mir, |_, _| Ok(()) ); } fn source_info<'a, 'tcx>(mir: &Mir<'tcx>) -> SourceInfo { @@ -816,14 +816,14 @@ impl MirPass for StateTransform { // This is expanded to a drop ladder in `elaborate_generator_drops`. let drop_clean = insert_clean_drop(mir); - dump_mir(tcx, None, "generator_pre-elab", &0, source, mir); + dump_mir(tcx, None, "generator_pre-elab", &0, source, mir, |_, _| Ok(()) ); // Expand `drop(generator_struct)` to a drop ladder which destroys upvars. // If any upvars are moved out of, drop elaboration will handle upvar destruction. // However we need to also elaborate the code generated by `insert_clean_drop`. elaborate_generator_drops(tcx, def_id, mir); - dump_mir(tcx, None, "generator_post-transform", &0, source, mir); + dump_mir(tcx, None, "generator_post-transform", &0, source, mir, |_, _| Ok(()) ); // Create a copy of our MIR and use it to create the drop shim for the generator let drop_shim = create_generator_drop_shim(tcx, diff --git a/src/librustc_mir/transform/nll/mod.rs b/src/librustc_mir/transform/nll/mod.rs index bd02788df1653..4925b1fcfed28 100644 --- a/src/librustc_mir/transform/nll/mod.rs +++ b/src/librustc_mir/transform/nll/mod.rs @@ -15,12 +15,19 @@ use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind}; use rustc::mir::visit::{MutVisitor, Lookup}; use rustc::mir::transform::{MirPass, MirSource}; use rustc::infer::{self, InferCtxt}; +use rustc::util::nodemap::FxHashSet; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use syntax_pos::DUMMY_SP; use std::collections::HashMap; +use std::fmt; + +use util as mir_util; +use self::mir_util::PassWhere; #[allow(dead_code)] struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { lookup_map: HashMap, + regions: IndexVec, infcx: InferCtxt<'a, 'gcx, 'tcx>, } @@ -29,6 +36,7 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { NLLVisitor { infcx, lookup_map: HashMap::new(), + regions: IndexVec::new(), } } @@ -36,8 +44,9 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { self.lookup_map } - fn renumber_regions(&self, value: &T) -> T where T: TypeFoldable<'tcx> { + fn renumber_regions(&mut self, value: &T) -> T where T: TypeFoldable<'tcx> { self.infcx.tcx.fold_regions(value, &mut false, |_region, _depth| { + self.regions.push(Region::default()); self.infcx.next_region_var(infer::MiscVariable(DUMMY_SP)) }) } @@ -129,7 +138,7 @@ pub struct NLL; impl MirPass for NLL { fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource, + source: MirSource, mir: &mut Mir<'tcx>) { if !tcx.sess.opts.debugging_opts.nll { return; @@ -140,7 +149,30 @@ impl MirPass for NLL { let mut renumbered_mir = mir.clone(); let mut visitor = NLLVisitor::new(infcx); visitor.visit_mir(&mut renumbered_mir); + mir_util::dump_mir(tcx, None, "nll", &0, source, mir, |pass_where, out| { + if let PassWhere::BeforeCFG = pass_where { + for (index, value) in visitor.regions.iter_enumerated() { + writeln!(out, "// R{:03}: {:?}", index.0, value)?; + } + } + Ok(()) + }); let _results = visitor.into_results(); }) } -} \ No newline at end of file +} + +#[derive(Clone, Default, PartialEq, Eq)] +struct Region { + points: FxHashSet, +} + +impl fmt::Debug for Region { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(formatter, "{:?}", self.points) + } +} + + + +newtype_index!(RegionIndex); diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index e6d3a82ff9b53..1424c063d7385 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -232,7 +232,7 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, writeln!(w, "{} {{{}}}", prefix, live.join(", ")) }; print(w, " ", &result.ins)?; - write_basic_block(tcx, block, mir, w)?; + write_basic_block(tcx, block, mir, &mut |_, _| Ok(()), w)?; print(w, " ", &result.outs)?; if block.index() + 1 != mir.basic_blocks().len() { writeln!(w, "")?; diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs index 4b6da96824dcd..13c14f8920f4e 100644 --- a/src/librustc_mir/util/mod.rs +++ b/src/librustc_mir/util/mod.rs @@ -17,6 +17,6 @@ mod graphviz; mod pretty; pub mod liveness; -pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty}; +pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere}; pub use self::graphviz::{write_mir_graphviz}; pub use self::graphviz::write_node_label as write_graphviz_node_label; diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 9e1f05f6d2f77..8a9047fb4911c 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -25,6 +25,22 @@ const INDENT: &'static str = " "; /// Alignment for lining up comments following MIR statements const ALIGN: usize = 40; +/// An indication of where we are in the control flow graph. Used for printing +/// extra information in `dump_mir` +pub enum PassWhere { + /// We have not started dumping the control flow graph, but we are about to. + BeforeCFG, + + /// We just finished dumping the control flow graph. This is right before EOF + AfterCFG, + + /// We are about to start dumping the given basic block. + BeforeBlock(BasicBlock), + + /// We are just about to dumpt the given statement or terminator. + InCFG(Location), +} + /// If the session is properly configured, dumps a human-readable /// representation of the mir into: /// @@ -39,12 +55,16 @@ const ALIGN: usize = 40; /// - `substring1&substring2,...` -- `&`-separated list of substrings /// that can appear in the pass-name or the `item_path_str` for the given /// node-id. If any one of the substrings match, the data is dumped out. -pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_num: Option<(MirSuite, MirPassIndex)>, - pass_name: &str, - disambiguator: &Display, - source: MirSource, - mir: &Mir<'tcx>) { +pub fn dump_mir<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass_num: Option<(MirSuite, MirPassIndex)>, + pass_name: &str, + disambiguator: &Display, + source: MirSource, + mir: &Mir<'tcx>, + extra_data: F) +where + F: FnMut(PassWhere, &mut Write) -> io::Result<()> +{ if !dump_enabled(tcx, pass_name, source) { return; } @@ -53,12 +73,7 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.item_path_str(tcx.hir.local_def_id(source.item_id())) }); dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, - disambiguator, source, mir); - for (index, promoted_mir) in mir.promoted.iter_enumerated() { - let promoted_source = MirSource::Promoted(source.item_id(), index); - dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator, - promoted_source, promoted_mir); - } + disambiguator, source, mir, extra_data); } pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -85,13 +100,17 @@ pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // `item_path_str()` would otherwise trigger `type_of`, and this can // run while we are already attempting to evaluate `type_of`. -fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - pass_num: Option<(MirSuite, MirPassIndex)>, - pass_name: &str, - node_path: &str, - disambiguator: &Display, - source: MirSource, - mir: &Mir<'tcx>) { +fn dump_matched_mir_node<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass_num: Option<(MirSuite, MirPassIndex)>, + pass_name: &str, + node_path: &str, + disambiguator: &Display, + source: MirSource, + mir: &Mir<'tcx>, + mut extra_data: F) +where + F: FnMut(PassWhere, &mut Write) -> io::Result<()> +{ let promotion_id = match source { MirSource::Promoted(_, id) => format!("-{:?}", id), MirSource::GeneratorDrop(_) => format!("-drop"), @@ -125,7 +144,9 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, writeln!(file, "// generator_layout = {:?}", layout)?; } writeln!(file, "")?; - write_mir_fn(tcx, source, mir, &mut file)?; + extra_data(PassWhere::BeforeCFG, &mut file)?; + write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?; + extra_data(PassWhere::AfterCFG, &mut file)?; Ok(()) }); } @@ -152,24 +173,29 @@ pub fn write_mir_pretty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let id = tcx.hir.as_local_node_id(def_id).unwrap(); let src = MirSource::from_node(tcx, id); - write_mir_fn(tcx, src, mir, w)?; + write_mir_fn(tcx, src, mir, &mut |_, _| Ok(()), w)?; for (i, mir) in mir.promoted.iter_enumerated() { writeln!(w, "")?; - write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w)?; + write_mir_fn(tcx, MirSource::Promoted(id, i), mir, &mut |_, _| Ok(()), w)?; } } Ok(()) } -pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, - mir: &Mir<'tcx>, - w: &mut Write) - -> io::Result<()> { +pub fn write_mir_fn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + extra_data: &mut F, + w: &mut Write) + -> io::Result<()> +where + F: FnMut(PassWhere, &mut Write) -> io::Result<()> +{ write_mir_intro(tcx, src, mir, w)?; for block in mir.basic_blocks().indices() { - write_basic_block(tcx, block, mir, w)?; + extra_data(PassWhere::BeforeBlock(block), w)?; + write_basic_block(tcx, block, mir, extra_data, w)?; if block.index() + 1 != mir.basic_blocks().len() { writeln!(w, "")?; } @@ -180,11 +206,15 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } /// Write out a human-readable textual representation for the given basic block. -pub fn write_basic_block(tcx: TyCtxt, - block: BasicBlock, - mir: &Mir, - w: &mut Write) - -> io::Result<()> { +pub fn write_basic_block(tcx: TyCtxt, + block: BasicBlock, + mir: &Mir, + extra_data: &mut F, + w: &mut Write) + -> io::Result<()> +where + F: FnMut(PassWhere, &mut Write) -> io::Result<()> +{ let data = &mir[block]; // Basic block label at the top. @@ -195,6 +225,7 @@ pub fn write_basic_block(tcx: TyCtxt, // List of statements in the middle. let mut current_location = Location { block: block, statement_index: 0 }; for statement in &data.statements { + extra_data(PassWhere::InCFG(current_location), w)?; let indented_mir = format!("{0}{0}{1:?};", INDENT, statement); writeln!(w, "{0:1$} // {2}", indented_mir, @@ -205,6 +236,7 @@ pub fn write_basic_block(tcx: TyCtxt, } // Terminator at the bottom. + extra_data(PassWhere::InCFG(current_location), w)?; let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); writeln!(w, "{0:1$} // {2}", indented_terminator,