use crate::{MachineEnv, PReg, PRegSet, PRegSetIter, RegClass};
struct Cursor {
first: PRegSetIter,
second: PRegSetIter,
}
impl Cursor {
#[inline]
fn new(registers: &PRegSet, class: RegClass, offset_hint: usize) -> Self {
let mut mask = PRegSet::empty();
mask.add_up_to(PReg::new(offset_hint % PReg::MAX, class));
let first = *registers & mask.invert();
let second = *registers & mask;
Self {
first: first.into_iter(),
second: second.into_iter(),
}
}
fn next(&mut self) -> Option<PReg> {
self.first.next().or_else(|| self.second.next())
}
}
pub struct RegTraversalIter {
is_fixed: bool,
fixed: Option<PReg>,
use_hint: bool,
hint: Option<PReg>,
preferred: Cursor,
non_preferred: Cursor,
limit: Option<usize>,
}
impl RegTraversalIter {
pub fn new(
env: &MachineEnv,
class: RegClass,
fixed: Option<PReg>,
hint: Option<PReg>,
offset: usize,
limit: Option<usize>,
) -> Self {
debug_assert!(fixed != Some(PReg::invalid()));
debug_assert!(hint != Some(PReg::invalid()));
let class_index = class as u8 as usize;
let preferred = Cursor::new(&env.preferred_regs_by_class[class_index], class, offset);
let non_preferred =
Cursor::new(&env.non_preferred_regs_by_class[class_index], class, offset);
Self {
is_fixed: fixed.is_some(),
fixed,
use_hint: hint.is_some(),
hint,
preferred,
non_preferred,
limit,
}
}
}
impl core::iter::Iterator for RegTraversalIter {
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;
if self.hint.unwrap().hw_enc() < self.limit.unwrap_or(usize::MAX) {
return self.hint;
}
}
while let Some(reg) = self.preferred.next() {
if Some(reg) == self.hint || reg.hw_enc() >= self.limit.unwrap_or(usize::MAX) {
continue; }
return Some(reg);
}
while let Some(reg) = self.non_preferred.next() {
if Some(reg) == self.hint || reg.hw_enc() >= self.limit.unwrap_or(usize::MAX) {
continue; }
return Some(reg);
}
None
}
}