| 1608 | } |
| 1609 | |
| 1610 | fn optimize_load_fast_borrow(&mut self) { |
| 1611 | // NOT_LOCAL marker: instruction didn't come from a LOAD_FAST |
| 1612 | const NOT_LOCAL: usize = usize::MAX; |
| 1613 | |
| 1614 | for block in &mut self.blocks { |
| 1615 | if block.instructions.is_empty() { |
| 1616 | continue; |
| 1617 | } |
| 1618 | |
| 1619 | // Track which instructions' outputs are still on stack at block end |
| 1620 | // For each instruction, we track if its pushed value(s) are unconsumed |
| 1621 | let mut unconsumed = vec![false; block.instructions.len()]; |
| 1622 | |
| 1623 | // Simulate stack: each entry is the instruction index that pushed it |
| 1624 | // (or NOT_LOCAL if not from LOAD_FAST/LOAD_FAST_LOAD_FAST). |
| 1625 | // |
| 1626 | // CPython (flowgraph.c optimize_load_fast) pre-fills the stack with |
| 1627 | // dummy refs for values inherited from predecessor blocks. We take |
| 1628 | // the simpler approach of aborting the optimisation for the whole |
| 1629 | // block on stack underflow. |
| 1630 | let mut stack: Vec<usize> = Vec::new(); |
| 1631 | let mut underflow = false; |
| 1632 | |
| 1633 | for (i, info) in block.instructions.iter().enumerate() { |
| 1634 | let Some(instr) = info.instr.real() else { |
| 1635 | continue; |
| 1636 | }; |
| 1637 | |
| 1638 | let stack_effect_info = instr.stack_effect_info(info.arg.into()); |
| 1639 | let (pushes, pops) = (stack_effect_info.pushed(), stack_effect_info.popped()); |
| 1640 | |
| 1641 | // Pop values from stack |
| 1642 | for _ in 0..pops { |
| 1643 | if stack.pop().is_none() { |
| 1644 | // Stack underflow — block receives values from a predecessor. |
| 1645 | // Abort optimisation for the entire block. |
| 1646 | underflow = true; |
| 1647 | break; |
| 1648 | } |
| 1649 | } |
| 1650 | if underflow { |
| 1651 | break; |
| 1652 | } |
| 1653 | |
| 1654 | // Push values to stack with source instruction index |
| 1655 | let source = match instr { |
| 1656 | Instruction::LoadFast { .. } | Instruction::LoadFastLoadFast { .. } => i, |
| 1657 | _ => NOT_LOCAL, |
| 1658 | }; |
| 1659 | for _ in 0..pushes { |
| 1660 | stack.push(source); |
| 1661 | } |
| 1662 | } |
| 1663 | |
| 1664 | if underflow { |
| 1665 | continue; |
| 1666 | } |
| 1667 | |