Commit Graph

31 Commits

Author SHA1 Message Date
Pat Hickey
03ee007624 Use clippy (#276)
* cton-util: fix some clippy unnecessary pass-by-value warnings

* clippy: ignore too many arguments / cyclomatic complexity in module

since these functions are taking args coming from the command line, i
dont think this is actually a valid lint, morally the arguments are all
from one structure

* cton-util: take care of remaining clippy warnings

* cton-reader: fix all non-suspicious clippy warnings

* cton-reader: disable clippy at site of suspicious lint

* cton-frontend: disable clippy at the site of an invalid lint

* cton-frontend: fix clippy warnings, or ignore benign ones

* clippy: ignore the camelcase word WebAssembly in docs

* cton-wasm: fix clippy complaints or ignore benign ones

* cton-wasm tests: fix clippy complaints

* cretonne: starting point turns off all clippy warnings

* cretonne: clippy fixes, or lower allow() to source of problem

* cretonne: more clippy fixes

* cretonne: fix or disable needless_lifetimes lint

this linter is buggy when the declared lifetime is used for another type
constraint.

* cretonne: fix clippy complaint about Pass::NoPass

* rustfmt

* fix prev minor api changes clippy suggested

* add clippy to test-all

* cton-filetests: clippy fixes

* simplify clippy reporting in test-all

* cretonne: document clippy allows better

* cretonne: fix some more clippy lints

* cretonne: fix clippy lints (mostly doc comments)

* cretonne: allow all needless_lifetimes clippy warnings

remove overrides at the false positives

* rustfmt
2018-03-22 13:10:41 -07:00
Dan Gohman
2b3df1a506 Add use declarations for std features.
Merge the `use` parts of the `no_std` branch. This reduces the diffs
between master and the `no_std` branch, making it easier to maintain.

Most of these changes are derived from patches by @lachlansneff in
https://github.com/Cretonne/cretonne/tree/no_std.
2018-03-20 14:07:05 -07:00
Dan Gohman
30f8daa9d6 Replace assert! with debug_assert! in production code paths.
This allows the assertions to be disabled in release builds, so that
the code is faster and smaller, at the expense of not performing the
checks. Assertions can be re-enabled in release builds with the
debug-assertions flag in Cargo.toml, as the top-level Cargo.toml
file does.
2018-03-12 12:38:30 -07:00
Jakob Stoklund Olesen
1bbc529ef9 Improve the variable ordering used by the coloring constraint solver.
The fuzzer bugs #219 and #227 are both cases where the register
allocator coloring pass "runs out of registers". What's really happening
is that the constraint solver failed to find a solution, even when one
existed.

Suppose we have three solver variables:

    v0(GPR, out, global)
    v1(GPR, in)
    v2(GPR, in, out)

And suppose registers %r0 and %r1 are available on both input and output
sides of the instruction, but only %r1 is available for global outputs.
A valid solution would be:

    v0 -> %r1
    v1 -> %r1
    v2 -> %r0

However, the solver would pick registers for the three values in
numerical order because v1 and v2 have the same domain size (=2). This
would assign v1 -> %r0 and then fail to find a free register for v2.

Fix this by prioritizing in+out variables over single-sided variables
even when their domains are equal. This means the v2 gets assigned a
register before v1, and it gets a chance to pick a register that is
still available on both in and out sides.

Also try to avoid depending on value numbers in the solver. These bugs
were hard to reproduce because a test case invariably would have
different value numbers, causing the solver to order its variables
differently and succeed. Throw in the previous solution and original
register assignments as tie breakers which are stable and not dependent
on value numbers.

This is still not a substitute for a proper solver search algorithm that
we will probably have to write eventually.

Fixes #219
Fixes #227
2018-01-19 13:31:26 -08:00
Jakob Stoklund Olesen
dcad3fa339 Fix coloring bug with combined constraints and global values.
The Intel instruction "v1 = ushr v2, v2" will implicitly fix the output
register for v2 to %rcx because the output is tied to the first input
operand and the second input operand is fixed to %rcx.

Make sure we handle this transitive constraint when checking for
interference with the globally live registers.

Fixes #218
2018-01-17 15:51:08 -08:00
Dan Gohman
4d9aedbaca Add a 'clear()' function to Context.
This includes adding `clear()` functions to its (transitive) members.
2017-11-15 11:15:30 -08:00
Dan Gohman
889b06fd16 Replace as casts with type-conversion functions. 2017-11-08 10:48:44 -08:00
Dan Gohman
5d3ae0596c Avoid matching with reference patterns. 2017-11-08 10:43:12 -08:00
Dan Gohman
3ab4349c1b Use Self instead of repeating the type name. 2017-11-08 10:43:11 -08:00
Dan Gohman
8b053aa923 Remove a trivial cast. 2017-11-08 10:40:39 -08:00
Jakob Stoklund Olesen
994af598f5 Avoid interference on CFG edges.
Track allocatable registers both locally and globally: Add a second
AllocatableSet which tracks registers allocated to global values without
accounting for register diversions. Since diversions are only local to
an EBB, global values must be assigned un-diverted locations that don't
interfere.

Handle the third "global" interference domain in the constraint solver in
addition to the existing "input" and "output" domains.

Extend the solver error code to indicate when a global define just can't
be allocated because there are not enough available global registers.
Resolve this problem by replacing the instruction's global defines with
local defines that are copied into their global destinations
afterwards.
2017-10-11 15:38:30 -07:00
Jakob Stoklund Olesen
893a6716c6 Enforce all instruction constraints in iterate_solution().
During iterate_solution(), live-through values may be converted to
solver variables so they can be moved out of the way in order to satisfy
all constraints. Make sure that the instruction's operand constraints
are also considered for these new variables.

Add a program_complete_input_constraints() which turns all the
instruction's input operands into variables with the proper constraints.
That makes it safe for try_add_var() to re-add these values as variables
with looser generic constraints.

The solver's add_var() function is split into three functions: add_var
for use before inputs_done(), and add_killed_var/add_through_var for use
after.
2017-10-09 14:08:37 -07:00
Jakob Stoklund Olesen
4a2bf6d9a6 Use a more compact display of AllocatableSet.
Since only Intel uses named registers, we can use a one-char shorthand
for the registers.
2017-10-09 14:08:37 -07:00
Jakob Stoklund Olesen
b3fa47cacc Add support for emergency spill slots.
- 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.
2017-10-06 10:45:13 -07:00
Jakob Stoklund Olesen
e32aa8ab60 Emergency spilling for the solver's move scheduler.
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.
2017-10-04 17:02:09 -07:00
Jakob Stoklund Olesen
ce4d723a73 Give RegClassData a reference to its parent RegInfo.
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.
2017-10-04 17:02:09 -07:00
Jakob Stoklund Olesen
fb0999ce33 Check the top-level register class for available registers.
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.
2017-10-03 14:12:18 -07:00
Jakob Stoklund Olesen
51a6901a7f Implement coloring::iterate_solution().
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.
2017-09-29 14:55:35 -07:00
Dan Gohman
fe12fe0e63 Avoid unneeded calls to .as_slice(). 2017-09-01 12:15:14 -07:00
Dan Gohman
2efdc0ed37 Update rustfmt to 0.9.0. 2017-08-31 10:44:59 -07:00
Jakob Stoklund Olesen
0deaa616a3 Record identity assignments in regalloc constraint solver.
Fixes #147.

The Solver::reassign_in() method would previously not record fixed
register assignments for values that are already in the correct
register. The register would simply be marked as unavailable for the
solver.

This did have the effect of tripping up the sanity checks in
Solver::add_var() when that method was called with such a "reassigned"
value. The function can be called for a value that already has a fixed
assignment, but the sanity checks want to make sure the variable
constraints are compatible with the existing fixed assignment. When no
such assignment could be found, the method panicked.

To fix this, make sure that even identity reassignments are recorded
in the assignments vector. Instead, filter the identity assignments out
before scheduling a move sequence for the assignments.

Also add some debug tracing to the regalloc solver.
2017-08-29 10:45:33 -07:00
Jakob Stoklund Olesen
9cb0529be4 Move EntityList and SparseMap into the entity module.
These data structures are dependent on EntityRef and EntityMap, so it
makes sense to keep them in the same module.
2017-08-18 16:14:06 -07:00
Jakob Stoklund Olesen
8599372098 Rename the entity_ref module to 'entity'.
This is in preparation for moving a number of data structures into
sub-modules of the 'entity' module:

- EntityList
- EntityMap
- SparseMap
2017-08-18 15:07:21 -07:00
Aleksey Kuznetsov
5fa991e325 Apply conditional compilation of isa targets 2017-08-03 06:28:16 -07:00
Jakob Stoklund Olesen
0d2d1ea8cf Add support for tied operands.
Include a very basic test using an Intel 'sub' instruction. More to
follow.
2017-06-30 13:36:41 -07:00
Jakob Stoklund Olesen
b6cff6a98a Move EntityRef and entity_impl! into a new module.
The EntityRef trait is used by more than just the EntityMap now, so it
should live in its own module.

Also move the entity_impl! macro into the new module so it can be used
for defining new entity references anywhere.
2017-06-20 10:16:27 -07:00
Jakob Stoklund Olesen
96f1228211 Always call reassign_in for register ABI arguments.
Even if an argument is already in the correct register, make sure that
we detect conflicts by registering the no-op move. This also means that
the ABI argument register won't be turned into a variable for the
solver.
2017-06-14 12:10:57 -07:00
Benjamin Bouvier
29dc723e25 Update rustfmt to 0.8.4; (#81) 2017-05-15 15:10:47 -07:00
Jakob Stoklund Olesen
9be262e878 Implement a move resolver for the register constraint solver.
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.
2017-05-11 11:54:02 -07:00
Jakob Stoklund Olesen
b521254149 Solver variables keep track of where they came from.
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.
2017-05-11 11:54:02 -07:00
Jakob Stoklund Olesen
6b4c28d554 Use a constraint solver for register coloring.
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.
2017-05-09 14:48:45 -07:00