rustc_mir_dataflow/
points.rs

1use rustc_index::{Idx, IndexVec};
2use rustc_middle::mir::{BasicBlock, Body, Location};
3
4/// Maps between a `Location` and a `PointIndex` (and vice versa).
5pub struct DenseLocationMap {
6    /// For each basic block, how many points are contained within?
7    statements_before_block: IndexVec<BasicBlock, usize>,
8
9    /// Map backward from each point to the basic block that it
10    /// belongs to.
11    basic_blocks: IndexVec<PointIndex, BasicBlock>,
12
13    num_points: usize,
14}
15
16impl DenseLocationMap {
17    #[inline]
18    pub fn new(body: &Body<'_>) -> Self {
19        let mut num_points = 0;
20        let statements_before_block: IndexVec<BasicBlock, usize> = body
21            .basic_blocks
22            .iter()
23            .map(|block_data| {
24                let v = num_points;
25                num_points += block_data.statements.len() + 1;
26                v
27            })
28            .collect();
29
30        let mut basic_blocks = IndexVec::with_capacity(num_points);
31        for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
32            basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
33        }
34
35        Self { statements_before_block, basic_blocks, num_points }
36    }
37
38    /// Total number of point indices
39    #[inline]
40    pub fn num_points(&self) -> usize {
41        self.num_points
42    }
43
44    /// Converts a `Location` into a `PointIndex`. O(1).
45    #[inline]
46    pub fn point_from_location(&self, location: Location) -> PointIndex {
47        let Location { block, statement_index } = location;
48        let start_index = self.statements_before_block[block];
49        PointIndex::new(start_index + statement_index)
50    }
51
52    /// Returns the `PointIndex` for the first statement in the given `BasicBlock`. O(1).
53    #[inline]
54    pub fn entry_point(&self, block: BasicBlock) -> PointIndex {
55        let start_index = self.statements_before_block[block];
56        PointIndex::new(start_index)
57    }
58
59    /// Return the PointIndex for the block start of this index.
60    #[inline]
61    pub fn to_block_start(&self, index: PointIndex) -> PointIndex {
62        PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
63    }
64
65    /// Converts a `PointIndex` back to a location. O(1).
66    #[inline]
67    pub fn to_location(&self, index: PointIndex) -> Location {
68        assert!(index.index() < self.num_points);
69        let block = self.basic_blocks[index];
70        let start_index = self.statements_before_block[block];
71        let statement_index = index.index() - start_index;
72        Location { block, statement_index }
73    }
74
75    /// Sometimes we get point-indices back from bitsets that may be
76    /// out of range (because they round up to the nearest 2^N number
77    /// of bits). Use this function to filter such points out if you
78    /// like.
79    #[inline]
80    pub fn point_in_range(&self, index: PointIndex) -> bool {
81        index.index() < self.num_points
82    }
83}
84
85rustc_index::newtype_index! {
86    /// A single integer representing a `Location` in the MIR control-flow
87    /// graph. Constructed efficiently from `DenseLocationMap`.
88    #[orderable]
89    #[debug_format = "PointIndex({})"]
90    pub struct PointIndex {}
91}