Record vreg classes explicitly during liverange pass. (#35)

This resolves an issue seen when the source program uses multiple
regclasses (Int and Float): in some cases, the logic that grabs the
vregs and retains them (with class) in `vreg_regs` missed a register and
we had a class mismatch. This occurred because data structures were
initialized assuming `Int` regclass at first.

This PR instead removes the `vreg_regs` array, stores the class
explicitly as an `Option<RegClass>` in the `VRegData`, and provides a
`Env::vreg()` method that reconstitutes a `VReg` given its index and its
observed class. We "observe" the class of every vreg seen during the
liveness pass (and we assert that every occurrence of the vreg index has
the same class). In this way, we still have a single source-of-truth for
the vreg class (the mention of the vreg itself) and we explicitly
represent the "not observed yet" state (and panic on attempting to use
such a vreg) rather than implicitly taking the wrong class.
This commit is contained in:
Chris Fallin
2022-03-29 14:00:14 -07:00
committed by GitHub
parent 433e8b3776
commit ad41f8a7a5
5 changed files with 53 additions and 23 deletions

View File

@@ -52,11 +52,11 @@ impl<'a, F: Function> Env<'a, F> {
// Sanity check: both bundles should contain only ranges with appropriate VReg classes.
for entry in &self.bundles[from.index()].ranges {
let vreg = self.ranges[entry.index.index()].vreg;
debug_assert_eq!(from_rc, self.vreg_regs[vreg.index()].class());
debug_assert_eq!(from_rc, self.vreg(vreg).class());
}
for entry in &self.bundles[to.index()].ranges {
let vreg = self.ranges[entry.index.index()].vreg;
debug_assert_eq!(to_rc, self.vreg_regs[vreg.index()].class());
debug_assert_eq!(to_rc, self.vreg(vreg).class());
}
}
@@ -234,7 +234,7 @@ impl<'a, F: Function> Env<'a, F> {
// If this is a pinned vreg, go ahead and add it to the
// commitment map, and avoid creating a bundle entirely.
if let Some(preg) = self.func.is_pinned_vreg(self.vreg_regs[vreg.index()]) {
if let Some(preg) = self.func.is_pinned_vreg(self.vreg(vreg)) {
for entry in &self.vregs[vreg.index()].ranges {
let key = LiveRangeKey::from_range(&entry.range);
self.pregs[preg.index()]
@@ -281,7 +281,7 @@ impl<'a, F: Function> Env<'a, F> {
// Create a spillslot for this bundle.
let ssidx = SpillSetIndex::new(self.spillsets.len());
let reg = self.vreg_regs[vreg.index()];
let reg = self.vreg(vreg);
let size = self.func.spillslot_size(reg.class()) as u8;
self.spillsets.push(SpillSet {
vregs: smallvec![vreg],
@@ -361,8 +361,8 @@ impl<'a, F: Function> Env<'a, F> {
dst
);
let dst_vreg = self.vreg_regs[self.ranges[dst.index()].vreg.index()];
let src_vreg = self.vreg_regs[self.ranges[src.index()].vreg.index()];
let dst_vreg = self.vreg(self.ranges[dst.index()].vreg);
let src_vreg = self.vreg(self.ranges[src.index()].vreg);
if self.func.is_pinned_vreg(src_vreg).is_some()
&& self.func.is_pinned_vreg(dst_vreg).is_some()
{