some start for homemade regalloc
This commit is contained in:
parent
4664240e08
commit
38a00cbaa0
|
@ -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"
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -68,6 +68,7 @@ pub mod fs;
|
|||
pub mod fuzz;
|
||||
pub mod lexer;
|
||||
pub mod parser;
|
||||
pub mod regalloc;
|
||||
pub mod son;
|
||||
|
||||
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},
|
||||
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 {
|
||||
|
|
|
@ -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> {
|
||||
|
|
Loading…
Reference in a new issue