use core::fmt;
pub const MAX_PREGS: usize = 128;
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct PReg(u8);
impl PReg {
#[inline]
#[must_use]
pub const fn new(index: usize) -> Option<PReg> {
if index < MAX_PREGS {
Some(PReg(index as u8))
} else {
None
}
}
pub(crate) const fn from_index(index: u8) -> PReg {
PReg(index & (MAX_PREGS as u8 - 1))
}
#[inline]
#[must_use]
pub const fn index(self) -> usize {
self.0 as usize
}
}
impl fmt::Debug for PReg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "p{}", self.0)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct VReg(u32);
impl VReg {
pub const MAX: usize = (1 << 31) - 1;
pub(crate) const fn from_index(index: u32) -> VReg {
VReg(index & VIRT_MASK)
}
#[inline]
#[must_use]
pub const fn index(self) -> usize {
self.0 as usize
}
}
impl fmt::Debug for VReg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "%{}", self.0)
}
}
const VIRT_BIT: u32 = 1 << 31;
const VIRT_MASK: u32 = VIRT_BIT - 1;
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Reg(u32);
impl Reg {
#[inline]
#[must_use]
pub const fn as_phys(self) -> Option<PReg> {
if self.0 & VIRT_BIT == 0 {
Some(PReg::from_index(self.0 as u8))
} else {
None
}
}
#[inline]
#[must_use]
pub const fn as_virt(self) -> Option<VReg> {
if self.0 & VIRT_BIT != 0 {
Some(VReg(self.0 & VIRT_MASK))
} else {
None
}
}
#[inline]
#[must_use]
pub const fn is_virtual(self) -> bool {
self.0 & VIRT_BIT != 0
}
}
impl From<PReg> for Reg {
#[inline]
fn from(p: PReg) -> Reg {
Reg(u32::from(p.0))
}
}
impl From<VReg> for Reg {
#[inline]
fn from(v: VReg) -> Reg {
Reg(v.0 | VIRT_BIT)
}
}
impl fmt::Debug for Reg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match (self.as_phys(), self.as_virt()) {
(Some(p), _) => fmt::Debug::fmt(&p, f),
(_, Some(v)) => fmt::Debug::fmt(&v, f),
_ => Ok(()),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct RegClass(u8);
impl RegClass {
#[inline]
#[must_use]
pub const fn new(index: u8) -> RegClass {
RegClass(index)
}
#[inline]
#[must_use]
pub const fn index(self) -> usize {
self.0 as usize
}
}
impl fmt::Debug for RegClass {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "class{}", self.0)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct RegSet([u64; 2]);
impl RegSet {
pub const EMPTY: RegSet = RegSet([0, 0]);
#[must_use]
pub const fn of(regs: &[PReg]) -> RegSet {
let mut set = RegSet::EMPTY;
let mut i = 0;
while i < regs.len() {
set = set.with(regs[i]);
i += 1;
}
set
}
#[inline]
#[must_use]
pub const fn with(self, reg: PReg) -> RegSet {
let i = reg.index();
let mut words = self.0;
words[i >> 6] |= 1 << (i & 63);
RegSet(words)
}
#[inline]
#[must_use]
pub const fn without(self, reg: PReg) -> RegSet {
let i = reg.index();
let mut words = self.0;
words[i >> 6] &= !(1 << (i & 63));
RegSet(words)
}
#[inline]
#[must_use]
pub const fn contains(self, reg: PReg) -> bool {
let i = reg.index();
self.0[i >> 6] & (1 << (i & 63)) != 0
}
#[inline]
#[must_use]
pub const fn union(self, other: RegSet) -> RegSet {
RegSet([self.0[0] | other.0[0], self.0[1] | other.0[1]])
}
#[inline]
#[must_use]
pub const fn intersect(self, other: RegSet) -> RegSet {
RegSet([self.0[0] & other.0[0], self.0[1] & other.0[1]])
}
#[inline]
#[must_use]
pub const fn difference(self, other: RegSet) -> RegSet {
RegSet([self.0[0] & !other.0[0], self.0[1] & !other.0[1]])
}
#[inline]
#[must_use]
pub const fn is_empty(self) -> bool {
self.0[0] == 0 && self.0[1] == 0
}
#[inline]
#[must_use]
pub const fn len(self) -> usize {
(self.0[0].count_ones() + self.0[1].count_ones()) as usize
}
#[inline]
#[must_use]
pub const fn first(self) -> Option<PReg> {
if self.0[0] != 0 {
Some(PReg::from_index(self.0[0].trailing_zeros() as u8))
} else if self.0[1] != 0 {
Some(PReg::from_index(64 + self.0[1].trailing_zeros() as u8))
} else {
None
}
}
#[must_use]
pub fn iter(self) -> RegSetIter {
RegSetIter(self)
}
}
impl fmt::Debug for RegSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_set().entries(self.iter()).finish()
}
}
impl FromIterator<PReg> for RegSet {
fn from_iter<I: IntoIterator<Item = PReg>>(iter: I) -> RegSet {
iter.into_iter().fold(RegSet::EMPTY, RegSet::with)
}
}
#[derive(Clone, Debug)]
pub struct RegSetIter(RegSet);
impl Iterator for RegSetIter {
type Item = PReg;
#[inline]
fn next(&mut self) -> Option<PReg> {
let first = self.0.first()?;
self.0 = self.0.without(first);
Some(first)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.0.len();
(n, Some(n))
}
}
impl ExactSizeIterator for RegSetIter {}
#[cfg(test)]
mod tests {
use alloc::vec::Vec;
use super::*;
#[test]
fn test_reg_packing_round_trips_both_kinds() {
for i in [0u8, 1, 15, 127] {
let p = PReg::from_index(i);
assert_eq!(Reg::from(p).as_phys(), Some(p));
assert_eq!(Reg::from(p).as_virt(), None);
}
for i in [0u32, 1, 1 << 20, VIRT_MASK] {
let v = VReg::from_index(i);
assert_eq!(Reg::from(v).as_virt(), Some(v));
assert_eq!(Reg::from(v).as_phys(), None);
assert!(Reg::from(v).is_virtual());
}
}
#[test]
fn test_regset_high_word_and_iteration_order() {
let regs: Vec<PReg> = [0u8, 63, 64, 100, 127]
.iter()
.map(|&i| PReg::from_index(i))
.collect();
let set: RegSet = regs.iter().copied().collect();
assert_eq!(set.len(), 5);
assert_eq!(set.iter().collect::<Vec<_>>(), regs);
assert_eq!(set.iter().len(), 5);
assert_eq!(set.without(regs[0]).first(), Some(regs[1]));
let high = RegSet::of(&[PReg::from_index(100)]);
assert_eq!(high.first(), Some(PReg::from_index(100)));
assert!(set.difference(set).is_empty());
assert_eq!(set.intersect(high), high);
}
#[test]
fn test_preg_new_bounds() {
assert!(PReg::new(127).is_some());
assert!(PReg::new(128).is_none());
assert!(PReg::new(usize::MAX).is_none());
}
}