diff --git a/lib/cretonne/src/isa/registers.rs b/lib/cretonne/src/isa/registers.rs index 76fd39685a..122dec8e71 100644 --- a/lib/cretonne/src/isa/registers.rs +++ b/lib/cretonne/src/isa/registers.rs @@ -151,6 +151,11 @@ impl RegClassData { let uoffset = offset * self.width as usize; self.first + uoffset as RegUnit } + + /// Does this register class contain `regunit`? + pub fn contains(&self, regunit: RegUnit) -> bool { + self.mask[(regunit / 32) as usize] & (1u32 << (regunit % 32)) != 0 + } } impl fmt::Display for RegClassData { diff --git a/lib/cretonne/src/isa/riscv/registers.rs b/lib/cretonne/src/isa/riscv/registers.rs index 7deef9251a..9447e5ea29 100644 --- a/lib/cretonne/src/isa/riscv/registers.rs +++ b/lib/cretonne/src/isa/riscv/registers.rs @@ -6,7 +6,7 @@ include!(concat!(env!("OUT_DIR"), "/registers-riscv.rs")); #[cfg(test)] mod tests { - use super::INFO; + use super::{INFO, GPR, FPR}; use isa::RegUnit; #[test] @@ -34,4 +34,16 @@ mod tests { assert_eq!(uname(63), "%f31"); assert_eq!(uname(64), "%INVALID64"); } + + #[test] + fn classes() { + assert!(GPR.contains(GPR.unit(0))); + assert!(GPR.contains(GPR.unit(31))); + assert!(!FPR.contains(GPR.unit(0))); + assert!(!FPR.contains(GPR.unit(31))); + assert!(!GPR.contains(FPR.unit(0))); + assert!(!GPR.contains(FPR.unit(31))); + assert!(FPR.contains(FPR.unit(0))); + assert!(FPR.contains(FPR.unit(31))); + } } diff --git a/lib/cretonne/src/regalloc/allocatable_set.rs b/lib/cretonne/src/regalloc/allocatable_set.rs index 29a7e26964..714a82aab7 100644 --- a/lib/cretonne/src/regalloc/allocatable_set.rs +++ b/lib/cretonne/src/regalloc/allocatable_set.rs @@ -78,6 +78,25 @@ impl AllocatableSet { } rsi } + + /// Check if any register units allocated out of this set interferes with units allocated out + /// of `other`. + /// + /// This assumes that unused bits are 1. + pub fn interferes_with(&self, other: &AllocatableSet) -> bool { + self.avail + .iter() + .zip(&other.avail) + .any(|(&x, &y)| (x | y) != !0) + } + + /// Intersect this set of allocatable registers with `other`. This has the effect of removing + /// any register units from this set that are not in `other`. + pub fn intersect(&mut self, other: &AllocatableSet) { + for (x, &y) in self.avail.iter_mut().zip(&other.avail) { + *x &= y; + } + } } /// Iterator over available registers in a register class. @@ -179,4 +198,18 @@ mod tests { assert_eq!(regs.iter(GPR).count(), 7); assert_eq!(regs.iter(DPR).collect::>(), [30, 33, 35]); } + + #[test] + fn interference() { + let mut regs1 = AllocatableSet::new(); + let mut regs2 = AllocatableSet::new(); + + assert!(!regs1.interferes_with(®s2)); + regs1.take(&GPR, 32); + assert!(!regs1.interferes_with(®s2)); + regs2.take(&GPR, 31); + assert!(!regs1.interferes_with(®s2)); + regs1.intersect(®s2); + assert!(regs1.interferes_with(®s2)); + } }