@@ -3,8 +3,9 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC
3
3
use rustc_middle:: mir:: {
4
4
self , CallReturnPlaces , Local , Location , Place , StatementKind , TerminatorEdges ,
5
5
} ;
6
+ use rustc_middle:: ty:: TyCtxt ;
6
7
7
- use crate :: { Analysis , Backward , GenKill } ;
8
+ use crate :: { Analysis , Backward , GenKill , ResultsCursor } ;
8
9
9
10
/// A [live-variable dataflow analysis][liveness].
10
11
///
@@ -203,21 +204,42 @@ impl DefUse {
203
204
/// This is basically written for dead store elimination and nothing else.
204
205
///
205
206
/// All of the caveats of `MaybeLiveLocals` apply.
206
- pub struct MaybeTransitiveLiveLocals < ' a > {
207
+ pub struct MaybeTransitiveLiveLocals < ' tcx , ' mir , ' a > {
207
208
always_live : & ' a DenseBitSet < Local > ,
209
+ live : Option < ResultsCursor < ' mir , ' tcx , MaybeLiveLocals > > ,
208
210
}
209
211
210
- impl < ' a > MaybeTransitiveLiveLocals < ' a > {
212
+ impl < ' tcx , ' mir , ' a > MaybeTransitiveLiveLocals < ' tcx , ' mir , ' a > {
211
213
/// The `always_alive` set is the set of locals to which all stores should unconditionally be
212
214
/// considered live.
215
+ /// The `may_live_in_other_bbs` indicates that, when analyzing the current statement,
216
+ /// statements in other basic blocks are assumed to be live.
213
217
///
214
218
/// This should include at least all locals that are ever borrowed.
215
- pub fn new ( always_live : & ' a DenseBitSet < Local > ) -> Self {
216
- MaybeTransitiveLiveLocals { always_live }
219
+ pub fn new (
220
+ always_live : & ' a DenseBitSet < Local > ,
221
+ may_live_in_other_bbs : bool ,
222
+ tcx : TyCtxt < ' tcx > ,
223
+ body : & ' mir mir:: Body < ' tcx > ,
224
+ ) -> Self {
225
+ let live = if may_live_in_other_bbs {
226
+ Some ( MaybeLiveLocals . iterate_to_fixpoint ( tcx, body, None ) . into_results_cursor ( body) )
227
+ } else {
228
+ None
229
+ } ;
230
+ MaybeTransitiveLiveLocals { always_live, live }
231
+ }
232
+
233
+ fn live_on ( & mut self , place : Place < ' _ > , location : Location ) -> bool {
234
+ let Some ( live) = & mut self . live else {
235
+ return false ;
236
+ } ;
237
+ live. seek_before_primary_effect ( location) ;
238
+ live. get ( ) . contains ( place. local )
217
239
}
218
240
}
219
241
220
- impl < ' a , ' tcx > Analysis < ' tcx > for MaybeTransitiveLiveLocals < ' a > {
242
+ impl < ' a , ' tcx > Analysis < ' tcx > for MaybeTransitiveLiveLocals < ' tcx , ' _ , ' a > {
221
243
type Domain = DenseBitSet < Local > ;
222
244
type Direction = Backward ;
223
245
@@ -256,14 +278,14 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
256
278
| StatementKind :: BackwardIncompatibleDropHint { .. }
257
279
| StatementKind :: Nop => None ,
258
280
} ;
259
- if let Some ( destination) = destination {
260
- if !destination. is_indirect ( )
261
- && !state. contains ( destination. local )
262
- && !self . always_live . contains ( destination. local )
263
- {
264
- // This store is dead
265
- return ;
266
- }
281
+ if let Some ( destination) = destination
282
+ && !destination. is_indirect ( )
283
+ && !state. contains ( destination. local )
284
+ && !self . always_live . contains ( destination. local )
285
+ && ! self . live_on ( destination , location )
286
+ {
287
+ // This store is dead
288
+ return ;
267
289
}
268
290
TransferFunction ( state) . visit_statement ( statement, location) ;
269
291
}
0 commit comments