about summary refs log tree commit diff
path: root/compiler/rustc_mir_dataflow
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2024-12-10 13:51:12 +0100
committerGitHub <noreply@github.com>2024-12-10 13:51:12 +0100
commit06107a20e3eaac0da5ac0f6729bbf52ec90541d3 (patch)
tree4560afba44fce86c051fdc8deb15f394d02e49fd /compiler/rustc_mir_dataflow
parent599ff4d2489ddd3c242abf864693cb7398f04521 (diff)
parentb59c4dc2612865a945ae200385115d7815a6f91f (diff)
downloadrust-06107a20e3eaac0da5ac0f6729bbf52ec90541d3.tar.gz
rust-06107a20e3eaac0da5ac0f6729bbf52ec90541d3.zip
Rollup merge of #134065 - nnethercote:mv-write_graphviz_results, r=tmiasko
Move `write_graphviz_results`

r? ``@tmiasko``
Diffstat (limited to 'compiler/rustc_mir_dataflow')
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs183
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/results.rs184
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs4
4 files changed, 182 insertions, 191 deletions
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index 561229cf725..f844e8fbe03 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -2,19 +2,186 @@
 
 use std::borrow::Cow;
 use std::cell::RefCell;
+use std::ffi::OsString;
+use std::path::PathBuf;
 use std::sync::OnceLock;
 use std::{io, ops, str};
 
 use regex::Regex;
-use rustc_graphviz as dot;
+use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::{self, BasicBlock, Body, Location, graphviz_safe_def_name};
+use rustc_middle::mir::{
+    self, BasicBlock, Body, Location, create_dump_file, dump_enabled, graphviz_safe_def_name,
+    traversal,
+};
+use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_span::symbol::{Symbol, sym};
+use tracing::debug;
+use {rustc_ast as ast, rustc_graphviz as dot};
 
 use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext};
 use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor};
+use crate::errors::{
+    DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
+};
+
+/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
+/// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are
+/// the same.
+pub(super) fn write_graphviz_results<'tcx, A>(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+    results: &mut Results<'tcx, A>,
+    pass_name: Option<&'static str>,
+) -> std::io::Result<()>
+where
+    A: Analysis<'tcx>,
+    A::Domain: DebugWithContext<A>,
+{
+    use std::fs;
+    use std::io::Write;
+
+    let def_id = body.source.def_id();
+    let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else {
+        // Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
+        return Ok(());
+    };
+
+    let file = try {
+        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)?;
+                }
+                fs::File::create_buffered(&path)?
+            }
+
+            None if dump_enabled(tcx, A::NAME, def_id) => {
+                create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
+            }
+
+            _ => return Ok(()),
+        }
+    };
+    let mut file = match file {
+        Ok(f) => f,
+        Err(e) => return Err(e),
+    };
+
+    let style = match attrs.formatter {
+        Some(sym::two_phase) => OutputStyle::BeforeAndAfter,
+        _ => OutputStyle::AfterOnly,
+    };
+
+    let mut buf = Vec::new();
+
+    let graphviz = Formatter::new(body, results, style);
+    let mut render_opts =
+        vec![dot::RenderOption::Fontname(tcx.sess.opts.unstable_opts.graphviz_font.clone())];
+    if tcx.sess.opts.unstable_opts.graphviz_dark_mode {
+        render_opts.push(dot::RenderOption::DarkTheme);
+    }
+    let r = with_no_trimmed_paths!(dot::render_opts(&graphviz, &mut buf, &render_opts));
+
+    let lhs = try {
+        r?;
+        file.write_all(&buf)?;
+    };
+
+    lhs
+}
+
+#[derive(Default)]
+struct RustcMirAttrs {
+    basename_and_suffix: Option<PathBuf>,
+    formatter: Option<Symbol>,
+}
+
+impl RustcMirAttrs {
+    fn parse(tcx: TyCtxt<'_>, def_id: DefId) -> Result<Self, ()> {
+        let mut result = Ok(());
+        let mut ret = RustcMirAttrs::default();
+
+        let rustc_mir_attrs = tcx
+            .get_attrs(def_id, sym::rustc_mir)
+            .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
+
+        for attr in rustc_mir_attrs {
+            let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) {
+                Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| {
+                    let path = PathBuf::from(s.to_string());
+                    match path.file_name() {
+                        Some(_) => Ok(path),
+                        None => {
+                            tcx.dcx().emit_err(PathMustEndInFilename { span: attr.span() });
+                            Err(())
+                        }
+                    }
+                })
+            } else if attr.has_name(sym::borrowck_graphviz_format) {
+                Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s {
+                    sym::gen_kill | sym::two_phase => Ok(s),
+                    _ => {
+                        tcx.dcx().emit_err(UnknownFormatter { span: attr.span() });
+                        Err(())
+                    }
+                })
+            } else {
+                Ok(())
+            };
+
+            result = result.and(attr_result);
+        }
+
+        result.map(|()| ret)
+    }
+
+    fn set_field<T>(
+        field: &mut Option<T>,
+        tcx: TyCtxt<'_>,
+        attr: &ast::MetaItemInner,
+        mapper: impl FnOnce(Symbol) -> Result<T, ()>,
+    ) -> Result<(), ()> {
+        if field.is_some() {
+            tcx.dcx()
+                .emit_err(DuplicateValuesFor { span: attr.span(), name: attr.name_or_empty() });
+
+            return Err(());
+        }
+
+        if let Some(s) = attr.value_str() {
+            *field = Some(mapper(s)?);
+            Ok(())
+        } else {
+            tcx.dcx()
+                .emit_err(RequiresAnArgument { span: attr.span(), name: attr.name_or_empty() });
+            Err(())
+        }
+    }
+
+    /// Returns the path where dataflow results should be written, or `None`
+    /// `borrowck_graphviz_postflow` was not specified.
+    ///
+    /// This performs the following transformation to the argument of `borrowck_graphviz_postflow`:
+    ///
+    /// "path/suffix.dot" -> "path/analysis_name_suffix.dot"
+    fn output_path(&self, analysis_name: &str) -> Option<PathBuf> {
+        let mut ret = self.basename_and_suffix.as_ref().cloned()?;
+        let suffix = ret.file_name().unwrap(); // Checked when parsing attrs
+
+        let mut file_name: OsString = analysis_name.into();
+        file_name.push("_");
+        file_name.push(suffix);
+        ret.set_file_name(file_name);
+
+        Some(ret)
+    }
+}
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub(crate) enum OutputStyle {
+enum OutputStyle {
     AfterOnly,
     BeforeAndAfter,
 }
@@ -28,7 +195,7 @@ impl OutputStyle {
     }
 }
 
-pub(crate) struct Formatter<'mir, 'tcx, A>
+struct Formatter<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
@@ -45,12 +212,12 @@ impl<'mir, 'tcx, A> Formatter<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
-    pub(crate) fn new(
+    fn new(
         body: &'mir Body<'tcx>,
         results: &'mir mut Results<'tcx, A>,
         style: OutputStyle,
     ) -> Self {
-        let reachable = mir::traversal::reachable_as_bitset(body);
+        let reachable = traversal::reachable_as_bitset(body);
         Formatter { cursor: results.as_results_cursor(body).into(), style, reachable }
     }
 
@@ -61,7 +228,7 @@ where
 
 /// A pair of a basic block and an index into that basic blocks `successors`.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub(crate) struct CfgEdge {
+struct CfgEdge {
     source: BasicBlock,
     index: usize,
 }
@@ -520,7 +687,7 @@ struct StateDiffCollector<D> {
 
 impl<D> StateDiffCollector<D> {
     fn run<'tcx, A>(
-        body: &mir::Body<'tcx>,
+        body: &Body<'tcx>,
         block: BasicBlock,
         results: &mut Results<'tcx, A>,
         style: OutputStyle,
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index caff2a81ff3..7f5a68e884e 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -42,7 +42,7 @@ use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, Terminator
 use rustc_middle::ty::TyCtxt;
 use tracing::error;
 
-use self::results::write_graphviz_results;
+use self::graphviz::write_graphviz_results;
 use super::fmt::DebugWithContext;
 
 mod cursor;
diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs
index c4321c454e6..a7dbd99b8ab 100644
--- a/compiler/rustc_mir_dataflow/src/framework/results.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/results.rs
@@ -1,22 +1,9 @@
 //! Dataflow analysis results.
 
-use std::ffi::OsString;
-use std::path::PathBuf;
-
-use rustc_hir::def_id::DefId;
 use rustc_index::IndexVec;
-use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal};
-use rustc_middle::ty::TyCtxt;
-use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_span::symbol::{Symbol, sym};
-use tracing::debug;
-use {rustc_ast as ast, rustc_graphviz as dot};
+use rustc_middle::mir::{BasicBlock, Body, traversal};
 
-use super::fmt::DebugWithContext;
-use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results};
-use crate::errors::{
-    DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
-};
+use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results};
 use crate::framework::cursor::ResultsHandle;
 
 pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
@@ -41,16 +28,13 @@ where
     /// `Results` is also used outside the cursor.
     pub fn as_results_cursor<'mir>(
         &'mir mut self,
-        body: &'mir mir::Body<'tcx>,
+        body: &'mir Body<'tcx>,
     ) -> ResultsCursor<'mir, 'tcx, A> {
         ResultsCursor::new(body, ResultsHandle::BorrowedMut(self))
     }
 
     /// Creates a `ResultsCursor` that takes ownership of the `Results`.
-    pub fn into_results_cursor<'mir>(
-        self,
-        body: &'mir mir::Body<'tcx>,
-    ) -> ResultsCursor<'mir, 'tcx, A> {
+    pub fn into_results_cursor<'mir>(self, body: &'mir Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> {
         ResultsCursor::new(body, ResultsHandle::Owned(self))
     }
 
@@ -61,7 +45,7 @@ where
 
     pub fn visit_with<'mir>(
         &mut self,
-        body: &'mir mir::Body<'tcx>,
+        body: &'mir Body<'tcx>,
         blocks: impl IntoIterator<Item = BasicBlock>,
         vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) {
@@ -70,166 +54,10 @@ where
 
     pub fn visit_reachable_with<'mir>(
         &mut self,
-        body: &'mir mir::Body<'tcx>,
+        body: &'mir Body<'tcx>,
         vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
     ) {
         let blocks = traversal::reachable(body);
         visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
     }
 }
-
-// Graphviz
-
-/// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
-/// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are
-/// the same.
-pub(super) fn write_graphviz_results<'tcx, A>(
-    tcx: TyCtxt<'tcx>,
-    body: &mir::Body<'tcx>,
-    results: &mut Results<'tcx, A>,
-    pass_name: Option<&'static str>,
-) -> std::io::Result<()>
-where
-    A: Analysis<'tcx>,
-    A::Domain: DebugWithContext<A>,
-{
-    use std::fs;
-    use std::io::Write;
-
-    let def_id = body.source.def_id();
-    let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else {
-        // Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
-        return Ok(());
-    };
-
-    let file = try {
-        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)?;
-                }
-                fs::File::create_buffered(&path)?
-            }
-
-            None if dump_enabled(tcx, A::NAME, def_id) => {
-                create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
-            }
-
-            _ => return Ok(()),
-        }
-    };
-    let mut file = match file {
-        Ok(f) => f,
-        Err(e) => return Err(e),
-    };
-
-    let style = match attrs.formatter {
-        Some(sym::two_phase) => graphviz::OutputStyle::BeforeAndAfter,
-        _ => graphviz::OutputStyle::AfterOnly,
-    };
-
-    let mut buf = Vec::new();
-
-    let graphviz = graphviz::Formatter::new(body, results, style);
-    let mut render_opts =
-        vec![dot::RenderOption::Fontname(tcx.sess.opts.unstable_opts.graphviz_font.clone())];
-    if tcx.sess.opts.unstable_opts.graphviz_dark_mode {
-        render_opts.push(dot::RenderOption::DarkTheme);
-    }
-    let r = with_no_trimmed_paths!(dot::render_opts(&graphviz, &mut buf, &render_opts));
-
-    let lhs = try {
-        r?;
-        file.write_all(&buf)?;
-    };
-
-    lhs
-}
-
-#[derive(Default)]
-struct RustcMirAttrs {
-    basename_and_suffix: Option<PathBuf>,
-    formatter: Option<Symbol>,
-}
-
-impl RustcMirAttrs {
-    fn parse(tcx: TyCtxt<'_>, def_id: DefId) -> Result<Self, ()> {
-        let mut result = Ok(());
-        let mut ret = RustcMirAttrs::default();
-
-        let rustc_mir_attrs = tcx
-            .get_attrs(def_id, sym::rustc_mir)
-            .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
-
-        for attr in rustc_mir_attrs {
-            let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) {
-                Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| {
-                    let path = PathBuf::from(s.to_string());
-                    match path.file_name() {
-                        Some(_) => Ok(path),
-                        None => {
-                            tcx.dcx().emit_err(PathMustEndInFilename { span: attr.span() });
-                            Err(())
-                        }
-                    }
-                })
-            } else if attr.has_name(sym::borrowck_graphviz_format) {
-                Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s {
-                    sym::gen_kill | sym::two_phase => Ok(s),
-                    _ => {
-                        tcx.dcx().emit_err(UnknownFormatter { span: attr.span() });
-                        Err(())
-                    }
-                })
-            } else {
-                Ok(())
-            };
-
-            result = result.and(attr_result);
-        }
-
-        result.map(|()| ret)
-    }
-
-    fn set_field<T>(
-        field: &mut Option<T>,
-        tcx: TyCtxt<'_>,
-        attr: &ast::MetaItemInner,
-        mapper: impl FnOnce(Symbol) -> Result<T, ()>,
-    ) -> Result<(), ()> {
-        if field.is_some() {
-            tcx.dcx()
-                .emit_err(DuplicateValuesFor { span: attr.span(), name: attr.name_or_empty() });
-
-            return Err(());
-        }
-
-        if let Some(s) = attr.value_str() {
-            *field = Some(mapper(s)?);
-            Ok(())
-        } else {
-            tcx.dcx()
-                .emit_err(RequiresAnArgument { span: attr.span(), name: attr.name_or_empty() });
-            Err(())
-        }
-    }
-
-    /// Returns the path where dataflow results should be written, or `None`
-    /// `borrowck_graphviz_postflow` was not specified.
-    ///
-    /// This performs the following transformation to the argument of `borrowck_graphviz_postflow`:
-    ///
-    /// "path/suffix.dot" -> "path/analysis_name_suffix.dot"
-    fn output_path(&self, analysis_name: &str) -> Option<PathBuf> {
-        let mut ret = self.basename_and_suffix.as_ref().cloned()?;
-        let suffix = ret.file_name().unwrap(); // Checked when parsing attrs
-
-        let mut file_name: OsString = analysis_name.into();
-        file_name.push("_");
-        file_name.push(suffix);
-        ret.set_file_name(file_name);
-
-        Some(ret)
-    }
-}
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index b9e194b00c5..d69a8019c8d 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -1,7 +1,3 @@
-//! Dataflow analyses are built upon some interpretation of the
-//! bitvectors attached to each basic block, represented via a
-//! zero-sized structure.
-
 mod borrowed_locals;
 mod initialized;
 mod liveness;