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:
@@ -251,11 +251,21 @@ pub(super) fn build(
|
|||||||
adj_sets.entry(v).or_default();
|
adj_sets.entry(v).or_default();
|
||||||
}
|
}
|
||||||
for i in 0..inst_count {
|
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();
|
let mut at_i: Vec<u32> = Vec::new();
|
||||||
for &v in &node_ids {
|
let before = &live.inst_live_before[i];
|
||||||
if oxide_liveness::bitset_get(&live.inst_live_before[i], v as usize) {
|
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);
|
at_i.push(v);
|
||||||
}
|
}
|
||||||
|
bits &= bits - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for fr in fresh {
|
for fr in fresh {
|
||||||
if fr.at == i {
|
if fr.at == i {
|
||||||
@@ -275,14 +285,18 @@ pub(super) fn build(
|
|||||||
// 寄存器同色会覆盖其值(elision 解构返回值被覆盖),须补此干涉边。
|
// 寄存器同色会覆盖其值(elision 解构返回值被覆盖),须补此干涉边。
|
||||||
if let Some(d) = f.insts[i].def_reg() {
|
if let Some(d) = f.insts[i].def_reg() {
|
||||||
if nodes.contains_key(&d) {
|
if nodes.contains_key(&d) {
|
||||||
for &v in &node_ids {
|
let after = &live.inst_live_after[i];
|
||||||
if v == d {
|
for (word_idx, word) in after.iter().enumerate() {
|
||||||
continue;
|
let mut bits = *word;
|
||||||
}
|
while bits != 0 {
|
||||||
if oxide_liveness::bitset_get(&live.inst_live_after[i], v as usize) {
|
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(d).or_default().insert(v);
|
||||||
adj_sets.entry(v).or_default().insert(d);
|
adj_sets.entry(v).or_default().insert(d);
|
||||||
}
|
}
|
||||||
|
bits &= bits - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,12 @@ use crate::alloc_map::{Alloc, AllocMap};
|
|||||||
/// 就地改写 f.insts + f.label_pos。
|
/// 就地改写 f.insts + f.label_pos。
|
||||||
pub(super) fn run(f: &mut IRFunction, map: &AllocMap) {
|
pub(super) fn run(f: &mut IRFunction, map: &AllocMap) {
|
||||||
// ── 1. spill 查询表 ──
|
// ── 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 defs_at: BTreeMap<(usize, u32), u32> = BTreeMap::new();
|
||||||
let mut uses_at: BTreeMap<(usize, u32), u32> = BTreeMap::new();
|
|
||||||
let mut spill_slot: BTreeMap<u32, u16> = BTreeMap::new();
|
let mut spill_slot: BTreeMap<u32, u16> = BTreeMap::new();
|
||||||
|
let mut use_spill_pts: Vec<Vec<(u32, u32)>> = vec![Vec::new(); f.insts.len()];
|
||||||
for sp in &map.spills {
|
for sp in &map.spills {
|
||||||
spill_slot.insert(sp.vreg, sp.slot);
|
spill_slot.insert(sp.vreg, sp.slot);
|
||||||
for &(inst, fresh_id) in &sp.defs {
|
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 {
|
for &(inst, fresh_id) in &sp.uses {
|
||||||
if let Some(Alloc::Phys(c)) = map.map.get(&fresh_id) {
|
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
|
// RMW 判定:inst 同时 def 且 use 同一 spilled vreg
|
||||||
let rmw_v = inst
|
let rmw_v = inst
|
||||||
.def_reg()
|
.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 色)
|
let mut use_unspills: Vec<(u32, u32)> = Vec::new(); // (vreg, fresh 色)
|
||||||
for (&(inst_at, vreg), &color) in &uses_at {
|
for &(vreg, color) in &use_spill_pts[i] {
|
||||||
if inst_at == i && rmw_v != Some(vreg) {
|
if rmw_v != Some(vreg) {
|
||||||
use_unspills.push((vreg, color));
|
use_unspills.push((vreg, color));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user