Re-introduce optional dedicated scratch registers (#117)

* Re-introduce optional dedicated scratch registers

Dedicated scratch registers used for resolving move cycles were removed
in #51 and replaced with an algorithm to automatically allocate a
scratch register as needed.

However in many cases, a client will already have a non-allocatable
scratch register available for things like extended jumps (see #91). It
makes sense to re-use this register for regalloc than potentially
spilling an existing register.

* Clarify comment
This commit is contained in:
Amanieu d'Antras
2023-03-04 23:49:10 +01:00
committed by GitHub
parent 34a9ae7379
commit 54f074e507
3 changed files with 30 additions and 1 deletions

View File

@@ -662,11 +662,13 @@ pub fn machine_env() -> MachineEnv {
}
let preferred_regs_by_class: [Vec<PReg>; 2] = [regs(0..24), vec![]];
let non_preferred_regs_by_class: [Vec<PReg>; 2] = [regs(24..32), vec![]];
let scratch_by_class: [Option<PReg>; 2] = [None, None];
let fixed_stack_slots = regs(32..63);
// Register 63 is reserved for use as a fixed non-allocatable register.
MachineEnv {
preferred_regs_by_class,
non_preferred_regs_by_class,
scratch_by_class,
fixed_stack_slots,
}
}

View File

@@ -986,6 +986,9 @@ impl<'a, F: Function> Env<'a, F> {
to: pos_prio.pos.next(),
});
let get_reg = || {
if let Some(reg) = self.env.scratch_by_class[regclass as usize] {
return Some(Allocation::reg(reg));
}
while let Some(preg) = scratch_iter.next() {
if !self.pregs[preg.index()]
.allocations

View File

@@ -1326,19 +1326,43 @@ impl<'a> Iterator for OutputIter<'a> {
pub struct MachineEnv {
/// Preferred physical registers for each class. These are the
/// registers that will be allocated first, if free.
///
/// If an explicit scratch register is provided in `scratch_by_class` then
/// it must not appear in this list.
pub preferred_regs_by_class: [Vec<PReg>; 2],
/// Non-preferred physical registers for each class. These are the
/// registers that will be allocated if a preferred register is
/// not available; using one of these is considered suboptimal,
/// but still better than spilling.
///
/// If an explicit scratch register is provided in `scratch_by_class` then
/// it must not appear in this list.
pub non_preferred_regs_by_class: [Vec<PReg>; 2],
/// Optional dedicated scratch register per class. This is needed to perform
/// moves between registers when cyclic move patterns occur. The
/// register should not be placed in either the preferred or
/// non-preferred list (i.e., it is not otherwise allocatable).
///
/// Note that the register allocator will freely use this register
/// between instructions, but *within* the machine code generated
/// by a single (regalloc-level) instruction, the client is free
/// to use the scratch register. E.g., if one "instruction" causes
/// the emission of two machine-code instructions, this lowering
/// can use the scratch register between them.
///
/// If a scratch register is not provided then the register allocator will
/// automatically allocate one as needed, spilling a value to the stack if
/// necessary.
pub scratch_by_class: [Option<PReg>; 2],
/// Some `PReg`s can be designated as locations on the stack rather than
/// actual registers. These can be used to tell the register allocator about
/// pre-defined stack slots used for function arguments and return values.
///
/// `PReg`s in this list cannot be used as an allocatable register.
/// `PReg`s in this list cannot be used as an allocatable or scratch
/// register.
pub fixed_stack_slots: Vec<PReg>,
}