When try_add_var is looking for values that can be moved out of the way
in order to satisfy constraints for the current instruction, avoid
values that are live on a CFG edge originating at the current (branch)
instruction.
These values must be in their globally assigned location when entering
the branch destination EBB.
This is covered by the existing regalloc/iterate.cton test case which
fails with an upcoming commit.
- Create a new kind of stack slot: emergency_slot.
- Add a get_emergency_slot() method which finds a suitable emergency
slot given a list of slots already in use.
- Use emergency spill slots when schedule_moves needs them.
This method was important back when result values couldn't be moved
between instructions. Now that results can be moved, value aliases do
everything we need.
Copy instructions are still used to break interferences in the register
allocator's coalescing phase, but there isn't really any reason to use a
copy instruction over a value alias anywhere else.
After and during register allocation, copy instructions are significant,
so we never want to "see through" them like the resolve_copies()
function did.
This is related to #166, but probably doesn't fix the underlying
problem.
This is a verification pass that can be run after register allocation.
It verifies that value locations are consistent with constraints on
their uses, and that the register diversions are consistent.
Make it clear that register diversions are local to an EBB only. This
affects what branch relaxation is allowed to do.
The verify_locations() takes an optional Liveness parameter which is
used to check that no diverted values are live across CFG edges.
When "binemit" tests encode instructions, keep track of the current set
of register diversions, and use the diverted locations to check operand
constraints.
This matches how constraints are applied during a real binemit phase.
These are parallels to the existing regmove instruction, but the divert
the value to and from a stack slot.
Like regmove diversions, this is a temporary diversion that must be
local to the EBB.
The register constraint solver schedules a set of move instructions to
execute before the instruction getting colored. In extreme cases, this
is not possible because there are no available registers to break cycles
in the register assignments that must be scheduled.
When that happens, we spill one register to an emergency slot so it
becomes available for implementing the assignment cycle. Then the
original register is restored.
The coloring pass can't yet understand the spill and fill move types.
This will be implemented next.
This makes it possible to materialize new RegClass references without
requiring a RegInfo reference to be passed around.
- Move the RegInfo::toprc() method to RegClassData.
- Rename RegClassData::intersect() to intersect_index() and provide a
new intersect() which returns a register class.
- Remove some &RegInfo parameters that are no longer needed.
Fixes#165.
The constraint solver's schedule_move() function sometimes need to use
an extra available register when the moves to be scheduled contains
cycles.
The pending moves have associated register classes that come from the
constraint programming. Since the moves have hard-coded to and from
registers, these register classes are only meant to indicate the
register sizes. In particular, we can use the whole top-level register
class when scavenging for a spare register to break a cycle.
When we detect interference between the values that have already been
merged into the candidate virtual register and an EBB argument, we first
try to resolve the conflict by splitting. We also check if the existing
interfering value is fundamentally incompatible with the branch
instruction so it needs to be removed from the virtual register,
restarting the merge operation.
However, this existing interfering value is not necessarily the only
interference, so the split is not guaranteed to resolve the conflict. If
it turns out that splitting didn't resolve the conflict, restart the
merge after removing this second conflicting value.
A value passed as an argument to a function call may live in an incoming
stack slot initially. Fix the call legalizer so it copies such an
argument into the expected outgoing stack slot for the call.
This removes the `optimize` option, as one can do that with
`--set`, eg. `--set opt_level=best`. And it adds an option to
print the compilation output.
And, it enables simple_gvn and licm for opt_level=best.
It can happen that the currently live registers are blocking a smaller
register class completely, so the only way of solving the allocation
problem is to turn some of the live-through registers into solver
variables.
When the quick_solve attempt fails, try to free up registers in the
critical register class by turning live-through values into solver
variables.
When the return value from a call has been spilled, the reload pass
needs to insert a spill instruction right after the call instruction
which returns its results in registers.
The x86_divmodx traps on integer overflow, but the srem instruction is
not supposed to trap with a -1 divisor.
Generate a legalization expansion for srem that special-cases the -1
divisor to simply return 0.
The extend and reduce instructions have additional type constraints.
Stop inserting sextend instructions after ctz, clz, and popcnt when
translating from WebAssembly. The Cretonne instructions have the same
signature as the WebAssembly equivalents.
An f64 can represent multiple values in the range INT_MIN-1 < x <=
INT_MIN which all truncate to INT_MIN, so comparing the input value
against INT_MIN is not good enough.
Instead, detect overflow on x <= INT_MIN-1 when INT_MIN-1 is an exact
floating point value.
Also make sure we generate type checks for the controlling type variable
in legalization patterns. This is not needed for encodings since the
encoding tables are already keyed on the controlling type variable.
In 32-bit mode, all function arguments are passed on the stack, not in
registers.
This ABI support is not complete or properly tested, but at least it
doesn't try to pass arguments in r8.
The native x86_fmin and x86_fmax instructions don't behave correctly for
NaN inputs and when comparing +0.0 to -0.0, so we need separate branches
for those cases.
To begin with, these are catch-all encodings with a SIB byte and a
32-bit displacement, so they can access any stack slot via both the
stack pointer and the frame pointer.
In the future, we will add encodings for 8-bit displacements as well as
EBP-relative references without a SIB byte.
This contains encoding details for a stack reference: The base register
and offset to use in the specific instruction encoding.
Generate StackRef objects called in_stk0 etc for the binemit recipe
code. All binemit recipes need to compute base pointer offsets for stack
references, so have the automatically generated code do it.
This is a larger refactoring because all the changes need to be done
together. Either you pass a Function reference around, or you pass
around references to the parts. There is no in between.
A cursor now also remembers a current source location which will be
assigned to all new instructions created with the cursor.
The old layout::Cursor can't support source locations because it doesn't
have a reference to the full ir::Function.
These formats are not used any longer after the heap_load and heap_store
instructions were replaced by heap_addr.
Also drop the Uoffset32 immediate operand type which isn't used either.