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:
@@ -662,11 +662,13 @@ pub fn machine_env() -> MachineEnv {
|
|||||||
}
|
}
|
||||||
let preferred_regs_by_class: [Vec<PReg>; 2] = [regs(0..24), vec![]];
|
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 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);
|
let fixed_stack_slots = regs(32..63);
|
||||||
// Register 63 is reserved for use as a fixed non-allocatable register.
|
// Register 63 is reserved for use as a fixed non-allocatable register.
|
||||||
MachineEnv {
|
MachineEnv {
|
||||||
preferred_regs_by_class,
|
preferred_regs_by_class,
|
||||||
non_preferred_regs_by_class,
|
non_preferred_regs_by_class,
|
||||||
|
scratch_by_class,
|
||||||
fixed_stack_slots,
|
fixed_stack_slots,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -986,6 +986,9 @@ impl<'a, F: Function> Env<'a, F> {
|
|||||||
to: pos_prio.pos.next(),
|
to: pos_prio.pos.next(),
|
||||||
});
|
});
|
||||||
let get_reg = || {
|
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() {
|
while let Some(preg) = scratch_iter.next() {
|
||||||
if !self.pregs[preg.index()]
|
if !self.pregs[preg.index()]
|
||||||
.allocations
|
.allocations
|
||||||
|
|||||||
26
src/lib.rs
26
src/lib.rs
@@ -1326,19 +1326,43 @@ impl<'a> Iterator for OutputIter<'a> {
|
|||||||
pub struct MachineEnv {
|
pub struct MachineEnv {
|
||||||
/// Preferred physical registers for each class. These are the
|
/// Preferred physical registers for each class. These are the
|
||||||
/// registers that will be allocated first, if free.
|
/// 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],
|
pub preferred_regs_by_class: [Vec<PReg>; 2],
|
||||||
|
|
||||||
/// Non-preferred physical registers for each class. These are the
|
/// Non-preferred physical registers for each class. These are the
|
||||||
/// registers that will be allocated if a preferred register is
|
/// registers that will be allocated if a preferred register is
|
||||||
/// not available; using one of these is considered suboptimal,
|
/// not available; using one of these is considered suboptimal,
|
||||||
/// but still better than spilling.
|
/// 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],
|
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
|
/// 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
|
/// actual registers. These can be used to tell the register allocator about
|
||||||
/// pre-defined stack slots used for function arguments and return values.
|
/// 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>,
|
pub fixed_stack_slots: Vec<PReg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user