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
90#[automatically_derived]
impl ::core::marker::Copy for PointIndex { }
impl PointIndex {
    #[doc = r" Maximum value the index can take, as a `u32`."]
    pub const MAX_AS_U32: u32 = 0xFFFF_FF00;
    #[doc = r" Maximum value the index can take."]
    pub const MAX: Self = Self::from_u32(0xFFFF_FF00);
    #[doc = r" Zero value of the index."]
    pub const ZERO: Self = Self::from_u32(0);
    #[doc = r" Creates a new index from a given `usize`."]
    #[doc = r""]
    #[doc = r" # Panics"]
    #[doc = r""]
    #[doc = r" Will panic if `value` exceeds `MAX`."]
    #[inline]
    pub const fn from_usize(value: usize) -> Self {
        if !(value <= (0xFFFF_FF00 as usize)) {
            ::core::panicking::panic("assertion failed: value <= (0xFFFF_FF00 as usize)")
        };
        unsafe { Self::from_u32_unchecked(value as u32) }
    }
    #[doc = r" Creates a new index from a given `u32`."]
    #[doc = r""]
    #[doc = r" # Panics"]
    #[doc = r""]
    #[doc = r" Will panic if `value` exceeds `MAX`."]
    #[inline]
    pub const fn from_u32(value: u32) -> Self {
        if !(value <= 0xFFFF_FF00) {
            ::core::panicking::panic("assertion failed: value <= 0xFFFF_FF00")
        };
        unsafe { Self::from_u32_unchecked(value) }
    }
    #[doc = r" Creates a new index from a given `u16`."]
    #[doc = r""]
    #[doc = r" # Panics"]
    #[doc = r""]
    #[doc = r" Will panic if `value` exceeds `MAX`."]
    #[inline]
    pub const fn from_u16(value: u16) -> Self {
        let value = value as u32;
        if !(value <= 0xFFFF_FF00) {
            ::core::panicking::panic("assertion failed: value <= 0xFFFF_FF00")
        };
        unsafe { Self::from_u32_unchecked(value) }
    }
    #[doc = r" Creates a new index from a given `u32`."]
    #[doc = r""]
    #[doc = r" # Safety"]
    #[doc = r""]
    #[doc =
    r" The provided value must be less than or equal to the maximum value for the newtype."]
    #[doc =
    r" Providing a value outside this range is undefined due to layout restrictions."]
    #[doc = r""]
    #[doc = r" Prefer using `from_u32`."]
    #[inline]
    pub const unsafe fn from_u32_unchecked(value: u32) -> Self {
        Self {
            private_use_as_methods_instead: unsafe {
                std::mem::transmute(value)
            },
        }
    }
    #[doc = r" Extracts the value of this index as a `usize`."]
    #[inline]
    pub const fn index(self) -> usize { self.as_usize() }
    #[doc = r" Extracts the value of this index as a `u32`."]
    #[inline]
    pub const fn as_u32(self) -> u32 {
        unsafe { std::mem::transmute(self.private_use_as_methods_instead) }
    }
    #[doc = r" Extracts the value of this index as a `usize`."]
    #[inline]
    pub const fn as_usize(self) -> usize { self.as_u32() as usize }
}
impl std::ops::Add<usize> for PointIndex {
    type Output = Self;
    #[inline]
    fn add(self, other: usize) -> Self {
        Self::from_usize(self.index() + other)
    }
}
impl std::ops::AddAssign<usize> for PointIndex {
    #[inline]
    fn add_assign(&mut self, other: usize) { *self = *self + other; }
}
impl rustc_index::Idx for PointIndex {
    #[inline]
    fn new(value: usize) -> Self { Self::from_usize(value) }
    #[inline]
    fn index(self) -> usize { self.as_usize() }
}
impl ::std::iter::Step for PointIndex {
    #[inline]
    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
        <usize as
                ::std::iter::Step>::steps_between(&Self::index(*start),
            &Self::index(*end))
    }
    #[inline]
    fn forward_checked(start: Self, u: usize) -> Option<Self> {
        Self::index(start).checked_add(u).map(Self::from_usize)
    }
    #[inline]
    fn backward_checked(start: Self, u: usize) -> Option<Self> {
        Self::index(start).checked_sub(u).map(Self::from_usize)
    }
    #[inline]
    fn forward_overflowing(start: Self, u: usize) -> (Self, bool) {
        let (s, o) = Self::index(start).overflowing_add(u);
        (Self::from_usize(s), o)
    }
    #[inline]
    fn backward_overflowing(start: Self, u: usize) -> (Self, bool) {
        let (s, o) = Self::index(start).overflowing_sub(u);
        (Self::from_usize(s), o)
    }
}
impl ::std::cmp::Ord for PointIndex {
    #[inline]
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.as_u32().cmp(&other.as_u32())
    }
}
impl ::std::cmp::PartialOrd for PointIndex {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}
impl From<PointIndex> for u32 {
    #[inline]
    fn from(v: PointIndex) -> u32 { v.as_u32() }
}
impl From<PointIndex> for usize {
    #[inline]
    fn from(v: PointIndex) -> usize { v.as_usize() }
}
impl From<usize> for PointIndex {
    #[inline]
    fn from(value: usize) -> Self { Self::from_usize(value) }
}
impl From<u32> for PointIndex {
    #[inline]
    fn from(value: u32) -> Self { Self::from_u32(value) }
}
impl ::std::cmp::Eq for PointIndex {}
impl ::std::cmp::PartialEq for PointIndex {
    fn eq(&self, other: &Self) -> bool { self.as_u32().eq(&other.as_u32()) }
}
impl ::std::marker::StructuralPartialEq for PointIndex {}
impl ::std::hash::Hash for PointIndex {
    fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
        self.as_u32().hash(state)
    }
}
impl ::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}