Auto merge of #123272 - saethlin:reachable-mono-cleanup, r=cjgillot · rust-lang/rust@bb78dba (original) (raw)
`@@ -245,7 +245,7 @@ pub fn reachable<'a, 'tcx>(
`
245
245
`` /// Returns a BitSet
containing all basic blocks reachable from the START_BLOCK
.
``
246
246
`pub fn reachable_as_bitset(body: &Body<'_>) -> BitSet {
`
247
247
`let mut iter = preorder(body);
`
248
``
`-
iter.by_ref().for_each(drop);
`
``
248
`+
while let Some(_) = iter.next() {}
`
249
249
` iter.visited
`
250
250
`}
`
251
251
``
`@@ -279,3 +279,97 @@ pub fn reverse_postorder<'a, 'tcx>(
`
279
279
`{
`
280
280
` body.basic_blocks.reverse_postorder().iter().map(|&bb| (bb, &body.basic_blocks[bb]))
`
281
281
`}
`
``
282
+
``
283
`` +
/// Traversal of a [Body
] that tries to avoid unreachable blocks in a monomorphized [Instance
].
``
``
284
`+
///
`
``
285
`+
/// This is allowed to have false positives; blocks may be visited even if they are not actually
`
``
286
`+
/// reachable.
`
``
287
`+
///
`
``
288
`` +
/// Such a traversal is mostly useful because it lets us skip lowering the false
side
``
``
289
`` +
/// of if <T as Trait>::CONST
, as well as [NullOp::UbChecks
].
``
``
290
`+
///
`
``
291
`` +
/// [NullOp::UbChecks
]: rustc_middle::mir::NullOp::UbChecks
``
``
292
`+
pub fn mono_reachable<'a, 'tcx>(
`
``
293
`+
body: &'a Body<'tcx>,
`
``
294
`+
tcx: TyCtxt<'tcx>,
`
``
295
`+
instance: Instance<'tcx>,
`
``
296
`+
) -> MonoReachable<'a, 'tcx> {
`
``
297
`+
MonoReachable::new(body, tcx, instance)
`
``
298
`+
}
`
``
299
+
``
300
`` +
/// [MonoReachable
] internally accumulates a [BitSet
] of visited blocks. This is just a
``
``
301
`+
/// convenience function to run that traversal then extract its set of reached blocks.
`
``
302
`+
pub fn mono_reachable_as_bitset<'a, 'tcx>(
`
``
303
`+
body: &'a Body<'tcx>,
`
``
304
`+
tcx: TyCtxt<'tcx>,
`
``
305
`+
instance: Instance<'tcx>,
`
``
306
`+
) -> BitSet {
`
``
307
`+
let mut iter = mono_reachable(body, tcx, instance);
`
``
308
`+
while let Some(_) = iter.next() {}
`
``
309
`+
iter.visited
`
``
310
`+
}
`
``
311
+
``
312
`+
pub struct MonoReachable<'a, 'tcx> {
`
``
313
`+
body: &'a Body<'tcx>,
`
``
314
`+
tcx: TyCtxt<'tcx>,
`
``
315
`+
instance: Instance<'tcx>,
`
``
316
`+
visited: BitSet,
`
``
317
`+
// Other traversers track their worklist in a Vec. But we don't care about order, so we can
`
``
318
`+
// store ours in a BitSet and thus save allocations because BitSet has a small size
`
``
319
`+
// optimization.
`
``
320
`+
worklist: BitSet,
`
``
321
`+
}
`
``
322
+
``
323
`+
impl<'a, 'tcx> MonoReachable<'a, 'tcx> {
`
``
324
`+
pub fn new(
`
``
325
`+
body: &'a Body<'tcx>,
`
``
326
`+
tcx: TyCtxt<'tcx>,
`
``
327
`+
instance: Instance<'tcx>,
`
``
328
`+
) -> MonoReachable<'a, 'tcx> {
`
``
329
`+
let mut worklist = BitSet::new_empty(body.basic_blocks.len());
`
``
330
`+
worklist.insert(START_BLOCK);
`
``
331
`+
MonoReachable {
`
``
332
`+
body,
`
``
333
`+
tcx,
`
``
334
`+
instance,
`
``
335
`+
visited: BitSet::new_empty(body.basic_blocks.len()),
`
``
336
`+
worklist,
`
``
337
`+
}
`
``
338
`+
}
`
``
339
+
``
340
`+
fn add_work(&mut self, blocks: impl IntoIterator<Item = BasicBlock>) {
`
``
341
`+
for block in blocks.into_iter() {
`
``
342
`+
if !self.visited.contains(block) {
`
``
343
`+
self.worklist.insert(block);
`
``
344
`+
}
`
``
345
`+
}
`
``
346
`+
}
`
``
347
`+
}
`
``
348
+
``
349
`+
impl<'a, 'tcx> Iterator for MonoReachable<'a, 'tcx> {
`
``
350
`+
type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
`
``
351
+
``
352
`+
fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
`
``
353
`+
while let Some(idx) = self.worklist.iter().next() {
`
``
354
`+
self.worklist.remove(idx);
`
``
355
`+
if !self.visited.insert(idx) {
`
``
356
`+
continue;
`
``
357
`+
}
`
``
358
+
``
359
`+
let data = &self.body[idx];
`
``
360
+
``
361
`+
if let Some((bits, targets)) =
`
``
362
`+
Body::try_const_mono_switchint(self.tcx, self.instance, data)
`
``
363
`+
{
`
``
364
`+
let target = targets.target_for_value(bits);
`
``
365
`+
self.add_work([target]);
`
``
366
`+
} else {
`
``
367
`+
self.add_work(data.terminator().successors());
`
``
368
`+
}
`
``
369
+
``
370
`+
return Some((idx, data));
`
``
371
`+
}
`
``
372
+
``
373
`+
None
`
``
374
`+
}
`
``
375
`+
}
`