| use std::io; |
| |
| use rustc_attr_ir::{RustcMirKind, find_attr}; |
| use rustc_data_structures::fx::FxIndexMap; |
| use rustc_middle::mir::{self, Body, Local, MirDumper, PassWhere, traversal}; |
| use rustc_middle::ty::TyCtxt; |
| |
| use crate::debuginfo::debuginfo_locals; |
| use crate::framework::Analysis; |
| use crate::impls::{ |
| MaybeLiveLocals, MaybeTransitiveLiveLocals, SplitPointEffect, SplitPointIndex, borrowed_locals, |
| liveness_matrix, |
| }; |
| use crate::points::DenseLocationMap; |
| use crate::{ResultsVisitor, visit_results}; |
| |
| type ExtraDataFn = dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>; |
| |
| pub(crate) fn mir_pretty_extra_data<'tcx>( |
| tcx: TyCtxt<'tcx>, |
| body: &Body<'tcx>, |
| ) -> Option<Box<ExtraDataFn>> { |
| let def_id = body.source.def_id(); |
| let Some(kinds) = find_attr!(tcx, def_id, RustcMir(kind) => kind) else { |
| return None; |
| }; |
| let mut annotations = Annotations::default(); |
| for kind in kinds { |
| match kind { |
| RustcMirKind::PrettyLiveLocals => { |
| let results = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None); |
| let blocks = traversal::reachable(body).map(|(bb, _)| bb); |
| visit_results( |
| body, |
| blocks, |
| &results, |
| &mut Annotator { annotations: &mut annotations }, |
| ); |
| } |
| RustcMirKind::PrettyPreciseLiveness => { |
| let points = DenseLocationMap::new(body); |
| let matrix = liveness_matrix(tcx, body, &points, None); |
| for (block, data) in body.basic_blocks.iter_enumerated() { |
| for statement_index in 0..=data.statements.len() { |
| let location = mir::Location { block, statement_index }; |
| let point = points.point_from_location(location); |
| let locals_live_at = |effect| { |
| let split_point = SplitPointIndex::new(point, effect); |
| matrix |
| .rows() |
| .filter(|&r| matrix.contains(r, split_point)) |
| .collect::<Vec<_>>() |
| }; |
| let early = locals_live_at(SplitPointEffect::Early); |
| annotations |
| .add(PassWhere::BeforeLocation(location), format!("early: {early:?}")); |
| let late = locals_live_at(SplitPointEffect::Late); |
| annotations |
| .add(PassWhere::BeforeLocation(location), format!("late: {late:?}")); |
| } |
| } |
| } |
| RustcMirKind::PrettyTransitiveLiveLocals => { |
| let borrowed_locals = borrowed_locals(body); |
| let debuginfo_locals = debuginfo_locals(body); |
| let results = MaybeTransitiveLiveLocals::new(&borrowed_locals, &debuginfo_locals) |
| .iterate_to_fixpoint(tcx, body, None); |
| let blocks = traversal::reachable(body).map(|(bb, _)| bb); |
| visit_results( |
| body, |
| blocks, |
| &results, |
| &mut Annotator { annotations: &mut annotations }, |
| ); |
| } |
| _ => {} |
| } |
| } |
| let extra_data = annotations.into_extra_data()?; |
| if let Some(dumper) = MirDumper::new(tcx, "dataflow", body) { |
| dumper.set_extra_data(&*extra_data).dump_mir(body); |
| } |
| Some(extra_data) |
| } |
| |
| #[derive(Default)] |
| struct Annotations { |
| entries: FxIndexMap<PassWhere, Vec<String>>, |
| } |
| |
| impl Annotations { |
| fn add(&mut self, pass_where: PassWhere, s: String) { |
| self.entries.entry(pass_where).or_default().push(s); |
| } |
| |
| fn into_extra_data(self) -> Option<Box<ExtraDataFn>> { |
| if self.entries.is_empty() { |
| return None; |
| } |
| Some(Box::new(move |pass_where: PassWhere, out: &mut dyn io::Write| { |
| let Some(notes) = self.entries.get(&pass_where) else { |
| return Ok(()); |
| }; |
| for s in notes { |
| writeln!(out, " // {s}")?; |
| } |
| Ok(()) |
| })) |
| } |
| } |
| |
| /// Examines dataflow results and collects extra annotations for inclusion in MIR pretty printing. |
| struct Annotator<'a> { |
| annotations: &'a mut Annotations, |
| } |
| |
| impl<'tcx> ResultsVisitor<'tcx, MaybeLiveLocals> for Annotator<'_> { |
| fn visit_after_primary_statement_effect( |
| &mut self, |
| state: &<MaybeLiveLocals as Analysis<'tcx>>::Domain, |
| _statement: &mir::Statement<'tcx>, |
| location: mir::Location, |
| ) { |
| let live: Vec<Local> = state.iter().collect(); |
| self.annotations.add(PassWhere::BeforeLocation(location), format!("live: {live:?}")); |
| } |
| |
| fn visit_after_primary_terminator_effect( |
| &mut self, |
| state: &<MaybeLiveLocals as Analysis<'tcx>>::Domain, |
| _terminator: &mir::Terminator<'tcx>, |
| location: mir::Location, |
| ) { |
| let live: Vec<Local> = state.iter().collect(); |
| self.annotations.add(PassWhere::BeforeLocation(location), format!("live: {live:?}")); |
| } |
| } |
| |
| impl<'tcx> ResultsVisitor<'tcx, MaybeTransitiveLiveLocals<'_>> for Annotator<'_> { |
| fn visit_after_primary_statement_effect( |
| &mut self, |
| state: &<MaybeLiveLocals as Analysis<'tcx>>::Domain, |
| _statement: &mir::Statement<'tcx>, |
| location: mir::Location, |
| ) { |
| let live: Vec<Local> = state.iter().collect(); |
| self.annotations.add(PassWhere::BeforeLocation(location), format!("live: {live:?}")); |
| } |
| |
| fn visit_after_primary_terminator_effect( |
| &mut self, |
| state: &<MaybeLiveLocals as Analysis<'tcx>>::Domain, |
| _terminator: &mir::Terminator<'tcx>, |
| location: mir::Location, |
| ) { |
| let live: Vec<Local> = state.iter().collect(); |
| self.annotations.add(PassWhere::BeforeLocation(location), format!("live: {live:?}")); |
| } |
| } |