Compute register class intersections.

Ensure that the set of register classes is closed under intersection.

Provide a RegClass::intersect() method which finds the register class
representing the intersection of two classes.

Generate a bit-mask of subclasses for each register class to be used by
the intersect() method.

Ensure that register classes are sorted topologically. This is also used
by the intersect() method.
This commit is contained in:
Jakob Stoklund Olesen
2017-01-25 13:57:43 -08:00
parent 0394f35034
commit 672e4abd7e
6 changed files with 200 additions and 13 deletions

View File

@@ -6,7 +6,7 @@ include!(concat!(env!("OUT_DIR"), "/registers-intel.rs"));
#[cfg(test)]
mod tests {
use super::INFO;
use super::*;
use isa::RegUnit;
#[test]
@@ -46,4 +46,17 @@ mod tests {
assert_eq!(uname(16), "%xmm0");
assert_eq!(uname(31), "%xmm15");
}
#[test]
fn regclasses() {
assert_eq!(GPR.intersect(GPR), Some(GPR.into()));
assert_eq!(GPR.intersect(ABCD), Some(ABCD.into()));
assert_eq!(GPR.intersect(FPR), None);
assert_eq!(ABCD.intersect(GPR), Some(ABCD.into()));
assert_eq!(ABCD.intersect(ABCD), Some(ABCD.into()));
assert_eq!(ABCD.intersect(FPR), None);
assert_eq!(FPR.intersect(FPR), Some(FPR.into()));
assert_eq!(FPR.intersect(GPR), None);
assert_eq!(FPR.intersect(ABCD), None);
}
}

View File

@@ -1,5 +1,6 @@
//! Data structures describing the registers in an ISA.
use entity_map::EntityRef;
use std::fmt;
/// Register units are the smallest units of register allocation.
@@ -106,11 +107,59 @@ pub struct RegClassData {
/// How many register units to allocate per register.
pub width: u8,
/// Bit-mask of sub-classes of this register class, including itself.
///
/// Bits correspond to RC indexes.
pub subclasses: u32,
/// Mask of register units in the class. If `width > 1`, the mask only has a bit set for the
/// first register unit in each allocatable register.
pub mask: RegUnitMask,
}
impl RegClassData {
/// Get the register class corresponding to the intersection of `self` and `other`.
///
/// This register class is guaranteed to exist if the register classes overlap. If the register
/// classes don't overlap, returns `None`.
pub fn intersect(&self, other: RegClass) -> Option<RegClassIndex> {
// Compute the set of common subclasses.
let mask = self.subclasses & other.subclasses;
if mask == 0 {
// No overlap.
None
} else {
// Register class indexes are topologically ordered, so the largest common subclass has
// the smallest index.
Some(RegClassIndex(mask.trailing_zeros() as u8))
}
}
}
/// A small reference to a register class.
///
/// Use this when storing register classes in compact data structures. The `RegInfo::rc()` method
/// can be used to get the real register class reference back.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RegClassIndex(u8);
impl EntityRef for RegClassIndex {
fn new(idx: usize) -> Self {
RegClassIndex(idx as u8)
}
fn index(self) -> usize {
self.0 as usize
}
}
impl From<RegClass> for RegClassIndex {
fn from(rc: RegClass) -> Self {
RegClassIndex(rc.index)
}
}
/// Information about the registers in an ISA.
///
/// The `RegUnit` data structure collects all relevant static information about the registers in an
@@ -143,6 +192,11 @@ impl RegInfo {
reginfo: self,
}
}
/// Get the register class corresponding to `idx`.
pub fn rc(&self, idx: RegClassIndex) -> RegClass {
&self.classes[idx.index()]
}
}
/// Temporary object that holds enough information to print a register unit.

View File

@@ -120,11 +120,13 @@ mod tests {
const GPR: RegClass = &RegClassData {
index: 0,
width: 1,
subclasses: 0,
mask: [0xf0000000, 0x0000000f, 0],
};
const DPR: RegClass = &RegClassData {
index: 0,
width: 2,
subclasses: 0,
mask: [0x50000000, 0x0000000a, 0],
};