use crate::regs::{PhysReg, RegClass};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Role {
Use,
Def,
EarlyDef,
}
impl Role {
#[must_use]
pub const fn is_def(self) -> bool {
matches!(self, Role::Def | Role::EarlyDef)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Constraint {
Reg,
Any,
Stack,
Fixed(PhysReg),
Reuse(u8),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OperandDesc {
pub class: RegClass,
pub role: Role,
pub constraint: Constraint,
}
impl OperandDesc {
#[must_use]
pub const fn read(class: RegClass) -> Self {
Self { class, role: Role::Use, constraint: Constraint::Reg }
}
#[must_use]
pub const fn write(class: RegClass) -> Self {
Self { class, role: Role::Def, constraint: Constraint::Reg }
}
#[must_use]
pub const fn write_early(class: RegClass) -> Self {
Self { class, role: Role::EarlyDef, constraint: Constraint::Reg }
}
#[must_use]
pub const fn with(mut self, constraint: Constraint) -> Self {
self.constraint = constraint;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_role_that_writes_says_so_however_early_it_writes() {
assert!(Role::Def.is_def());
assert!(Role::EarlyDef.is_def());
assert!(!Role::Use.is_def());
}
#[test]
fn a_described_operand_keeps_what_it_was_constrained_to() {
let class = RegClass::new(0);
let plain = OperandDesc::write(class);
assert_eq!(plain.constraint, Constraint::Reg);
let tied = plain.with(Constraint::Reuse(1));
assert_eq!(tied.constraint, Constraint::Reuse(1));
assert_eq!(tied.role, Role::Def);
assert_eq!(OperandDesc::read(class).role, Role::Use);
assert_eq!(OperandDesc::write_early(class).role, Role::EarlyDef);
}
}