1
1
use rustc_index:: bit_set:: DenseBitSet ;
2
2
use rustc_index:: interval:: SparseIntervalMatrix ;
3
- use rustc_index:: { Idx , IndexVec } ;
3
+ use rustc_index:: { Idx , IndexSlice , IndexVec } ;
4
4
use rustc_middle:: mir:: { self , BasicBlock , Body , Location } ;
5
5
6
- use crate :: framework:: { Analysis , Results , ResultsVisitor , visit_results} ;
6
+ use crate :: framework:: { Analysis , Direction , Results , ResultsVisitor , visit_results} ;
7
7
8
8
/// Maps between a `Location` and a `PointIndex` (and vice versa).
9
9
pub struct DenseLocationMap {
@@ -95,37 +95,65 @@ rustc_index::newtype_index! {
95
95
}
96
96
97
97
/// Add points depending on the result of the given dataflow analysis.
98
- pub fn save_as_intervals < ' tcx , N , A > (
98
+ pub fn save_as_intervals < ' tcx , N , M , A > (
99
99
elements : & DenseLocationMap ,
100
100
body : & mir:: Body < ' tcx > ,
101
+ relevant : & IndexSlice < N , M > ,
101
102
mut analysis : A ,
102
103
results : Results < A :: Domain > ,
103
104
) -> SparseIntervalMatrix < N , PointIndex >
104
105
where
105
106
N : Idx ,
106
- A : Analysis < ' tcx , Domain = DenseBitSet < N > > ,
107
+ M : Idx ,
108
+ A : Analysis < ' tcx , Domain = DenseBitSet < M > > ,
107
109
{
108
- let values = SparseIntervalMatrix :: new ( elements. num_points ( ) ) ;
109
- let mut visitor = Visitor { elements, values } ;
110
- visit_results (
111
- body,
112
- body. basic_blocks . reverse_postorder ( ) . iter ( ) . copied ( ) ,
113
- & mut analysis,
114
- & results,
115
- & mut visitor,
116
- ) ;
117
- visitor. values
110
+ let mut values = SparseIntervalMatrix :: new ( elements. num_points ( ) ) ;
111
+ let reachable_blocks = mir:: traversal:: reachable_as_bitset ( body) ;
112
+ if A :: Direction :: IS_BACKWARD {
113
+ // Iterate blocks in decreasing order, to visit locations in decreasing order. This
114
+ // allows to use the more efficient `prepend` method to interval sets.
115
+ let callback = |state : & DenseBitSet < M > , location| {
116
+ let point = elements. point_from_location ( location) ;
117
+ for ( relevant, & original) in relevant. iter_enumerated ( ) {
118
+ if state. contains ( original) {
119
+ values. prepend ( relevant, point) ;
120
+ }
121
+ }
122
+ } ;
123
+ let mut visitor = Visitor { callback } ;
124
+ visit_results (
125
+ body,
126
+ // Note the `.rev()`.
127
+ body. basic_blocks . indices ( ) . filter ( |& bb| reachable_blocks. contains ( bb) ) . rev ( ) ,
128
+ & mut analysis,
129
+ & results,
130
+ & mut visitor,
131
+ ) ;
132
+ } else {
133
+ // Iterate blocks in increasing order, to visit locations in increasing order. This
134
+ // allows to use the more efficient `append` method to interval sets.
135
+ let callback = |state : & DenseBitSet < M > , location| {
136
+ let point = elements. point_from_location ( location) ;
137
+ for ( relevant, & original) in relevant. iter_enumerated ( ) {
138
+ if state. contains ( original) {
139
+ values. append ( relevant, point) ;
140
+ }
141
+ }
142
+ } ;
143
+ let mut visitor = Visitor { callback } ;
144
+ visit_results ( body, reachable_blocks. iter ( ) , & mut analysis, & results, & mut visitor) ;
145
+ }
146
+ values
118
147
}
119
148
120
- struct Visitor < ' a , N : Idx > {
121
- elements : & ' a DenseLocationMap ,
122
- values : SparseIntervalMatrix < N , PointIndex > ,
149
+ struct Visitor < F > {
150
+ callback : F ,
123
151
}
124
152
125
- impl < ' tcx , A , N > ResultsVisitor < ' tcx , A > for Visitor < ' _ , N >
153
+ impl < ' tcx , A , F > ResultsVisitor < ' tcx , A > for Visitor < F >
126
154
where
127
- A : Analysis < ' tcx , Domain = DenseBitSet < N > > ,
128
- N : Idx ,
155
+ A : Analysis < ' tcx > ,
156
+ F : FnMut ( & A :: Domain , Location ) ,
129
157
{
130
158
fn visit_after_primary_statement_effect < ' mir > (
131
159
& mut self ,
@@ -134,11 +162,7 @@ where
134
162
_statement : & ' mir mir:: Statement < ' tcx > ,
135
163
location : Location ,
136
164
) {
137
- let point = self . elements . point_from_location ( location) ;
138
- // Use internal iterator manually as it is much more efficient.
139
- state. iter ( ) . for_each ( |node| {
140
- self . values . insert ( node, point) ;
141
- } ) ;
165
+ ( self . callback ) ( state, location) ;
142
166
}
143
167
144
168
fn visit_after_primary_terminator_effect < ' mir > (
@@ -148,10 +172,6 @@ where
148
172
_terminator : & ' mir mir:: Terminator < ' tcx > ,
149
173
location : Location ,
150
174
) {
151
- let point = self . elements . point_from_location ( location) ;
152
- // Use internal iterator manually as it is much more efficient.
153
- state. iter ( ) . for_each ( |node| {
154
- self . values . insert ( node, point) ;
155
- } ) ;
175
+ ( self . callback ) ( state, location) ;
156
176
}
157
177
}
0 commit comments