Clear blocks that are unreachable (not entry, not a jump target, and only reachable via fall-through from a terminal block).
(&mut self)
| 604 | /// Clear blocks that are unreachable (not entry, not a jump target, |
| 605 | /// and only reachable via fall-through from a terminal block). |
| 606 | fn eliminate_unreachable_blocks(&mut self) { |
| 607 | let mut reachable = vec![false; self.blocks.len()]; |
| 608 | reachable[0] = true; |
| 609 | |
| 610 | // Fixpoint: only mark targets of already-reachable blocks |
| 611 | let mut changed = true; |
| 612 | while changed { |
| 613 | changed = false; |
| 614 | for i in 0..self.blocks.len() { |
| 615 | if !reachable[i] { |
| 616 | continue; |
| 617 | } |
| 618 | // Mark jump targets and exception handlers |
| 619 | for ins in &self.blocks[i].instructions { |
| 620 | if ins.target != BlockIdx::NULL && !reachable[ins.target.idx()] { |
| 621 | reachable[ins.target.idx()] = true; |
| 622 | changed = true; |
| 623 | } |
| 624 | if let Some(eh) = &ins.except_handler |
| 625 | && !reachable[eh.handler_block.idx()] |
| 626 | { |
| 627 | reachable[eh.handler_block.idx()] = true; |
| 628 | changed = true; |
| 629 | } |
| 630 | } |
| 631 | // Mark fall-through |
| 632 | let next = self.blocks[i].next; |
| 633 | if next != BlockIdx::NULL |
| 634 | && !reachable[next.idx()] |
| 635 | && !self.blocks[i].instructions.last().is_some_and(|ins| { |
| 636 | ins.instr.is_scope_exit() || ins.instr.is_unconditional_jump() |
| 637 | }) |
| 638 | { |
| 639 | reachable[next.idx()] = true; |
| 640 | changed = true; |
| 641 | } |
| 642 | } |
| 643 | } |
| 644 | |
| 645 | for (i, block) in self.blocks.iter_mut().enumerate() { |
| 646 | if !reachable[i] { |
| 647 | block.instructions.clear(); |
| 648 | } |
| 649 | } |
| 650 | } |
| 651 | |
| 652 | /// Fold LOAD_CONST/LOAD_SMALL_INT + UNARY_NEGATIVE → LOAD_CONST (negative value) |
| 653 | fn fold_unary_negative(&mut self) { |
no test coverage detected