]> git.lizzy.rs Git - rust.git/commitdiff
allow dumping intermediate IR with -Z dump-mir
authorNiko Matsakis <niko@alum.mit.edu>
Tue, 22 Mar 2016 20:05:28 +0000 (16:05 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Wed, 23 Mar 2016 20:42:53 +0000 (16:42 -0400)
src/librustc/session/config.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/mir_map.rs
src/librustc_mir/pretty.rs
src/librustc_mir/transform/simplify_cfg.rs

index 17f70b2d8dc663ebd7cd01a6b51e48081f74fe62..bf532d9ccf9ed3263aedc2e79c78de71e500e1ef 100644 (file)
@@ -663,6 +663,8 @@ fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
           "print the result of the translation item collection pass"),
     mir_opt_level: Option<usize> = (None, parse_opt_uint,
           "set the MIR optimization level (0-3)"),
+    dump_mir: Option<String> = (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"),
 }
index f2def53d4ead02db34ed77bc13b3a2c17de506e6..2da2a15cbd70917a20d94b253187ddd0ec523219 100644 (file)
@@ -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,
index 71037d1f080700b6d6311eb9e91e8fa638daad1b..242d2506c82f172886cec4c1dc7e4ee765c63528 100644 (file)
@@ -22,6 +22,7 @@
 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)
 }
 
index 650f2d5bcb8027f6ec37117ef6b099991398d7f6..d8cfd8a88cf9b43bb8feb4f97945e5baf62e9d48 100644 (file)
 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<node_id>.<pass_name>.<disambiguator>
+/// ```
+///
+/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
+/// where `<filter>` 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<ScopeAuxiliary>>) {
+    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)
index 4e192095043eb075b83afa084d81fe04b8ba6405..d1f9a5bd259aa025d4e6fe582202a9b853bce0f2 100644 (file)
@@ -30,6 +30,7 @@ fn final_target(mir: &Mir, mut target: BasicBlock) -> Option<BasicBlock> {
             let mut seen: Vec<BasicBlock> = 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 @@ fn final_target(mir: &Mir, mut target: BasicBlock) -> Option<BasicBlock> {
             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,