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

`+

}

`