Skip to content

Commit

Permalink
Re-introduce optional dedicated scratch registers (#117)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Amanieu authored Mar 4, 2023
1 parent 34a9ae7 commit 54f074e
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/fuzzing/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
3 changes: 3 additions & 0 deletions src/ion/moves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 25 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
}

Expand Down

0 comments on commit 54f074e

Please sign in to comment.