some start for homemade regalloc
This commit is contained in:
parent
4664240e08
commit
38a00cbaa0
|
@ -23,8 +23,8 @@ hbjit = { path = "jit" }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
debug = true
|
#debug = true
|
||||||
#strip = true
|
strip = true
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ panic = "abort"
|
||||||
rustflags = ["-Zfmt-debug=none", "-Zlocation-detail=none"]
|
rustflags = ["-Zfmt-debug=none", "-Zlocation-detail=none"]
|
||||||
inherits = "release"
|
inherits = "release"
|
||||||
opt-level = "z"
|
opt-level = "z"
|
||||||
strip = true
|
strip = "debuginfo"
|
||||||
lto = true
|
lto = true
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
|
@ -20,9 +20,9 @@ log = "0.4.22"
|
||||||
[dependencies.regalloc2]
|
[dependencies.regalloc2]
|
||||||
git = "https://github.com/jakubDoka/regalloc2"
|
git = "https://github.com/jakubDoka/regalloc2"
|
||||||
branch = "reuse-allocations"
|
branch = "reuse-allocations"
|
||||||
features = ["trace-log"]
|
default-features = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std", "regalloc2/trace-log"]
|
||||||
std = []
|
std = []
|
||||||
no_log = ["log/max_level_off"]
|
no_log = ["log/max_level_off"]
|
||||||
|
|
|
@ -68,6 +68,7 @@ pub mod fs;
|
||||||
pub mod fuzz;
|
pub mod fuzz;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
pub mod regalloc;
|
||||||
pub mod son;
|
pub mod son;
|
||||||
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
150
lang/src/regalloc.rs
Normal file
150
lang/src/regalloc.rs
Normal file
|
@ -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<Item = Nid>;
|
||||||
|
fn params_of(&self, nid: Nid) -> impl Iterator<Item = Nid>;
|
||||||
|
fn args_of(&self, nid: Nid) -> impl Iterator<Item = Nid>;
|
||||||
|
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<Bundle>,
|
||||||
|
pub reg_to_node: Vec<Reg>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Bundle {
|
||||||
|
//unit_range: Range<usize>,
|
||||||
|
//set: BitSet,
|
||||||
|
taken: Vec<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bundle {
|
||||||
|
fn new(size: usize) -> Self {
|
||||||
|
Self { taken: vec![false; size] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(&mut self, range: Range<usize>) {
|
||||||
|
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<Block>,
|
||||||
|
pub instrs: Vec<Nid>,
|
||||||
|
pub id_to_instr: Vec<Nid>,
|
||||||
|
pub id_to_block: Vec<Nid>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Block {
|
||||||
|
pub range: Range<usize>,
|
||||||
|
pub start_id: Nid,
|
||||||
|
pub eld_id: Nid,
|
||||||
|
}
|
|
@ -9,10 +9,9 @@ use {
|
||||||
utils::{BitSet, Vc},
|
utils::{BitSet, Vc},
|
||||||
HashMap, Offset, PLoc, Reloc, Sig, Size, TypedReloc, Types,
|
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},
|
core::{assert_matches::debug_assert_matches, mem},
|
||||||
hbbytecode::{self as instrs, *},
|
hbbytecode::{self as instrs, *},
|
||||||
std::{boxed::Box, collections::BTreeMap},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Types {
|
impl Types {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![expect(dead_code)]
|
||||||
use {
|
use {
|
||||||
alloc::alloc,
|
alloc::alloc,
|
||||||
core::{
|
core::{
|
||||||
|
@ -176,15 +177,47 @@ impl BitSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self, len: usize) {
|
pub fn clear(&mut self, len: usize) {
|
||||||
if len > self.data_and_len().1 {
|
self.reserve(len);
|
||||||
self.grow(len.next_power_of_two().max(4 * Self::UNIT));
|
|
||||||
}
|
|
||||||
if self.is_inline() {
|
if self.is_inline() {
|
||||||
unsafe { self.inline &= Self::FLAG };
|
unsafe { self.inline &= Self::FLAG };
|
||||||
} else {
|
} else {
|
||||||
self.data_mut_and_len().0.fill(0);
|
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> {
|
pub struct BitSetIter<'a> {
|
||||||
|
|
Loading…
Reference in a new issue