Skip to main content

rustc_mir_dataflow/
pretty.rs

1use std::io;
2
3use rustc_attr_ir::{RustcMirKind, find_attr};
4use rustc_data_structures::fx::FxIndexMap;
5use rustc_middle::mir::{self, Body, Local, MirDumper, PassWhere, traversal};
6use rustc_middle::ty::TyCtxt;
7
8use crate::debuginfo::debuginfo_locals;
9use crate::framework::Analysis;
10use crate::impls::{
11    MaybeLiveLocals, MaybeTransitiveLiveLocals, SplitPointEffect, SplitPointIndex, borrowed_locals,
12    liveness_matrix,
13};
14use crate::points::DenseLocationMap;
15use crate::{ResultsVisitor, visit_results};
16
17type ExtraDataFn = dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>;
18
19pub(crate) fn mir_pretty_extra_data<'tcx>(
20    tcx: TyCtxt<'tcx>,
21    body: &Body<'tcx>,
22) -> Option<Box<ExtraDataFn>> {
23    let def_id = body.source.def_id();
24    let Some(kinds) = {
    {
        'done:
            {
            for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &tcx) {
                #[allow(unused_imports)]
                use ::rustc_attr_ir::AttributeKind::*;
                let i: &::rustc_attr_ir::Attribute = i;
                match i {
                    ::rustc_attr_ir::Attribute::Parsed(RustcMir(kind)) => {
                        break 'done Some(kind);
                    }
                    ::rustc_attr_ir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(tcx, def_id, RustcMir(kind) => kind) else {
25        return None;
26    };
27    let mut annotations = Annotations::default();
28    for kind in kinds {
29        match kind {
30            RustcMirKind::PrettyLiveLocals => {
31                let results = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None);
32                let blocks = traversal::reachable(body).map(|(bb, _)| bb);
33                visit_results(
34                    body,
35                    blocks,
36                    &results,
37                    &mut Annotator { annotations: &mut annotations },
38                );
39            }
40            RustcMirKind::PrettyPreciseLiveness => {
41                let points = DenseLocationMap::new(body);
42                let matrix = liveness_matrix(tcx, body, &points, None);
43                for (block, data) in body.basic_blocks.iter_enumerated() {
44                    for statement_index in 0..=data.statements.len() {
45                        let location = mir::Location { block, statement_index };
46                        let point = points.point_from_location(location);
47                        let locals_live_at = |effect| {
48                            let split_point = SplitPointIndex::new(point, effect);
49                            matrix
50                                .rows()
51                                .filter(|&r| matrix.contains(r, split_point))
52                                .collect::<Vec<_>>()
53                        };
54                        let early = locals_live_at(SplitPointEffect::Early);
55                        annotations
56                            .add(PassWhere::BeforeLocation(location), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("early: {0:?}", early))
    })format!("early: {early:?}"));
57                        let late = locals_live_at(SplitPointEffect::Late);
58                        annotations
59                            .add(PassWhere::BeforeLocation(location), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("late: {0:?}", late))
    })format!("late: {late:?}"));
60                    }
61                }
62            }
63            RustcMirKind::PrettyTransitiveLiveLocals => {
64                let borrowed_locals = borrowed_locals(body);
65                let debuginfo_locals = debuginfo_locals(body);
66                let results = MaybeTransitiveLiveLocals::new(&borrowed_locals, &debuginfo_locals)
67                    .iterate_to_fixpoint(tcx, body, None);
68                let blocks = traversal::reachable(body).map(|(bb, _)| bb);
69                visit_results(
70                    body,
71                    blocks,
72                    &results,
73                    &mut Annotator { annotations: &mut annotations },
74                );
75            }
76            _ => {}
77        }
78    }
79    let extra_data = annotations.into_extra_data()?;
80    if let Some(dumper) = MirDumper::new(tcx, "dataflow", body) {
81        dumper.set_extra_data(&*extra_data).dump_mir(body);
82    }
83    Some(extra_data)
84}
85
86#[derive(#[automatically_derived]
impl ::core::default::Default for Annotations {
    #[inline]
    fn default() -> Self {
        Annotations { entries: ::core::default::Default::default() }
    }
}Default)]
87struct Annotations {
88    entries: FxIndexMap<PassWhere, Vec<String>>,
89}
90
91impl Annotations {
92    fn add(&mut self, pass_where: PassWhere, s: String) {
93        self.entries.entry(pass_where).or_default().push(s);
94    }
95
96    fn into_extra_data(self) -> Option<Box<ExtraDataFn>> {
97        if self.entries.is_empty() {
98            return None;
99        }
100        Some(Box::new(move |pass_where: PassWhere, out: &mut dyn io::Write| {
101            let Some(notes) = self.entries.get(&pass_where) else {
102                return Ok(());
103            };
104            for s in notes {
105                out.write_fmt(format_args!("        // {0}\n", s))writeln!(out, "        // {s}")?;
106            }
107            Ok(())
108        }))
109    }
110}
111
112/// Examines dataflow results and collects extra annotations for inclusion in MIR pretty printing.
113struct Annotator<'a> {
114    annotations: &'a mut Annotations,
115}
116
117impl<'tcx> ResultsVisitor<'tcx, MaybeLiveLocals> for Annotator<'_> {
118    fn visit_after_primary_statement_effect(
119        &mut self,
120        state: &<MaybeLiveLocals as Analysis<'tcx>>::Domain,
121        _statement: &mir::Statement<'tcx>,
122        location: mir::Location,
123    ) {
124        let live: Vec<Local> = state.iter().collect();
125        self.annotations.add(PassWhere::BeforeLocation(location), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("live: {0:?}", live))
    })format!("live: {live:?}"));
126    }
127
128    fn visit_after_primary_terminator_effect(
129        &mut self,
130        state: &<MaybeLiveLocals as Analysis<'tcx>>::Domain,
131        _terminator: &mir::Terminator<'tcx>,
132        location: mir::Location,
133    ) {
134        let live: Vec<Local> = state.iter().collect();
135        self.annotations.add(PassWhere::BeforeLocation(location), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("live: {0:?}", live))
    })format!("live: {live:?}"));
136    }
137}
138
139impl<'tcx> ResultsVisitor<'tcx, MaybeTransitiveLiveLocals<'_>> for Annotator<'_> {
140    fn visit_after_primary_statement_effect(
141        &mut self,
142        state: &<MaybeLiveLocals as Analysis<'tcx>>::Domain,
143        _statement: &mir::Statement<'tcx>,
144        location: mir::Location,
145    ) {
146        let live: Vec<Local> = state.iter().collect();
147        self.annotations.add(PassWhere::BeforeLocation(location), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("live: {0:?}", live))
    })format!("live: {live:?}"));
148    }
149
150    fn visit_after_primary_terminator_effect(
151        &mut self,
152        state: &<MaybeLiveLocals as Analysis<'tcx>>::Domain,
153        _terminator: &mir::Terminator<'tcx>,
154        location: mir::Location,
155    ) {
156        let live: Vec<Local> = state.iter().collect();
157        self.annotations.add(PassWhere::BeforeLocation(location), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("live: {0:?}", live))
    })format!("live: {live:?}"));
158    }
159}