Skip to main content

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        // Invariant: no block is preceded by more than all statements.
35        if true {
    if !(*statements_before_block.iter().max().unwrap() < num_points) {
        ::core::panicking::panic("assertion failed: *statements_before_block.iter().max().unwrap() < num_points")
    };
};debug_assert!(*statements_before_block.iter().max().unwrap() < num_points);
36        Self { statements_before_block, basic_blocks, num_points }
37    }
38
39    /// Total number of point indices
40    #[inline]
41    pub fn num_points(&self) -> usize {
42        self.num_points
43    }
44
45    /// Converts a `Location` into a `PointIndex`. O(1).
46    /// [[`Self::point_in_range()`]] guaranteed for the returned index.
47    #[inline]
48    pub fn point_from_location(&self, location: Location) -> PointIndex {
49        let Location { block, statement_index } = location;
50        let start_index = self.statements_before_block[block];
51        // Note the invariant in [`Self::new()`]; if the indexing
52        // operation above did not panic then this holds by construction.
53        if true {
    if !(start_index < self.num_points) {
        ::core::panicking::panic("assertion failed: start_index < self.num_points")
    };
};debug_assert!(start_index < self.num_points);
54        PointIndex::new(start_index + statement_index)
55    }
56
57    /// Returns the `PointIndex` for the first statement in the given `BasicBlock`. O(1).
58    #[inline]
59    pub fn entry_point(&self, block: BasicBlock) -> PointIndex {
60        let start_index = self.statements_before_block[block];
61        PointIndex::new(start_index)
62    }
63
64    /// Return the PointIndex for the block start of this index.
65    #[inline]
66    pub fn to_block_start(&self, index: PointIndex) -> PointIndex {
67        PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
68    }
69
70    /// Converts a `PointIndex` back to a location. O(1).
71    #[inline]
72    pub fn to_location(&self, index: PointIndex) -> Location {
73        if !(index.index() < self.num_points) {
    ::core::panicking::panic("assertion failed: index.index() < self.num_points")
};assert!(index.index() < self.num_points);
74        let block = self.basic_blocks[index];
75        let start_index = self.statements_before_block[block];
76        let statement_index = index.index() - start_index;
77        Location { block, statement_index }
78    }
79
80    /// Sometimes we get point-indices back from bitsets that may be
81    /// out of range (because they round up to the nearest 2^N number
82    /// of bits). Use this function to filter such points out if you
83    /// like.
84    #[inline]
85    pub fn point_in_range(&self, index: PointIndex) -> bool {
86        index.index() < self.num_points
87    }
88}
89
90impl ::std::fmt::Debug for PointIndex {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        fmt.write_fmt(format_args!("PointIndex({0})", self.as_u32()))
    }
}rustc_index::newtype_index! {
91    /// A single integer representing a `Location` in the MIR control-flow
92    /// graph. Constructed efficiently from `DenseLocationMap`.
93    #[orderable]
94    #[debug_format = "PointIndex({})"]
95    pub struct PointIndex {}
96}