@@ -3,7 +3,7 @@ use rustc_index::interval::SparseIntervalMatrix;
3
3
use rustc_index:: { Idx , 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 {
@@ -105,27 +105,47 @@ where
105
105
N : Idx ,
106
106
A : Analysis < ' tcx , Domain = DenseBitSet < N > > ,
107
107
{
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
108
+ let mut values = SparseIntervalMatrix :: new ( elements. num_points ( ) ) ;
109
+ let reachable_blocks = mir:: traversal:: reachable_as_bitset ( body) ;
110
+ if A :: Direction :: IS_BACKWARD {
111
+ // Iterate blocks in decreasing order, to visit locations in decreasing order. This
112
+ // allows to use the more efficient `prepend` method to interval sets.
113
+ let callback = |state : & DenseBitSet < N > , location| {
114
+ let point = elements. point_from_location ( location) ;
115
+ // Use internal iterator manually as it is much more efficient.
116
+ state. iter ( ) . for_each ( |node| values. prepend ( node, point) ) ;
117
+ } ;
118
+ let mut visitor = Visitor { callback } ;
119
+ visit_results (
120
+ body,
121
+ // Note the `.rev()`.
122
+ body. basic_blocks . indices ( ) . filter ( |& bb| reachable_blocks. contains ( bb) ) . rev ( ) ,
123
+ & mut analysis,
124
+ & results,
125
+ & mut visitor,
126
+ ) ;
127
+ } else {
128
+ // Iterate blocks in increasing order, to visit locations in increasing order. This
129
+ // allows to use the more efficient `append` method to interval sets.
130
+ let callback = |state : & DenseBitSet < N > , location| {
131
+ let point = elements. point_from_location ( location) ;
132
+ // Use internal iterator manually as it is much more efficient.
133
+ state. iter ( ) . for_each ( |node| values. append ( node, point) ) ;
134
+ } ;
135
+ let mut visitor = Visitor { callback } ;
136
+ visit_results ( body, reachable_blocks. iter ( ) , & mut analysis, & results, & mut visitor) ;
137
+ }
138
+ values
118
139
}
119
140
120
- struct Visitor < ' a , N : Idx > {
121
- elements : & ' a DenseLocationMap ,
122
- values : SparseIntervalMatrix < N , PointIndex > ,
141
+ struct Visitor < F > {
142
+ callback : F ,
123
143
}
124
144
125
- impl < ' tcx , A , N > ResultsVisitor < ' tcx , A > for Visitor < ' _ , N >
145
+ impl < ' tcx , A , F > ResultsVisitor < ' tcx , A > for Visitor < F >
126
146
where
127
- A : Analysis < ' tcx , Domain = DenseBitSet < N > > ,
128
- N : Idx ,
147
+ A : Analysis < ' tcx > ,
148
+ F : FnMut ( & A :: Domain , Location ) ,
129
149
{
130
150
fn visit_after_primary_statement_effect < ' mir > (
131
151
& mut self ,
@@ -134,11 +154,7 @@ where
134
154
_statement : & ' mir mir:: Statement < ' tcx > ,
135
155
location : Location ,
136
156
) {
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
- } ) ;
157
+ ( self . callback ) ( state, location) ;
142
158
}
143
159
144
160
fn visit_after_primary_terminator_effect < ' mir > (
@@ -148,10 +164,6 @@ where
148
164
_terminator : & ' mir mir:: Terminator < ' tcx > ,
149
165
location : Location ,
150
166
) {
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
- } ) ;
167
+ ( self . callback ) ( state, location) ;
156
168
}
157
169
}
0 commit comments