| 8 | use alloc::{vec, vec::Vec}; |
| 9 | |
| 10 | pub fn constant_fold(chunk: &mut SSAChunk) { |
| 11 | let n = chunk.instructions.len(); |
| 12 | if n == 0 { |
| 13 | for (_, body, _, _) in chunk.functions.iter_mut() { constant_fold(body); } |
| 14 | for class_body in chunk.classes.iter_mut() { constant_fold(class_body); } |
| 15 | return; |
| 16 | } |
| 17 | |
| 18 | let mut dead = vec![false; n]; |
| 19 | |
| 20 | for ip in 0..n { |
| 21 | if dead[ip] { continue; } |
| 22 | let opcode = chunk.instructions[ip].opcode; |
| 23 | |
| 24 | match opcode { |
| 25 | OpCode::Add | OpCode::Sub | OpCode::Mul | OpCode::Div |
| 26 | | OpCode::Mod | OpCode::FloorDiv |
| 27 | | OpCode::Eq | OpCode::NotEq |
| 28 | | OpCode::Lt | OpCode::Gt | OpCode::LtEq | OpCode::GtEq |
| 29 | | OpCode::BitAnd | OpCode::BitOr | OpCode::BitXor |
| 30 | | OpCode::Shl | OpCode::Shr => { |
| 31 | try_fold_binop(chunk, &mut dead, ip); |
| 32 | } |
| 33 | OpCode::Not => try_fold_not(chunk, &mut dead, ip), |
| 34 | OpCode::Minus => try_fold_neg(chunk, &mut dead, ip), |
| 35 | _ => {} |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | // Pass 2: Phi-noop elimination; capture source pairs before marking dead. |
| 40 | let mut surviving_pairs: Vec<(u16, u16)> = Vec::new(); |
| 41 | if !chunk.phi_map.is_empty() && !chunk.phi_sources.is_empty() { |
| 42 | for (ip, ins) in chunk.instructions.iter().enumerate() { |
| 43 | if dead[ip] || ins.opcode != OpCode::Phi { continue; } |
| 44 | let phi_idx = chunk.phi_map[ip]; |
| 45 | let Some(&(a, b)) = chunk.phi_sources.get(phi_idx) else { continue }; |
| 46 | // Sources + dest collapsed to one slot, `slots[X] = slots[X]` is a no-op. |
| 47 | if a == b && a == ins.operand { |
| 48 | dead[ip] = true; |
| 49 | } else { |
| 50 | surviving_pairs.push((a, b)); |
| 51 | } |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | if dead.iter().any(|&d| d) { |
| 56 | compact_with_jump_remap(chunk, &dead); |
| 57 | // Rebuild phi_map; surviving Phis keep their relative order, so pair them sequentially. |
| 58 | if !surviving_pairs.is_empty() { |
| 59 | chunk.phi_sources = surviving_pairs; |
| 60 | chunk.phi_map = vec![0; chunk.instructions.len()]; |
| 61 | let mut idx = 0usize; |
| 62 | for (i, ins) in chunk.instructions.iter().enumerate() { |
| 63 | if ins.opcode == OpCode::Phi { |
| 64 | chunk.phi_map[i] = idx; |
| 65 | idx += 1; |
| 66 | } |
| 67 | } |