1
Fork 0

Take MIR dataflow analyses by mutable reference.

This commit is contained in:
Jason Newcomb 2023-02-20 17:28:03 -05:00
parent fdd030127c
commit eaddc37075
19 changed files with 491 additions and 288 deletions

View file

@ -1,6 +1,7 @@
//! A helpful diagram for debugging dataflow problems.
use std::borrow::Cow;
use std::cell::RefCell;
use std::sync::OnceLock;
use std::{io, ops, str};
@ -28,23 +29,27 @@ impl OutputStyle {
}
}
pub struct Formatter<'a, 'tcx, A>
pub struct Formatter<'res, 'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
body: &'a Body<'tcx>,
results: &'a Results<'tcx, A>,
body: &'mir Body<'tcx>,
results: RefCell<&'res mut Results<'tcx, A>>,
style: OutputStyle,
reachable: BitSet<BasicBlock>,
}
impl<'a, 'tcx, A> Formatter<'a, 'tcx, A>
impl<'res, 'mir, 'tcx, A> Formatter<'res, 'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle) -> Self {
pub fn new(
body: &'mir Body<'tcx>,
results: &'res mut Results<'tcx, A>,
style: OutputStyle,
) -> Self {
let reachable = mir::traversal::reachable_as_bitset(body);
Formatter { body, results, style, reachable }
Formatter { body, results: results.into(), style, reachable }
}
}
@ -64,7 +69,7 @@ fn dataflow_successors(body: &Body<'_>, bb: BasicBlock) -> Vec<CfgEdge> {
.collect()
}
impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, 'tcx, A>
impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, '_, 'tcx, A>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
@ -83,13 +88,14 @@ where
fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
let mut label = Vec::new();
let mut results = self.results.borrow_mut();
let mut fmt = BlockFormatter {
results: ResultsRefCursor::new(self.body, self.results),
results: results.as_results_cursor(self.body),
style: self.style,
bg: Background::Light,
};
fmt.write_node_label(&mut label, self.body, *block).unwrap();
fmt.write_node_label(&mut label, *block).unwrap();
dot::LabelText::html(String::from_utf8(label).unwrap())
}
@ -103,7 +109,7 @@ where
}
}
impl<'a, 'tcx, A> dot::GraphWalk<'a> for Formatter<'a, 'tcx, A>
impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'_, 'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
@ -137,16 +143,16 @@ where
}
}
struct BlockFormatter<'a, 'tcx, A>
struct BlockFormatter<'res, 'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
results: ResultsRefCursor<'a, 'a, 'tcx, A>,
results: ResultsRefCursor<'res, 'mir, 'tcx, A>,
bg: Background,
style: OutputStyle,
}
impl<'a, 'tcx, A> BlockFormatter<'a, 'tcx, A>
impl<'res, 'mir, 'tcx, A> BlockFormatter<'res, 'mir, 'tcx, A>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
@ -159,12 +165,7 @@ where
bg
}
fn write_node_label(
&mut self,
w: &mut impl io::Write,
body: &'a Body<'tcx>,
block: BasicBlock,
) -> io::Result<()> {
fn write_node_label(&mut self, w: &mut impl io::Write, block: BasicBlock) -> io::Result<()> {
// Sample output:
// +-+-----------------------------------------------+
// A | bb4 |
@ -215,11 +216,11 @@ where
self.write_row_with_full_state(w, "", "(on start)")?;
// D + E: Statement and terminator transfer functions
self.write_statements_and_terminator(w, body, block)?;
self.write_statements_and_terminator(w, block)?;
// F: State at end of block
let terminator = body[block].terminator();
let terminator = self.results.body()[block].terminator();
// Write the full dataflow state immediately after the terminator if it differs from the
// state at block entry.
@ -389,10 +390,14 @@ where
fn write_statements_and_terminator(
&mut self,
w: &mut impl io::Write,
body: &'a Body<'tcx>,
block: BasicBlock,
) -> io::Result<()> {
let diffs = StateDiffCollector::run(body, block, self.results.results(), self.style);
let diffs = StateDiffCollector::run(
self.results.body(),
block,
self.results.mut_results(),
self.style,
);
let mut diffs_before = diffs.before.map(|v| v.into_iter());
let mut diffs_after = diffs.after.into_iter();
@ -401,7 +406,7 @@ where
if A::Direction::IS_FORWARD { it.next().unwrap() } else { it.next_back().unwrap() }
};
for (i, statement) in body[block].statements.iter().enumerate() {
for (i, statement) in self.results.body()[block].statements.iter().enumerate() {
let statement_str = format!("{statement:?}");
let index_str = format!("{i}");
@ -423,7 +428,7 @@ where
assert!(diffs_after.is_empty());
assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty));
let terminator = body[block].terminator();
let terminator = self.results.body()[block].terminator();
let mut terminator_str = String::new();
terminator.kind.fmt_head(&mut terminator_str).unwrap();
@ -492,29 +497,24 @@ where
}
}
struct StateDiffCollector<'a, 'tcx, A>
where
A: Analysis<'tcx>,
{
analysis: &'a A,
prev_state: A::Domain,
struct StateDiffCollector<D> {
prev_state: D,
before: Option<Vec<String>>,
after: Vec<String>,
}
impl<'a, 'tcx, A> StateDiffCollector<'a, 'tcx, A>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
{
fn run(
body: &'a mir::Body<'tcx>,
impl<D> StateDiffCollector<D> {
fn run<'tcx, A>(
body: &mir::Body<'tcx>,
block: BasicBlock,
results: &'a Results<'tcx, A>,
results: &mut Results<'tcx, A>,
style: OutputStyle,
) -> Self {
) -> Self
where
A: Analysis<'tcx, Domain = D>,
D: DebugWithContext<A>,
{
let mut collector = StateDiffCollector {
analysis: &results.analysis,
prev_state: results.analysis.bottom_value(body),
after: vec![],
before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]),
@ -525,7 +525,7 @@ where
}
}
impl<'a, 'tcx, A> ResultsVisitor<'a, 'tcx> for StateDiffCollector<'a, 'tcx, A>
impl<'tcx, A> ResultsVisitor<'_, 'tcx, Results<'tcx, A>> for StateDiffCollector<A::Domain>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
@ -534,6 +534,7 @@ where
fn visit_block_start(
&mut self,
_results: &Results<'tcx, A>,
state: &Self::FlowState,
_block_data: &mir::BasicBlockData<'tcx>,
_block: BasicBlock,
@ -545,6 +546,7 @@ where
fn visit_block_end(
&mut self,
_results: &Results<'tcx, A>,
state: &Self::FlowState,
_block_data: &mir::BasicBlockData<'tcx>,
_block: BasicBlock,
@ -556,45 +558,49 @@ where
fn visit_statement_before_primary_effect(
&mut self,
results: &Results<'tcx, A>,
state: &Self::FlowState,
_statement: &mir::Statement<'tcx>,
_location: Location,
) {
if let Some(before) = self.before.as_mut() {
before.push(diff_pretty(state, &self.prev_state, self.analysis));
before.push(diff_pretty(state, &self.prev_state, &results.analysis));
self.prev_state.clone_from(state)
}
}
fn visit_statement_after_primary_effect(
&mut self,
results: &Results<'tcx, A>,
state: &Self::FlowState,
_statement: &mir::Statement<'tcx>,
_location: Location,
) {
self.after.push(diff_pretty(state, &self.prev_state, self.analysis));
self.after.push(diff_pretty(state, &self.prev_state, &results.analysis));
self.prev_state.clone_from(state)
}
fn visit_terminator_before_primary_effect(
&mut self,
results: &Results<'tcx, A>,
state: &Self::FlowState,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
if let Some(before) = self.before.as_mut() {
before.push(diff_pretty(state, &self.prev_state, self.analysis));
before.push(diff_pretty(state, &self.prev_state, &results.analysis));
self.prev_state.clone_from(state)
}
}
fn visit_terminator_after_primary_effect(
&mut self,
results: &Results<'tcx, A>,
state: &Self::FlowState,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
self.after.push(diff_pretty(state, &self.prev_state, self.analysis));
self.after.push(diff_pretty(state, &self.prev_state, &results.analysis));
self.prev_state.clone_from(state)
}
}