Take MIR dataflow analyses by mutable reference.
This commit is contained in:
parent
fdd030127c
commit
eaddc37075
19 changed files with 491 additions and 288 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue