Duplicate `LOAD_CONST None + RETURN_VALUE` for blocks that fall through to the final return block.
(blocks: &mut [Block])
| 2843 | /// Duplicate `LOAD_CONST None + RETURN_VALUE` for blocks that fall through |
| 2844 | /// to the final return block. |
| 2845 | fn duplicate_end_returns(blocks: &mut [Block]) { |
| 2846 | // Walk the block chain and keep the last non-empty block. |
| 2847 | let mut last_block = BlockIdx::NULL; |
| 2848 | let mut current = BlockIdx(0); |
| 2849 | while current != BlockIdx::NULL { |
| 2850 | if !blocks[current.idx()].instructions.is_empty() { |
| 2851 | last_block = current; |
| 2852 | } |
| 2853 | current = blocks[current.idx()].next; |
| 2854 | } |
| 2855 | if last_block == BlockIdx::NULL { |
| 2856 | return; |
| 2857 | } |
| 2858 | |
| 2859 | let last_insts = &blocks[last_block.idx()].instructions; |
| 2860 | // Only apply when the last block is EXACTLY a return-None epilogue |
| 2861 | let is_return_block = last_insts.len() == 2 |
| 2862 | && matches!( |
| 2863 | last_insts[0].instr, |
| 2864 | AnyInstruction::Real(Instruction::LoadConst { .. }) |
| 2865 | ) |
| 2866 | && matches!( |
| 2867 | last_insts[1].instr, |
| 2868 | AnyInstruction::Real(Instruction::ReturnValue) |
| 2869 | ); |
| 2870 | if !is_return_block { |
| 2871 | return; |
| 2872 | } |
| 2873 | |
| 2874 | // Get the return instructions to clone |
| 2875 | let return_insts: Vec<InstructionInfo> = last_insts[last_insts.len() - 2..].to_vec(); |
| 2876 | |
| 2877 | // Find non-cold blocks that fall through to the last block |
| 2878 | let mut blocks_to_fix = Vec::new(); |
| 2879 | current = BlockIdx(0); |
| 2880 | while current != BlockIdx::NULL { |
| 2881 | let block = &blocks[current.idx()]; |
| 2882 | let next = next_nonempty_block(blocks, block.next); |
| 2883 | if current != last_block && next == last_block && !block.cold && !block.except_handler { |
| 2884 | let last_ins = block.instructions.last(); |
| 2885 | let has_fallthrough = last_ins |
| 2886 | .map(|ins| !ins.instr.is_scope_exit() && !ins.instr.is_unconditional_jump()) |
| 2887 | .unwrap_or(true); |
| 2888 | // Don't duplicate if block already ends with the same return pattern |
| 2889 | let already_has_return = block.instructions.len() >= 2 && { |
| 2890 | let n = block.instructions.len(); |
| 2891 | matches!( |
| 2892 | block.instructions[n - 2].instr, |
| 2893 | AnyInstruction::Real(Instruction::LoadConst { .. }) |
| 2894 | ) && matches!( |
| 2895 | block.instructions[n - 1].instr, |
| 2896 | AnyInstruction::Real(Instruction::ReturnValue) |
| 2897 | ) |
| 2898 | }; |
| 2899 | if has_fallthrough && !already_has_return { |
| 2900 | blocks_to_fix.push(current); |
| 2901 | } |
| 2902 | } |
no test coverage detected