docs: 补充注释与格式化
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
//! 块级数据流迭代:gen/kill + reverse_postorder 不动点。
|
||||
//!
|
||||
//! gen/kill 直接消费 `oxide_ir::contract` 的 `def_reg`/`use_regs`(D-22),
|
||||
//! gen/kill 直接消费 `oxide_ir::contract` 的 `def_reg`/`use_regs`,
|
||||
//! None→0 / This→254 / NewTarget→255 / CALL 隐式 reg0 全内置,不重复建。
|
||||
//! Exception 边当普通边参与迭代(D-13);Exception 目标块入口 reg 0 隐式 def
|
||||
//! Exception 边当普通边参与迭代;Exception 目标块入口 reg 0 隐式 def
|
||||
//! (异常展开写 regs[0],vm_runtime.rs:204-205)在此建模:gen.remove(0)+kill.insert(0)。
|
||||
|
||||
use oxide_cfg::{Cfg, EdgeKind};
|
||||
@@ -63,7 +63,7 @@ pub(super) fn block_liveness(f: &IRFunction, cfg: &Cfg) -> (Vec<Vec<bool>>, Vec<
|
||||
}
|
||||
}
|
||||
|
||||
// 3. reverse_postorder(确定性,禁 HashMap 迭代序——B010)
|
||||
// 3. reverse_postorder(确定性,禁 HashMap 迭代序)
|
||||
let rpo = reverse_postorder(cfg);
|
||||
|
||||
// 4. 不动点迭代
|
||||
@@ -73,7 +73,7 @@ pub(super) fn block_liveness(f: &IRFunction, cfg: &Cfg) -> (Vec<Vec<bool>>, Vec<
|
||||
loop {
|
||||
let mut changed = false;
|
||||
for &b in &rpo {
|
||||
// live_out[b] = ∪ live_in[s](全部 succs,含 Exception 边——D-13 当普通边)
|
||||
// live_out[b] = ∪ live_in[s](全部 succs,含 Exception 边当普通边)
|
||||
let mut out = vec![false; bits];
|
||||
for &(succ, _kind) in &cfg.blocks[b].succs {
|
||||
for (r, &v) in live_in[succ].iter().enumerate() {
|
||||
@@ -104,7 +104,7 @@ pub(super) fn block_liveness(f: &IRFunction, cfg: &Cfg) -> (Vec<Vec<bool>>, Vec<
|
||||
}
|
||||
|
||||
/// 从 entry 出发 DFS 沿 succs 存储序(确定序)收集 postorder 后反转;
|
||||
/// 不可达块按升序追加在末尾。纯 Vec + visited 位图(B010)。
|
||||
/// 不可达块按升序追加在末尾。纯 Vec + visited 位图,保证确定性。
|
||||
fn reverse_postorder(cfg: &Cfg) -> Vec<usize> {
|
||||
let n = cfg.blocks.len();
|
||||
let mut visited = vec![false; n];
|
||||
@@ -131,9 +131,9 @@ fn reverse_postorder(cfg: &Cfg) -> Vec<usize> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
|
||||
fn set(v: &[bool], regs: &[u32]) -> bool {
|
||||
regs.iter().all(|&r| v[r as usize])
|
||||
@@ -146,8 +146,10 @@ mod tests {
|
||||
#[test]
|
||||
fn linear_function_liveness() {
|
||||
let mut f = empty_function();
|
||||
f.insts.push(Inst::new(OpCode::ADD, Operand::Reg(2), Operand::Reg(0), Operand::Reg(1)));
|
||||
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(2), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::ADD, Operand::Reg(2), Operand::Reg(0), Operand::Reg(1)));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::RETURN, Operand::Reg(2), Operand::None, Operand::None));
|
||||
let cfg = oxide_cfg::build_cfg(&f);
|
||||
let (live_in, live_out, reg_count) = block_liveness(&f, &cfg);
|
||||
assert!(reg_count >= 2);
|
||||
@@ -170,11 +172,15 @@ mod tests {
|
||||
// 5: RETURN Reg(6)
|
||||
let mut f = empty_function();
|
||||
f.insts.push(Inst::jmp_if_false(1, 1));
|
||||
f.insts.push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2)));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2)));
|
||||
f.insts.push(Inst::jmp(2));
|
||||
f.insts.push(Inst::new(OpCode::SUB, Operand::Reg(4), Operand::Reg(4), Operand::Reg(5)));
|
||||
f.insts.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None));
|
||||
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(6), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::SUB, Operand::Reg(4), Operand::Reg(4), Operand::Reg(5)));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::RETURN, Operand::Reg(6), Operand::None, Operand::None));
|
||||
f.label_pos = vec![None, Some(3), Some(4)];
|
||||
f.label_count = 3;
|
||||
let cfg = oxide_cfg::build_cfg(&f);
|
||||
@@ -201,10 +207,13 @@ mod tests {
|
||||
// 4: RETURN Reg(6)
|
||||
let mut f = empty_function();
|
||||
f.insts.push(Inst::jmp_if_false(1, 1));
|
||||
f.insts.push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2)));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2)));
|
||||
f.insts.push(Inst::jmp(0));
|
||||
f.insts.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None));
|
||||
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(6), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::NOP, Operand::None, Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::RETURN, Operand::Reg(6), Operand::None, Operand::None));
|
||||
f.label_pos = vec![Some(0), Some(3)];
|
||||
f.label_count = 2;
|
||||
let cfg = oxide_cfg::build_cfg(&f);
|
||||
@@ -227,10 +236,14 @@ mod tests {
|
||||
// 4: RETURN Reg(5)
|
||||
let mut f = empty_function();
|
||||
f.insts.push(Inst::try_begin(3));
|
||||
f.insts.push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2)));
|
||||
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(3), Operand::None, Operand::None));
|
||||
f.insts.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(5), Operand::None, Operand::None));
|
||||
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2)));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::RETURN, Operand::Reg(3), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(5), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None));
|
||||
f.label_pos = vec![None, None, None, Some(3)];
|
||||
f.label_count = 1;
|
||||
let cfg = oxide_cfg::build_cfg(&f);
|
||||
@@ -249,8 +262,10 @@ mod tests {
|
||||
// 0: LOAD_VAR(Reg(5), None, None) def 5 use {0}
|
||||
// 1: HALT(None, None, None) contract.rs HALT 读 regs[0]
|
||||
let mut f = empty_function();
|
||||
f.insts.push(Inst::new(OpCode::LOAD_VAR, Operand::Reg(5), Operand::None, Operand::None));
|
||||
f.insts.push(Inst::new(OpCode::HALT, Operand::None, Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::LOAD_VAR, Operand::Reg(5), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::HALT, Operand::None, Operand::None, Operand::None));
|
||||
let cfg = oxide_cfg::build_cfg(&f);
|
||||
let (live_in, _, _) = block_liveness(&f, &cfg);
|
||||
assert!(live_in[0][0], "None→0 映射由 contract.rs 消费生效");
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! liveness 分析 pass:IRFunction + CFG → LiveInfo(只读,D-15)。
|
||||
//! liveness 分析 pass:IRFunction + CFG → LiveInfo(只读)。
|
||||
//!
|
||||
//! 消费 `oxide_ir::IRFunction`(只读)与 `oxide_cfg::Cfg`(preds/succs + exit 哨兵,D-12),
|
||||
//! 产出 LiveInfo 分析视图(D-01:pass 输出不住进 IR)。两阶段:`dataflow`(块级
|
||||
//! 消费 `oxide_ir::IRFunction`(只读)与 `oxide_cfg::Cfg`(preds/succs + exit 哨兵),
|
||||
//! 产出 LiveInfo 分析视图(pass 输出不住进 IR)。两阶段:`dataflow`(块级
|
||||
//! liveIn/liveOut 不动点)→ `ranges`(块内反向扫描逐指令 live 集)。gen/kill 直接消费
|
||||
//! contract.rs def_reg/use_regs(D-22),None→0 / This→254 / NewTarget→255 零重复映射。
|
||||
//! contract.rs def_reg/use_regs,None→0 / This→254 / NewTarget→255 零重复映射。
|
||||
|
||||
mod dataflow;
|
||||
mod live_info;
|
||||
@@ -14,8 +14,8 @@ pub use live_info::LiveInfo;
|
||||
use oxide_cfg::Cfg;
|
||||
use oxide_ir::IRFunction;
|
||||
|
||||
/// 计算 liveness:`&IRFunction + &Cfg → LiveInfo`。纯函数,只读 IR(D-15)。
|
||||
/// 空 IRFunction 退化:返回 LiveInfo::new()(照 oxide_dce 空函数先例)。
|
||||
/// 计算 liveness:`&IRFunction + &Cfg → LiveInfo`。纯函数,只读 IR。
|
||||
/// 空 IRFunction 退化:返回 LiveInfo::new()。
|
||||
pub fn liveness(f: &IRFunction, cfg: &Cfg) -> LiveInfo {
|
||||
if f.insts.is_empty() {
|
||||
return LiveInfo::new();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! LiveInfo:liveness 分析输出视图(D-15:pass 输出,不住进 IR)。
|
||||
//! LiveInfo:liveness 分析输出视图(pass 输出,不住进 IR)。
|
||||
//!
|
||||
//! 全部 live 集为按 reg 号索引的 bitset(`Vec<bool>`,长度 = reg_count+1,由
|
||||
//! dataflow 求上界)。四字段语义:
|
||||
//! - `block_live_in` / `block_live_out`:块级数据流迭代结果(05-06 精确 DCE 消费)
|
||||
//! - `inst_live_before` / `inst_live_after`:逐指令活集(05-07 干涉图消费 live_before)
|
||||
//! - `block_live_in` / `block_live_out`:块级数据流迭代结果(精确 DCE 消费)
|
||||
//! - `inst_live_before` / `inst_live_after`:逐指令活集(RegAlloc 干涉图消费 live_before)
|
||||
|
||||
/// liveness 输出:块级 liveIn/liveOut + 逐指令 live_before/live_after。
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
//! 块内反向扫描:块级 liveOut → 逐指令 live_before/live_after。
|
||||
//!
|
||||
//! 起点是 **block_live_out**(非 liveIn,RESEARCH 伪代码笔误已修正——从 liveIn
|
||||
//! 出发会得到错误放大的逐指令集)。反向扫描 **kill 先于 gen**(`live = (live − def)
|
||||
//! ∪ use`):COMPOUND_ADD 等读-写同寄存器指令 use 含 rd(contract.rs:137),
|
||||
//! gen 先于 kill 会把 rd 旧值从 live_before 错误剔除。Exception 目标块入口
|
||||
//! reg 0 隐式 def 在此截断,并以 `debug_assert_eq!(live, block_live_in[b])`
|
||||
//! 校验与 dataflow 一致性。
|
||||
//! 起点是 **block_live_out**(非 liveIn——从 liveIn 出发会得到错误放大的逐指令集)。
|
||||
//! 反向扫描 **kill 先于 gen**(`live = (live − def) ∪ use`):COMPOUND_ADD 等读-写
|
||||
//! 同寄存器指令 use 含 rd(contract.rs:137),gen 先于 kill 会把 rd 旧值从
|
||||
//! live_before 错误剔除。Exception 目标块入口 reg 0 隐式 def 在此截断,并以
|
||||
//! `debug_assert_eq!(live, block_live_in[b])` 校验与 dataflow 一致性。
|
||||
|
||||
use oxide_cfg::{Cfg, EdgeKind};
|
||||
use oxide_ir::IRFunction;
|
||||
@@ -48,9 +47,9 @@ pub(super) fn inst_liveness(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::dataflow::block_liveness;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
|
||||
fn empty_function() -> IRFunction {
|
||||
IRFunction::new()
|
||||
@@ -60,8 +59,10 @@ mod tests {
|
||||
fn linear_block_instruction_sets() {
|
||||
// 0: ADD r2=r0+r1 1: RETURN r2
|
||||
let mut f = empty_function();
|
||||
f.insts.push(Inst::new(OpCode::ADD, Operand::Reg(2), Operand::Reg(0), Operand::Reg(1)));
|
||||
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(2), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::ADD, Operand::Reg(2), Operand::Reg(0), Operand::Reg(1)));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::RETURN, Operand::Reg(2), Operand::None, Operand::None));
|
||||
let cfg = oxide_cfg::build_cfg(&f);
|
||||
let (live_in, live_out, rc) = block_liveness(&f, &cfg);
|
||||
let (before, after) = inst_liveness(&f, &cfg, &live_out, &live_in, rc);
|
||||
@@ -77,8 +78,10 @@ mod tests {
|
||||
// 0: COMPOUND_ADD rd=1, a=2 def {1} use {1,2}
|
||||
// 1: RETURN r1
|
||||
let mut f = empty_function();
|
||||
f.insts.push(Inst::new(OpCode::COMPOUND_ADD, Operand::Reg(1), Operand::Reg(2), Operand::None));
|
||||
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(1), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::COMPOUND_ADD, Operand::Reg(1), Operand::Reg(2), Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::RETURN, Operand::Reg(1), Operand::None, Operand::None));
|
||||
let cfg = oxide_cfg::build_cfg(&f);
|
||||
let (live_in, live_out, rc) = block_liveness(&f, &cfg);
|
||||
let (before, _) = inst_liveness(&f, &cfg, &live_out, &live_in, rc);
|
||||
@@ -94,8 +97,10 @@ mod tests {
|
||||
// 2: RETURN r4
|
||||
let mut f = empty_function();
|
||||
f.insts.push(Inst::call(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 1));
|
||||
f.insts.push(Inst::new(OpCode::LOAD_VAR, Operand::Reg(4), Operand::None, Operand::None));
|
||||
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(4), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::LOAD_VAR, Operand::Reg(4), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::RETURN, Operand::Reg(4), Operand::None, Operand::None));
|
||||
let cfg = oxide_cfg::build_cfg(&f);
|
||||
let (live_in, live_out, rc) = block_liveness(&f, &cfg);
|
||||
let (before, after) = inst_liveness(&f, &cfg, &live_out, &live_in, rc);
|
||||
@@ -111,10 +116,14 @@ mod tests {
|
||||
// 3: STORE_VAR(r5, None, None) 4: RETURN r5
|
||||
let mut f = empty_function();
|
||||
f.insts.push(Inst::try_begin(3));
|
||||
f.insts.push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2)));
|
||||
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(3), Operand::None, Operand::None));
|
||||
f.insts.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(5), Operand::None, Operand::None));
|
||||
f.insts.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::ADD, Operand::Reg(3), Operand::Reg(3), Operand::Reg(2)));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::RETURN, Operand::Reg(3), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::STORE_VAR, Operand::Reg(5), Operand::None, Operand::None));
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None));
|
||||
f.label_pos = vec![None, None, None, Some(3)];
|
||||
f.label_count = 1;
|
||||
let cfg = oxide_cfg::build_cfg(&f);
|
||||
|
||||
Reference in New Issue
Block a user