mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
46 lines
2.2 KiB
Rust
46 lines
2.2 KiB
Rust
//! 常量折叠 pass:单向前扫常量传播加就地改写(IR 层)。
|
||
//!
|
||
//! `fold` 对每个函数(递归 nested,每个 nested 函数有独立常量池与指令流,独立前扫)
|
||
//! 运行单向前扫:维护 per-register known 表记录各虚拟寄存器的已知常量值,命中
|
||
//! 改写表即就地改写——A 组一元与算术常量折叠改写为 `LOAD_CONST`(新常量入池),
|
||
//! C 组位运算与比较常量折叠改写为 `LOAD_CONST`(新常量入池),B 组逻辑短路
|
||
//! 改写为 `MOV`(无新常量)。
|
||
//!
|
||
//! 不变量:
|
||
//! - 不删指令、不重映射 `label_pos`:改写只改变指令的 op 与操作数,不改变跳转
|
||
//! 结构,CFG 的块划分与边集不变,由下游 DCE 在折叠后的指令流上重建 CFG 吸收。
|
||
//! - 汇合点健全性:`label_pos` 指向的指令下标(控制流汇合点)整体清空 known 表,
|
||
//! 跨汇合的陈旧知识不用于折叠。
|
||
//! - 负零守卫:算术折叠做实际运算(f64 加),不取恒等捷径——`-0.0 + 0.0` 得
|
||
//! `+0.0`(`Object.is` 可区分)。
|
||
//! - 池溢出守卫:常量池满(`u16::MAX`)时 A 组与 C 组改写禁用(不新增常量),
|
||
//! B 组(MOV)不受影响;`const_overflow` 已被 emit 层置位时整个 pass 跳过。
|
||
//!
|
||
//! 折值计算复用 `oxide_runtime_api::coercion` 的纯函数族(`to_number` /
|
||
//! `to_int32` / `to_uint32` / `to_boolean` / `relational_compare` /
|
||
//! `abstract_eq_primitives` / `strict_equality`),与 emit 层字面量折叠同源,
|
||
//! 杜绝两层折叠各自镜像运行时语义的漂移风险。
|
||
|
||
mod fold_log;
|
||
mod fold_table;
|
||
mod propagate;
|
||
|
||
use oxide_ir::IRFunction;
|
||
|
||
/// 常量传播与折叠:对函数(递归 nested)单向前扫,就地改写。
|
||
///
|
||
/// 返回是否发生改写(仅调试日志用)。接在 emit 与 DCE 之间:改写后失去消费者
|
||
/// 的 `LOAD_CONST` 与死 `MOV` 由下游 DCE 清理,本 pass 不删指令。
|
||
pub fn fold(f: &mut IRFunction) -> bool {
|
||
let mut changed = propagate::fold_function(f);
|
||
for nested in f.nested.iter_mut() {
|
||
if fold(nested) {
|
||
changed = true;
|
||
}
|
||
}
|
||
if changed {
|
||
fold_info!("fold: rewrites applied");
|
||
}
|
||
changed
|
||
}
|