This is a bare-bones outline of the SSA coloring pass. Many features are
missing, including:
- Handling instruction operand constraints beyond simple register
classes.
- Handling ABI requirements for function arguments and return values.
- Generating shuffle code for EBB arguments.
Some polymorphic instructions don't return the controlling type
variable, so it has to be computed from the designated operand instead.
- Add a requires_typevar_operand() method to the operand constraints
which indicates that.
- Add a ctrl_typevar(dfg) method to InstructionData which computes the
controlling type variable correctly, and returns VOID for monomorphic
instructions.
- Use ctrl_typevar(dfg) to drive the level-1 encoding table lookups.
When the liveness pass implements dead code elimination, missing live
ranges can be used to indicate unused values that it may be possible to
remove. But even then, we may have to keep dead defs around if the
instruction has side effects or other live defs.
Move the flow graph computation into a compute method which can be
called with multiple functions.
This allows us to reuse the ControlFlowGraph memory and keep an instance
in the Context.
This will provide main entry points for compiling functions, and it
serves as a place for keeping data structures that should be preserved
between function compilations to reduce allocator thrashing.
So far, Context is just basic scaffolding. More to be added.
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.