* Skeleton simple_gvn pass.
* Basic testing infrastructure for simple-gvn.
* Add can_load and can_store flags to instructions.
* Move the replace_values function into the DataFlowGraph.
* Make InstructionData derive from Hash, PartialEq, and Eq.
* Make EntityList's hash and eq functions panic.
* Change Ieee32 and Ieee64 to store u32 and u64, respectively.
The spilling and reload passes need to ensure that the set of live
ranges with register affinity can always be assigned registers. The
register pressure tracker can count how many registers are in use for
each top-level register class and give guidance on the type of
registers that need to be spilled when limits are exceeded.
Pressure tracking is extra complicated for the arm32 floating point
register bank because there are multiple top-level register classes (S,
D, Q) competing for the same register units.
Avoid spreading u32 as a bitmask of register classes throughout the
code.
Enforce the limit of 32 register classes total. This could easily be
raised if needed.
The MAX_TOPRCS constant is the highest possible number of top-level
register classes in an ISA. The RegClassData.toprc field is always
smaller than this limit.
A top-level register class is one that has no sub-classes. It is
possible to have multiple top-level register classes in the same
register bank. For example, ARM's FPR bank has both D and Q top-level
register classes.
Number register classes such that all top-level register classes appear
as a contiguous sequence starting from 0. This will be used by the
register allocator when counting used registers per top-level register
class.
Cretonne's encoding recipes need to have a fixed size so we can compute
accurate branch destination addresses. Intel's instruction encoding has
a lot of variance in the number of bytes needed to encode the opcode
which leads to a number of duplicated encoding recipes that only differ
in the opcode size.
Add an Intel-specific TailEnc Python class which represents an
abstraction over a set of recipes that are identical except for the
opcode encoding. The TailEnc can then generate specific encoding recipes
for each opcode format.
The opcode format is a prefix of the recipe name, so for example, the
'rr' TailEnc will generate the 'Op1rr', 'Op2rr', 'Mp2rr' etc recipes.
The TailEnc class provides a __call__ implementation that simply takes
the sequence of opcode bytes as arguments. It then looks up the right
prefix for the opcode bytes.
We don't support the full set of Intel addressing modes yet. So far we
have:
- Register indirect, no displacement.
- Register indirect, 8-bit signed displacement.
- Register indirect, 32-bit signed displacement.
The SIB addressing modes will need new Cretonne instruction formats to
represent.
We'll arrange encoding lists such that the first suitable encoding is
the best choice for the legalizer. This is the most intuitive way of
generating the encodings.
After register allocation, we may choose a different encoding, but that
will require looking at the whole list.
After finding a register solution, it need to be executed as a sequence
of regmove instructions. This often requires a topological ordering of
the moves so they don't conflict.
When the solution contains cycles, try to grab an available scratch
register to implement the copies. Panic if that fails (later, we'll
implement emergency spilling in this case).
Make sure we handle odd aliasing in the arm32 floating point register
bank. Not everything is a simple cycle in that case, so make sure we
don't assume so.
The register constraint solver has two kinds of variables:
1. Live values that were already in a register, and
2. Values defined by the instruction.
Make a record of the original register holding the first kind of value.
It is not necessary to to a second pass over the live values to update
the set of available registers. The color_args() and color_entry_args()
functions can do that in a single pass.
The live value tracker expects them to be there.
We may eventually delete dead arguments from internal EBBs, but at least
the entry block needs to be able to handle dead function arguments.
Provide a drop_dead_args() function which deletes them instead.
We still need to assign a register to dead EBB arguments, so they can't
just be ignored.
The live value tracker goes through the trouble of looking up the live
range for each value it tracks. We can cache a few more interesting
properties from the live range in the LiveValue struct.
Most of the time, register coloring is almost trivial: just pick
available registers for the values defined by the current instruction.
However, some instructions have register operand constraints, and it may
be necessary to move live registers around to satisfy the constraints.
Sometimes the instruction's own operands can interfere with each other
in a way that you can't just pick a register assignment for each output
in order.
This is complicated enough that it is worthwhile to represent as a
constraint satisfaction problem in a separate solver module. The
representation is chosen to be very fast in the common case where the
constraints are trivial to solve.
The current implementation is still incomplete, but as functional as the
code it's replacing. Missing features:
- Handle tied operand constraints.
- Handle ABI constraints on calls and return instructions.
- Execute a constraint solution by emitting regmove instructions.
- Handling register diversions before leaving the EBB.
These instructions have a fixed register constraint; the shift amount is
passed in CL.
Add meta language syntax so a fixed register can be specified as
"GPR.rcx".
Tabulate the Intel opcode representations and implement an OP() function
which computes the encoding bits.
Implement the single-byte opcode with a reg-reg ModR/M byte.
Most instructions don't have any fixed register constraints. Add boolean
summaries that can be used to check if it is worthwhile to scan the
constraint lists when looking for a fixed register constraint.
Also add a tied_ops summary bool which indicates that the instruction
has tied operand constraints.
The register constraint for an output operand can be specified as an
integer indicating the input operand number to tie. The tied operands
must use the same register.
Generate operand constraints using ConstraintKind::Tied(n) for both the
tied operands. The n index refers to the opposite array. The input
operand refers to the outs array and vice versa.
This still picks up the 2.7 type annotations in comments.
Fix the compute_quadratic signature to allow for the ValuewView of an
OrderedDict in python 3.
A recent mypy update started writing the .mypy_cache directory which we
don't want under version control. The cache is only used by the
experimental "mypy --incremental" mode which we don't use, but it is
always written anyway.
- Add a check-rustfmt.sh script which checks if the right version of
rustfmt is installed.
- Run check-rustfmt.sh --install as an install step under travis_wait.
This is to work around the issue where cargo takes forever to build
rustfmt, causing Travis to terminate the build because it hasn't
produced any output for 10 minutes.
The arguments to the entry block arrive in registers determined by the
ABI. This information is stored in the signature.
Use a separate function for coloring entry block arguments using the
signature information. We can't handle stack arguments yet.
This value affinity doesn't mean "whatever", it means that the value
does not interact with any real instructions, where "real" means
instructions that have a legal encoding.
Update the liveness verifier to check this property:
- Encoded instructions can only use real values.
- Encoded instructions define real values.
- Ghost instructions define ghost values.
The legalize_signature() function will return ArgumentLoc::Reg arguments
that contain a register unit. However, the register also needs to be
able to associate a register class with the argument values to fully
track the used registers.
When values are defined by instructions, the register class is part for
the operand constraints for the instruction. For values defined on ABI
boundaries like function arguments and return values from a call, the
register class is provided by the new regclass_for_abi_type() function.
Provide implementations of this function in abi modules of all the
targets, even those that don't have a legalize_signature()
implementation yet.
Since we're adding abi modules to all targets, move the
legalize_signature() stubs in there and make the function mandatory in
TargetIsa. All targets will eventually need this function.
If we generated new instructions as part of legalize, and the new
instructions failed to legalize, we'd be left with a func.encodings[]
that would panic when you dereferenced the inst.
The other legalizer cases have a continue after setting the position
to double back, while this one didn't. Make sure that we do, in case
another legalizer block is added after this one.