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::bit_set::{HybridBitSet, SparseBitMatrix};
14 use rustc_data_structures::fx::FxHashMap;
15 use rustc_data_structures::indexed_vec::Idx;
16 use rustc_data_structures::indexed_vec::IndexVec;
20 /// Maps between a `Location` and a `PointIndex` (and vice versa).
21 crate struct RegionValueElements {
22 /// For each basic block, how many points are contained within?
23 statements_before_block: IndexVec<BasicBlock, usize>,
25 /// Map backward from each point to the basic block that it
27 basic_blocks: IndexVec<PointIndex, BasicBlock>,
32 impl RegionValueElements {
33 crate fn new(mir: &Mir<'_>) -> Self {
34 let mut num_points = 0;
35 let statements_before_block: IndexVec<BasicBlock, usize> = mir.basic_blocks()
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()).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;
94 /// Sometimes we get point-indices back from bitsets that may be
95 /// out of range (because they round up to the nearest 2^N number
96 /// of bits). Use this function to filter such points out if you
98 crate fn point_in_range(&self, index: PointIndex) -> bool {
99 index.index() < self.num_points
102 /// Pushes all predecessors of `index` onto `stack`.
103 crate fn push_predecessors(
107 stack: &mut Vec<PointIndex>,
112 } = self.to_location(index);
113 if statement_index == 0 {
114 // If this is a basic block head, then the predecessors are
115 // the terminators of other basic blocks
117 mir.predecessors_for(block)
119 .map(|&pred_bb| mir.terminator_loc(pred_bb))
120 .map(|pred_loc| self.point_from_location(pred_loc)),
123 // Otherwise, the pred is just the previous statement
124 stack.push(PointIndex::new(index.index() - 1));
129 /// A single integer representing a `Location` in the MIR control-flow
130 /// graph. Constructed efficiently from `RegionValueElements`.
132 pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" }
135 /// A single integer representing a `ty::Placeholder`.
137 pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" }
140 /// An individual element in a region value -- the value of a
141 /// particular region variable consists of a set of these elements.
142 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
143 crate enum RegionElement {
144 /// A point in the control-flow graph.
147 /// A universally quantified region from the root universe (e.g.,
148 /// a lifetime parameter).
149 RootUniversalRegion(RegionVid),
151 /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)`
153 PlaceholderRegion(ty::PlaceholderRegion),
156 /// When we initially compute liveness, we use a bit matrix storing
157 /// points for each region-vid.
158 crate struct LivenessValues<N: Idx> {
159 elements: Rc<RegionValueElements>,
160 points: SparseBitMatrix<N, PointIndex>,
163 impl<N: Idx> LivenessValues<N> {
164 /// Creates a new set of "region values" that tracks causal information.
165 /// Each of the regions in num_region_variables will be initialized with an
166 /// empty set of points and no causal information.
167 crate fn new(elements: &Rc<RegionValueElements>) -> Self {
169 elements: elements.clone(),
170 points: SparseBitMatrix::new(elements.num_points),
174 /// Iterate through each region that has a value in this set.
175 crate fn rows<'a>(&'a self) -> impl Iterator<Item = N> {
179 /// Adds the given element to the value for the given region. Returns true if
180 /// the element is newly added (i.e., was not already present).
181 crate fn add_element(&mut self, row: N, location: Location) -> bool {
182 debug!("LivenessValues::add(r={:?}, location={:?})", row, location);
183 let index = self.elements.point_from_location(location);
184 self.points.insert(row, index)
187 /// Adds all the elements in the given bit array into the given
188 /// region. Returns true if any of them are newly added.
189 crate fn add_elements(&mut self, row: N, locations: &HybridBitSet<PointIndex>) -> bool {
191 "LivenessValues::add_elements(row={:?}, locations={:?})",
194 self.points.union_into_row(row, locations)
197 /// Adds all the control-flow points to the values for `r`.
198 crate fn add_all_points(&mut self, row: N) {
199 self.points.insert_all_into_row(row);
202 /// True if the region `r` contains the given element.
203 crate fn contains(&self, row: N, location: Location) -> bool {
204 let index = self.elements.point_from_location(location);
205 self.points.contains(row, index)
208 /// Returns a "pretty" string value of the region. Meant for debugging.
209 crate fn region_value_str(&self, r: N) -> String {
214 .flat_map(|set| set.iter())
215 .take_while(|&p| self.elements.point_in_range(p))
216 .map(|p| self.elements.to_location(p))
217 .map(RegionElement::Location),
222 /// Maps from `ty::PlaceholderRegion` values that are used in the rest of
223 /// rustc to the internal `PlaceholderIndex` values that are used in
226 crate struct PlaceholderIndices {
227 to_index: FxHashMap<ty::PlaceholderRegion, PlaceholderIndex>,
228 from_index: IndexVec<PlaceholderIndex, ty::PlaceholderRegion>,
231 impl PlaceholderIndices {
232 crate fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
233 let PlaceholderIndices {
239 .or_insert_with(|| from_index.push(placeholder))
242 crate fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
243 self.to_index[&placeholder]
246 crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::PlaceholderRegion {
247 self.from_index[placeholder]
250 crate fn len(&self) -> usize {
251 self.from_index.len()
255 /// Stores the full values for a set of regions (in contrast to
256 /// `LivenessValues`, which only stores those points in the where a
257 /// region is live). The full value for a region may contain points in
258 /// the CFG, but also free regions as well as bound universe
264 /// fn foo(x: &'a u32) -> &'a u32 {
265 /// let y: &'0 u32 = x; // let's call this `'0`
270 /// Here, the variable `'0` would contain the free region `'a`,
271 /// because (since it is returned) it must live for at least `'a`. But
272 /// it would also contain various points from within the function.
274 crate struct RegionValues<N: Idx> {
275 elements: Rc<RegionValueElements>,
276 placeholder_indices: Rc<PlaceholderIndices>,
277 points: SparseBitMatrix<N, PointIndex>,
278 free_regions: SparseBitMatrix<N, RegionVid>,
280 /// Placeholders represent bound regions -- so something like `'a`
281 /// in for<'a> fn(&'a u32)`.
282 placeholders: SparseBitMatrix<N, PlaceholderIndex>,
285 impl<N: Idx> RegionValues<N> {
286 /// Creates a new set of "region values" that tracks causal information.
287 /// Each of the regions in num_region_variables will be initialized with an
288 /// empty set of points and no causal information.
290 elements: &Rc<RegionValueElements>,
291 num_universal_regions: usize,
292 placeholder_indices: &Rc<PlaceholderIndices>,
294 let num_placeholders = placeholder_indices.len();
296 elements: elements.clone(),
297 points: SparseBitMatrix::new(elements.num_points),
298 placeholder_indices: placeholder_indices.clone(),
299 free_regions: SparseBitMatrix::new(num_universal_regions),
300 placeholders: SparseBitMatrix::new(num_placeholders),
304 /// Adds the given element to the value for the given region. Returns true if
305 /// the element is newly added (i.e., was not already present).
306 crate fn add_element(&mut self, r: N, elem: impl ToElementIndex) -> bool {
307 debug!("add(r={:?}, elem={:?})", r, elem);
308 elem.add_to_row(self, r)
311 /// Adds all the control-flow points to the values for `r`.
312 crate fn add_all_points(&mut self, r: N) {
313 self.points.insert_all_into_row(r);
316 /// Add all elements in `r_from` to `r_to` (because e.g. `r_to:
318 crate fn add_region(&mut self, r_to: N, r_from: N) -> bool {
319 self.points.union_rows(r_from, r_to)
320 | self.free_regions.union_rows(r_from, r_to)
321 | self.placeholders.union_rows(r_from, r_to)
324 /// True if the region `r` contains the given element.
325 crate fn contains(&self, r: N, elem: impl ToElementIndex) -> bool {
326 elem.contained_in_row(self, r)
329 /// `self[to] |= values[from]`, essentially: that is, take all the
330 /// elements for the region `from` from `values` and add them to
331 /// the region `to` in `self`.
332 crate fn merge_liveness<M: Idx>(&mut self, to: N, from: M, values: &LivenessValues<M>) {
333 if let Some(set) = values.points.row(from) {
334 self.points.union_into_row(to, set);
338 /// True if `sup_region` contains all the CFG points that
339 /// `sub_region` contains. Ignores universal regions.
340 crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
341 if let Some(sub_row) = self.points.row(sub_region) {
342 if let Some(sup_row) = self.points.row(sup_region) {
343 sup_row.superset(sub_row)
345 // sup row is empty, so sub row must be empty
349 // sub row is empty, always true
354 /// Returns the locations contained within a given region `r`.
355 crate fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
356 self.points.row(r).into_iter().flat_map(move |set| {
358 .take_while(move |&p| self.elements.point_in_range(p))
359 .map(move |p| self.elements.to_location(p))
363 /// Returns just the universal regions that are contained in a given region's value.
364 crate fn universal_regions_outlived_by<'a>(
367 ) -> impl Iterator<Item = RegionVid> + 'a {
371 .flat_map(|set| set.iter())
374 /// Returns all the elements contained in a given region's value.
375 crate fn placeholders_contained_in<'a>(
378 ) -> impl Iterator<Item = ty::PlaceholderRegion> + 'a {
382 .flat_map(|set| set.iter())
383 .map(move |p| self.placeholder_indices.lookup_placeholder(p))
386 /// Returns all the elements contained in a given region's value.
387 crate fn elements_contained_in<'a>(&'a self, r: N) -> impl Iterator<Item = RegionElement> + 'a {
388 let points_iter = self.locations_outlived_by(r).map(RegionElement::Location);
390 let free_regions_iter = self.universal_regions_outlived_by(r)
391 .map(RegionElement::RootUniversalRegion);
393 let placeholder_universes_iter = self.placeholders_contained_in(r)
394 .map(RegionElement::PlaceholderRegion);
397 .chain(free_regions_iter)
398 .chain(placeholder_universes_iter)
401 /// Returns a "pretty" string value of the region. Meant for debugging.
402 crate fn region_value_str(&self, r: N) -> String {
403 region_value_str(self.elements_contained_in(r))
407 crate trait ToElementIndex: Debug + Copy {
408 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool;
410 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool;
413 impl ToElementIndex for Location {
414 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
415 let index = values.elements.point_from_location(self);
416 values.points.insert(row, index)
419 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
420 let index = values.elements.point_from_location(self);
421 values.points.contains(row, index)
425 impl ToElementIndex for RegionVid {
426 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
427 values.free_regions.insert(row, self)
430 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
431 values.free_regions.contains(row, self)
435 impl ToElementIndex for ty::PlaceholderRegion {
436 fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
437 let index = values.placeholder_indices.lookup_index(self);
438 values.placeholders.insert(row, index)
441 fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
442 let index = values.placeholder_indices.lookup_index(self);
443 values.placeholders.contains(row, index)
447 crate fn location_set_str(
448 elements: &RegionValueElements,
449 points: impl IntoIterator<Item = PointIndex>,
454 .take_while(|&p| elements.point_in_range(p))
455 .map(|p| elements.to_location(p))
456 .map(RegionElement::Location),
460 fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String {
461 let mut result = String::new();
462 result.push_str("{");
464 // Set to Some(l1, l2) when we have observed all the locations
465 // from l1..=l2 (inclusive) but not yet printed them. This
466 // gets extended if we then see l3 where l3 is the successor
468 let mut open_location: Option<(Location, Location)> = None;
471 let mut push_sep = |s: &mut String| {
476 for element in elements {
478 RegionElement::Location(l) => {
479 if let Some((location1, location2)) = open_location {
480 if location2.block == l.block
481 && location2.statement_index == l.statement_index - 1
483 open_location = Some((location1, l));
487 push_sep(&mut result);
488 push_location_range(&mut result, location1, location2);
491 open_location = Some((l, l));
494 RegionElement::RootUniversalRegion(fr) => {
495 if let Some((location1, location2)) = open_location {
496 push_sep(&mut result);
497 push_location_range(&mut result, location1, location2);
498 open_location = None;
501 push_sep(&mut result);
502 result.push_str(&format!("{:?}", fr));
505 RegionElement::PlaceholderRegion(placeholder) => {
506 if let Some((location1, location2)) = open_location {
507 push_sep(&mut result);
508 push_location_range(&mut result, location1, location2);
509 open_location = None;
512 push_sep(&mut result);
513 result.push_str(&format!("{:?}", placeholder));
518 if let Some((location1, location2)) = open_location {
519 push_sep(&mut result);
520 push_location_range(&mut result, location1, location2);
523 result.push_str("}");
527 fn push_location_range(str: &mut String, location1: Location, location2: Location) {
528 if location1 == location2 {
529 str.push_str(&format!("{:?}", location1));
531 assert_eq!(location1.block, location2.block);
532 str.push_str(&format!(
534 location1.block, location1.statement_index, location2.statement_index