feat: 指令改写 + 元数据回写 + alloc 入口,RegAlloc on/off 运行时等价(D-16/D-20)

This commit is contained in:
2026-08-06 17:44:31 +08:00
parent 0b0d36fa85
commit 08f061dfd3
6 changed files with 974 additions and 5 deletions
+92
View File
@@ -0,0 +1,92 @@
//! REG-04 断言:RegAlloc on ≤253 且 < off(寄存器收缩);B005 大函数 on 编译成功。
fn n_registers(src: &str, regalloc: bool) -> Result<u8, 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)?;
}
let module = oxide_ir::lower::lower(&ir)?;
// 返回模块树最大 n_registers(嵌套函数是实际寄存器压力来源)
Ok(module_max_n_registers(&module))
}
fn module_max_n_registers(m: &oxide_bytecode::module::CompiledModule) -> u8 {
let mut max = m.n_registers;
for sub in &m.sub_modules {
max = max.max(module_max_n_registers(sub));
}
max
}
fn gen_sum_function(n: u32) -> String {
let mut src = String::from("function f() { ");
for i in 0..n {
src.push_str(&format!("var v{i} = {i}; "));
}
src.push_str("return ");
for i in 0..n {
if i > 0 {
src.push('+');
}
src.push_str(&format!("v{i}"));
}
src.push_str("; } f();");
src
}
/// 长活 L + n 次短活:L 干扰 n 个短活临时值 → L degree ≥ k → spill L → fresh 单点可着色。
fn gen_spill_function(n: u32) -> String {
let mut src = String::from("function f(a) { var L = a; var s = 0; ");
for _ in 0..n {
src.push_str("s = s + L; ");
}
src.push_str("return s; } f(1);");
src
}
/// 中等函数 on ≤253 且 < off(寄存器复用收缩)。
#[test]
fn n_registers_shrinks_with_regalloc() {
let samples = [
gen_sum_function(50),
"function f(a, b, c) { return a * 100 + b * 10 + c; } function g() { return f(1, 2, 3); } g();".to_string(),
"function f(n) { var s = 0; for (var i = 0; i < n; i++) { s += i * i; } return s; } f(10);".to_string(),
"function f() { try { throw 1; } catch (e) { return e + 1; } } f();".to_string(),
"function f() { var x = 1; return function() { return x++; }; } var g = f(); g();".to_string(),
];
for src in &samples {
let on = n_registers(src, true).expect("on 应成功");
let off = n_registers(src, false).expect("off 应成功");
assert!(on <= 253, "on ≤253: {on} for {src}");
assert!(on < off, "on({on}) < off({off}) for {src}");
}
}
/// B005 大函数:on 编译成功 ≤253;off 报 RangeError(B005 解决证据)。
#[test]
fn b005_large_function_fits_in_253() {
let src = gen_sum_function(220);
let on = n_registers(&src, true);
assert!(on.is_ok(), "B005 样例 on 应编译成功");
assert!(on.unwrap() <= 253, "on ≤253");
let off = n_registers(&src, false);
assert!(off.is_err(), "B005 样例 off 应报 RangeError");
assert!(off.unwrap_err().contains("too many registers"), "off Err 消息");
}
/// spill 压力样例(长活 L + 254 短活)on ≤253 且成功。
#[test]
fn spill_sample_under_limit() {
let src = gen_spill_function(254);
let on = n_registers(&src, true);
assert!(on.is_ok(), "spill 样例 on 应编译成功: {on:?}");
assert!(on.unwrap() <= 253, "on ≤253");
}