diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 17f70b2d8dc6..bf532d9ccf9e 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -663,6 +663,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print the result of the translation item collection pass"), mir_opt_level: Option = (None, parse_opt_uint, "set the MIR optimization level (0-3)"), + dump_mir: Option = (None, parse_opt_string, + "dump MIR state at various points in translation"), orbit: bool = (false, parse_bool, "get MIR where it belongs - everywhere; most importantly, in orbit"), } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index f2def53d4ead..2da2a15cbd70 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -173,6 +173,18 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>, builder.cfg.terminate(END_BLOCK, arg_scope_id, span, TerminatorKind::Return); + assert!( + builder.cfg.basic_blocks + .iter() + .enumerate() + .all(|(index, block)| { + if block.terminator.is_none() { + panic!("no terminator on block {:?} in {:?}", + index, argument_extent) + } + true + })); + MirPlusPlus { mir: Mir { basic_blocks: builder.cfg.basic_blocks, diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 71037d1f0807..242d2506c82f 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -22,6 +22,7 @@ extern crate rustc_front; use build::{self, MirPlusPlus}; use rustc::dep_graph::DepNode; use rustc::mir::repr::Mir; +use pretty; use hair::cx::Cx; use rustc::mir::mir_map::MirMap; @@ -182,7 +183,7 @@ fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>, let parameter_scope = cx.tcx().region_maps.lookup_code_extent( CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id }); - let MirPlusPlus { mut mir, scope_auxiliary: _ } = + let MirPlusPlus { mut mir, scope_auxiliary } = build::construct(cx, span, implicit_arg_tys, @@ -201,6 +202,13 @@ fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>, _ => {} } + pretty::dump_mir(cx.tcx(), + "mir_map", + &0, + fn_id, + &mir, + Some(&scope_auxiliary)); + Ok(mir) } diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index 650f2d5bcb80..d8cfd8a88cf9 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -12,12 +12,63 @@ use build::{Location, ScopeAuxiliary}; use rustc::mir::repr::*; use rustc::middle::ty::{self, TyCtxt}; use rustc_data_structures::fnv::FnvHashMap; +use std::fmt::Display; +use std::fs; use std::io::{self, Write}; use syntax::ast::NodeId; use syntax::codemap::Span; const INDENT: &'static str = " "; +/// If the session is properly configured, dumps a human-readable +/// representation of the mir into: +/// +/// ``` +/// rustc.node.. +/// ``` +/// +/// Output from this function is controlled by passing `-Z dump-mir=`, +/// where `` takes the following forms: +/// +/// - `all` -- dump MIR for all fns, all passes, all everything +/// - `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<'tcx>, + pass_name: &str, + disambiguator: &Display, + node_id: NodeId, + mir: &Mir<'tcx>, + auxiliary: Option<&Vec>) { + let filters = match tcx.sess.opts.debugging_opts.dump_mir { + None => return, + Some(ref filters) => filters, + }; + let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id)); + let is_matched = + filters.split("&") + .any(|filter| { + filter == "all" || + pass_name.contains(filter) || + node_path.contains(filter) + }); + if !is_matched { + return; + } + + let file_name = format!("rustc.node{}.{}.{}.mir", + node_id, pass_name, disambiguator); + let _ = fs::File::create(&file_name).and_then(|mut file| { + try!(writeln!(file, "// MIR for `{}`", node_path)); + try!(writeln!(file, "// node_id = {}", node_id)); + try!(writeln!(file, "// pass_name = {}", pass_name)); + try!(writeln!(file, "// disambiguator = {}", disambiguator)); + try!(writeln!(file, "")); + try!(write_mir_fn(tcx, node_id, mir, &mut file, auxiliary)); + Ok(()) + }); +} + /// Write out a human-readable textual representation for the given MIR. pub fn write_mir_pretty<'a, 'tcx, I>(tcx: &TyCtxt<'tcx>, iter: I, @@ -117,7 +168,7 @@ fn write_basic_block(tcx: &TyCtxt, // Terminator at the bottom. writeln!(w, "{0}{0}{1:?}; // {2}", INDENT, - data.terminator(), + data.terminator().kind, comment(tcx, data.terminator().scope, data.terminator().span))?; writeln!(w, "{}}}", INDENT) diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index 4e192095043e..d1f9a5bd259a 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -30,6 +30,7 @@ impl SimplifyCfg { let mut seen: Vec = Vec::with_capacity(8); while mir.basic_block_data(target).statements.is_empty() { + debug!("final_target: target={:?}", target); match mir.basic_block_data(target).terminator().kind { TerminatorKind::Goto { target: next } => { if seen.contains(&next) { @@ -51,6 +52,8 @@ impl SimplifyCfg { let mut terminator = mir.basic_block_data_mut(bb).terminator.take() .expect("invalid terminator state"); + debug!("remove_goto_chains: bb={:?} terminator={:?}", bb, terminator); + for target in terminator.successors_mut() { let new_target = match final_target(mir, *target) { Some(new_target) => new_target,