mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 10:41:11 +08:00
feat: 新增 IR 层常量传播与折叠 pass
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
//! 常量折叠 pass 日志宏:`fold_error!/warn!/info!/debug!/trace!`,经由 oxide_log 上报。
|
||||
//! 编译管线属 Kernel 子系统,`OXIDE_LOG=oxide::kernel=debug` 控制本 crate 日志。
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! fold_error {
|
||||
($($arg:tt)*) => {
|
||||
oxide_log::__log_event!("oxide::kernel", oxide_log::tracing::Level::ERROR, $($arg)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! fold_warn {
|
||||
($($arg:tt)*) => {
|
||||
oxide_log::__log_event!("oxide::kernel", oxide_log::tracing::Level::WARN, $($arg)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! fold_info {
|
||||
($($arg:tt)*) => {
|
||||
oxide_log::__log_event!("oxide::kernel", oxide_log::tracing::Level::INFO, $($arg)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! fold_debug {
|
||||
($($arg:tt)*) => {
|
||||
oxide_log::__log_event!("oxide::kernel", oxide_log::tracing::Level::DEBUG, $($arg)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! fold_trace {
|
||||
($($arg:tt)*) => {
|
||||
oxide_log::__log_event!("oxide::kernel", oxide_log::tracing::Level::TRACE, $($arg)*)
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
//! 折叠表:一元与算术常量折叠(A 组)加逻辑短路选支(B 组)。
|
||||
//!
|
||||
//! 折值编码逐运算符镜像运行时产物编码,保证物化后与运行时执行结果逐字节
|
||||
//! 一致:折值计算复用 `oxide_runtime_api::coercion` 的纯函数族(`to_number` /
|
||||
//! `to_int32` / `to_boolean`),与 emit 层字面量折叠同源,杜绝两层折叠各自
|
||||
//! 镜像运行时语义的漂移风险。
|
||||
//!
|
||||
//! 语义守卫:
|
||||
//! - 算术二元(ADD/SUB/MUL/DIV/MOD/EXP)任一操作数非数值不折;BigInt 混合
|
||||
//! (一 BigInt 一非 BigInt)不折(运行期抛 TypeError,BigInt 与 BigInt 有
|
||||
//! 独立指令族);SUB/MUL/DIV/MOD/EXP 的 BigInt 操作数不折(折值恒升 f64,
|
||||
//! 无法表示 BigInt 结果);DIV/MOD 除数为零不折、EXP 指数为负不折(保持
|
||||
//! 运行时指令为除零/负指数编码的唯一来源)。
|
||||
//! - ADD 的 int+int 经 `checked_add` 在 i32 内保 `Int`,溢出升 `Number`
|
||||
//! (镜像运行时 `int_add`);其余组合 f64 加(不做恒等捷径,负零操作数
|
||||
//! 经实加得 `+0.0`)。
|
||||
//! - UNARY_PLUS 作用 BigInt 不折(运行期抛 TypeError)。
|
||||
//!
|
||||
//! B 组逻辑短路:结果恒为某一操作数的原值(无类型转换,任何类型安全),
|
||||
//! 仅左操作数已知即可选支,右操作数类型不限。
|
||||
|
||||
use oxide_bytecode::module::Constant;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_runtime_api::{to_boolean, to_int32, to_number};
|
||||
use oxide_types::string_forge::encode_key;
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
/// 常量转 `JsValue`(纯 NaN-box 构造,零分配):`Int`/`Number`/`Boolean`/
|
||||
/// `Null`/`Undefined` 五臂;`BigInt`/`String` 是引用形态(指针载荷),不在此
|
||||
/// 转换,由调用方按常量类型分派处理。
|
||||
fn const_to_jsvalue(c: &Constant) -> Option<JsValue> {
|
||||
match c {
|
||||
Constant::Int(i) => Some(JsValue::int(*i)),
|
||||
Constant::Number(d) => Some(JsValue::float(*d)),
|
||||
Constant::Boolean(b) => Some(JsValue::bool(*b)),
|
||||
Constant::Null => Some(JsValue::null()),
|
||||
Constant::Undefined => Some(JsValue::undefined()),
|
||||
Constant::BigInt(_) | Constant::String(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// 常量的数值(`Int`/`Number` 臂,调用方已守卫非 BigInt 数值)。
|
||||
fn const_to_number(c: &Constant) -> f64 {
|
||||
to_number(const_to_jsvalue(c).expect("数值常量(非 BigInt)必有 JsValue 形态"))
|
||||
}
|
||||
|
||||
/// 是否为数值常量(`Int`/`Number`/`BigInt` 三臂)。
|
||||
fn is_numeric(c: &Constant) -> bool {
|
||||
matches!(c, Constant::Int(_) | Constant::Number(_) | Constant::BigInt(_))
|
||||
}
|
||||
|
||||
/// 是否为 BigInt 常量。
|
||||
fn is_bigint(c: &Constant) -> bool {
|
||||
matches!(c, Constant::BigInt(_))
|
||||
}
|
||||
|
||||
/// 常量的布尔值(`ToBoolean` 口径):BigInt 臂判零、字符串臂判非空(池键形态
|
||||
/// 空串即空串),其余经 `const_to_jsvalue` 加 `to_boolean`。
|
||||
fn is_truthy(c: &Constant) -> bool {
|
||||
match c {
|
||||
Constant::BigInt(b) => *b != num_bigint::BigInt::from(0),
|
||||
Constant::String(s) => !s.is_empty(),
|
||||
_ => to_boolean(const_to_jsvalue(c).expect("非 BigInt/String 常量必有 JsValue 形态")),
|
||||
}
|
||||
}
|
||||
|
||||
/// 常量是否为 nullish(`Null`/`Undefined` 两臂)。
|
||||
fn is_nullish(c: &Constant) -> bool {
|
||||
matches!(c, Constant::Null | Constant::Undefined)
|
||||
}
|
||||
|
||||
/// A 组一元折叠:按操作码计算折值,守卫命中返回 `None`。
|
||||
///
|
||||
/// 折值编码逐运算符镜像运行时产物:
|
||||
/// - `VOID`:恒 `Undefined`(操作数副作用已在发射期为独立指令,本指令恒装 undefined)
|
||||
/// - `NOT`:`Boolean`(`ToBoolean` 取反,任意常量类型安全)
|
||||
/// - `TYPEOF`:`String`(池键形态,逐类型镜像运行时 `TYPEOF_TEXTS` 分派:
|
||||
/// Int/Number 归 "number"、BigInt 归 "bigint"、Boolean 归 "boolean"、
|
||||
/// Null 归 "object"、String 归 "string"、Undefined 归 "undefined")
|
||||
/// - `NEG`:BigInt 取负保 `BigInt`;其余数值恒 `Number`(NEG 恒升 double,
|
||||
/// 不保 `Int`);非数值不折
|
||||
/// - `UNARY_PLUS`:`Int`/`Number` 恒 `Number`(`ToNumber`);BigInt 不折
|
||||
/// (运行期抛 TypeError)
|
||||
/// - `BIT_NOT`:BigInt 按位取反保 `BigInt`;其余数值恒 `Int`(`ToInt32` 取反)
|
||||
pub fn fold_unary(op: OpCode, c: &Constant) -> Option<Constant> {
|
||||
match op {
|
||||
OpCode::VOID => Some(Constant::Undefined),
|
||||
OpCode::NOT => Some(Constant::Boolean(!is_truthy(c))),
|
||||
OpCode::TYPEOF => {
|
||||
let text = match c {
|
||||
Constant::Int(_) | Constant::Number(_) => "number",
|
||||
Constant::BigInt(_) => "bigint",
|
||||
Constant::Boolean(_) => "boolean",
|
||||
Constant::Null => "object",
|
||||
Constant::String(_) => "string",
|
||||
Constant::Undefined => "undefined",
|
||||
};
|
||||
let units: Vec<u16> = text.encode_utf16().collect();
|
||||
Some(Constant::String(encode_key(&units)))
|
||||
}
|
||||
OpCode::NEG => match c {
|
||||
Constant::BigInt(b) => Some(Constant::BigInt(-b.clone())),
|
||||
Constant::Int(i) => Some(Constant::Number(-(*i as f64))),
|
||||
Constant::Number(d) => Some(Constant::Number(-*d)),
|
||||
_ => None,
|
||||
},
|
||||
OpCode::UNARY_PLUS => match c {
|
||||
Constant::Int(i) => Some(Constant::Number(*i as f64)),
|
||||
Constant::Number(d) => Some(Constant::Number(*d)),
|
||||
_ => None,
|
||||
},
|
||||
OpCode::BIT_NOT => match c {
|
||||
Constant::BigInt(b) => Some(Constant::BigInt(!b.clone())),
|
||||
Constant::Int(_) | Constant::Number(_) => Some(Constant::Int(!to_int32(
|
||||
const_to_jsvalue(c).expect("数值常量(非 BigInt)必有 JsValue 形态"),
|
||||
))),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A 组二元算术折叠:按操作码计算折值,守卫命中返回 `None`。
|
||||
///
|
||||
/// 折值编码逐运算符镜像运行时产物:
|
||||
/// - `ADD`:int+int 经 `checked_add` 在 i32 内保 `Int`,溢出升 `Number`
|
||||
/// (镜像 `int_add`);BigInt+BigInt 精确加;其余组合 f64 加(实加,
|
||||
/// 不做恒等捷径)
|
||||
/// - `SUB`/`MUL`/`DIV`/`MOD`:恒 `Number` 的 f64 运算(镜像 `binary_arith!`
|
||||
/// 宏的 `as f64`);DIV/MOD 除数为零不折
|
||||
/// - `EXP`:恒 `Number` 的 `powf`(镜像 `exp_result`);指数为负不折
|
||||
pub fn fold_binary(op: OpCode, l: &Constant, r: &Constant) -> Option<Constant> {
|
||||
// 两操作数均须数值;BigInt 混合(一 BigInt 一非 BigInt)不折。
|
||||
if !is_numeric(l) || !is_numeric(r) {
|
||||
return None;
|
||||
}
|
||||
if is_bigint(l) != is_bigint(r) {
|
||||
return None;
|
||||
}
|
||||
match op {
|
||||
OpCode::ADD => {
|
||||
if is_bigint(l) {
|
||||
return match (l, r) {
|
||||
(Constant::BigInt(a), Constant::BigInt(b)) => Some(Constant::BigInt(a + b)),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
// int+int:checked_add 在 i32 内保 Int,溢出升 f64(镜像 int_add)。
|
||||
if let (Constant::Int(a), Constant::Int(b)) = (l, r) {
|
||||
return a
|
||||
.checked_add(*b)
|
||||
.map(Constant::Int)
|
||||
.or(Some(Constant::Number(*a as f64 + *b as f64)));
|
||||
}
|
||||
// 其余组合 f64 实加(负零操作数经实加得 +0.0,不取恒等捷径)。
|
||||
Some(Constant::Number(const_to_number(l) + const_to_number(r)))
|
||||
}
|
||||
OpCode::SUB | OpCode::MUL | OpCode::DIV | OpCode::MOD | OpCode::EXP => {
|
||||
// BigInt 操作数不折:折值恒升 f64,无法表示 BigInt 结果。
|
||||
if is_bigint(l) {
|
||||
return None;
|
||||
}
|
||||
// 除零守卫:Int(0) 与 Number(±0.0) 均判零(v == 0.0 对 -0.0 亦真);
|
||||
// 负指数守卫:Int 与 Number 负值均判负。命中即不折,落回运行时指令。
|
||||
if (matches!(op, OpCode::DIV | OpCode::MOD) && const_to_number(r) == 0.0)
|
||||
|| (op == OpCode::EXP && const_to_number(r) < 0.0)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let (ln, rn) = (const_to_number(l), const_to_number(r));
|
||||
Some(match op {
|
||||
OpCode::SUB => Constant::Number(ln - rn),
|
||||
OpCode::MUL => Constant::Number(ln * rn),
|
||||
OpCode::DIV => Constant::Number(ln / rn),
|
||||
OpCode::MOD => Constant::Number(ln % rn),
|
||||
OpCode::EXP => Constant::Number(ln.powf(rn)),
|
||||
_ => unreachable!("守卫已限定 SUB/MUL/DIV/MOD/EXP"),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// B 组逻辑短路选支:左操作数已知时返回选定操作数(`true` = 左,`false` =
|
||||
/// 右),左操作数未知返回 `None`。
|
||||
///
|
||||
/// 结果恒为某一操作数的原值(无类型转换):
|
||||
/// - `AND`:左真选右、左假选左
|
||||
/// - `OR`:左真选左、左假选右
|
||||
/// - `NULLISH`:左 nullish 选右、左非 nullish 选左
|
||||
pub fn short_circuit(op: OpCode, l: &Constant) -> Option<bool> {
|
||||
match op {
|
||||
OpCode::AND => Some(!is_truthy(l)),
|
||||
OpCode::OR => Some(is_truthy(l)),
|
||||
OpCode::NULLISH => Some(!is_nullish(l)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//! 常量折叠 pass:单向前扫常量传播加就地改写(IR 层)。
|
||||
//!
|
||||
//! `fold` 对每个函数(递归 nested,每个 nested 函数有独立常量池与指令流,独立前扫)
|
||||
//! 运行单向前扫:维护 per-register known 表记录各虚拟寄存器的已知常量值,命中
|
||||
//! 改写表即就地改写——A 组一元与算术常量折叠改写为 `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 组改写禁用(不新增常量),B 组
|
||||
//! (MOV)不受影响。
|
||||
//!
|
||||
//! 折值计算复用 `oxide_runtime_api::coercion` 的纯函数族(`to_number` /
|
||||
//! `to_int32` / `to_boolean`),与 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
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
//! 单向前扫常量传播:per-register known 表 + 汇合点清空 + 就地改写。
|
||||
//!
|
||||
//! pass 形态:对单个函数逐条前扫,维护 `known: Vec<Option<Constant>>`(按 vreg
|
||||
//! 号索引)记录各寄存器的已知常量值。命中改写表即就地改写指令(改 op 与操作数
|
||||
//! 槽,指令位置不动),不删除任何指令、不重映射 `label_pos`。
|
||||
//!
|
||||
//! 汇合点健全性:`label_pos` 指向的指令下标(控制流汇合点)整体清空 known 表——
|
||||
//! 单向前扫状态只在前一条路径上有效,跨汇合的陈旧知识会误折。
|
||||
//!
|
||||
//! 改写后失去消费者的 `LOAD_CONST` 与死 `MOV` 由下游 DCE 清理(保守 DCE 的 use
|
||||
//! 计数迭代删纯指令、精确 DCE 删死 MOV),本 pass 不产生残留。
|
||||
|
||||
use oxide_bytecode::module::Constant;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
use oxide_ir::IRFunction;
|
||||
|
||||
use crate::fold_table;
|
||||
|
||||
/// 常量传播与折叠:单函数单向前扫,就地改写。
|
||||
///
|
||||
/// 返回是否发生改写(仅调试日志用)。不删指令、不重映射 label;改写只改变指令
|
||||
/// 的 op 与操作数,不改变跳转结构,CFG 的块划分与边集不变,由下游 DCE 在折叠后
|
||||
/// 的指令流上重建 CFG 吸收。
|
||||
pub fn fold_function(f: &mut IRFunction) -> bool {
|
||||
let insts = &mut f.insts;
|
||||
let constants = &mut f.constants;
|
||||
let label_pos = &f.label_pos;
|
||||
|
||||
// 预计算 label 目标位图(控制流汇合点)。
|
||||
let mut label_targets = vec![false; insts.len()];
|
||||
for &pos in label_pos.iter().flatten() {
|
||||
if pos < insts.len() {
|
||||
label_targets[pos] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// known 表上界 = 函数内 def/use 寄存器号最大值加一。
|
||||
let max_reg = insts.iter().fold(0u32, |m, inst| {
|
||||
let mut mx = m;
|
||||
if let Some(r) = inst.def_reg() {
|
||||
mx = mx.max(r);
|
||||
}
|
||||
for r in inst.use_regs() {
|
||||
mx = mx.max(r);
|
||||
}
|
||||
mx
|
||||
});
|
||||
|
||||
let mut known: Vec<Option<Constant>> = vec![None; (max_reg + 1) as usize];
|
||||
let mut changed = false;
|
||||
|
||||
for (i, inst) in insts.iter_mut().enumerate() {
|
||||
// 汇合点:label 目标整体清空 known(单向前扫状态只在前一条路径上有效)。
|
||||
if label_targets[i] {
|
||||
known.fill(None);
|
||||
}
|
||||
|
||||
match inst.op {
|
||||
// LOAD_CONST 是常量值来源:known[rd] = constants[idx]。
|
||||
OpCode::LOAD_CONST => {
|
||||
if let Some(rd) = inst.def_reg() {
|
||||
known[rd as usize] = match inst.a {
|
||||
Operand::Const(idx) => constants.get(idx as usize).cloned(),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// MOV 是纯拷贝:known[rd] = known[src]。
|
||||
OpCode::MOV => {
|
||||
if let Some(rd) = inst.def_reg() {
|
||||
known[rd as usize] = match inst.a {
|
||||
Operand::Reg(src) => known.get(src as usize).and_then(|c| c.clone()),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
continue;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// A 组:常量折叠(操作数均已知)→ 改写为 LOAD_CONST。
|
||||
let folded = match inst.op {
|
||||
// VOID 无操作数,恒折 Undefined。
|
||||
OpCode::VOID => Some(Constant::Undefined),
|
||||
// 其余一元:操作数须为已知寄存器。
|
||||
OpCode::NOT | OpCode::TYPEOF | OpCode::NEG | OpCode::UNARY_PLUS | OpCode::BIT_NOT => {
|
||||
match inst.a {
|
||||
Operand::Reg(x) => known
|
||||
.get(x as usize)
|
||||
.and_then(|c| c.as_ref())
|
||||
.and_then(|c| fold_table::fold_unary(inst.op, c)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
// 二元算术:两操作数须为已知寄存器。
|
||||
OpCode::ADD | OpCode::SUB | OpCode::MUL | OpCode::DIV | OpCode::MOD | OpCode::EXP => {
|
||||
match (inst.a, inst.b) {
|
||||
(Operand::Reg(x), Operand::Reg(y)) => match (
|
||||
known.get(x as usize).and_then(|c| c.as_ref()),
|
||||
known.get(y as usize).and_then(|c| c.as_ref()),
|
||||
) {
|
||||
(Some(l), Some(r)) => fold_table::fold_binary(inst.op, l, r),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(value) = folded {
|
||||
// 新常量入池(去重加溢出守卫);池满时 A 组失效,跳过改写。
|
||||
if let Some(idx) = intern(constants, &value) {
|
||||
*inst = Inst::load_const(inst.rd, idx);
|
||||
changed = true;
|
||||
if let Some(rd) = inst.def_reg() {
|
||||
known[rd as usize] = Some(value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// B 组:逻辑短路(左操作数已知)→ 改写为 MOV。
|
||||
let select_left = match (inst.op, inst.a) {
|
||||
(OpCode::AND | OpCode::OR | OpCode::NULLISH, Operand::Reg(x)) => known
|
||||
.get(x as usize)
|
||||
.and_then(|c| c.as_ref())
|
||||
.and_then(|c| fold_table::short_circuit(inst.op, c)),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(select_left) = select_left {
|
||||
let src = if select_left { inst.a } else { inst.b };
|
||||
*inst = Inst::inst_mov(inst.rd, src);
|
||||
changed = true;
|
||||
if let (Some(rd), Operand::Reg(s)) = (inst.def_reg(), src) {
|
||||
known[rd as usize] = known.get(s as usize).and_then(|c| c.clone());
|
||||
}
|
||||
} else {
|
||||
// 不可折:def 寄存器为不定值。
|
||||
if let Some(rd) = inst.def_reg() {
|
||||
known[rd as usize] = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changed
|
||||
}
|
||||
|
||||
/// 常量池判等:`Number` 臂按位模式比较(区分 `-0.0` 与 `+0.0`,与 emit 层
|
||||
/// `ConstantKey` 的 `to_bits` 口径一致),其余臂用派生 `PartialEq`。
|
||||
fn const_eq(a: &Constant, b: &Constant) -> bool {
|
||||
match (a, b) {
|
||||
(Constant::Number(x), Constant::Number(y)) => x.to_bits() == y.to_bits(),
|
||||
_ => a == b,
|
||||
}
|
||||
}
|
||||
|
||||
/// 新常量入池:线性扫描判等(命中复用既有下标);未命中推尾取新下标;池满
|
||||
/// (`u16::MAX`)时返回 `None` 禁用 A 组改写(B 组 MOV 不新增常量,不受影响)。
|
||||
fn intern(constants: &mut Vec<Constant>, c: &Constant) -> Option<u16> {
|
||||
if let Some(idx) = constants.iter().position(|x| const_eq(x, c)) {
|
||||
return Some(idx as u16);
|
||||
}
|
||||
if constants.len() >= u16::MAX as usize {
|
||||
return None;
|
||||
}
|
||||
constants.push(c.clone());
|
||||
Some((constants.len() - 1) as u16)
|
||||
}
|
||||
Reference in New Issue
Block a user