@@ -20,13 +20,23 @@ use std::rc::Rc;
2020crate struct RegionValueElements {
2121 /// For each basic block, how many points are contained within?
2222 statements_before_block : IndexVec < BasicBlock , usize > ,
23+
24+ /// Map backward from each point into to one of two possible values:
25+ ///
26+ /// - `None`: if this point index represents a Location with non-zero index
27+ /// - `Some(bb)`: if this point index represents a Location with zero index
28+ ///
29+ /// NB. It may be better to just map back to a full `Location`. We
30+ /// should probably try that.
31+ basic_block_heads : IndexVec < PointIndex , Option < BasicBlock > > ,
32+
2333 num_points : usize ,
2434}
2535
2636impl RegionValueElements {
2737 crate fn new ( mir : & Mir < ' _ > ) -> Self {
2838 let mut num_points = 0 ;
29- let statements_before_block = mir
39+ let statements_before_block: IndexVec < BasicBlock , usize > = mir
3040 . basic_blocks ( )
3141 . iter ( )
3242 . map ( |block_data| {
@@ -41,8 +51,16 @@ impl RegionValueElements {
4151 ) ;
4252 debug ! ( "RegionValueElements: num_points={:#?}" , num_points) ;
4353
54+ let mut basic_block_heads: IndexVec < PointIndex , Option < BasicBlock > > =
55+ ( 0 ..num_points) . map ( |_| None ) . collect ( ) ;
56+ for ( bb, & first_point) in statements_before_block. iter_enumerated ( ) {
57+ let first_point = PointIndex :: new ( first_point) ;
58+ basic_block_heads[ first_point] = Some ( bb) ;
59+ }
60+
4461 Self {
4562 statements_before_block,
63+ basic_block_heads,
4664 num_points,
4765 }
4866 }
@@ -70,47 +88,55 @@ impl RegionValueElements {
7088
7189 /// Converts a `PointIndex` back to a location. O(N) where N is
7290 /// the number of blocks; could be faster if we ever cared.
73- crate fn to_location ( & self , i : PointIndex ) -> Location {
74- let point_index = i. index ( ) ;
75-
76- // Find the basic block. We have a vector with the
77- // starting index of the statement in each block. Imagine
78- // we have statement #22, and we have a vector like:
79- //
80- // [0, 10, 20]
81- //
82- // In that case, this represents point_index 2 of
83- // basic block BB2. We know this because BB0 accounts for
84- // 0..10, BB1 accounts for 11..20, and BB2 accounts for
85- // 20...
86- //
87- // To compute this, we could do a binary search, but
88- // because I am lazy we instead iterate through to find
89- // the last point where the "first index" (0, 10, or 20)
90- // was less than the statement index (22). In our case, this will
91- // be (BB2, 20).
92- //
93- // Nit: we could do a binary search here but I'm too lazy.
94- let ( block, & first_index) = self
95- . statements_before_block
96- . iter_enumerated ( )
97- . filter ( |( _, first_index) | * * first_index <= point_index)
98- . last ( )
99- . unwrap ( ) ;
100-
101- Location {
102- block,
103- statement_index : point_index - first_index,
91+ crate fn to_location ( & self , index : PointIndex ) -> Location {
92+ assert ! ( index. index( ) < self . num_points) ;
93+
94+ let mut statement_index = 0 ;
95+
96+ for opt_bb in self . basic_block_heads . raw [ ..= index. index ( ) ] . iter ( ) . rev ( ) {
97+ if let & Some ( block) = opt_bb {
98+ return Location { block, statement_index } ;
99+ }
100+
101+ statement_index += 1 ;
104102 }
105- }
106103
107- /// Returns an iterator of each basic block and the first point
108- /// index within the block; the point indices for all statements
109- /// within the block follow afterwards.
110- crate fn head_indices ( & self ) -> impl Iterator < Item = ( BasicBlock , PointIndex ) > + ' _ {
111- self . statements_before_block
112- . iter_enumerated ( )
113- . map ( move |( bb, & first_index) | ( bb, PointIndex :: new ( first_index) ) )
104+ bug ! ( "did not find basic block as expected for index = {:?}" , index)
105+ }
106+
107+ /// Sometimes we get point-indices back from bitsets that may be
108+ /// out of range (because they round up to the nearest 2^N number
109+ /// of bits). Use this function to filter such points out if you
110+ /// like.
111+ crate fn point_in_range ( & self , index : PointIndex ) -> bool {
112+ index. index ( ) < self . num_points
113+ }
114+
115+ /// Pushes all predecessors of `index` onto `stack`.
116+ crate fn push_predecessors (
117+ & self ,
118+ mir : & Mir < ' _ > ,
119+ index : PointIndex ,
120+ stack : & mut Vec < PointIndex > ,
121+ ) {
122+ match self . basic_block_heads [ index] {
123+ // If this is a basic block head, then the predecessors are
124+ // the the terminators of other basic blocks
125+ Some ( bb_head) => {
126+ stack. extend (
127+ mir
128+ . predecessors_for ( bb_head)
129+ . iter ( )
130+ . map ( |& pred_bb| mir. terminator_loc ( pred_bb) )
131+ . map ( |pred_loc| self . point_from_location ( pred_loc) ) ,
132+ ) ;
133+ }
134+
135+ // Otherwise, the pred is just the previous statement
136+ None => {
137+ stack. push ( PointIndex :: new ( index. index ( ) - 1 ) ) ;
138+ }
139+ }
114140 }
115141}
116142
@@ -196,6 +222,7 @@ impl<N: Idx> LivenessValues<N> {
196222 . row ( r)
197223 . into_iter ( )
198224 . flat_map ( |set| set. iter ( ) )
225+ . take_while ( |& p| self . elements . point_in_range ( p) )
199226 . map ( |p| self . elements . to_location ( p) )
200227 . map ( RegionElement :: Location ) ,
201228 )
@@ -304,7 +331,11 @@ impl<N: Idx> RegionValues<N> {
304331 self . points
305332 . row ( r)
306333 . into_iter ( )
307- . flat_map ( move |set| set. iter ( ) . map ( move |p| self . elements . to_location ( p) ) )
334+ . flat_map ( move |set| {
335+ set. iter ( )
336+ . take_while ( move |& p| self . elements . point_in_range ( p) )
337+ . map ( move |p| self . elements . to_location ( p) )
338+ } )
308339 }
309340
310341 /// Returns just the universal regions that are contained in a given region's value.
@@ -400,6 +431,7 @@ crate fn location_set_str(
400431 region_value_str (
401432 points
402433 . into_iter ( )
434+ . take_while ( |& p| elements. point_in_range ( p) )
403435 . map ( |p| elements. to_location ( p) )
404436 . map ( RegionElement :: Location ) ,
405437 )
0 commit comments