Most of the register allocator algorithms will only have to look at the
currently live values as presented by LiveValueTracker. Many also need
the value's affinity which is stored in the LiveRange associated with
the value.
Save the extra table lookup by caching the affinity value inside
LiveValue.
LiveRanges represent the live-in range of a value as a sorted
list of intervals. Each interval starts at an EBB and continues
to an instruction. Before this commit, the LiveRange would store
an interval for each EBB. This commit changes the representation
such that intervals continuing from one EBB to another are coalesced
into one.
Fixes#37.
Each live range has an affinity hint containing the preferred register
class (or stack slot). Compute the affinity by merging the constraints
of the def and all uses.
On ISAs with no instruction predicates, just emit an unimplemented!()
stub for the check_instp() function. It is unlikely that a finished ISA
will not have any instruction predicates.
An SSA value is usually biased towards a specific register class or a
stack slot, depending on the constraints of the instructions using it.
Represent this bias as an Affinity enum, and implement a merging
algorithm for updating an affinity to satisfy a new constraint.
Affinities will be computed as part of the liveness analysis. This is
not implemented yet.
Ensure that the set of register classes is closed under intersection.
Provide a RegClass::intersect() method which finds the register class
representing the intersection of two classes.
Generate a bit-mask of subclasses for each register class to be used by
the intersect() method.
Ensure that register classes are sorted topologically. This is also used
by the intersect() method.
Every encoding recipe must specify register constraints on input and
output values.
Generate recipe constraint tables along with the other encoding tables.
This set of available register units also manages register aliasing in
an efficient way.
Detect if the units in a register straddles mask words. The algorithm
for allocating multi-unit registers expect the whole register to be
inside a single mask word. We could handle this if necessary, but so far
no ISAs need it.
Also rework the algorithm to be more robust against unreachable blocks.
- Add an is_reachable(ebb) method.
- Change idom(ebb) to just return an instruction.
- Make idom() return None for the entry block as well as unreachable
blocks.
- Remove NO_VALUE and ExpandedValue::None.
- Remove the Default implelmentation for Value.
- InstructionData::second_result() returns an Option<Value>.
- InstructionData::second_result() returns a reference to the packed
option.
This was only used for the comment rewrite mechanism, and we can just
predict the next allocated instruction number instead. See the other
uses of next_key() for gather_comments().
This is simply the slice iterator for the dense vector.
- map.values() returns an iterator with references to the values.
- for i in &map iterates over references to the values.
This implements the classic Briggs/Torczon sparse set construct.
Adapt it to our existing EntityRef infrastructure so we can use types
keys instead of just integers like the original paper does.
Also provide a SparseSet<T> type alias which implements a sparse set of
entity refeences. This is actually closer to what the original paper
describes.
We will track live ranges separately for each SSA value, rather than per
virtual register like LLVM does.
This is the basis for a register allocator, so place it in a new
regalloc module.