From 38a00cbaa09434324d209fc5f59480d2b6743fb3 Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Thu, 31 Oct 2024 14:56:55 +0100 Subject: [PATCH] some start for homemade regalloc --- Cargo.toml | 6 +- lang/Cargo.toml | 4 +- lang/src/lib.rs | 1 + lang/src/regalloc.rs | 150 +++++++++++++++++++++++++++++++++++++++++++ lang/src/son/hbvm.rs | 3 +- lang/src/utils.rs | 39 ++++++++++- 6 files changed, 193 insertions(+), 10 deletions(-) create mode 100644 lang/src/regalloc.rs diff --git a/Cargo.toml b/Cargo.toml index 50c8d8c6..d4c33a3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,8 +23,8 @@ hbjit = { path = "jit" } [profile.release] lto = true -debug = true -#strip = true +#debug = true +strip = true codegen-units = 1 panic = "abort" @@ -32,7 +32,7 @@ panic = "abort" rustflags = ["-Zfmt-debug=none", "-Zlocation-detail=none"] inherits = "release" opt-level = "z" -strip = true +strip = "debuginfo" lto = true codegen-units = 1 panic = "abort" diff --git a/lang/Cargo.toml b/lang/Cargo.toml index 3c404239..6c7e5e08 100644 --- a/lang/Cargo.toml +++ b/lang/Cargo.toml @@ -20,9 +20,9 @@ log = "0.4.22" [dependencies.regalloc2] git = "https://github.com/jakubDoka/regalloc2" branch = "reuse-allocations" -features = ["trace-log"] +default-features = false [features] -default = ["std"] +default = ["std", "regalloc2/trace-log"] std = [] no_log = ["log/max_level_off"] diff --git a/lang/src/lib.rs b/lang/src/lib.rs index b9153ddb..a06763a4 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -68,6 +68,7 @@ pub mod fs; pub mod fuzz; pub mod lexer; pub mod parser; +pub mod regalloc; pub mod son; mod utils; diff --git a/lang/src/regalloc.rs b/lang/src/regalloc.rs new file mode 100644 index 00000000..ecaccf70 --- /dev/null +++ b/lang/src/regalloc.rs @@ -0,0 +1,150 @@ +use {crate::reg::Reg, alloc::vec::Vec, core::ops::Range}; + +type Nid = u16; + +pub trait Ctx { + fn uses_of(&self, nid: Nid) -> impl Iterator; + fn params_of(&self, nid: Nid) -> impl Iterator; + fn args_of(&self, nid: Nid) -> impl Iterator; + fn dom_of(&self, nid: Nid) -> Nid; +} + +pub struct Env<'a, C: Ctx> { + ctx: &'a C, + func: &'a Func, + res: &'a mut Res, +} + +impl<'a, C: Ctx> Env<'a, C> { + pub fn new(ctx: &'a C, func: &'a Func, res: &'a mut Res) -> Self { + Self { ctx, func, res } + } + + pub fn run(&mut self) { + self.res.reg_to_node.clear(); + self.res.reg_to_node.resize(self.func.instrs.len(), 0); + + let mut bundle = Bundle::new(self.func.instrs.len()); + for &inst in &self.func.instrs { + for uinst in self.ctx.uses_of(inst) { + let mut cursor = self.ctx.dom_of(uinst); + while cursor != self.ctx.dom_of(inst) { + let mut range = self.func.blocks + [self.func.id_to_block[cursor as usize] as usize] + .range + .clone(); + range.start = range.start.max(inst as usize); + range.end = range.end.min(uinst as usize); + bundle.add(range); + cursor = self.ctx.dom_of(cursor); + } + } + + match self.res.bundles.iter_mut().enumerate().find(|(_, b)| !b.overlaps(&bundle)) { + Some((i, other)) => { + other.merge(&bundle); + bundle.clear(); + self.res.reg_to_node[inst as usize] = i as Reg; + } + None => { + self.res.reg_to_node[inst as usize] = self.res.bundles.len() as Reg; + self.res.bundles.push(bundle); + bundle = Bundle::new(self.func.instrs.len()); + } + } + } + } +} + +pub struct Res { + bundles: Vec, + pub reg_to_node: Vec, +} + +pub struct Bundle { + //unit_range: Range, + //set: BitSet, + taken: Vec, +} + +impl Bundle { + fn new(size: usize) -> Self { + Self { taken: vec![false; size] } + } + + fn add(&mut self, range: Range) { + self.taken[range].fill(true); + } + + fn overlaps(&self, other: &Self) -> bool { + self.taken.iter().zip(other.taken.iter()).any(|(a, b)| a & b) + } + + fn merge(&mut self, other: &Self) { + debug_assert!(!self.overlaps(other)); + self.taken.iter_mut().zip(other.taken.iter()).for_each(|(a, b)| *a = *b); + } + + fn clear(&mut self) { + self.taken.fill(false); + } + + //fn overlaps(&self, other: &Self) -> bool { + // if self.unit_range.start >= other.unit_range.end + // || self.unit_range.end <= other.unit_range.start + // { + // return false; + // } + + // let [mut a, mut b] = [self, other]; + // if a.unit_range.start > b.unit_range.start { + // mem::swap(&mut a, &mut b); + // } + // let [mut tmp_a, mut tmp_b] = [0; 2]; + // let [units_a, units_b] = [a.set.units(&mut tmp_a), b.set.units(&mut tmp_b)]; + // let len = a.unit_range.len().min(b.unit_range.len()); + // let [units_a, units_b] = + // [&units_a[b.unit_range.start - a.unit_range.start..][..len], &units_b[..len]]; + // units_a.iter().zip(units_b).any(|(&a, &b)| a & b != 0) + //} + + //fn merge(mut self, mut other: Self) -> Self { + // debug_assert!(!self.overlaps(&other)); + + // if self.unit_range.start > other.unit_range.start { + // mem::swap(&mut self, &mut other); + // } + + // let final_range = self.unit_range.start..self.unit_range.end.max(other.unit_range.end); + + // self.set.reserve(final_range.len()); + + // let mut tmp = 0; + // let other_units = other.set.units(&mut tmp); + + // match self.set.units_mut() { + // Ok(units) => { + // units[other.unit_range.start - self.unit_range.start..] + // .iter_mut() + // .zip(other_units) + // .for_each(|(a, b)| *a |= b); + // } + // Err(view) => view.add_mask(tmp), + // } + + // self + //} +} + +pub struct Func { + pub blocks: Vec, + pub instrs: Vec, + pub id_to_instr: Vec, + pub id_to_block: Vec, +} + +pub struct Block { + pub range: Range, + pub start_id: Nid, + pub eld_id: Nid, +} diff --git a/lang/src/son/hbvm.rs b/lang/src/son/hbvm.rs index 7a4d9040..cdb38236 100644 --- a/lang/src/son/hbvm.rs +++ b/lang/src/son/hbvm.rs @@ -9,10 +9,9 @@ use { utils::{BitSet, Vc}, HashMap, Offset, PLoc, Reloc, Sig, Size, TypedReloc, Types, }, - alloc::{borrow::ToOwned, string::String, vec::Vec}, + alloc::{borrow::ToOwned, boxed::Box, collections::BTreeMap, string::String, vec::Vec}, core::{assert_matches::debug_assert_matches, mem}, hbbytecode::{self as instrs, *}, - std::{boxed::Box, collections::BTreeMap}, }; impl Types { diff --git a/lang/src/utils.rs b/lang/src/utils.rs index a2f1d7ac..ca781bfb 100644 --- a/lang/src/utils.rs +++ b/lang/src/utils.rs @@ -1,3 +1,4 @@ +#![expect(dead_code)] use { alloc::alloc, core::{ @@ -176,15 +177,47 @@ impl BitSet { } pub fn clear(&mut self, len: usize) { - if len > self.data_and_len().1 { - self.grow(len.next_power_of_two().max(4 * Self::UNIT)); - } + self.reserve(len); if self.is_inline() { unsafe { self.inline &= Self::FLAG }; } else { self.data_mut_and_len().0.fill(0); } } + + pub fn units<'a>(&'a self, slot: &'a mut usize) -> &'a [usize] { + if self.is_inline() { + *slot = unsafe { self.inline } & !Self::FLAG; + core::slice::from_ref(slot) + } else { + self.data_and_len().0 + } + } + + pub fn reserve(&mut self, len: usize) { + if len > self.data_and_len().1 { + self.grow(len.next_power_of_two().max(4 * Self::UNIT)); + } + } + + pub fn units_mut(&mut self) -> Result<&mut [usize], &mut InlineBitSetView> { + if self.is_inline() { + Err(unsafe { + core::mem::transmute::<&mut usize, &mut InlineBitSetView>(&mut self.inline) + }) + } else { + Ok(self.data_mut_and_len().0) + } + } +} + +pub struct InlineBitSetView(usize); + +impl InlineBitSetView { + pub(crate) fn add_mask(&mut self, tmp: usize) { + debug_assert!(tmp & BitSet::FLAG == 0); + self.0 |= tmp; + } } pub struct BitSetIter<'a> {