diff --git a/crates/oxide_regalloc/src/graph.rs b/crates/oxide_regalloc/src/graph.rs index 9c1f8817..d65c3d0a 100644 --- a/crates/oxide_regalloc/src/graph.rs +++ b/crates/oxide_regalloc/src/graph.rs @@ -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 = 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; } } } diff --git a/crates/oxide_regalloc/src/rewrite.rs b/crates/oxide_regalloc/src/rewrite.rs index 28d8adb7..a5003a5c 100644 --- a/crates/oxide_regalloc/src/rewrite.rs +++ b/crates/oxide_regalloc/src/rewrite.rs @@ -22,10 +22,12 @@ use crate::alloc_map::{Alloc, AllocMap}; /// 就地改写 f.insts + f.label_pos。 pub(super) fn run(f: &mut IRFunction, map: &AllocMap) { // ── 1. spill 查询表 ── - // defs_at: (inst, vreg) → def-fresh 色;uses_at: (inst, vreg) → use-fresh 色;spill_slot: vreg → slot + // defs_at: (inst, vreg) → def-fresh 色;spill_slot: vreg → slot。 + // use 点按 inst 分组(use_spill_pts[inst]),主循环只取本 inst 的 use 点—— + // 全表扫描会构成 O(insts × spills) 二次方(大函数数千 spill 点 × 数万指令)。 let mut defs_at: BTreeMap<(usize, u32), u32> = BTreeMap::new(); - let mut uses_at: BTreeMap<(usize, u32), u32> = BTreeMap::new(); let mut spill_slot: BTreeMap = BTreeMap::new(); + let mut use_spill_pts: Vec> = vec![Vec::new(); f.insts.len()]; for sp in &map.spills { spill_slot.insert(sp.vreg, sp.slot); for &(inst, fresh_id) in &sp.defs { @@ -35,7 +37,7 @@ pub(super) fn run(f: &mut IRFunction, map: &AllocMap) { } for &(inst, fresh_id) in &sp.uses { if let Some(Alloc::Phys(c)) = map.map.get(&fresh_id) { - uses_at.insert((inst, sp.vreg), *c); + use_spill_pts[inst].push((sp.vreg, *c)); } } } @@ -56,12 +58,12 @@ pub(super) fn run(f: &mut IRFunction, map: &AllocMap) { // RMW 判定:inst 同时 def 且 use 同一 spilled vreg let rmw_v = inst .def_reg() - .filter(|d| uses_at.contains_key(&(i, *d)) && spill_slot.contains_key(d)); + .filter(|d| spill_slot.contains_key(d) && use_spill_pts[i].iter().any(|(v, _)| *v == *d)); - // before-插入:非 RMW 的 use 点 UNSPILL + // before-插入:非 RMW 的 use 点 UNSPILL(取本 inst 分组的 use 点) let mut use_unspills: Vec<(u32, u32)> = Vec::new(); // (vreg, fresh 色) - for (&(inst_at, vreg), &color) in &uses_at { - if inst_at == i && rmw_v != Some(vreg) { + for &(vreg, color) in &use_spill_pts[i] { + if rmw_v != Some(vreg) { use_unspills.push((vreg, color)); } }