use super::{
AllocRegResult, Env, LiveRangeKey, LiveRangeSet, PReg, PRegIndex, RegTraversalIter,
SpillSetIndex, SpillSlotData, SpillSlotIndex, SpillSlotList,
};
use crate::{Allocation, Function, SpillSlot};
use smallvec::smallvec;
impl<'a, F: Function> Env<'a, F> {
pub fn try_allocating_regs_for_spilled_bundles(&mut self) {
trace!("allocating regs for spilled bundles");
for i in 0..self.spilled_bundles.len() {
let bundle = self.spilled_bundles[i]; if self.bundles[bundle.index()].ranges.is_empty() {
continue;
}
let class = self.spillsets[self.bundles[bundle.index()].spillset.index()].class;
let hint = self.spillsets[self.bundles[bundle.index()].spillset.index()].reg_hint;
self.bundles[bundle.index()]
.ranges
.sort_unstable_by_key(|entry| entry.range.from);
let mut success = false;
self.stats.spill_bundle_reg_probes += 1;
for preg in
RegTraversalIter::new(self.env, class, hint, PReg::invalid(), bundle.index(), None)
{
trace!("trying bundle {:?} to preg {:?}", bundle, preg);
let preg_idx = PRegIndex::new(preg.index());
if let AllocRegResult::Allocated(_) =
self.try_to_allocate_bundle_to_reg(bundle, preg_idx, None)
{
self.stats.spill_bundle_reg_success += 1;
success = true;
break;
}
}
if !success {
trace!(
"spilling bundle {:?}: marking spillset {:?} as required",
bundle,
self.bundles[bundle.index()].spillset
);
self.spillsets[self.bundles[bundle.index()].spillset.index()].required = true;
}
}
}
pub fn spillslot_can_fit_spillset(
&mut self,
spillslot: SpillSlotIndex,
spillset: SpillSetIndex,
) -> bool {
for &vreg in &self.spillsets[spillset.index()].vregs {
for entry in &self.vregs[vreg.index()].ranges {
if self.spillslots[spillslot.index()]
.ranges
.btree
.contains_key(&LiveRangeKey::from_range(&entry.range))
{
return false;
}
}
}
true
}
pub fn allocate_spillset_to_spillslot(
&mut self,
spillset: SpillSetIndex,
spillslot: SpillSlotIndex,
) {
self.spillsets[spillset.index()].slot = spillslot;
for vreg in &self.spillsets[spillset.index()].vregs {
trace!(
"spillslot {:?} alloc'ed to spillset {:?}: vreg {:?}",
spillslot,
spillset,
vreg,
);
for entry in &self.vregs[vreg.index()].ranges {
trace!(
"spillslot {:?} getting range {:?} from LR {:?} from vreg {:?}",
spillslot,
entry.range,
entry.index,
vreg,
);
self.spillslots[spillslot.index()]
.ranges
.btree
.insert(LiveRangeKey::from_range(&entry.range), entry.index);
}
}
}
pub fn allocate_spillslots(&mut self) {
const MAX_ATTEMPTS: usize = 10;
for spillset in 0..self.spillsets.len() {
trace!("allocate spillslot: {}", spillset);
let spillset = SpillSetIndex::new(spillset);
if !self.spillsets[spillset.index()].required {
continue;
}
let size = self.spillsets[spillset.index()].size as usize;
if size >= self.slots_by_size.len() {
self.slots_by_size.resize(
size + 1,
SpillSlotList {
slots: smallvec![],
probe_start: 0,
},
);
}
let mut i = self.slots_by_size[size].probe_start;
let mut success = false;
for _attempt in 0..std::cmp::min(self.slots_by_size[size].slots.len(), MAX_ATTEMPTS) {
let spillslot = self.slots_by_size[size].slots[i];
if self.spillslot_can_fit_spillset(spillslot, spillset) {
self.allocate_spillset_to_spillslot(spillset, spillslot);
success = true;
self.slots_by_size[size].probe_start = i;
break;
}
i = self.slots_by_size[size].next_index(i);
}
if !success {
let spillslot = SpillSlotIndex::new(self.spillslots.len());
self.spillslots.push(SpillSlotData {
ranges: LiveRangeSet::new(),
alloc: Allocation::none(),
slots: size as u32,
});
self.slots_by_size[size].slots.push(spillslot);
self.slots_by_size[size].probe_start = self.slots_by_size[size].slots.len() - 1;
self.allocate_spillset_to_spillslot(spillset, spillslot);
}
}
for i in 0..self.spillslots.len() {
self.spillslots[i].alloc = self.allocate_spillslot(self.spillslots[i].slots);
}
trace!("spillslot allocator done");
}
pub fn allocate_spillslot(&mut self, size: u32) -> Allocation {
let mut offset = self.num_spillslots;
debug_assert!(size.is_power_of_two());
offset = (offset + size - 1) & !(size - 1);
let slot = if self.func.multi_spillslot_named_by_last_slot() {
offset + size - 1
} else {
offset
};
offset += size;
self.num_spillslots = offset;
Allocation::stack(SpillSlot::new(slot as usize))
}
}