use crate::{MachineEnv, PReg, RegClass};
struct Cursor<'a> {
registers: &'a [PReg],
index: usize,
offset: usize,
}
impl<'a> Cursor<'a> {
#[inline]
fn new(registers: &'a [PReg], offset_hint: usize) -> Self {
let offset = if registers.len() > 0 {
offset_hint % registers.len()
} else {
0
};
Self {
registers,
index: 0,
offset,
}
}
#[inline]
fn wrap(index: usize, end: usize) -> usize {
if index >= end {
index - end
} else {
index
}
}
#[inline]
fn advance(&mut self) -> PReg {
let loc = Self::wrap(self.index + self.offset, self.registers.len());
let reg = self.registers[loc];
self.index += 1;
reg
}
#[inline]
fn done(&self) -> bool {
self.index >= self.registers.len()
}
}
pub struct RegTraversalIter<'a> {
is_fixed: bool,
fixed: Option<PReg>,
use_hint: bool,
hint: Option<PReg>,
preferred: Cursor<'a>,
non_preferred: Cursor<'a>,
}
impl<'a> RegTraversalIter<'a> {
pub fn new(
env: &'a MachineEnv,
class: RegClass,
fixed: Option<PReg>,
hint: Option<PReg>,
offset: usize,
) -> Self {
debug_assert!(fixed != Some(PReg::invalid()));
debug_assert!(hint != Some(PReg::invalid()));
let class = class as u8 as usize;
let preferred = Cursor::new(&env.preferred_regs_by_class[class], offset);
let non_preferred = Cursor::new(&env.non_preferred_regs_by_class[class], offset);
Self {
is_fixed: fixed.is_some(),
fixed,
use_hint: hint.is_some(),
hint,
preferred,
non_preferred,
}
}
}
impl<'a> core::iter::Iterator for RegTraversalIter<'a> {
type Item = PReg;
fn next(&mut self) -> Option<PReg> {
if self.is_fixed {
return self.fixed.take();
}
if self.use_hint {
self.use_hint = false;
return self.hint;
}
while !self.preferred.done() {
let reg = self.preferred.advance();
if Some(reg) == self.hint {
continue; }
return Some(reg);
}
while !self.non_preferred.done() {
let reg = self.non_preferred.advance();
if Some(reg) == self.hint {
continue; }
return Some(reg);
}
None
}
}