1use rustc_index::{Idx, IndexVec};
2use rustc_middle::mir::{BasicBlock, Body, Location};
34/// Maps between a `Location` and a `PointIndex` (and vice versa).
5pub struct DenseLocationMap {
6/// For each basic block, how many points are contained within?
7statements_before_block: IndexVec<BasicBlock, usize>,
89/// Map backward from each point to the basic block that it
10 /// belongs to.
11basic_blocks: IndexVec<PointIndex, BasicBlock>,
1213 num_points: usize,
14}
1516impl DenseLocationMap {
17#[inline]
18pub fn new(body: &Body<'_>) -> Self {
19let mut num_points = 0;
20let statements_before_block: IndexVec<BasicBlock, usize> = body21 .basic_blocks
22 .iter()
23 .map(|block_data| {
24let v = num_points;
25num_points += block_data.statements.len() + 1;
26v27 })
28 .collect();
2930let mut basic_blocks = IndexVec::with_capacity(num_points);
31for (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.
35if 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);
36Self { statements_before_block, basic_blocks, num_points }
37 }
3839/// Total number of point indices
40#[inline]
41pub fn num_points(&self) -> usize {
42self.num_points
43 }
4445/// Converts a `Location` into a `PointIndex`. O(1).
46 /// [[`Self::point_in_range()`]] guaranteed for the returned index.
47#[inline]
48pub fn point_from_location(&self, location: Location) -> PointIndex {
49let Location { block, statement_index } = location;
50let 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.
53if true {
if !(start_index < self.num_points) {
::core::panicking::panic("assertion failed: start_index < self.num_points")
};
};debug_assert!(start_index < self.num_points);
54PointIndex::new(start_index + statement_index)
55 }
5657/// Returns the `PointIndex` for the first statement in the given `BasicBlock`. O(1).
58#[inline]
59pub fn entry_point(&self, block: BasicBlock) -> PointIndex {
60let start_index = self.statements_before_block[block];
61PointIndex::new(start_index)
62 }
6364/// Return the PointIndex for the block start of this index.
65#[inline]
66pub fn to_block_start(&self, index: PointIndex) -> PointIndex {
67PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
68 }
6970/// Converts a `PointIndex` back to a location. O(1).
71#[inline]
72pub fn to_location(&self, index: PointIndex) -> Location {
73if !(index.index() < self.num_points) {
::core::panicking::panic("assertion failed: index.index() < self.num_points")
};assert!(index.index() < self.num_points);
74let block = self.basic_blocks[index];
75let start_index = self.statements_before_block[block];
76let statement_index = index.index() - start_index;
77Location { block, statement_index }
78 }
7980/// 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]
85pub fn point_in_range(&self, index: PointIndex) -> bool {
86index.index() < self.num_points
87 }
88}
8990impl ::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({})"]
95pub struct PointIndex {}
96}