- Cache the most recent u64 chunk in the set to avoid some hashmap
lookups;
- Defer the live-set union'ing over the loop body until query time
(remember the set that would have been union'd in instead), and lazily
propagate the liveness bit at that query time, union-find style;
- Do n-1 rather than n union operations for n successors (first is a
clone instead);
- Don't union in liveness sets from blocks we haven't visited yet (the
loop-body/backedge handling handles these).
The main enhancement in this commit is support for reference types and
stackmaps. This requires tracking whether each VReg is a "reference" or
"pointer". At certain instructions designated as "safepoints", the
regalloc will (i) ensure that all references are in spillslots rather
than in registers, and (ii) provide a list of exactly which spillslots
have live references at that program point. This can be used by, e.g., a
GC to trace and possibly modify pointers. The stackmap of spillslots is
precise: it includes all live references, and *only* live references.
This commit also brings in some API tweaks as part of the in-progress
Cranelift glue. In particular, it makes Allocations and Operands
mutually disjoint by using the same bitfield for the type-tag in both
and choosing non-overlapping tags. This will allow instructions to carry
an Operand for each register slot and then overwrite these in place with
Allocations. The `OperandOrAllocation` type does the necessary magic to
make this look like an enum, but staying in 32 bits.