From c47a0a73d1a050a2a373f51de15b0d0aaad53d54 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Thu, 6 Aug 2026 19:33:16 +0800 Subject: [PATCH] =?UTF-8?q?test:=20vreg=20=E8=B6=85=20253=20=E9=AB=98?= =?UTF-8?q?=E5=A4=8D=E7=94=A8=E5=A4=8D=E7=8E=B0=E6=A0=B7=E4=BE=8B=20+=20n?= =?UTF-8?q?=5Fregisters=20=E6=B1=87=E6=80=BB=E6=96=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_regalloc/tests/b005_samples.rs | 112 ++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 crates/oxide_regalloc/tests/b005_samples.rs diff --git a/crates/oxide_regalloc/tests/b005_samples.rs b/crates/oxide_regalloc/tests/b005_samples.rs new file mode 100644 index 00000000..84043aac --- /dev/null +++ b/crates/oxide_regalloc/tests/b005_samples.rs @@ -0,0 +1,112 @@ +//! B005 复现 + n_registers 汇总断言(REG-04 直接验收)。 +//! +//! 低层管线直调(不经 Compiler——oxide_regalloc dev-dep oxide_compiler 会构成依赖环): +//! parse → emit → dce(保守)→(regalloc on/off)→ lower。on 分支按 RESEARCH 例 6: +//! 精确 DCE 后重跑 build_cfg + liveness 再 alloc(D-17 索引位移修正);off 分支 = D-18 +//! 降级路径(vreg 原样当物理号 → lower Reg>253 抛 RangeError)。 + +use oxide_bytecode::module::CompiledModule; + +fn compile_source(src: &str, regalloc: bool) -> Result { + let allocator = oxide_parser::Allocator::default(); + let program = oxide_parser::parse(&allocator, src).expect("parse failed"); + let mut ir = oxide_emit::Emitter::new().emit_program(&program).expect("emit failed"); + oxide_dce::dce(&mut ir); + if regalloc { + let cfg = oxide_cfg::build_cfg(&ir); + let live = oxide_liveness::liveness(&ir, &cfg); + oxide_dce::dce_precise(&mut ir, &live); + let cfg2 = oxide_cfg::build_cfg(&ir); + let live2 = oxide_liveness::liveness(&ir, &cfg2); + oxide_regalloc::alloc(&mut ir, &live2)?; + } + oxide_ir::lower::lower(&ir) +} + +/// B005 样例生成器:n 个逐语句独立 vreg(各值立即死)→ vreg 总数 ≈ 2n ≫ 253, +/// 但峰值活度极小 → RegAlloc 有充分复用空间。 +fn gen_big(n: usize) -> String { + let mut src = String::from("function f() { "); + for i in 0..n { + src.push_str(&format!("let v{i} = {i}; v{i}; ")); + } + src.push_str(&format!("return v{}; }} f();", n - 1)); + src +} + +/// 遍历模块树找最大 n_registers。 +fn module_max_n_registers(m: &CompiledModule) -> u8 { + let mut max = m.n_registers; + for sub in &m.sub_modules { + max = max.max(module_max_n_registers(sub)); + } + max +} + +/// B005 前置复现:off 模式(降级路径)250 变量函数报 RangeError。 +#[test] +fn b005_repro_errors_without_regalloc() { + let err = match compile_source(&gen_big(250), false) { + Err(e) => e, + Ok(_) => panic!("off 模式应报 RangeError"), + }; + assert!(err.contains("RangeError"), "off 模式应报 RangeError: {err}"); +} + +/// B005 修复达成:on 模式 250 变量函数编译成功,模块树 n_registers ≤ 253。 +#[test] +fn b005_compiles_with_regalloc() { + let module = compile_source(&gen_big(250), true).expect("on 模式应编译成功"); + assert!(module_max_n_registers(&module) <= 253, "模块树 n_registers 应 ≤253"); +} + +/// 样例集 n_registers on ≤ off 且至少一个严格下降(证明寄存器复用,REG-04 核心)。 +#[test] +fn n_registers_on_off_aggregate() { + let samples = [ + // 12 变量顺序死链:on 个位 vs off 数十(复用空间大) + "function f() { let v0=0; v0; let v1=1; v1; let v2=2; v2; let v3=3; v3; let v4=4; v4; let v5=5; v5; let v6=6; v6; let v7=7; v7; let v8=8; v8; let v9=9; v9; let v10=10; v10; let v11=11; v11; return v11; } f();", + // for 循环累加 + "function f(n) { var s = 0; for (var i = 0; i < n; i++) { s += i * i; } return s; } f(10);", + // 嵌套调用 + "function f(a, b, c) { return a * 100 + b * 10 + c; } function g() { return f(1, 2, 3) + f(4, 5, 6); } g();", + // try/catch + "function f() { try { throw 1; } catch (e) { return e + 1; } } f();", + // 闭包捕获 + "function f() { var x = 1; return function() { return x++; }; } var g = f(); g();", + // 解构 + "function f() { var [a, b] = [1, 2]; var { c, d } = { c: 3, d: 4 }; return a + b + c + d; } f();", + // 箭头函数 + "var f = (a, b) => a * b; f(6, 7);", + // switch+const(B011 回归) + "function f(x) { switch (x) { case 1: break; } const c = 5; return c; } f(1);", + // 数组字面量 + "function f() { var a = [1, 2, 3, 4, 5]; return a[0] + a[4]; } f();", + ]; + let mut strict_decrease = false; + for (i, src) in samples.iter().enumerate() { + let on = compile_source(src, true).expect("on 应编译成功"); + let on_max = module_max_n_registers(&on); + assert!(on_max <= 253, "样例 {i} on n_registers {on_max} 超 253"); + if let Ok(off) = compile_source(src, false) { + let off_max = module_max_n_registers(&off); + assert!( + on_max <= off_max, + "样例 {i} on({on_max}) > off({off_max})——RegAlloc 不应增寄存器窗口" + ); + if on_max < off_max { + strict_decrease = true; + } + } + } + assert!(strict_decrease, "至少一个样例应严格 on < off(复用证明)"); +} + +/// 确定性:同一源码 on 模式编译两次字节码逐字节相同(B010,structural_hash 缓存依赖)。 +#[test] +fn regalloc_deterministic_output() { + let a = compile_source(&gen_big(50), true).expect("on 编译成功"); + let b = compile_source(&gen_big(50), true).expect("on 编译成功"); + assert_eq!(a.bytecode, b.bytecode, "两次编译字节码应逐字节相同"); + assert_eq!(a.n_registers, b.n_registers); +}