1 use rustc
::mir
::{BasicBlock, Location, Mir}
;
2 use rustc
::ty
::{self, RegionVid}
;
3 use rustc_data_structures
::bit_set
::{HybridBitSet, SparseBitMatrix}
;
4 use rustc_data_structures
::fx
::FxHashMap
;
5 use rustc_data_structures
::indexed_vec
::Idx
;
6 use rustc_data_structures
::indexed_vec
::IndexVec
;
10 /// Maps between a `Location` and a `PointIndex` (and vice versa).
11 crate struct RegionValueElements
{
12 /// For each basic block, how many points are contained within?
13 statements_before_block
: IndexVec
<BasicBlock
, usize>,
15 /// Map backward from each point to the basic block that it
17 basic_blocks
: IndexVec
<PointIndex
, BasicBlock
>,
22 impl RegionValueElements
{
23 crate fn new(mir
: &Mir
<'_
>) -> Self {
24 let mut num_points
= 0;
25 let statements_before_block
: IndexVec
<BasicBlock
, usize> = mir
.basic_blocks()
29 num_points
+= block_data
.statements
.len() + 1;
34 "RegionValueElements: statements_before_block={:#?}",
35 statements_before_block
37 debug
!("RegionValueElements: num_points={:#?}", num_points
);
39 let mut basic_blocks
= IndexVec
::with_capacity(num_points
);
40 for (bb
, bb_data
) in mir
.basic_blocks().iter_enumerated() {
41 basic_blocks
.extend((0..=bb_data
.statements
.len()).map(|_
| bb
));
45 statements_before_block
,
51 /// Total number of point indices
52 crate fn num_points(&self) -> usize {
56 /// Converts a `Location` into a `PointIndex`. O(1).
57 crate fn point_from_location(&self, location
: Location
) -> PointIndex
{
62 let start_index
= self.statements_before_block
[block
];
63 PointIndex
::new(start_index
+ statement_index
)
66 /// Converts a `Location` into a `PointIndex`. O(1).
67 crate fn entry_point(&self, block
: BasicBlock
) -> PointIndex
{
68 let start_index
= self.statements_before_block
[block
];
69 PointIndex
::new(start_index
)
72 /// Converts a `PointIndex` back to a location. O(1).
73 crate fn to_location(&self, index
: PointIndex
) -> Location
{
74 assert
!(index
.index() < self.num_points
);
75 let block
= self.basic_blocks
[index
];
76 let start_index
= self.statements_before_block
[block
];
77 let statement_index
= index
.index() - start_index
;
84 /// Sometimes we get point-indices back from bitsets that may be
85 /// out of range (because they round up to the nearest 2^N number
86 /// of bits). Use this function to filter such points out if you
88 crate fn point_in_range(&self, index
: PointIndex
) -> bool
{
89 index
.index() < self.num_points
92 /// Pushes all predecessors of `index` onto `stack`.
93 crate fn push_predecessors(
97 stack
: &mut Vec
<PointIndex
>,
102 } = self.to_location(index
);
103 if statement_index
== 0 {
104 // If this is a basic block head, then the predecessors are
105 // the terminators of other basic blocks
107 mir
.predecessors_for(block
)
109 .map(|&pred_bb
| mir
.terminator_loc(pred_bb
))
110 .map(|pred_loc
| self.point_from_location(pred_loc
)),
113 // Otherwise, the pred is just the previous statement
114 stack
.push(PointIndex
::new(index
.index() - 1));
120 /// A single integer representing a `Location` in the MIR control-flow
121 /// graph. Constructed efficiently from `RegionValueElements`.
122 pub struct PointIndex { DEBUG_FORMAT = "PointIndex({}
)" }
126 /// A single integer representing a `ty::Placeholder`.
127 pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" }
130 /// An individual element in a region value -- the value of a
131 /// particular region variable consists of a set of these elements.
132 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
133 crate enum RegionElement
{
134 /// A point in the control-flow graph.
137 /// A universally quantified region from the root universe (e.g.,
138 /// a lifetime parameter).
139 RootUniversalRegion(RegionVid
),
141 /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)`
143 PlaceholderRegion(ty
::PlaceholderRegion
),
146 /// When we initially compute liveness, we use a bit matrix storing
147 /// points for each region-vid.
148 crate struct LivenessValues
<N
: Idx
> {
149 elements
: Rc
<RegionValueElements
>,
150 points
: SparseBitMatrix
<N
, PointIndex
>,
153 impl<N
: Idx
> LivenessValues
<N
> {
154 /// Creates a new set of "region values" that tracks causal information.
155 /// Each of the regions in num_region_variables will be initialized with an
156 /// empty set of points and no causal information.
157 crate fn new(elements
: Rc
<RegionValueElements
>) -> Self {
159 points
: SparseBitMatrix
::new(elements
.num_points
),
164 /// Iterate through each region that has a value in this set.
165 crate fn rows
<'a
>(&'a
self) -> impl Iterator
<Item
= N
> {
169 /// Adds the given element to the value for the given region. Returns whether
170 /// the element is newly added (i.e., was not already present).
171 crate fn add_element(&mut self, row
: N
, location
: Location
) -> bool
{
172 debug
!("LivenessValues::add(r={:?}, location={:?})", row
, location
);
173 let index
= self.elements
.point_from_location(location
);
174 self.points
.insert(row
, index
)
177 /// Adds all the elements in the given bit array into the given
178 /// region. Returns whether any of them are newly added.
179 crate fn add_elements(&mut self, row
: N
, locations
: &HybridBitSet
<PointIndex
>) -> bool
{
181 "LivenessValues::add_elements(row={:?}, locations={:?})",
184 self.points
.union_into_row(row
, locations
)
187 /// Adds all the control-flow points to the values for `r`.
188 crate fn add_all_points(&mut self, row
: N
) {
189 self.points
.insert_all_into_row(row
);
192 /// Returns `true` if the region `r` contains the given element.
193 crate fn contains(&self, row
: N
, location
: Location
) -> bool
{
194 let index
= self.elements
.point_from_location(location
);
195 self.points
.contains(row
, index
)
198 /// Returns a "pretty" string value of the region. Meant for debugging.
199 crate fn region_value_str(&self, r
: N
) -> String
{
204 .flat_map(|set
| set
.iter())
205 .take_while(|&p
| self.elements
.point_in_range(p
))
206 .map(|p
| self.elements
.to_location(p
))
207 .map(RegionElement
::Location
),
212 /// Maps from `ty::PlaceholderRegion` values that are used in the rest of
213 /// rustc to the internal `PlaceholderIndex` values that are used in
216 crate struct PlaceholderIndices
{
217 to_index
: FxHashMap
<ty
::PlaceholderRegion
, PlaceholderIndex
>,
218 from_index
: IndexVec
<PlaceholderIndex
, ty
::PlaceholderRegion
>,
221 impl PlaceholderIndices
{
222 crate fn insert(&mut self, placeholder
: ty
::PlaceholderRegion
) -> PlaceholderIndex
{
223 let PlaceholderIndices
{
229 .or_insert_with(|| from_index
.push(placeholder
))
232 crate fn lookup_index(&self, placeholder
: ty
::PlaceholderRegion
) -> PlaceholderIndex
{
233 self.to_index
[&placeholder
]
236 crate fn lookup_placeholder(&self, placeholder
: PlaceholderIndex
) -> ty
::PlaceholderRegion
{
237 self.from_index
[placeholder
]
240 crate fn len(&self) -> usize {
241 self.from_index
.len()
245 /// Stores the full values for a set of regions (in contrast to
246 /// `LivenessValues`, which only stores those points in the where a
247 /// region is live). The full value for a region may contain points in
248 /// the CFG, but also free regions as well as bound universe
254 /// fn foo(x: &'a u32) -> &'a u32 {
255 /// let y: &'0 u32 = x; // let's call this `'0`
260 /// Here, the variable `'0` would contain the free region `'a`,
261 /// because (since it is returned) it must live for at least `'a`. But
262 /// it would also contain various points from within the function.
264 crate struct RegionValues
<N
: Idx
> {
265 elements
: Rc
<RegionValueElements
>,
266 placeholder_indices
: Rc
<PlaceholderIndices
>,
267 points
: SparseBitMatrix
<N
, PointIndex
>,
268 free_regions
: SparseBitMatrix
<N
, RegionVid
>,
270 /// Placeholders represent bound regions -- so something like `'a`
271 /// in for<'a> fn(&'a u32)`.
272 placeholders
: SparseBitMatrix
<N
, PlaceholderIndex
>,
275 impl<N
: Idx
> RegionValues
<N
> {
276 /// Creates a new set of "region values" that tracks causal information.
277 /// Each of the regions in num_region_variables will be initialized with an
278 /// empty set of points and no causal information.
280 elements
: &Rc
<RegionValueElements
>,
281 num_universal_regions
: usize,
282 placeholder_indices
: &Rc
<PlaceholderIndices
>,
284 let num_placeholders
= placeholder_indices
.len();
286 elements
: elements
.clone(),
287 points
: SparseBitMatrix
::new(elements
.num_points
),
288 placeholder_indices
: placeholder_indices
.clone(),
289 free_regions
: SparseBitMatrix
::new(num_universal_regions
),
290 placeholders
: SparseBitMatrix
::new(num_placeholders
),
294 /// Adds the given element to the value for the given region. Returns whether
295 /// the element is newly added (i.e., was not already present).
296 crate fn add_element(&mut self, r
: N
, elem
: impl ToElementIndex
) -> bool
{
297 debug
!("add(r={:?}, elem={:?})", r
, elem
);
298 elem
.add_to_row(self, r
)
301 /// Adds all the control-flow points to the values for `r`.
302 crate fn add_all_points(&mut self, r
: N
) {
303 self.points
.insert_all_into_row(r
);
306 /// Adds all elements in `r_from` to `r_to` (because e.g., `r_to:
308 crate fn add_region(&mut self, r_to
: N
, r_from
: N
) -> bool
{
309 self.points
.union_rows(r_from
, r_to
)
310 | self.free_regions
.union_rows(r_from
, r_to
)
311 | self.placeholders
.union_rows(r_from
, r_to
)
314 /// Returns `true` if the region `r` contains the given element.
315 crate fn contains(&self, r
: N
, elem
: impl ToElementIndex
) -> bool
{
316 elem
.contained_in_row(self, r
)
319 /// `self[to] |= values[from]`, essentially: that is, take all the
320 /// elements for the region `from` from `values` and add them to
321 /// the region `to` in `self`.
322 crate fn merge_liveness
<M
: Idx
>(&mut self, to
: N
, from
: M
, values
: &LivenessValues
<M
>) {
323 if let Some(set
) = values
.points
.row(from
) {
324 self.points
.union_into_row(to
, set
);
328 /// Returns `true` if `sup_region` contains all the CFG points that
329 /// `sub_region` contains. Ignores universal regions.
330 crate fn contains_points(&self, sup_region
: N
, sub_region
: N
) -> bool
{
331 if let Some(sub_row
) = self.points
.row(sub_region
) {
332 if let Some(sup_row
) = self.points
.row(sup_region
) {
333 sup_row
.superset(sub_row
)
335 // sup row is empty, so sub row must be empty
339 // sub row is empty, always true
344 /// Returns the locations contained within a given region `r`.
345 crate fn locations_outlived_by
<'a
>(&'a
self, r
: N
) -> impl Iterator
<Item
= Location
> + 'a
{
346 self.points
.row(r
).into_iter().flat_map(move |set
| {
348 .take_while(move |&p
| self.elements
.point_in_range(p
))
349 .map(move |p
| self.elements
.to_location(p
))
353 /// Returns just the universal regions that are contained in a given region's value.
354 crate fn universal_regions_outlived_by
<'a
>(
357 ) -> impl Iterator
<Item
= RegionVid
> + 'a
{
361 .flat_map(|set
| set
.iter())
364 /// Returns all the elements contained in a given region's value.
365 crate fn placeholders_contained_in
<'a
>(
368 ) -> impl Iterator
<Item
= ty
::PlaceholderRegion
> + 'a
{
372 .flat_map(|set
| set
.iter())
373 .map(move |p
| self.placeholder_indices
.lookup_placeholder(p
))
376 /// Returns all the elements contained in a given region's value.
377 crate fn elements_contained_in
<'a
>(&'a
self, r
: N
) -> impl Iterator
<Item
= RegionElement
> + 'a
{
378 let points_iter
= self.locations_outlived_by(r
).map(RegionElement
::Location
);
380 let free_regions_iter
= self.universal_regions_outlived_by(r
)
381 .map(RegionElement
::RootUniversalRegion
);
383 let placeholder_universes_iter
= self.placeholders_contained_in(r
)
384 .map(RegionElement
::PlaceholderRegion
);
387 .chain(free_regions_iter
)
388 .chain(placeholder_universes_iter
)
391 /// Returns a "pretty" string value of the region. Meant for debugging.
392 crate fn region_value_str(&self, r
: N
) -> String
{
393 region_value_str(self.elements_contained_in(r
))
397 crate trait ToElementIndex
: Debug
+ Copy
{
398 fn add_to_row
<N
: Idx
>(self, values
: &mut RegionValues
<N
>, row
: N
) -> bool
;
400 fn contained_in_row
<N
: Idx
>(self, values
: &RegionValues
<N
>, row
: N
) -> bool
;
403 impl ToElementIndex
for Location
{
404 fn add_to_row
<N
: Idx
>(self, values
: &mut RegionValues
<N
>, row
: N
) -> bool
{
405 let index
= values
.elements
.point_from_location(self);
406 values
.points
.insert(row
, index
)
409 fn contained_in_row
<N
: Idx
>(self, values
: &RegionValues
<N
>, row
: N
) -> bool
{
410 let index
= values
.elements
.point_from_location(self);
411 values
.points
.contains(row
, index
)
415 impl ToElementIndex
for RegionVid
{
416 fn add_to_row
<N
: Idx
>(self, values
: &mut RegionValues
<N
>, row
: N
) -> bool
{
417 values
.free_regions
.insert(row
, self)
420 fn contained_in_row
<N
: Idx
>(self, values
: &RegionValues
<N
>, row
: N
) -> bool
{
421 values
.free_regions
.contains(row
, self)
425 impl ToElementIndex
for ty
::PlaceholderRegion
{
426 fn add_to_row
<N
: Idx
>(self, values
: &mut RegionValues
<N
>, row
: N
) -> bool
{
427 let index
= values
.placeholder_indices
.lookup_index(self);
428 values
.placeholders
.insert(row
, index
)
431 fn contained_in_row
<N
: Idx
>(self, values
: &RegionValues
<N
>, row
: N
) -> bool
{
432 let index
= values
.placeholder_indices
.lookup_index(self);
433 values
.placeholders
.contains(row
, index
)
437 crate fn location_set_str(
438 elements
: &RegionValueElements
,
439 points
: impl IntoIterator
<Item
= PointIndex
>,
444 .take_while(|&p
| elements
.point_in_range(p
))
445 .map(|p
| elements
.to_location(p
))
446 .map(RegionElement
::Location
),
450 fn region_value_str(elements
: impl IntoIterator
<Item
= RegionElement
>) -> String
{
451 let mut result
= String
::new();
452 result
.push_str("{");
454 // Set to Some(l1, l2) when we have observed all the locations
455 // from l1..=l2 (inclusive) but not yet printed them. This
456 // gets extended if we then see l3 where l3 is the successor
458 let mut open_location
: Option
<(Location
, Location
)> = None
;
461 let mut push_sep
= |s
: &mut String
| {
466 for element
in elements
{
468 RegionElement
::Location(l
) => {
469 if let Some((location1
, location2
)) = open_location
{
470 if location2
.block
== l
.block
471 && location2
.statement_index
== l
.statement_index
- 1
473 open_location
= Some((location1
, l
));
477 push_sep(&mut result
);
478 push_location_range(&mut result
, location1
, location2
);
481 open_location
= Some((l
, l
));
484 RegionElement
::RootUniversalRegion(fr
) => {
485 if let Some((location1
, location2
)) = open_location
{
486 push_sep(&mut result
);
487 push_location_range(&mut result
, location1
, location2
);
488 open_location
= None
;
491 push_sep(&mut result
);
492 result
.push_str(&format
!("{:?}", fr
));
495 RegionElement
::PlaceholderRegion(placeholder
) => {
496 if let Some((location1
, location2
)) = open_location
{
497 push_sep(&mut result
);
498 push_location_range(&mut result
, location1
, location2
);
499 open_location
= None
;
502 push_sep(&mut result
);
503 result
.push_str(&format
!("{:?}", placeholder
));
508 if let Some((location1
, location2
)) = open_location
{
509 push_sep(&mut result
);
510 push_location_range(&mut result
, location1
, location2
);
513 result
.push_str("}");
517 fn push_location_range(str: &mut String
, location1
: Location
, location2
: Location
) {
518 if location1
== location2
{
519 str.push_str(&format
!("{:?}", location1
));
521 assert_eq
!(location1
.block
, location2
.block
);
522 str.push_str(&format
!(
524 location1
.block
, location1
.statement_index
, location2
.statement_index