docs: 补充注释与格式化

This commit is contained in:
爱特每羊队
2026-08-06 23:10:27 +08:00
parent 4e0fd762c2
commit 328b8a3ddc
156 changed files with 2393 additions and 1687 deletions
+115 -53
View File
@@ -1,8 +1,8 @@
//! Inst 寄存器契约:def/use 扫描 + 副作用判定(DCE 与 Phase 5 liveness 共用,D-06)。
//! Inst 寄存器契约:def/use 扫描 + 副作用判定(DCE 与 liveness 共用单源)。
//!
//! `def_reg` / `use_regs` / `is_pure` 是 `Inst` 的类型契约方法(`impl Inst` 与 `inst.rs`
//! 中的构造 API 同属一类型),落在 oxide_ir 契约层供 DCE 消费、liveness 复用。
//! 寄存器规则逐条对照 VM dispatch handler(RESEARCH Pattern 1/2 全表):
//! 寄存器规则与 VM dispatch handler 行为一致:
//! CALL 隐式写 reg 0、GET_PROP 结果写 a/b 槽、HALT 隐式读 reg 0、None 槽映射 Reg(0)。
use oxide_bytecode::opcode::OpCode;
@@ -17,9 +17,9 @@ impl Inst {
/// 无写入返回 None。
pub fn def_reg(&self) -> Option<u32> {
match self.op {
// CALL 系:结果隐式写 reg 0,rd 是 callee use(Pitfall 1)
// CALL 系:结果隐式写 reg 0,rd 是 callee 的 use
OpCode::CALL | OpCode::CALL_NATIVE => Some(0),
// GET_PROP 系:结果写 a/b 槽而非 rd(Pitfall 3)
// GET_PROP 系:结果写 a/b 槽而非 rd
OpCode::GET_PROP | OpCode::IC_GET_PROP => reg_of(&self.a),
OpCode::GET_PROP_DYNAMIC => reg_of(&self.b),
// 成员读写:val 槽原地更新(a 槽 / b 槽)
@@ -73,7 +73,7 @@ impl Inst {
pub fn use_regs(&self) -> SmallVec<[u32; 4]> {
let mut uses = SmallVec::new();
match self.op {
// CALL 系:rd=callee, a=this, b..b+nargs 参数区间(Pitfall 1)
// CALL 系:rd=callee, a=this, b..b+nargs 参数区间
OpCode::CALL | OpCode::CALL_NATIVE => {
push_operand(&mut uses, &self.rd);
push_operand(&mut uses, &self.a);
@@ -91,7 +91,7 @@ impl Inst {
let nargs = self.ext.first().copied().unwrap_or(0);
push_range(&mut uses, reg_of(&self.a), nargs);
}
// GET_PROP 系:结果写 a/b 槽,rd=obj 是 use(Pitfall 3)
// GET_PROP 系:结果写 a/b 槽,rd=obj 是 use
OpCode::GET_PROP => {
push_operand(&mut uses, &self.rd);
push_operand(&mut uses, &self.b);
@@ -144,11 +144,31 @@ impl Inst {
push_operand(&mut uses, &self.rd);
}
// 二元运算:a, b
OpCode::ADD | OpCode::SUB | OpCode::MUL | OpCode::DIV | OpCode::MOD | OpCode::EQ
| OpCode::NEQ | OpCode::LT | OpCode::GT | OpCode::LTE | OpCode::GTE | OpCode::AND
| OpCode::OR | OpCode::NULLISH | OpCode::STRICT_EQ | OpCode::STRICT_NEQ
| OpCode::BIT_AND | OpCode::BIT_OR | OpCode::BIT_XOR | OpCode::SHL | OpCode::SHR
| OpCode::USHR | OpCode::INSTANCEOF | OpCode::IN | OpCode::CREATE_REGEXP => {
OpCode::ADD
| OpCode::SUB
| OpCode::MUL
| OpCode::DIV
| OpCode::MOD
| OpCode::EQ
| OpCode::NEQ
| OpCode::LT
| OpCode::GT
| OpCode::LTE
| OpCode::GTE
| OpCode::AND
| OpCode::OR
| OpCode::NULLISH
| OpCode::STRICT_EQ
| OpCode::STRICT_NEQ
| OpCode::BIT_AND
| OpCode::BIT_OR
| OpCode::BIT_XOR
| OpCode::SHL
| OpCode::SHR
| OpCode::USHR
| OpCode::INSTANCEOF
| OpCode::IN
| OpCode::CREATE_REGEXP => {
push_operand(&mut uses, &self.a);
push_operand(&mut uses, &self.b);
}
@@ -157,19 +177,29 @@ impl Inst {
push_operand(&mut uses, &self.a);
}
// 无条件跳转 / try 标记:b 是 Label,无寄存器
OpCode::JMP | OpCode::TRY_BEGIN | OpCode::TRY_FINALLY_BEGIN | OpCode::TRY_END
| OpCode::TRY_FINALLY_END | OpCode::FOR_IN_CLEANUP | OpCode::FOR_OF_CLOSE => {}
OpCode::JMP
| OpCode::TRY_BEGIN
| OpCode::TRY_FINALLY_BEGIN
| OpCode::TRY_END
| OpCode::TRY_FINALLY_END
| OpCode::FOR_IN_CLEANUP
| OpCode::FOR_OF_CLOSE => {}
// 条件跳转:rd=cond
OpCode::JMP_IF_FALSE | OpCode::JMP_IF_TRUE | OpCode::JMP_IF_NULLISH => {
push_operand(&mut uses, &self.rd);
}
// HALT:隐式读 reg 0(顶层返回值,Pitfall 2)
// HALT:隐式读 reg 0(顶层返回值)
OpCode::HALT => uses.push(0),
// RETURN/THROW:读 rd(None→0)
OpCode::RETURN | OpCode::THROW => push_operand(&mut uses, &self.rd),
// 加载族:a 槽是 Const/Imm 立即数,无寄存器 use
OpCode::LOAD_CONST | OpCode::CREATE_CLOSURE | OpCode::LOAD_UPVALUE | OpCode::VOID
| OpCode::NEW_OBJECT | OpCode::NEW_ARRAY | OpCode::NOP => {}
OpCode::LOAD_CONST
| OpCode::CREATE_CLOSURE
| OpCode::LOAD_UPVALUE
| OpCode::VOID
| OpCode::NEW_OBJECT
| OpCode::NEW_ARRAY
| OpCode::NOP => {}
// 变量读写:LOAD_VAR/STORE_VAR/CELL_GET 读 a(None→0)
OpCode::LOAD_VAR | OpCode::STORE_VAR | OpCode::CELL_GET => {
push_operand(&mut uses, &self.a);
@@ -182,9 +212,15 @@ impl Inst {
OpCode::MAKE_CELL => push_operand(&mut uses, &self.rd),
OpCode::CELL_SET | OpCode::STORE_UPVALUE => push_operand(&mut uses, &self.a),
// 写对象属性:rd/a/b 全 use
OpCode::SET_PROP | OpCode::SET_PROP_DYNAMIC | OpCode::IC_SET_PROP | OpCode::SET_ELEM
| OpCode::GET_PRIVATE | OpCode::SET_PRIVATE | OpCode::INIT_PRIVATE
| OpCode::PRIVATE_BRAND_IN | OpCode::DEFINE_ACCESSOR => {
OpCode::SET_PROP
| OpCode::SET_PROP_DYNAMIC
| OpCode::IC_SET_PROP
| OpCode::SET_ELEM
| OpCode::GET_PRIVATE
| OpCode::SET_PRIVATE
| OpCode::INIT_PRIVATE
| OpCode::PRIVATE_BRAND_IN
| OpCode::DEFINE_ACCESSOR => {
push_operand(&mut uses, &self.rd);
push_operand(&mut uses, &self.a);
push_operand(&mut uses, &self.b);
@@ -210,7 +246,7 @@ impl Inst {
OpCode::FOR_IN_NEXT | OpCode::FOR_IN_DONE | OpCode::FOR_OF_NEXT | OpCode::FOR_OF_DONE => {}
// REST_OBJECT:读 a(ext 是 excluded_idx 常量)
OpCode::REST_OBJECT => push_operand(&mut uses, &self.a),
// TEMPLATE_STR:解析 ext,跳过 ext[0],后续 seg>>31==1 则低 8 位是 expr_reg(A1)
// TEMPLATE_STR:解析 ext,跳过 ext[0],后续 seg>>31==1 则低 8 位是 expr_reg
OpCode::TEMPLATE_STR => {
for seg in self.ext.iter().skip(1) {
if seg >> 31 == 1 {
@@ -219,42 +255,68 @@ impl Inst {
}
}
// 占位 opcode(emit 不产):按无 use 保守处理,不影响合法产物
OpCode::SWITCH_TABLE | OpCode::PROFILE_TYPE | OpCode::PROFILE_SHAPE
| OpCode::PROFILE_BRANCH | OpCode::PROFILE_CALL | OpCode::FORK | OpCode::JOIN => {}
OpCode::SWITCH_TABLE
| OpCode::PROFILE_TYPE
| OpCode::PROFILE_SHAPE
| OpCode::PROFILE_BRANCH
| OpCode::PROFILE_CALL
| OpCode::FORK
| OpCode::JOIN => {}
}
uses
}
/// 本指令是否无观察副作用(Pattern 1 纯表;LOAD_VAR 的 This+derived 特判需 &IRFunction)。
/// 本指令是否无观察副作用(LOAD_VAR 的 This+derived 特判需要函数元信息)。
///
/// 纯 = 结果未用时可删。表外 opcode 一律有副作用(D-05 精确表,宁少删不错删)。
/// 纯 = 结果未用时可删。表外 opcode 一律视为有副作用,宁少删不错删。
pub fn is_pure(&self, f: &IRFunction) -> bool {
match self.op {
// 算术 / 比较 / 位 / 逻辑:coerce 对象路径有抛错风险,D-05 决策算纯(运行时等价兜底)
OpCode::ADD | OpCode::SUB | OpCode::MUL | OpCode::DIV | OpCode::MOD | OpCode::NEG
| OpCode::UNARY_PLUS | OpCode::EQ | OpCode::NEQ | OpCode::LT | OpCode::GT
| OpCode::LTE | OpCode::GTE | OpCode::STRICT_EQ | OpCode::STRICT_NEQ
| OpCode::BIT_AND | OpCode::BIT_OR | OpCode::BIT_XOR | OpCode::SHL | OpCode::SHR
| OpCode::USHR | OpCode::BIT_NOT | OpCode::AND | OpCode::OR | OpCode::NOT
// 算术 / 比较 / 位 / 逻辑:coerce 对象路径有抛错风险,仍按纯处理(运行时等价兜底)
OpCode::ADD
| OpCode::SUB
| OpCode::MUL
| OpCode::DIV
| OpCode::MOD
| OpCode::NEG
| OpCode::UNARY_PLUS
| OpCode::EQ
| OpCode::NEQ
| OpCode::LT
| OpCode::GT
| OpCode::LTE
| OpCode::GTE
| OpCode::STRICT_EQ
| OpCode::STRICT_NEQ
| OpCode::BIT_AND
| OpCode::BIT_OR
| OpCode::BIT_XOR
| OpCode::SHL
| OpCode::SHR
| OpCode::USHR
| OpCode::BIT_NOT
| OpCode::AND
| OpCode::OR
| OpCode::NOT
| OpCode::NULLISH => true,
// 分配 / 常量 / 空操作(a 槽非寄存器)
OpCode::NOP | OpCode::LOAD_CONST | OpCode::VOID | OpCode::TYPEOF | OpCode::NEW_OBJECT
OpCode::NOP
| OpCode::LOAD_CONST
| OpCode::VOID
| OpCode::TYPEOF
| OpCode::NEW_OBJECT
| OpCode::NEW_ARRAY => true,
// MOV:寄存器复制无副作用,可删无害
OpCode::MOV => true,
// SPILL/UNSPILL:RegAlloc 插入的指令,删 SPILL 后 UNSPILL 读陈旧值(Pitfall 7),永不删
// SPILL/UNSPILL:RegAlloc 插入的指令,删 SPILL 后 UNSPILL 读陈旧值,永不删
OpCode::SPILL | OpCode::UNSPILL => false,
// 闭包 / cell 读取:无抛错路径(D-07)
// 闭包 / cell 读取:无抛错路径
OpCode::CREATE_CLOSURE | OpCode::LOAD_UPVALUE | OpCode::CELL_GET => true,
// 模板字符串:纯拼接写 rd,无抛错(use 统计覆盖其 ext)
OpCode::TEMPLATE_STR => true,
// LOAD_VAR:仅 a==This 且 derived 构造函数读 this 可能抛 ReferenceError(misc.rs:52-63)
OpCode::LOAD_VAR => {
!(self.a == Operand::This && f.is_derived_constructor)
}
// STORE_VAR:写变量目标寄存器。脚本顶层/模块作用域的变量是**全局可观察状态**
// (Pitfall 6:`let x=0; class C{[x=1](){}}` 无后续本地读取时删除 `x=1` 会改变
// 外部 `assert(x===1)` 的观察结果);函数内局部未用赋值的优化留给 Phase 5 精确活度。
// LOAD_VAR:仅 a==This 且 derived 构造函数读 this 时可能抛 ReferenceError
OpCode::LOAD_VAR => !(self.a == Operand::This && f.is_derived_constructor),
// STORE_VAR:写变量目标寄存器。脚本顶层/模块作用域的变量是全局可观察状态,
// 删除会改变外部观察结果;函数内局部未用赋值的优化交给精确 DCE。
OpCode::STORE_VAR => false,
// 其余全部有副作用(getter/调用/控制流/迭代器/复合更新/写共享状态/占位防御)
_ => false,
@@ -262,7 +324,7 @@ impl Inst {
}
}
/// 操作数 → 物理寄存器号。None 槽映射 reg 0(A3,与 lower.rs operand_to_u8 一致);
/// 操作数 → 物理寄存器号。None 槽映射 reg 0(与 lower.rs operand_to_u8 一致);
/// Const/Imm/Label 不是寄存器槽,返回 None。
fn reg_of(o: &Operand) -> Option<u32> {
match o {
@@ -295,7 +357,7 @@ mod tests {
use crate::operand::Operand;
use crate::IRFunction;
// ── def_reg / use_regs 契约测试(Pattern 2 全表,反直觉槽位锁定)──
// ── def_reg / use_regs 契约测试(反直觉槽位断言)──
#[test]
fn binary_op_def_rd_use_ab() {
@@ -313,7 +375,7 @@ mod tests {
#[test]
fn get_prop_def_is_a_slot_not_rd() {
// Pitfall 3:GET_PROP rd=obj 是 use,结果写 a 槽
// GET_PROP rd=obj 是 use,结果写 a 槽
let inst = Inst::new(OpCode::GET_PROP, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2));
assert_eq!(inst.def_reg(), Some(1));
assert_eq!(inst.use_regs().as_slice(), &[0, 2]);
@@ -321,7 +383,7 @@ mod tests {
#[test]
fn get_prop_dynamic_def_is_b_slot() {
// Pitfall 3:GET_PROP_DYNAMIC rd=obj 是 use,结果写 b 槽
// GET_PROP_DYNAMIC rd=obj 是 use,结果写 b 槽
let inst = Inst::new(OpCode::GET_PROP_DYNAMIC, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2));
assert_eq!(inst.def_reg(), Some(2));
assert_eq!(inst.use_regs().as_slice(), &[0, 1]);
@@ -329,7 +391,7 @@ mod tests {
#[test]
fn ic_get_prop_a_slot_is_use_and_def() {
// Pitfall 3:IC_GET_PROP a 槽既是对象 use 又是结果 def
// IC_GET_PROP a 槽既是对象 use 又是结果 def
let inst = Inst::ic_get(Operand::Reg(1), Operand::Reg(2));
assert_eq!(inst.def_reg(), Some(1));
let uses = inst.use_regs();
@@ -338,7 +400,7 @@ mod tests {
#[test]
fn call_def_is_implicit_reg0_with_arg_range() {
// Pitfall 1:CALL rd=callee 是 use,结果隐式写 reg 0;参数 b..b+nargs 连续
// CALL rd=callee 是 use,结果隐式写 reg 0;参数 b..b+nargs 连续
let inst = Inst::call(Operand::Reg(0), Operand::Reg(1), Operand::Reg(2), 3);
assert_eq!(inst.def_reg(), Some(0));
assert_eq!(inst.use_regs().as_slice(), &[0, 1, 2, 3, 4]);
@@ -367,7 +429,7 @@ mod tests {
#[test]
fn halt_implicitly_uses_reg0() {
// Pitfall 2:HALT 返回 regs[0],顶层 LOAD_VAR(None, r) 链靠它保活
// HALT 返回 regs[0],顶层 LOAD_VAR(None, r) 链靠它保活
let inst = Inst::new(OpCode::HALT, Operand::None, Operand::None, Operand::None);
assert_eq!(inst.def_reg(), None);
assert_eq!(inst.use_regs().as_slice(), &[0]);
@@ -399,7 +461,7 @@ mod tests {
#[test]
fn none_slot_maps_to_reg0() {
// A3:None 槽与 lower.rs operand_to_u8 一致,统一映射物理 reg 0
// None 槽与 lower.rs operand_to_u8 一致,统一映射物理 reg 0
let lv = Inst::new(OpCode::LOAD_VAR, Operand::Reg(1), Operand::None, Operand::None);
assert_eq!(lv.use_regs().as_slice(), &[0]);
@@ -409,7 +471,7 @@ mod tests {
#[test]
fn template_str_parses_expr_regs_from_ext() {
// ext[0] 跳过;后续 seg>>31==1 则低 8 位是 expr_reg(A1,emit 8 位编码)
// ext[0] 跳过;后续 seg>>31==1 则低 8 位是 expr_reg(emit 8 位编码)
let with_expr = Inst::template_str(Operand::Reg(1), 2, 10, &[0x1234, 0x8000_0000 | 5]);
assert_eq!(with_expr.use_regs().as_slice(), &[5]);
@@ -497,7 +559,7 @@ mod tests {
assert!(unspill.use_regs().is_empty());
}
// ── is_pure 契约测试(Pattern 1 表,纯/非纯族代表 opcode)──
// ── is_pure 契约测试(纯/非纯族代表 opcode)──
#[test]
fn pure_ops_are_deletable() {
@@ -533,7 +595,7 @@ mod tests {
assert!(Inst::inst_mov(Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
// LOAD_VAR 普通(a=Reg)纯
assert!(Inst::new(OpCode::LOAD_VAR, Operand::Reg(1), Operand::Reg(2), Operand::None).is_pure(&f));
// STORE_VAR 一律有副作用(Pitfall 6:顶层变量赋值全局可观察,不删)
// STORE_VAR 一律有副作用(顶层变量赋值全局可观察,不删)
assert!(!Inst::new(OpCode::STORE_VAR, Operand::Reg(0), Operand::Reg(1), Operand::None).is_pure(&f));
assert!(!Inst::new(OpCode::STORE_VAR, Operand::Reg(0), Operand::Reg(1), Operand::Imm(0)).is_pure(&f));
assert!(!Inst::new(OpCode::STORE_VAR, Operand::Reg(0), Operand::Reg(1), Operand::Imm(1)).is_pure(&f));
@@ -580,7 +642,7 @@ mod tests {
assert!(!Inst::new(OpCode::STORE_UPVALUE, Operand::None, Operand::Reg(1), Operand::Imm(0)).is_pure(&f));
assert!(!Inst::new(OpCode::CELL_SET, Operand::None, Operand::Reg(1), Operand::Imm(0)).is_pure(&f));
assert!(!Inst::new(OpCode::MAKE_CELL, Operand::Reg(5), Operand::None, Operand::None).is_pure(&f));
// RegAlloc 辅助:SPILL/UNSPILL 有副作用(删 SPILL 后 UNSPILL 读陈旧值,Pitfall 7)
// RegAlloc 辅助:SPILL/UNSPILL 有副作用(删 SPILL 后 UNSPILL 读陈旧值)
assert!(!Inst::inst_spill(Operand::Reg(5), 42).is_pure(&f));
assert!(!Inst::inst_unspill(Operand::Reg(9), 42).is_pure(&f));
// 占位 opcode 防御性有副作用
@@ -589,7 +651,7 @@ mod tests {
#[test]
fn store_var_all_branches_are_impure() {
// Pitfall 6:STORE_VAR 写目标变量寄存器,顶层/模块作用域变量全局可观察,一律不删
// STORE_VAR 写目标变量寄存器,顶层/模块作用域变量全局可观察,一律不删
// (const guard 抛错、普通 var/let 赋值都可能改变外部观察状态)
let f = IRFunction::new();
assert!(!Inst::new(OpCode::STORE_VAR, Operand::Reg(0), Operand::Reg(1), Operand::None).is_pure(&f));
+8 -23
View File
@@ -42,7 +42,7 @@ impl Inst {
}
}
// ── IC 系:ext = [0, 0, 0](shape/slot/proto 占位字,VM 运行时 patch)──
// ── IC 系:ext = [0, 0, 0](shape/slot/proto 占位字,VM 运行时回填)──
/// 内联缓存读属性:结果写入 `dst`,属性键为 `key`。
pub fn ic_get(dst: Operand, key: Operand) -> Self {
@@ -148,20 +148,20 @@ impl Inst {
}
}
// ── RegAlloc 辅助指令(D-06/D-07)──
// ── RegAlloc 辅助指令 ──
/// 寄存器复制 rd = a(D-07,RegAlloc 区间拆分搬值)。
/// 寄存器复制 rd = a(RegAlloc 区间拆分时搬值)。
/// 不可用 LOAD_VAR/STORE_VAR 组合模拟——引入变量绑定语义会误触 const guard。
pub fn inst_mov(dst: Operand, src: Operand) -> Self {
Self::with_ext(OpCode::MOV, dst, src, Operand::None, &[])
}
/// 溢出:regs[rd] → spill_stack[frame_base + slot],ext=[slot u16](D-06)。
/// 溢出:regs[rd] → spill_stack[frame_base + slot],ext=[slot u16]。
pub fn inst_spill(src: Operand, slot: u16) -> Self {
Self::with_ext(OpCode::SPILL, src, Operand::None, Operand::None, &[slot as u32])
}
/// 恢复:spill_stack[frame_base + slot] → regs[rd],ext=[slot u16](D-06)。
/// 恢复:spill_stack[frame_base + slot] → regs[rd],ext=[slot u16]。
pub fn inst_unspill(dst: Operand, slot: u16) -> Self {
Self::with_ext(OpCode::UNSPILL, dst, Operand::None, Operand::None, &[slot as u32])
}
@@ -187,32 +187,17 @@ impl Inst {
/// 条件寄存器为 false 时跳转。
pub fn jmp_if_false(cond_reg: u32, label: LabelId) -> Self {
Self::new(
OpCode::JMP_IF_FALSE,
Operand::Reg(cond_reg),
Operand::None,
Operand::Label(label),
)
Self::new(OpCode::JMP_IF_FALSE, Operand::Reg(cond_reg), Operand::None, Operand::Label(label))
}
/// 条件寄存器为 true 时跳转。
pub fn jmp_if_true(cond_reg: u32, label: LabelId) -> Self {
Self::new(
OpCode::JMP_IF_TRUE,
Operand::Reg(cond_reg),
Operand::None,
Operand::Label(label),
)
Self::new(OpCode::JMP_IF_TRUE, Operand::Reg(cond_reg), Operand::None, Operand::Label(label))
}
/// 条件寄存器为 null/undefined 时跳转(`??` / 可选链短路)。
pub fn jmp_if_nullish(cond_reg: u32, label: LabelId) -> Self {
Self::new(
OpCode::JMP_IF_NULLISH,
Operand::Reg(cond_reg),
Operand::None,
Operand::Label(label),
)
Self::new(OpCode::JMP_IF_NULLISH, Operand::Reg(cond_reg), Operand::None, Operand::Label(label))
}
/// try 块起始,label 指向对应的 catch/finally 处理入口。
+3 -3
View File
@@ -1,6 +1,6 @@
//! IR 中间表示:AST→IR→字节码 流水线的程序表示。
//!
//! 单一程序表示(D-01),分域组合(D-02):
//! 单一程序表示,分域组合:
//! - code: 指令流 + label 位置
//! - data: 常量池
//! - bindings: 参数布局
@@ -52,8 +52,8 @@ pub struct IRFunction {
pub needs_home_object: bool,
pub captured_this_const_idx: u16,
pub function_name: Option<String>,
/// 本函数是否为顶层脚本函数(D-19):顶层 STORE_VAR 全局可观察(B008)不可删,
/// 函数内局部 STORE_VAR 才可被精确 DCE 删除。emit 在 assemble_ir 处由
/// 本函数是否为顶层脚本函数:顶层 STORE_VAR 写全局可观察状态,不可被精确 DCE
/// 删除;函数内局部 STORE_VAR 才可删。emit 在 assemble_ir 处由
/// `parent_ctx.is_none()` 填充;nested/手工构造默认 false。
pub is_top_level: bool,
pub const_overflow: bool,
+4 -4
View File
@@ -1,8 +1,8 @@
//! IRFunction → CompiledModule 等价转换。
//!
//! 字节码格式(4 字节 u32 + 扩展字)与现状逐指令一致(D-13 锚)。
//! 字节码格式(4 字节 u32 + 扩展字)逐指令一致。
//! label 用前缀和:`label_pos` 记 Inst 下标,平铺时维护 inst→instr 映射,
//! 跳转 offset 以 Instr(含 ext 字)为单位(D-17)。
//! 跳转 offset 以 Instr(含 ext 字)为单位。
use oxide_bytecode::module::CompiledModule;
use oxide_bytecode::opcode::{self, OpCode};
@@ -11,7 +11,7 @@ use crate::inst::Inst;
use crate::operand::Operand;
use crate::IRFunction;
/// IRFunction → CompiledModule。错误消息与现状(退役前 compiler.rs)逐字一致。
/// IRFunction → CompiledModule 等价转换。溢出/标签错误消息为既有格式,逐字保持一致。
pub fn lower(f: &IRFunction) -> Result<CompiledModule, String> {
// 溢出检查 1:常量池(先于寄存器——超大常量池伴生的海量 vreg 会使后续检查的
// 稠密 bitset 表示爆内存;常量池超限是更基础的失效,先报它)
@@ -47,7 +47,7 @@ pub fn lower(f: &IRFunction) -> Result<CompiledModule, String> {
encode_inst(inst, &mut instrs, &mut jumps)?;
}
// 跳转回填:offset = 目标 Instr - 当前 Instr(前缀和,D-17)
// 跳转回填:offset = 目标 Instr - 当前 Instr(前缀和)
for (instr_idx, label) in jumps {
let target_inst = f
.label_pos
+2 -2
View File
@@ -1,13 +1,13 @@
//! 类型安全操作数。IR 中不出现裸寄存器下标。
//!
//! - `Reg(u32)`:寄存器。本阶段存物理号(≤253);254/255 为 VM 保留,语义由 `This`/`NewTarget` 表达
//! - `Reg(u32)`:寄存器,vreg 表示(RegAlloc 后收敛到物理号 ≤253);254/255 为 VM 保留,语义由 `This`/`NewTarget` 表达
//! - `Const(u16)`:常量池下标
//! - `Label(u32)`:跳转目标(`LabelId`)
//! - `Imm(u16)`:立即数
//! - `This` / `NewTarget`:语义化特殊寄存器,由 lowering 映射物理 254/255(IR 中禁止裸下标)
//! - `None`:操作数槽未使用
/// 统一跳转目标标识(取代语义化 `Label` 枚举)。
/// 统一跳转目标标识。id 连续递增,`label_pos` 的 Vec 索引即 id。
pub type LabelId = u32;
/// 类型安全操作数。IR 中不出现裸寄存器下标,语义见文件头 `//!`。