refactor(dce): 拆分单文件为三 Pass 独立模块(可达性/迭代删除/重建)

This commit is contained in:
爱特每羊队
2026-08-06 14:01:31 +08:00
parent 50216d7d00
commit 0e7c3208d5
4 changed files with 408 additions and 388 deletions
+80
View File
@@ -0,0 +1,80 @@
//! Pass C:mark-sweep 一次性重建 insts + label_pos 重映射(D-13,不用就地逐删平移——
//! 多删点叠加偏移易错)。sweep:keep 序 compact 重建;label_pos 逐 id 重写,
//! 目标被删的 label 置 None 保留 id 槽位(lowering 只读 label_pos 不读 label_count)。
use oxide_ir::inst::Inst;
use oxide_ir::IRFunction;
/// mark-sweep 重建:按 `keep` 序 compact `f.insts`,同步重映射 `f.label_pos`。
pub(super) fn pass_c_sweep(f: &mut IRFunction, keep: &[bool]) {
// old_to_new:存活位置记新下标,被删记 usize::MAX
let mut old_to_new = vec![usize::MAX; f.insts.len()];
let mut new_insts: Vec<Inst> = Vec::with_capacity(keep.iter().filter(|k| **k).count());
for (old, k) in keep.iter().enumerate() {
if *k {
old_to_new[old] = new_insts.len();
new_insts.push(f.insts[old].clone());
}
}
f.insts = new_insts;
// label_pos 逐 id 重写:get + usize::MAX 过滤做越界守卫(T-04-03,不信任 label_pos 长度)
for pos in f.label_pos.iter_mut() {
if let Some(old) = *pos {
*pos = old_to_new.get(old).filter(|n| **n != usize::MAX).copied();
}
}
// 防御性校验(T-04-03):存活 label 新下标不越界(空尾块映射 new insts.len() 合法透传)
let new_len = f.insts.len();
debug_assert!(f.label_pos.iter().all(|p| p.map_or(true, |np| np <= new_len)));
}
#[cfg(test)]
mod tests {
use super::*;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
/// 存活 label 新旧下标对应:删除前置死指令后,label 目标重映射到新下标。
#[test]
fn live_label_remapped_to_new_index() {
let mut f = IRFunction::new();
f.insts.push(Inst::load_const(Operand::Reg(5), 1)); // 0: 存活
f.insts.push(Inst::load_const(Operand::Reg(9), 2)); // 1: 死(删)
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 2
f.label_pos = vec![Some(2)]; // label 0 → inst 2(RETURN)
f.label_count = 1;
pass_c_sweep(&mut f, &[true, false, true]);
assert_eq!(f.insts.len(), 2, "死 LOAD_CONST 删除");
assert_eq!(f.insts[0].op, OpCode::LOAD_CONST);
assert_eq!(f.insts[1].op, OpCode::RETURN);
assert_eq!(f.label_pos, vec![Some(1)], "存活 label 2 → 新下标 1");
}
/// 不动域断言(D-14/D-04/D-03/D-13):constants / n_registers / nested / label_count
/// 一律不动;死 label 置 None、存活 label 重映射、原 None 保持。
#[test]
fn untouched_domains_asserted() {
let mut f = IRFunction::new();
f.insts.push(Inst::load_const(Operand::Reg(1), 0)); // 0: label 0 目标(死值,保守保留)
f.insts.push(Inst::load_const(Operand::Reg(2), 1)); // 1: 非 label 目标的死指令(删)
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 2
f.label_pos = vec![Some(0), Some(2), None];
f.label_count = 3;
f.n_registers = 10;
f.constants = vec![Constant::Number(1.0)];
f.nested.push(IRFunction::new());
pass_c_sweep(&mut f, &[true, false, true]);
assert_eq!(f.insts.len(), 2, "非目标死指令删、label 目标死指令保守保留");
assert_eq!(f.insts[0].op, OpCode::LOAD_CONST);
assert_eq!(f.insts[1].op, OpCode::RETURN);
assert_eq!(f.label_pos, vec![Some(0), Some(1), None], "存活 label→新下标、原 None 保持");
assert_eq!(f.label_count, 3, "label_count 不动(D-13)");
assert_eq!(f.n_registers, 10, "n_registers 不收缩(D-04)");
assert_eq!(f.constants, vec![Constant::Number(1.0)], "常量池不清理(D-14)");
assert_eq!(f.nested.len(), 1, "nested 不递归不回收(D-03)");
}
}