rustc_mir_dataflow/
points.rs
1use rustc_index::bit_set::DenseBitSet;
2use rustc_index::interval::SparseIntervalMatrix;
3use rustc_index::{Idx, IndexVec};
4use rustc_middle::mir::{self, BasicBlock, Body, Location};
5
6use crate::framework::{Analysis, Results, ResultsVisitor, visit_results};
7
8pub struct DenseLocationMap {
10 statements_before_block: IndexVec<BasicBlock, usize>,
12
13 basic_blocks: IndexVec<PointIndex, BasicBlock>,
16
17 num_points: usize,
18}
19
20impl DenseLocationMap {
21 #[inline]
22 pub fn new(body: &Body<'_>) -> Self {
23 let mut num_points = 0;
24 let statements_before_block: IndexVec<BasicBlock, usize> = body
25 .basic_blocks
26 .iter()
27 .map(|block_data| {
28 let v = num_points;
29 num_points += block_data.statements.len() + 1;
30 v
31 })
32 .collect();
33
34 let mut basic_blocks = IndexVec::with_capacity(num_points);
35 for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
36 basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
37 }
38
39 Self { statements_before_block, basic_blocks, num_points }
40 }
41
42 #[inline]
44 pub fn num_points(&self) -> usize {
45 self.num_points
46 }
47
48 #[inline]
50 pub fn point_from_location(&self, location: Location) -> PointIndex {
51 let Location { block, statement_index } = location;
52 let start_index = self.statements_before_block[block];
53 PointIndex::new(start_index + statement_index)
54 }
55
56 #[inline]
58 pub fn entry_point(&self, block: BasicBlock) -> PointIndex {
59 let start_index = self.statements_before_block[block];
60 PointIndex::new(start_index)
61 }
62
63 #[inline]
65 pub fn to_block_start(&self, index: PointIndex) -> PointIndex {
66 PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
67 }
68
69 #[inline]
71 pub fn to_location(&self, index: PointIndex) -> Location {
72 assert!(index.index() < self.num_points);
73 let block = self.basic_blocks[index];
74 let start_index = self.statements_before_block[block];
75 let statement_index = index.index() - start_index;
76 Location { block, statement_index }
77 }
78
79 #[inline]
84 pub fn point_in_range(&self, index: PointIndex) -> bool {
85 index.index() < self.num_points
86 }
87}
88
89rustc_index::newtype_index! {
90 #[orderable]
93 #[debug_format = "PointIndex({})"]
94 pub struct PointIndex {}
95}
96
97pub fn save_as_intervals<'tcx, N, A>(
99 elements: &DenseLocationMap,
100 body: &mir::Body<'tcx>,
101 mut results: Results<'tcx, A>,
102) -> SparseIntervalMatrix<N, PointIndex>
103where
104 N: Idx,
105 A: Analysis<'tcx, Domain = DenseBitSet<N>>,
106{
107 let values = SparseIntervalMatrix::new(elements.num_points());
108 let mut visitor = Visitor { elements, values };
109 visit_results(
110 body,
111 body.basic_blocks.reverse_postorder().iter().copied(),
112 &mut results,
113 &mut visitor,
114 );
115 visitor.values
116}
117
118struct Visitor<'a, N: Idx> {
119 elements: &'a DenseLocationMap,
120 values: SparseIntervalMatrix<N, PointIndex>,
121}
122
123impl<'mir, 'tcx, A, N> ResultsVisitor<'mir, 'tcx, A> for Visitor<'_, N>
124where
125 A: Analysis<'tcx, Domain = DenseBitSet<N>>,
126 N: Idx,
127{
128 fn visit_after_primary_statement_effect(
129 &mut self,
130 _results: &mut Results<'tcx, A>,
131 state: &A::Domain,
132 _statement: &'mir mir::Statement<'tcx>,
133 location: Location,
134 ) {
135 let point = self.elements.point_from_location(location);
136 state.iter().for_each(|node| {
138 self.values.insert(node, point);
139 });
140 }
141
142 fn visit_after_primary_terminator_effect(
143 &mut self,
144 _results: &mut Results<'tcx, A>,
145 state: &A::Domain,
146 _terminator: &'mir mir::Terminator<'tcx>,
147 location: Location,
148 ) {
149 let point = self.elements.point_from_location(location);
150 state.iter().for_each(|node| {
152 self.values.insert(node, point);
153 });
154 }
155}