X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=compiler%2Frustc_mir%2Fsrc%2Fdataflow%2Fframework%2Fengine.rs;h=c1e500d01b1d34cb070d550ae820ad31be561c89;hb=0242f963c631a130a3c405d7e54f4695ef10a139;hp=f39c78f503daed8aff0461584a715fdd38a6620f;hpb=4ae7710e1df02a1c38f2d2908fbbe5543c2e9d51;p=rust.git diff --git a/compiler/rustc_mir/src/dataflow/framework/engine.rs b/compiler/rustc_mir/src/dataflow/framework/engine.rs index f39c78f503d..3f9f558223b 100644 --- a/compiler/rustc_mir/src/dataflow/framework/engine.rs +++ b/compiler/rustc_mir/src/dataflow/framework/engine.rs @@ -2,7 +2,6 @@ use std::borrow::BorrowMut; use std::ffi::OsString; -use std::fs; use std::path::PathBuf; use rustc_ast as ast; @@ -12,7 +11,7 @@ use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::{self, traversal, BasicBlock}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{sym, Symbol}; use super::fmt::DebugWithContext; @@ -21,7 +20,7 @@ visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice, ResultsCursor, ResultsVisitor, }; -use crate::util::pretty::dump_enabled; +use crate::util::pretty::{create_dump_file, dump_enabled}; /// A dataflow analysis that has converged to fixpoint. pub struct Results<'tcx, A> @@ -63,15 +62,6 @@ pub fn visit_reachable_with( let blocks = mir::traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) } - - pub fn visit_in_rpo_with( - &self, - body: &'mir mir::Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, - ) { - let blocks = mir::traversal::reverse_postorder(body); - visit_results(body, blocks.map(|(bb, _)| bb), self, vis) - } } /// A solver for dataflow problems. @@ -81,7 +71,6 @@ pub struct Engine<'a, 'tcx, A> { tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, - def_id: DefId, dead_unwinds: Option<&'a BitSet>, entry_sets: IndexVec, pass_name: Option<&'static str>, @@ -103,18 +92,13 @@ impl Engine<'a, 'tcx, A> T: Idx, { /// Creates a new `Engine` to solve a gen-kill dataflow problem. - pub fn new_gen_kill( - tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, - def_id: DefId, - analysis: A, - ) -> Self { + pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self { // If there are no back-edges in the control-flow graph, we only ever need to apply the // transfer function for each block exactly once (assuming that we process blocks in RPO). // // In this case, there's no need to compute the block transfer functions ahead of time. if !body.is_cfg_cyclic() { - return Self::new(tcx, body, def_id, analysis, None); + return Self::new(tcx, body, analysis, None); } // Otherwise, compute and store the cumulative transfer function for each block. @@ -131,7 +115,7 @@ pub fn new_gen_kill( trans_for_block[bb].apply(state.borrow_mut()); }); - Self::new(tcx, body, def_id, analysis, Some(apply_trans as Box<_>)) + Self::new(tcx, body, analysis, Some(apply_trans as Box<_>)) } } @@ -145,19 +129,13 @@ impl Engine<'a, 'tcx, A> /// /// Gen-kill problems should use `new_gen_kill`, which will coalesce transfer functions for /// better performance. - pub fn new_generic( - tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, - def_id: DefId, - analysis: A, - ) -> Self { - Self::new(tcx, body, def_id, analysis, None) + pub fn new_generic(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self { + Self::new(tcx, body, analysis, None) } fn new( tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, - def_id: DefId, analysis: A, apply_trans_for_block: Option>, ) -> Self { @@ -173,7 +151,6 @@ fn new( analysis, tcx, body, - def_id, dead_unwinds: None, pass_name: None, entry_sets, @@ -209,7 +186,6 @@ pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> analysis, body, dead_unwinds, - def_id, mut entry_sets, tcx, apply_trans_for_block, @@ -232,12 +208,19 @@ pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> } } + // `state` is not actually used between iterations; + // this is just an optimization to avoid reallocating + // every iteration. let mut state = analysis.bottom_value(body); while let Some(bb) = dirty_queue.pop() { let bb_data = &body[bb]; - // Apply the block transfer function, using the cached one if it exists. + // Set the state to the entry state of the block. + // This is equivalent to `state = entry_sets[bb].clone()`, + // but it saves an allocation, thus improving compile times. state.clone_from(&entry_sets[bb]); + + // Apply the block transfer function, using the cached one if it exists. match &apply_trans_for_block { Some(apply) => apply(bb, &mut state), None => A::Direction::apply_effects_in_block(&analysis, &mut state, bb, bb_data), @@ -261,9 +244,9 @@ pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> let results = Results { analysis, entry_sets }; - let res = write_graphviz_results(tcx, def_id, &body, &results, pass_name); + let res = write_graphviz_results(tcx, &body, &results, pass_name); if let Err(e) = res { - warn!("Failed to write graphviz dataflow results: {}", e); + error!("Failed to write graphviz dataflow results: {}", e); } results @@ -276,7 +259,6 @@ pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> /// `rustc_mir` attributes. fn write_graphviz_results( tcx: TyCtxt<'tcx>, - def_id: DefId, body: &mir::Body<'tcx>, results: &Results<'tcx, A>, pass_name: Option<&'static str>, @@ -285,6 +267,10 @@ fn write_graphviz_results( A: Analysis<'tcx>, A::Domain: DebugWithContext, { + use std::fs; + use std::io::{self, Write}; + + let def_id = body.source.def_id(); let attrs = match RustcMirAttrs::parse(tcx, def_id) { Ok(attrs) => attrs, @@ -292,27 +278,29 @@ fn write_graphviz_results( Err(()) => return Ok(()), }; - let path = match attrs.output_path(A::NAME) { - Some(path) => path, + let mut file = match attrs.output_path(A::NAME) { + Some(path) => { + debug!("printing dataflow results for {:?} to {}", def_id, path.display()); + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + io::BufWriter::new(fs::File::create(&path)?) + } None if tcx.sess.opts.debugging_opts.dump_mir_dataflow && dump_enabled(tcx, A::NAME, def_id) => { - // FIXME: Use some variant of `pretty::dump_path` for this - let mut path = PathBuf::from(&tcx.sess.opts.debugging_opts.dump_mir_dir); - - let crate_name = tcx.crate_name(def_id.krate); - let item_name = ty::print::with_forced_impl_filename_line(|| { - tcx.def_path(def_id).to_filename_friendly_no_crate() - }); - - let pass_name = pass_name.map(|s| format!(".{}", s)).unwrap_or_default(); - - path.push(format!("{}.{}.{}{}.dot", crate_name, item_name, A::NAME, pass_name)); - path + create_dump_file( + tcx, + ".dot", + None, + A::NAME, + &pass_name.unwrap_or("-----"), + body.source, + )? } - None => return Ok(()), + _ => return Ok(()), }; let style = match attrs.formatter { @@ -320,10 +308,9 @@ fn write_graphviz_results( _ => graphviz::OutputStyle::AfterOnly, }; - debug!("printing dataflow results for {:?} to {}", def_id, path.display()); let mut buf = Vec::new(); - let graphviz = graphviz::Formatter::new(body, def_id, results, style); + let graphviz = graphviz::Formatter::new(body, results, style); let mut render_opts = vec![dot::RenderOption::Fontname(tcx.sess.opts.debugging_opts.graphviz_font.clone())]; if tcx.sess.opts.debugging_opts.graphviz_dark_mode { @@ -331,10 +318,7 @@ fn write_graphviz_results( } dot::render_opts(&graphviz, &mut buf, &render_opts)?; - if let Some(parent) = path.parent() { - fs::create_dir_all(parent)?; - } - fs::write(&path, buf)?; + file.write_all(&buf)?; Ok(()) }