1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use rustc
::mir
::{BasicBlock, Location, Mir}
;
12 use rustc
::ty
::{self, RegionVid}
;
13 use rustc_data_structures
::bitvec
::{BitArray, SparseBitMatrix}
;
14 use rustc_data_structures
::indexed_vec
::Idx
;
15 use rustc_data_structures
::indexed_vec
::IndexVec
;
19 /// Maps between a `Location` and a `PointIndex` (and vice versa).
20 crate struct RegionValueElements
{
21 /// For each basic block, how many points are contained within?
22 statements_before_block
: IndexVec
<BasicBlock
, usize>,
24 /// Map backward from each point to the basic block that it
26 basic_blocks
: IndexVec
<PointIndex
, BasicBlock
>,
31 impl RegionValueElements
{
32 crate fn new(mir
: &Mir
<'_
>) -> Self {
33 let mut num_points
= 0;
34 let statements_before_block
: IndexVec
<BasicBlock
, usize> = mir
39 num_points
+= block_data
.statements
.len() + 1;
44 "RegionValueElements: statements_before_block={:#?}",
45 statements_before_block
47 debug
!("RegionValueElements: num_points={:#?}", num_points
);
49 let mut basic_blocks
= IndexVec
::with_capacity(num_points
);
50 for (bb
, bb_data
) in mir
.basic_blocks().iter_enumerated() {
51 basic_blocks
.extend((0 .. bb_data
.statements
.len() + 1).map(|_
| bb
));
55 statements_before_block
,
61 /// Total number of point indices
62 crate fn num_points(&self) -> usize {
66 /// Converts a `Location` into a `PointIndex`. O(1).
67 crate fn point_from_location(&self, location
: Location
) -> PointIndex
{
72 let start_index
= self.statements_before_block
[block
];
73 PointIndex
::new(start_index
+ statement_index
)
76 /// Converts a `Location` into a `PointIndex`. O(1).
77 crate fn entry_point(&self, block
: BasicBlock
) -> PointIndex
{
78 let start_index
= self.statements_before_block
[block
];
79 PointIndex
::new(start_index
)
82 /// Converts a `PointIndex` back to a location. O(1).
83 crate fn to_location(&self, index
: PointIndex
) -> Location
{
84 assert
!(index
.index() < self.num_points
);
85 let block
= self.basic_blocks
[index
];
86 let start_index
= self.statements_before_block
[block
];
87 let statement_index
= index
.index() - start_index
;
88 Location { block, statement_index }
91 /// Sometimes we get point-indices back from bitsets that may be
92 /// out of range (because they round up to the nearest 2^N number
93 /// of bits). Use this function to filter such points out if you
95 crate fn point_in_range(&self, index
: PointIndex
) -> bool
{
96 index
.index() < self.num_points
99 /// Pushes all predecessors of `index` onto `stack`.
100 crate fn push_predecessors(
104 stack
: &mut Vec
<PointIndex
>,
106 let Location { block, statement_index }
= self.to_location(index
);
107 if statement_index
== 0 {
108 // If this is a basic block head, then the predecessors are
109 // the the terminators of other basic blocks
112 .predecessors_for(block
)
114 .map(|&pred_bb
| mir
.terminator_loc(pred_bb
))
115 .map(|pred_loc
| self.point_from_location(pred_loc
)),
118 // Otherwise, the pred is just the previous statement
119 stack
.push(PointIndex
::new(index
.index() - 1));
124 /// A single integer representing a `Location` in the MIR control-flow
125 /// graph. Constructed efficiently from `RegionValueElements`.
127 pub struct PointIndex { DEBUG_FORMAT = "PointIndex({}
)" }
130 /// A single integer representing a (non-zero) `UniverseIndex`.
131 /// Computed just by subtracting one from `UniverseIndex`; this is
132 /// because the `0` value for `UniverseIndex` represents the root
133 /// universe, and we don't need/want a bit for that one.
135 pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" }
138 /// An individual element in a region value -- the value of a
139 /// particular region variable consists of a set of these elements.
140 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
141 crate enum RegionElement
{
142 /// A point in the control-flow graph.
145 /// A universally quantified region from the root universe (e.g.,
146 /// a lifetime parameter).
147 RootUniversalRegion(RegionVid
),
149 /// A subuniverse from a subuniverse (e.g., instantiated from a
150 /// `for<'a> fn(&'a u32)` type).
151 SubUniversalRegion(ty
::UniverseIndex
),
154 /// When we initially compute liveness, we use a bit matrix storing
155 /// points for each region-vid.
156 crate struct LivenessValues
<N
: Idx
> {
157 elements
: Rc
<RegionValueElements
>,
158 points
: SparseBitMatrix
<N
, PointIndex
>,
161 impl<N
: Idx
> LivenessValues
<N
> {
162 /// Creates a new set of "region values" that tracks causal information.
163 /// Each of the regions in num_region_variables will be initialized with an
164 /// empty set of points and no causal information.
165 crate fn new(elements
: &Rc
<RegionValueElements
>) -> Self {
167 elements
: elements
.clone(),
168 points
: SparseBitMatrix
::new(elements
.num_points
),
172 /// Iterate through each region that has a value in this set.
173 crate fn rows
<'a
>(&'a
self) -> impl Iterator
<Item
= N
> {
177 /// Adds the given element to the value for the given region. Returns true if
178 /// the element is newly added (i.e., was not already present).
179 crate fn add_element(&mut self, row
: N
, location
: Location
) -> bool
{
180 debug
!("LivenessValues::add(r={:?}, location={:?})", row
, location
);
181 let index
= self.elements
.point_from_location(location
);
182 self.points
.add(row
, index
)
185 /// Adds all the elements in the given bit array into the given
186 /// region. Returns true if any of them are newly added.
187 crate fn add_elements(&mut self, row
: N
, locations
: &BitArray
<PointIndex
>) -> bool
{
188 debug
!("LivenessValues::add_elements(row={:?}, locations={:?})", row
, locations
);
189 self.points
.merge_into(row
, locations
)
192 /// Adds all the control-flow points to the values for `r`.
193 crate fn add_all_points(&mut self, row
: N
) {
194 self.points
.add_all(row
);
197 /// True if the region `r` contains the given element.
198 crate fn contains(&self, row
: N
, location
: Location
) -> bool
{
199 let index
= self.elements
.point_from_location(location
);
200 self.points
.contains(row
, index
)
203 /// Returns a "pretty" string value of the region. Meant for debugging.
204 crate fn region_value_str(&self, r
: N
) -> String
{
209 .flat_map(|set
| set
.iter())
210 .take_while(|&p
| self.elements
.point_in_range(p
))
211 .map(|p
| self.elements
.to_location(p
))
212 .map(RegionElement
::Location
),
217 /// Stores the full values for a set of regions (in contrast to
218 /// `LivenessValues`, which only stores those points in the where a
219 /// region is live). The full value for a region may contain points in
220 /// the CFG, but also free regions as well as bound universe
226 /// fn foo(x: &'a u32) -> &'a u32 {
227 /// let y: &'0 u32 = x; // let's call this `'0`
232 /// Here, the variable `'0` would contain the free region `'a`,
233 /// because (since it is returned) it must live for at least `'a`. But
234 /// it would also contain various points from within the function.
236 crate struct RegionValues
<N
: Idx
> {
237 elements
: Rc
<RegionValueElements
>,
238 points
: SparseBitMatrix
<N
, PointIndex
>,
239 free_regions
: SparseBitMatrix
<N
, RegionVid
>,
241 /// Placeholders represent bound regions -- so something like `'a`
242 /// in for<'a> fn(&'a u32)`.
243 placeholders
: SparseBitMatrix
<N
, PlaceholderIndex
>,
246 impl<N
: Idx
> RegionValues
<N
> {
247 /// Creates a new set of "region values" that tracks causal information.
248 /// Each of the regions in num_region_variables will be initialized with an
249 /// empty set of points and no causal information.
251 elements
: &Rc
<RegionValueElements
>,
252 num_universal_regions
: usize,
253 max_universe
: ty
::UniverseIndex
,
255 let num_placeholders
= max_universe
.as_usize();
257 elements
: elements
.clone(),
258 points
: SparseBitMatrix
::new(elements
.num_points
),
259 free_regions
: SparseBitMatrix
::new(num_universal_regions
),
260 placeholders
: SparseBitMatrix
::new(num_placeholders
),
264 /// Adds the given element to the value for the given region. Returns true if
265 /// the element is newly added (i.e., was not already present).
266 crate fn add_element(&mut self, r
: N
, elem
: impl ToElementIndex
) -> bool
{
267 debug
!("add(r={:?}, elem={:?})", r
, elem
);
268 elem
.add_to_row(self, r
)
271 /// Adds all the control-flow points to the values for `r`.
272 crate fn add_all_points(&mut self, r
: N
) {
273 self.points
.add_all(r
);
276 /// Add all elements in `r_from` to `r_to` (because e.g. `r_to:
278 crate fn add_region(&mut self, r_to
: N
, r_from
: N
) -> bool
{
279 self.points
.merge(r_from
, r_to
)
280 | self.free_regions
.merge(r_from
, r_to
)
281 | self.placeholders
.merge(r_from
, r_to
)
284 /// True if the region `r` contains the given element.
285 crate fn contains(&self, r
: N
, elem
: impl ToElementIndex
) -> bool
{
286 elem
.contained_in_row(self, r
)
289 /// `self[to] |= values[from]`, essentially: that is, take all the
290 /// elements for the region `from` from `values` and add them to
291 /// the region `to` in `self`.
292 crate fn merge_liveness
<M
: Idx
>(&mut self, to
: N
, from
: M
, values
: &LivenessValues
<M
>) {
293 if let Some(set
) = values
.points
.row(from
) {
294 self.points
.merge_into(to
, set
);
298 /// True if `sup_region` contains all the CFG points that
299 /// `sub_region` contains. Ignores universal regions.
300 crate fn contains_points(&self, sup_region
: N
, sub_region
: N
) -> bool
{
301 if let Some(sub_row
) = self.points
.row(sub_region
) {
302 if let Some(sup_row
) = self.points
.row(sup_region
) {
303 sup_row
.contains_all(sub_row
)
305 // sup row is empty, so sub row must be empty
309 // sub row is empty, always true
314 /// Returns the locations contained within a given region `r`.
315 crate fn locations_outlived_by
<'a
>(&'a
self, r
: N
) -> impl Iterator
<Item
= Location
> + 'a
{
319 .flat_map(move |set
| {
321 .take_while(move |&p
| self.elements
.point_in_range(p
))
322 .map(move |p
| self.elements
.to_location(p
))
326 /// Returns just the universal regions that are contained in a given region's value.
327 crate fn universal_regions_outlived_by
<'a
>(
330 ) -> impl Iterator
<Item
= RegionVid
> + 'a
{
334 .flat_map(|set
| set
.iter())
337 /// Returns all the elements contained in a given region's value.
338 crate fn subuniverses_contained_in
<'a
>(
341 ) -> impl Iterator
<Item
= ty
::UniverseIndex
> + 'a
{
345 .flat_map(|set
| set
.iter())
346 .map(|p
| ty
::UniverseIndex
::from_u32((p
.index() + 1) as u32))
349 /// Returns all the elements contained in a given region's value.
350 crate fn elements_contained_in
<'a
>(&'a
self, r
: N
) -> impl Iterator
<Item
= RegionElement
> + 'a
{
351 let points_iter
= self.locations_outlived_by(r
).map(RegionElement
::Location
);
353 let free_regions_iter
= self
354 .universal_regions_outlived_by(r
)
355 .map(RegionElement
::RootUniversalRegion
);
357 let subuniverses_iter
= self
358 .subuniverses_contained_in(r
)
359 .map(RegionElement
::SubUniversalRegion
);
362 .chain(free_regions_iter
)
363 .chain(subuniverses_iter
)
366 /// Returns a "pretty" string value of the region. Meant for debugging.
367 crate fn region_value_str(&self, r
: N
) -> String
{
368 region_value_str(self.elements_contained_in(r
))
372 crate trait ToElementIndex
: Debug
+ Copy
{
373 fn add_to_row
<N
: Idx
>(self, values
: &mut RegionValues
<N
>, row
: N
) -> bool
;
375 fn contained_in_row
<N
: Idx
>(self, values
: &RegionValues
<N
>, row
: N
) -> bool
;
378 impl ToElementIndex
for Location
{
379 fn add_to_row
<N
: Idx
>(self, values
: &mut RegionValues
<N
>, row
: N
) -> bool
{
380 let index
= values
.elements
.point_from_location(self);
381 values
.points
.add(row
, index
)
384 fn contained_in_row
<N
: Idx
>(self, values
: &RegionValues
<N
>, row
: N
) -> bool
{
385 let index
= values
.elements
.point_from_location(self);
386 values
.points
.contains(row
, index
)
390 impl ToElementIndex
for RegionVid
{
391 fn add_to_row
<N
: Idx
>(self, values
: &mut RegionValues
<N
>, row
: N
) -> bool
{
392 values
.free_regions
.add(row
, self)
395 fn contained_in_row
<N
: Idx
>(self, values
: &RegionValues
<N
>, row
: N
) -> bool
{
396 values
.free_regions
.contains(row
, self)
400 impl ToElementIndex
for ty
::UniverseIndex
{
401 fn add_to_row
<N
: Idx
>(self, values
: &mut RegionValues
<N
>, row
: N
) -> bool
{
402 let index
= PlaceholderIndex
::new(self.as_usize() - 1);
403 values
.placeholders
.add(row
, index
)
406 fn contained_in_row
<N
: Idx
>(self, values
: &RegionValues
<N
>, row
: N
) -> bool
{
407 let index
= PlaceholderIndex
::new(self.as_usize() - 1);
408 values
.placeholders
.contains(row
, index
)
412 crate fn location_set_str(
413 elements
: &RegionValueElements
,
414 points
: impl IntoIterator
<Item
= PointIndex
>,
419 .take_while(|&p
| elements
.point_in_range(p
))
420 .map(|p
| elements
.to_location(p
))
421 .map(RegionElement
::Location
),
425 fn region_value_str(elements
: impl IntoIterator
<Item
= RegionElement
>) -> String
{
426 let mut result
= String
::new();
427 result
.push_str("{");
429 // Set to Some(l1, l2) when we have observed all the locations
430 // from l1..=l2 (inclusive) but not yet printed them. This
431 // gets extended if we then see l3 where l3 is the successor
433 let mut open_location
: Option
<(Location
, Location
)> = None
;
436 let mut push_sep
= |s
: &mut String
| {
441 for element
in elements
{
443 RegionElement
::Location(l
) => {
444 if let Some((location1
, location2
)) = open_location
{
445 if location2
.block
== l
.block
446 && location2
.statement_index
== l
.statement_index
- 1
448 open_location
= Some((location1
, l
));
452 push_sep(&mut result
);
453 push_location_range(&mut result
, location1
, location2
);
456 open_location
= Some((l
, l
));
459 RegionElement
::RootUniversalRegion(fr
) => {
460 if let Some((location1
, location2
)) = open_location
{
461 push_sep(&mut result
);
462 push_location_range(&mut result
, location1
, location2
);
463 open_location
= None
;
466 push_sep(&mut result
);
467 result
.push_str(&format
!("{:?}", fr
));
470 RegionElement
::SubUniversalRegion(ur
) => {
471 if let Some((location1
, location2
)) = open_location
{
472 push_sep(&mut result
);
473 push_location_range(&mut result
, location1
, location2
);
474 open_location
= None
;
477 push_sep(&mut result
);
478 result
.push_str(&format
!("{:?}", ur
));
483 if let Some((location1
, location2
)) = open_location
{
484 push_sep(&mut result
);
485 push_location_range(&mut result
, location1
, location2
);
488 result
.push_str("}");
492 fn push_location_range(str: &mut String
, location1
: Location
, location2
: Location
) {
493 if location1
== location2
{
494 str.push_str(&format
!("{:?}", location1
));
496 assert_eq
!(location1
.block
, location2
.block
);
497 str.push_str(&format
!(
499 location1
.block
, location1
.statement_index
, location2
.statement_index