use regalloc::{RealReg, Reg, VirtualReg, Writable};
use std::fmt::Debug;
#[cfg(feature = "arm32")]
const VALUE_REGS_PARTS: usize = 4;
#[cfg(not(feature = "arm32"))]
const VALUE_REGS_PARTS: usize = 2;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ValueRegs<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> {
parts: [R; VALUE_REGS_PARTS],
}
pub trait InvalidSentinel: Copy + Eq {
fn invalid_sentinel() -> Self;
fn is_invalid_sentinel(self) -> bool {
self == Self::invalid_sentinel()
}
}
impl InvalidSentinel for Reg {
fn invalid_sentinel() -> Self {
Reg::invalid()
}
}
impl InvalidSentinel for VirtualReg {
fn invalid_sentinel() -> Self {
VirtualReg::invalid()
}
}
impl InvalidSentinel for RealReg {
fn invalid_sentinel() -> Self {
RealReg::invalid()
}
}
impl InvalidSentinel for Writable<Reg> {
fn invalid_sentinel() -> Self {
Writable::from_reg(Reg::invalid_sentinel())
}
}
impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> ValueRegs<R> {
pub fn invalid() -> Self {
ValueRegs {
parts: [R::invalid_sentinel(); VALUE_REGS_PARTS],
}
}
pub fn is_valid(self) -> bool {
!self.parts[0].is_invalid_sentinel()
}
pub fn is_invalid(self) -> bool {
self.parts[0].is_invalid_sentinel()
}
pub fn only_reg(self) -> Option<R> {
if self.len() == 1 {
Some(self.parts[0])
} else {
None
}
}
pub fn regs(&self) -> &[R] {
&self.parts[0..self.len()]
}
}
#[cfg(feature = "arm32")]
impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> ValueRegs<R> {
pub fn one(reg: R) -> Self {
ValueRegs {
parts: [
reg,
R::invalid_sentinel(),
R::invalid_sentinel(),
R::invalid_sentinel(),
],
}
}
pub fn two(r1: R, r2: R) -> Self {
ValueRegs {
parts: [r1, r2, R::invalid_sentinel(), R::invalid_sentinel()],
}
}
pub fn four(r1: R, r2: R, r3: R, r4: R) -> Self {
ValueRegs {
parts: [r1, r2, r3, r4],
}
}
pub fn len(self) -> usize {
(self.parts[0] != R::invalid_sentinel()) as usize
+ (self.parts[1] != R::invalid_sentinel()) as usize
+ (self.parts[2] != R::invalid_sentinel()) as usize
+ (self.parts[3] != R::invalid_sentinel()) as usize
}
pub fn map<NewR, F>(self, f: F) -> ValueRegs<NewR>
where
NewR: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel,
F: Fn(R) -> NewR,
{
ValueRegs {
parts: [
f(self.parts[0]),
f(self.parts[1]),
f(self.parts[2]),
f(self.parts[3]),
],
}
}
}
#[cfg(not(feature = "arm32"))]
impl<R: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel> ValueRegs<R> {
pub fn one(reg: R) -> Self {
ValueRegs {
parts: [reg, R::invalid_sentinel()],
}
}
pub fn two(r1: R, r2: R) -> Self {
ValueRegs { parts: [r1, r2] }
}
pub fn len(self) -> usize {
(self.parts[0] != R::invalid_sentinel()) as usize
+ (self.parts[1] != R::invalid_sentinel()) as usize
}
pub fn map<NewR, F>(self, f: F) -> ValueRegs<NewR>
where
NewR: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel,
F: Fn(R) -> NewR,
{
ValueRegs {
parts: [f(self.parts[0]), f(self.parts[1])],
}
}
}
#[allow(dead_code)]
pub(crate) fn writable_value_regs(regs: ValueRegs<Reg>) -> ValueRegs<Writable<Reg>> {
regs.map(|r| Writable::from_reg(r))
}
#[allow(dead_code)]
pub(crate) fn non_writable_value_regs(regs: ValueRegs<Writable<Reg>>) -> ValueRegs<Reg> {
regs.map(|r| r.to_reg())
}