This repository has been archived on 2026-09-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
OxideJS/crates/oxide_regalloc/tests/b005_samples.rs
T

113 lines
5.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 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<CompiledModule, String> {
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);
}