Implement new coloring logic with coalescing heuristic
commit02c118192aae7483240e6133cd741fc1d151f274
authorRick Lavoie <rlavoie@fb.com>
Tue, 2 Jul 2019 22:58:41 +0000 (2 15:58 -0700)
committerHhvm Bot <hhvm-bot@users.noreply.github.com>
Tue, 2 Jul 2019 23:03:47 +0000 (2 16:03 -0700)
tree36f924b7144f7878df15aafc1b4d43273d5fef07
parent3a4c9ddbfaa3bfb722838bf1d11f99ae328fb28d
Implement new coloring logic with coalescing heuristic

Summary:
Implement fully the new coloring logic now that physical registers are
not SSAized. Along with it, implement the new coalescing heuristic
which replaces the recursive recoloring pass.

The main idea is that we calculate "penalty vectors" for each
Vreg. Multiple Vregs which are joined by hinted operands may share the
same penalty vector. The penalty vector is a map of physical registers
to penalties, giving an estimate amount of (dynamic) copies which will
be generated if you assign the Vreg to that physical register. The
penalties arise from being live across an instruction writing to a
physical register, or if the Vreg is hinted with a physical
register. The penalty vectors are initially calculated before
coloring. The penalty vectors are mutated as the unit are colored,
reflecting coloring decisions already made.

In addition to the penalty vectors, we implement optimistic
moving. That is, if the penalty vector indicates that it would be most
profitable to assign a Vreg to a particular physical register, but
that register is already occupied, we see if that selection would
profitable still if we moved the occupying Vreg to another physical
register.

This makes the heuristic more powerful in some ways that the recursive
recoloring pass. The old colorer would assign a particular physical
register to a Vreg in a flow insensitive way. That is, that Vreg would
be assigned that register at every point its alive. This is no longer
true, as a Vreg can now shuffle around to different physical registers
at different points in the program. This is particularly profitable
when a Vreg is alive in both a cold and hot region, since we can
shuffle the Vreg around in the cold region without affecting its
assignment in the hot one. The downside of this is extra complexity,
as need extra bookkeeping. Another nice aspect is the exact same logic
can be used to ensure that physical registers are always available
when an instruction writes specifically to them. If not, we can just
move the occupying Vregs to something else.

The weights for this heuristic are now taken from the block weights
directly, where appropriate. Otherwise they're approximated from the
region like before.

The colorer also now rewrites the instructions directly, rather than
postponing it to a separate pass. This is easier because of the flow
sensitive nature of the colorings now, and is more efficient.

Spill slots are still assigned in a manner similar to how recursive
recoloring did it (by building chunks). This is fine because spilling
is relatively rare, so its not a computational burden (and shuffling
spills are more expensive).

Reviewed By: mxw, mofarrell

Differential Revision: D15865637

fbshipit-source-id: 3cb2e4fc594a211198121c5dea38003110104769
hphp/runtime/vm/jit/vasm-graph-color.cpp