regalloc: 建图只遍历活集 + rewrite use 点按指令分组

graph 建边由逐指令全 node 扫描(O(insts × nodes),活集小也扫全表)
改为只遍历该指令活集中置位的 vreg(u64 位集 trailing_zeros 升序,
与 node 表升序遍历逐字节同序,确定性不漂移)。rewrite 主循环对每
指令全扫全局 uses 表(O(insts × spills) 二次方)改为按指令分组的
use 点列表,只取本指令的 use 点。

实测(debug,test262 identifiers 最大样本):plain 17.0.0
16.9s → 1.06s(-94%),class 9.0.0 7.0s → 1.61s(-77%),
均低于 2s 达标线;identifiers 子集 268/268 全 PASS(原 32 个
10s 超时全部转 PASS)。
This commit is contained in:
2026-08-16 03:26:57 +08:00
parent 9bbe5ae67a
commit 63ccb0fcf3
2 changed files with 33 additions and 17 deletions
+24 -10
View File
@@ -251,10 +251,20 @@ pub(super) fn build(
adj_sets.entry(v).or_default();
}
for i in 0..inst_count {
// 只遍历该指令活集中置位的 vreg(u64 位集逐字 trailing_zeros 升序),
// 替代逐 node 全扫描——活集小(典型 2-4)时每指令从 O(nodes) 降到 O(live)。
// 升序遍历保证加边顺序与原 node 表升序扫描逐字节一致(确定性不漂移)。
let mut at_i: Vec<u32> = Vec::new();
for &v in &node_ids {
if oxide_liveness::bitset_get(&live.inst_live_before[i], v as usize) {
at_i.push(v);
let before = &live.inst_live_before[i];
for (word_idx, word) in before.iter().enumerate() {
let mut bits = *word;
while bits != 0 {
let bit = bits.trailing_zeros() as usize;
let v = (word_idx * 64 + bit) as u32;
if nodes.contains_key(&v) {
at_i.push(v);
}
bits &= bits - 1;
}
}
for fr in fresh {
@@ -275,13 +285,17 @@ pub(super) fn build(
// 寄存器同色会覆盖其值(elision 解构返回值被覆盖),须补此干涉边。
if let Some(d) = f.insts[i].def_reg() {
if nodes.contains_key(&d) {
for &v in &node_ids {
if v == d {
continue;
}
if oxide_liveness::bitset_get(&live.inst_live_after[i], v as usize) {
adj_sets.entry(d).or_default().insert(v);
adj_sets.entry(v).or_default().insert(d);
let after = &live.inst_live_after[i];
for (word_idx, word) in after.iter().enumerate() {
let mut bits = *word;
while bits != 0 {
let bit = bits.trailing_zeros() as usize;
let v = (word_idx * 64 + bit) as u32;
if v != d && nodes.contains_key(&v) {
adj_sets.entry(d).or_default().insert(v);
adj_sets.entry(v).or_default().insert(d);
}
bits &= bits - 1;
}
}
}