Alloc spillsets for whole vreg, not just spilled LRs. This is a prerequisite to allowing a "clean" value to remain in spillslot while also in reg and avoiding the re-spill. It should also reduce stack-to-stack moves (though they can still come from progmoves).

This commit is contained in:
Chris Fallin
2021-05-25 18:19:25 -07:00
parent ca5f24f6b7
commit b3dc2b25a5

View File

@@ -268,11 +268,12 @@ impl LiveBundle {
#[derive(Clone, Debug)]
struct SpillSet {
bundles: SmallVec<[LiveBundleIndex; 2]>,
vregs: SmallVec<[VRegIndex; 2]>,
slot: SpillSlotIndex,
reg_hint: PReg,
class: RegClass,
spill_bundle: LiveBundleIndex,
required: bool,
size: u8,
}
@@ -2158,6 +2159,19 @@ impl<'a, F: Function> Env<'a, F> {
self.bundles[to.index()].ranges = merged;
self.bundles[from.index()].ranges.clear();
if self.bundles[from.index()].spillset != self.bundles[to.index()].spillset {
let from_vregs = std::mem::replace(
&mut self.spillsets[self.bundles[from.index()].spillset.index()].vregs,
smallvec![],
);
let to_vregs = &mut self.spillsets[self.bundles[to.index()].spillset.index()].vregs;
for vreg in from_vregs {
if !to_vregs.contains(&vreg) {
to_vregs.push(vreg);
}
}
}
true
}
@@ -2204,9 +2218,10 @@ impl<'a, F: Function> Env<'a, F> {
let reg = self.vreg_regs[vreg.index()];
let size = self.func.spillslot_size(reg.class(), reg) as u8;
self.spillsets.push(SpillSet {
bundles: smallvec![],
vregs: smallvec![vreg],
slot: SpillSlotIndex::invalid(),
size,
required: false,
class: reg.class(),
reg_hint: PReg::invalid(),
spill_bundle: LiveBundleIndex::invalid(),
@@ -3035,11 +3050,9 @@ impl<'a, F: Function> Env<'a, F> {
}
Requirement::Stack(_) => {
// If we must be on the stack, put ourselves on
// the spillset's list immediately.
self.spillsets[self.bundles[bundle.index()].spillset.index()]
.bundles
.push(bundle);
// If we must be on the stack, mark our spillset
// as required immediately.
self.spillsets[self.bundles[bundle.index()].spillset.index()].required = true;
return Ok(());
}
@@ -3195,13 +3208,11 @@ impl<'a, F: Function> Env<'a, F> {
}
if !success {
log::debug!(
"spilling bundle {:?} to spillset bundle list {:?}",
"spilling bundle {:?}: marking spillset {:?} as required",
bundle,
self.bundles[bundle.index()].spillset
);
self.spillsets[self.bundles[bundle.index()].spillset.index()]
.bundles
.push(bundle);
self.spillsets[self.bundles[bundle.index()].spillset.index()].required = true;
}
}
}
@@ -3211,8 +3222,8 @@ impl<'a, F: Function> Env<'a, F> {
spillslot: SpillSlotIndex,
spillset: SpillSetIndex,
) -> bool {
for &bundle in &self.spillsets[spillset.index()].bundles {
for entry in &self.bundles[bundle.index()].ranges {
for &vreg in &self.spillsets[spillset.index()].vregs {
for entry in &self.vregs[vreg.index()].ranges {
if self.spillslots[spillslot.index()]
.ranges
.btree
@@ -3231,22 +3242,22 @@ impl<'a, F: Function> Env<'a, F> {
spillslot: SpillSlotIndex,
) {
self.spillsets[spillset.index()].slot = spillslot;
for i in 0..self.spillsets[spillset.index()].bundles.len() {
for i in 0..self.spillsets[spillset.index()].vregs.len() {
// don't borrow self
let bundle = self.spillsets[spillset.index()].bundles[i];
let vreg = self.spillsets[spillset.index()].vregs[i];
log::debug!(
"spillslot {:?} alloc'ed to spillset {:?}: bundle {:?}",
"spillslot {:?} alloc'ed to spillset {:?}: vreg {:?}",
spillslot,
spillset,
bundle
vreg,
);
for entry in &self.bundles[bundle.index()].ranges {
for entry in &self.vregs[vreg.index()].ranges {
log::debug!(
"spillslot {:?} getting range {:?} from bundle {:?}: {:?}",
"spillslot {:?} getting range {:?} from LR {:?} from vreg {:?}",
spillslot,
entry.range,
entry.index,
bundle,
vreg,
);
self.spillslots[spillslot.index()]
.ranges
@@ -3260,7 +3271,7 @@ impl<'a, F: Function> Env<'a, F> {
for spillset in 0..self.spillsets.len() {
log::debug!("allocate spillslot: {}", spillset);
let spillset = SpillSetIndex::new(spillset);
if self.spillsets[spillset.index()].bundles.is_empty() {
if !self.spillsets[spillset.index()].required {
continue;
}
// Get or create the spillslot list for this size.