Add support for emergency spill slots.
- Create a new kind of stack slot: emergency_slot. - Add a get_emergency_slot() method which finds a suitable emergency slot given a list of slots already in use. - Use emergency spill slots when schedule_moves needs them.
This commit is contained in:
@@ -48,6 +48,7 @@ use ir::{Ebb, Inst, Value, Function, ValueLoc, SigRef};
|
||||
use ir::{InstBuilder, ArgumentType, ArgumentLoc};
|
||||
use isa::{RegUnit, RegClass, RegInfo, regs_overlap};
|
||||
use isa::{TargetIsa, EncInfo, RecipeConstraints, OperandConstraint, ConstraintKind};
|
||||
use packed_option::PackedOption;
|
||||
use regalloc::RegDiversions;
|
||||
use regalloc::affinity::Affinity;
|
||||
use regalloc::allocatable_set::AllocatableSet;
|
||||
@@ -733,14 +734,47 @@ impl<'a> Context<'a> {
|
||||
fn shuffle_inputs(&mut self, regs: &mut AllocatableSet) {
|
||||
use regalloc::solver::Move::*;
|
||||
|
||||
self.solver.schedule_moves(regs);
|
||||
let spills = self.solver.schedule_moves(regs);
|
||||
|
||||
// The move operations returned by `schedule_moves` refer to emergency spill slots by
|
||||
// consecutive indexes starting from 0. Map these to real stack slots.
|
||||
// It is very unlikely (impossible?) that we would need more than one spill per top-level
|
||||
// register class, so avoid allocation by using a fixed array here.
|
||||
let mut slot = [PackedOption::default(); 8];
|
||||
assert!(spills <= slot.len(), "Too many spills ({})", spills);
|
||||
|
||||
for m in self.solver.moves() {
|
||||
match *m {
|
||||
Reg { value, from, to, .. } => {
|
||||
self.divert.regmove(value, from, to);
|
||||
self.cur.ins().regmove(value, from, to);
|
||||
}
|
||||
Spill { .. } | Fill { .. } => unimplemented!(),
|
||||
Spill {
|
||||
value,
|
||||
from,
|
||||
to_slot,
|
||||
..
|
||||
} => {
|
||||
debug_assert_eq!(slot[to_slot].expand(), None, "Overwriting slot in use");
|
||||
let ss = self.cur.func.stack_slots.get_emergency_slot(
|
||||
self.cur.func.dfg.value_type(value),
|
||||
&slot[0..spills],
|
||||
);
|
||||
slot[to_slot] = ss.into();
|
||||
self.divert.regspill(value, from, ss);
|
||||
self.cur.ins().regspill(value, from, ss);
|
||||
}
|
||||
Fill {
|
||||
value,
|
||||
from_slot,
|
||||
to,
|
||||
..
|
||||
} => {
|
||||
// These slots are single use, so mark `ss` as available again.
|
||||
let ss = slot[from_slot].take().expect("Using unallocated slot");
|
||||
self.divert.regfill(value, ss, to);
|
||||
self.cur.ins().regfill(value, ss, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,7 +523,13 @@ impl Solver {
|
||||
/// In either case, `to` will not be available for variables on the input side of the
|
||||
/// instruction.
|
||||
pub fn reassign_in(&mut self, value: Value, rc: RegClass, from: RegUnit, to: RegUnit) {
|
||||
dbg!("reassign_in({}:{}, %{} -> %{})", value, rc, from, to);
|
||||
dbg!(
|
||||
"reassign_in({}:{}, {} -> {})",
|
||||
value,
|
||||
rc,
|
||||
rc.info.display_regunit(from),
|
||||
rc.info.display_regunit(to)
|
||||
);
|
||||
debug_assert!(!self.inputs_done);
|
||||
if self.regs_in.is_avail(rc, from) {
|
||||
// It looks like `value` was already removed from the register set. It must have been
|
||||
@@ -826,7 +832,9 @@ impl Solver {
|
||||
Move::with_assignment,
|
||||
));
|
||||
|
||||
dbg!("collect_moves: {}", DisplayList(&self.moves));
|
||||
if !(self.moves.is_empty()) {
|
||||
dbg!("collect_moves: {}", DisplayList(&self.moves));
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to schedule a sequence of `regmove` instructions that will shuffle registers into
|
||||
|
||||
Reference in New Issue
Block a user