@@ -102,6 +102,7 @@ use smallvec::SmallVec;
102
102
use std:: borrow:: Cow ;
103
103
104
104
use crate :: dataflow_const_prop:: DummyMachine ;
105
+ use crate :: simplify:: UsedLocals ;
105
106
use crate :: ssa:: { AssignedValue , SsaLocals } ;
106
107
use either:: Either ;
107
108
@@ -163,14 +164,16 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
163
164
state. next_opaque = None ;
164
165
165
166
let reverse_postorder = body. basic_blocks . reverse_postorder ( ) . to_vec ( ) ;
166
- for dbg in body. var_debug_info . iter_mut ( ) {
167
- state. visit_var_debug_info ( dbg) ;
168
- }
169
167
for bb in reverse_postorder {
170
168
let data = & mut body. basic_blocks . as_mut_preserves_cfg ( ) [ bb] ;
171
169
state. visit_basic_block_data ( bb, data) ;
172
170
}
173
171
172
+ let mut used_locals = UsedLocals :: new ( body, false ) ;
173
+ for dbg in body. var_debug_info . iter_mut ( ) {
174
+ state. reduce_debuginfo ( dbg, & mut used_locals) ;
175
+ }
176
+
174
177
// For each local that is reused (`y` above), we remove its storage statements do avoid any
175
178
// difficulty. Those locals are SSA, so should be easy to optimize by LLVM without storage
176
179
// statements.
@@ -1256,45 +1259,93 @@ impl<'tcx> VnState<'_, 'tcx> {
1256
1259
. find ( |& & other| self . ssa . assignment_dominates ( self . dominators , other, loc) )
1257
1260
. copied ( )
1258
1261
}
1259
- }
1260
-
1261
- impl < ' tcx > MutVisitor < ' tcx > for VnState < ' _ , ' tcx > {
1262
- fn tcx ( & self ) -> TyCtxt < ' tcx > {
1263
- self . tcx
1264
- }
1265
-
1266
- fn visit_var_debug_info ( & mut self , var_debug_info : & mut VarDebugInfo < ' tcx > ) {
1267
- let mut replace_dereffed = |place : & mut Place < ' tcx > | -> Option < !> {
1268
- let last_deref = place. projection . iter ( ) . rposition ( |e| e == PlaceElem :: Deref ) ?;
1269
1262
1270
- // Another place that holds the same value.
1263
+ fn reduce_debuginfo (
1264
+ & mut self ,
1265
+ var_debug_info : & mut VarDebugInfo < ' tcx > ,
1266
+ used_locals : & mut UsedLocals ,
1267
+ ) {
1268
+ let mut simplify_place = |place : & mut Place < ' tcx > | -> Option < ConstOperand < ' tcx > > {
1269
+ // Another place that points to the same memory.
1271
1270
let mut place_ref = place. as_ref ( ) ;
1272
1271
let mut value = self . locals [ place. local ] ?;
1273
1272
1274
- for ( index, & proj) in place. projection [ ..last_deref] . iter ( ) . enumerate ( ) {
1275
- if let Some ( candidates) = self . rev_locals . get ( value)
1276
- && let Some ( & local) = candidates. first ( )
1273
+ // The position of the last deref projection. If there is one, the place preceding it
1274
+ // can be treated and simplified as a value. Afterwards, projections need to be treated
1275
+ // as a memory place.
1276
+ let last_deref = place. projection . iter ( ) . rposition ( |e| e == PlaceElem :: Deref ) ;
1277
+
1278
+ for ( index, proj) in place. projection . iter ( ) . enumerate ( ) {
1279
+ // We are before the last projection, so we can treat as a value.
1280
+ if last_deref. map_or ( false , |ld| index <= ld)
1281
+ && let Some ( candidates) = self . rev_locals . get ( value)
1282
+ // Do not introduce an unused local.
1283
+ && let Some ( & local) = candidates. iter ( ) . find ( |& & l| used_locals. is_used ( l) )
1277
1284
{
1278
1285
place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
1279
1286
}
1280
1287
1288
+ // We are at the last projection, treat as a value if possible.
1289
+ if Some ( index) == last_deref {
1290
+ * place = place_ref. project_deeper ( & [ ] , self . tcx ) ;
1291
+
1292
+ // If the base local is used, do not bother trying to simplify anything.
1293
+ if used_locals. is_used ( place_ref. local ) {
1294
+ return None ;
1295
+ }
1296
+ }
1297
+
1281
1298
let place_upto =
1282
1299
PlaceRef { local : place. local , projection : & place. projection [ ..index] } ;
1283
1300
if let Some ( projected) = self . project ( place_upto, value, proj) {
1284
1301
value = projected;
1285
1302
} else {
1286
- if place_ref. projection . len ( ) < place. projection . len ( ) {
1303
+ if last_deref. map_or ( false , |ld| index <= ld)
1304
+ && place_ref. projection . len ( ) < place. projection . len ( )
1305
+ {
1287
1306
* place = place_ref. project_deeper ( & [ ] , self . tcx ) ;
1288
1307
}
1289
1308
return None ;
1290
1309
}
1291
1310
}
1292
1311
1293
- if let Some ( candidates) = self . rev_locals . get ( value)
1294
- && let Some ( & local) = candidates. first ( )
1295
- {
1296
- let place_ref = PlaceRef { local, projection : & place. projection [ last_deref..] } ;
1297
- * place = place_ref. project_deeper ( & [ ] , self . tcx ) ;
1312
+ if let Some ( constant) = self . try_as_constant ( value) {
1313
+ return Some ( constant) ;
1314
+ }
1315
+
1316
+ let mut projections = vec ! [ ] ;
1317
+ loop {
1318
+ if let Some ( candidates) = self . rev_locals . get ( value)
1319
+ // Do not reintroduce an unused local.
1320
+ && let Some ( & local) = candidates. iter ( ) . find ( |& & l| used_locals. is_used ( l) )
1321
+ {
1322
+ projections. reverse ( ) ;
1323
+ * place = Place {
1324
+ local,
1325
+ projection : self . tcx . mk_place_elems_from_iter ( projections. into_iter ( ) ) ,
1326
+ } ;
1327
+ return None ;
1328
+ }
1329
+
1330
+ let Value :: Projection ( base, elem) = * self . get ( value) else {
1331
+ break ;
1332
+ } ;
1333
+
1334
+ let elem = match elem {
1335
+ ProjectionElem :: Deref => ProjectionElem :: Deref ,
1336
+ ProjectionElem :: Downcast ( name, read_variant) => {
1337
+ ProjectionElem :: Downcast ( name, read_variant)
1338
+ }
1339
+ ProjectionElem :: Field ( f, ty) => ProjectionElem :: Field ( f, ty) ,
1340
+ ProjectionElem :: ConstantIndex { offset, min_length, from_end : false } => {
1341
+ ProjectionElem :: ConstantIndex { offset, min_length, from_end : false }
1342
+ }
1343
+ // Not allowed in debuginfo.
1344
+ _ => return None ,
1345
+ } ;
1346
+
1347
+ projections. push ( elem) ;
1348
+ value = base;
1298
1349
}
1299
1350
1300
1351
return None ;
@@ -1303,10 +1354,20 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
1303
1354
match & mut var_debug_info. value {
1304
1355
VarDebugInfoContents :: Const ( _) => { }
1305
1356
VarDebugInfoContents :: Place ( place) => {
1306
- replace_dereffed ( place) ;
1357
+ if let Some ( constant) = simplify_place ( place) {
1358
+ var_debug_info. value = VarDebugInfoContents :: Const ( constant) ;
1359
+ } else {
1360
+ used_locals. use_count [ place. local ] += 1 ;
1361
+ }
1307
1362
}
1308
1363
}
1309
1364
}
1365
+ }
1366
+
1367
+ impl < ' tcx > MutVisitor < ' tcx > for VnState < ' _ , ' tcx > {
1368
+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
1369
+ self . tcx
1370
+ }
1310
1371
1311
1372
fn visit_place ( & mut self , place : & mut Place < ' tcx > , _: PlaceContext , location : Location ) {
1312
1373
self . simplify_place_projection ( place, location) ;
0 commit comments