@@ -20,13 +20,23 @@ use std::rc::Rc;
20
20
crate struct RegionValueElements {
21
21
/// For each basic block, how many points are contained within?
22
22
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
+
23
33
num_points : usize ,
24
34
}
25
35
26
36
impl RegionValueElements {
27
37
crate fn new ( mir : & Mir < ' _ > ) -> Self {
28
38
let mut num_points = 0 ;
29
- let statements_before_block = mir
39
+ let statements_before_block: IndexVec < BasicBlock , usize > = mir
30
40
. basic_blocks ( )
31
41
. iter ( )
32
42
. map ( |block_data| {
@@ -41,8 +51,16 @@ impl RegionValueElements {
41
51
) ;
42
52
debug ! ( "RegionValueElements: num_points={:#?}" , num_points) ;
43
53
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
+
44
61
Self {
45
62
statements_before_block,
63
+ basic_block_heads,
46
64
num_points,
47
65
}
48
66
}
@@ -70,47 +88,55 @@ impl RegionValueElements {
70
88
71
89
/// Converts a `PointIndex` back to a location. O(N) where N is
72
90
/// 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 ;
104
102
}
105
- }
106
103
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
+ }
114
140
}
115
141
}
116
142
@@ -196,6 +222,7 @@ impl<N: Idx> LivenessValues<N> {
196
222
. row ( r)
197
223
. into_iter ( )
198
224
. flat_map ( |set| set. iter ( ) )
225
+ . take_while ( |& p| self . elements . point_in_range ( p) )
199
226
. map ( |p| self . elements . to_location ( p) )
200
227
. map ( RegionElement :: Location ) ,
201
228
)
@@ -304,7 +331,11 @@ impl<N: Idx> RegionValues<N> {
304
331
self . points
305
332
. row ( r)
306
333
. 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
+ } )
308
339
}
309
340
310
341
/// Returns just the universal regions that are contained in a given region's value.
@@ -400,6 +431,7 @@ crate fn location_set_str(
400
431
region_value_str (
401
432
points
402
433
. into_iter ( )
434
+ . take_while ( |& p| elements. point_in_range ( p) )
403
435
. map ( |p| elements. to_location ( p) )
404
436
. map ( RegionElement :: Location ) ,
405
437
)
0 commit comments